[英]How to automatically remove remote-tracking branch when the corresponding local branch is removed using git
[英]Are their names the same: a local-tracking branch, the corresponding remote-tracking branch, and the corresponding remote branch being tracked?
远程跟踪分支的名称和跟踪的相应远程分支是否必须相同?
如果它们可以有不同的名称,那么git fetch
如何匹配这两个分支呢? ( git fetch
的典型refspec
是+refs/heads/*:refs/remotes/remote/*
)
如果我是正确的,给定远程跟踪分支,我们可以创建一个与之关联但具有不同分支名称的本地跟踪分支。 (通过git checkout
的-b
选项)
此外,如果跟踪的远程跟踪分支和相应的远程分支的名称相同, git push
如何匹配本地跟踪分支和远程分支? ( git push
的典型refspec
是+refs/heads/*:refs/heads/*
)
远程跟踪分支的名称和跟踪的相应远程分支是否必须相同?
不会。但是,让它们不匹配会导致很多痛苦(我没有在推动方面进行测试)。
如果它们可以有不同的名称,那么git fetch如何匹配这两个分支呢? (
git fetch
的典型refspec是+refs/heads/*:refs/remotes/remote/*
)
你可能有多个fetch =
行,所以你可以这样做:
[remote "strange"]
fetch = +refs/heads/master:refs/remotes/strange/surprise
fetch = +refs/heads/other:refs/remotes/strange/surprise2
但请注意,你不能再在任何额外的fetch refspecs的左边使用refs/heads/*
,因为那将匹配master
和other
并且(可能)将它们映射到除surprise
和surprise2
之外的名称,并且git fetch
aborts with这种情况下的错误消息。 这有效地强制您列出您希望从给定遥控器复制的每个refs/heads
名称(在这种情况下strange
)。
(正如我所说的,我没有用push来测试它,我不知道push是否遵循与fetch相同的映射规则。最近有一些变化,大约2.5左右,以更好地处理“三角形”工作流程例如,你从localmirror
获取并推送到centralserver
。其中一个变化是为推送遥控器添加相同类型的名称映射。据推测,在这个新代码进入之前,做这种推动带来了更多的痛苦,甚至可能没有三角形工作流程;并且可能现在它工作得更好....)
我们可能称之为“愚蠢的重命名技巧”,我的建议是:不要使用它们。 :-)我认为它们可以与大多数命令一起正常工作,并且与其他命令一起失败,但我不能指出任何特定的失败例子(只是模糊的回忆我以前做过的事情)。
如果我是正确的,给定远程跟踪分支,我们可以创建一个与之关联但具有不同分支名称的本地跟踪分支。 (通过git checkout中的-b选项)
是; 这适用于各种本地工作。 同样,我会避免使用“本地跟踪分支”这个短语,并且只是说“带有上游的本地分支”,因为这是git文档从大约1.7开始移动的方向(见下文)。
请记住,“本地分支$branch
的上游”由以下产生:
git config --get branch. $branch .remote
获取远程名称git config --get branch. $branch .remote
git config --get branch. $branch .remote
,和 git config --get branch. $branch .merge
映射branch-name git config --get branch. $branch .merge
git config --get branch. $branch .merge
通过该遥控器的fetch =
git config --get branch. $branch .merge
。 因此,假设我们已经创建了两个本地分支test1
和test2
并具有以下内容:
$ git config --get branch.test1.remote
origin
$ git config --get branch.test1.merge
refs/heads/test
$ git config --get branch.test2.remote
origin
$ git config --get branch.test2.merge
refs/heads/test
test1
和test2
引用了refs/heads/test
,它是另一个 git资源库中一个分支的名称,它将通过名称origin
来定位:这就是为什么我们需要通过fetch =
map来运行它们origin
。
在没有愚蠢的重命名技巧的情况下,“映射通过”部分保留了分支名称部分( refs/heads
之后的所有内容)不变,只是替换了中间位,因此refs/heads/test
成为refs/remotes/origin/test
。 这很容易做出假设。 我相信一些懒惰的脚本编写者(包括我自己过去)可能已经使用了这段shell脚本代码:
fullbranch=$(git rev-parse --symbolic-full-name $branch) || exit 1
remote=$(git config --get branch.$branch.remote)
rmtbranch=refs/remotes/$remote/$branch
它不仅假设缺乏愚蠢的重命名技巧,它甚至假设如果我们在分支test1
,上游必须是origin/test1
,而不是origin/test
。 略微不那么懒惰的脚本编写者(包括我自己过去)然后必须修复他们的脚本,例如:
fullbranch=$(git rev-parse --symbolic-full-name $branch) || exit 1
remote=$(git config --get branch.$branch.remote)
theirname=$(git config --get branch.$branch.merge)
rmtbranch=refs/remotes/$remote/${theirname#refs/heads/}
现在假设origin
上的refs/heads/test
映射到本地存储库中的refs/remotes/origin/test
。
添加愚蠢的重命名技巧意味着我们根本无法轻易找到实际的上游名称,但各种命令(例如, git merge
, git rebase
)会自动找到正确的上游名称。 为了使脚本更容易,git 1.7.0版增加了@{upstream}
符号:你现在可以简单地写$branch @{upstream}
。 git解析器为您查找上游,上面(损坏的)脚本片段可以重写为:
rmtbranch=$(git rev-parse --symbolic-full-name $branch@{upstream}) || exit 1
这对于fetch来说都很好,但是推送呢? 好吧,如果你正在推送你正在推送的同一个遥控器,你就是做同样的事情。 但是你可以为任意数量的原因,1拆起来:从存储库中取出F
推到仓库P
。 在这种情况下,我们可能需要F
和P
不同映射。
Git 2.5引入了@{push}
,正如VonC在一些早期的SO线程中所指出的那样,我无法随意找到,并在此github博客中发布 。 新的@{push}
表示法只是从使用上游提取切换到使用推送上游,即使用P
映射而不是F
映射。
还有一个很好的问题,这是你最后一个问题:
此外,如果跟踪的远程跟踪分支和相应的远程分支的名称相同,git push如何匹配本地跟踪分支和远程分支? (git push的典型refspec是
+refs/heads/*:refs/heads/*
)
我对git 2.5的回答是新的推送内容:我确实不知道,但是你的“典型refspec”不再是默认值(因为git 2.0)。 当您运行git push
没有的Refspec参数,git的查找你的push.default
设置(与一群多个可选的设置一起,但push.default
实际上是要求2)。 它有五个可能的值,只有其中一个 - 不是refs/heads/*:refs/heads/*
的默认值。
其中一个设置是upstream
,该设置通过map函数运行当前分支的merge
设置(可能是在git 2.5及更高版本中,通过新的单独推送映射(如果存在),或者通过获取映射)。
1一个原因是使用拉取请求存储库,如链接的github博客文章中所示。 另一种方法是从本地镜像获取(如在大型企业设置中使用本地镜像用于各种分支机构),但是推送到单个中央服务器(公司指定的“主”站点,所有本地镜像实际上都是镜像)。
2如果你没有设置push.default
,git会发出很多烦人的文字。 关闭它的最好方法是设置push.default
,这意味着你需要(在某种意义上)“设置”它。 而且,自从git 2.0以来,默认设置(如果你还没有设置)很simple
,禁止愚蠢的重命名技巧。
refspec
至于你说其refspec
它位于您的.git / config文件中。
git配置文件包含有关refspec
的信息
为了看到你所描述的内容,请执行以下操作:
// Checkout master
git checkout master
// rename the master branch to a new name
git branch -m <old name> <new name>
// View the .git/config file and you will see the the new branch is still
// pointing (tracking) to the master branch, just like you described
使用refspec
您可以控制pull/push
将引用哪个分支。
git branch -u <upstream>/<branch name>
当git push [$there]
没有说要推送什么时,我们到目前为止已经使用了传统的“匹配”语义(只要那里已经有相同名称的分支,所有分支都被发送到远程)。 在Git 2.0中,默认是现在的“简单”语义,它推动:
只有当前分支到具有相同名称的分支,并且仅当当前分支设置为与该远程分支集成时,如果您正在推送到同一个远程获取; 要么
只有当前分支到具有相同名称的分支,如果您要推送到通常不从中获取的远程。
您可以使用配置变量push.default
来更改此设置。
如果您是想要继续使用matching
语义的老计时器,则可以将变量设置为“匹配”,例如。 阅读文档了解其他可能性。
来自@codeWizard的答案是完整而完整的答案,但简单的英语答案(基于您对其答案的评论问题)是:
1真的是两个问题。 第一个答案是:不,它们不必具有相同的名称。 第二个答案是: fetch
实际上并不映射本地和远程分支。 所有fetch
(使用您的示例 - 默认值)都会询问远程的refs/heads/*
列表以及关联的blob,并使用远程名称将refs存储在refs/remotes/*
root中。
2本地分支到远程分支的映射由使用显式的pull
和fetch
调用控制,或者在.git/config
设置所有内容。 在git/config
,pull行为由$branch.merge
控制,但push由push.default
控制:默认情况下,它将推送到远程上与本地相同的分支名称。 如果将其设置为upstream
那么它将使用$branch.merge
作为推送目标。
演练:
mkdir t1 && cd t1
git init
touch file
git add file
git commit -a -m "remote"
cd ..
git clone t1 t2
cd t2
git branch -a # you should see 'master' and 'origin/master'
git branch -m master local
git pull # Should say "Already up-to-date"
git branch -a # you should now see 'local' and 'origin/master'
git push # damn! It pushed 'local' to 'origin/local'!
git push origin :local # delete 'origin/local'
git config push.default upstream # tell git to use 'local.merge' as the push target
git push # Now it should say "Everything up-to-date"
毕竟这个你的t1
配置应该是这样的:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
t2
应如下所示:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = /nas/src/t/t1
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "local"]
remote = origin
merge = refs/heads/master
[push]
default = upstream
我知道这是一个老问题,但明确的答案是正确的git-config手册页(输入git help config
或man git-config
)。 关于如何使用以下信息的示例就在报价之后:
push.default
如果没有明确给出refspec,则定义git push应采取的操作。 不同的值非常适合特定的工作流程; 例如,在纯粹的中心
工作流(即获取源等于推送目标),上游可能就是你想要的。 可能的值是:
什么都没有 - 除非明确给出refspec,否则不要推送任何东西(错误输出)。 这主要是针对那些希望通过永远存在而避免错误的人
明确。
·current - 推送当前分支以更新接收端具有相同名称的分支。 适用于中央和非中央工作流程。
·上游 - 将当前分支推回到分支,该分支的更改通常集成到当前分支(称为@ {upstream})。 仅此模式
如果您要推送到通常从中拉出的相同存储库(即中央工作流),这是有意义的。
·简单 - 在集中式工作流程中,像上游一样工作,如果上游分支的名称与本地分支不同,则可以更加安全地拒绝推送。
当推送到与您通常拉出的遥控器不同的遥控器时,请作为当前工作。 这是最安全的选择,适合初学者。
此模式已成为Git 2.0中的默认模式。
·匹配 - 推送两端具有相同名称的所有分支。 这使得您要推送的存储库记住将被推出的分支集
(例如,如果你总是在那里推动maint和master而没有其他分支,你推送的存储库将拥有这两个分支,以及你的本地maint和master
将被推到那里)。
要有效地使用此模式,您必须确保在运行git push之前准备好推出所有要推出的分支,作为整个点
此模式允许您一次性推送所有分支。 如果你通常只在一个分支上完成工作并推出结果,而其他分支则是
未完成,这种模式不适合你。 此模式也不适合推入共享中央存储库,因为其他人可能会在那里添加新的分支,或者
更新控制范围之外的现有分支的提示。
这曾经是默认值,但不是因为Git 2.0(简单是新的默认值)。
因此,要将git设置为适合您的配置,请输入:
git config push.default nothing
用您的首选配置替换nothing
。 如果您希望它是全局的(本地计算机上的所有存储库),请添加全局选项:
git config --global push.default nothing
回答你的问题:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.