git - Git fetch 未按预期工作“:gone]”未添加到分支描述中
问题描述
如果我们执行git fetch -p
,或者git fetch --prune
如果在远程删除,它将修剪分支。
执行此命令后,如果我们这样做git branch -vv
,假设显示: gone]
从远程删除的本地分支。
就我而言,有时它会按预期工作,但并非总是如此。有时它不会添加: gone]
到远程删除的分支中。
我的目标是在远程删除本地分支时删除分支。
我想知道为什么会这样?
解决方案
仅仅因为其他人删除了他的名为 X 的分支而删除名为 X 的分支并不一定是明智的。如果您正在开发一个新功能并且您调用了它feat
,并且 Bob 放弃了他正在调用的新功能feat
并且 Bob 删除了 Bob 的feat
,这并不意味着您应该删除您的feat
!
除此之外,让我们看看分支的一个特殊功能。此特殊功能仅适用于(本地)分支,不适用于origin/master
Git 的哪些部分调用远程跟踪分支以及在git branch -r
输出下列出的部分。1 它们实际上有几个特殊功能——例如,您可以使用“进入”分支git checkout
,如 aftergit checkout master
中,git status
命令将显示on branch master
。但这不是我在这里要说的特殊功能。
我们在这里关心的特殊功能是它们可以具有上游设置。也就是说,你master
的上游可以有一个,而且只有一个develop
,如果你有一个develop
,你的上游可以有一个feat
,如果你有一个,你的上游可以有一个,依此类推。您在这里的选择是有上游,或者没有上游。对于每个分支,您一次选择一个分支。
要取消分支的上游设置,请使用. 现在命名的分支没有上游。如果您省略该部分,则它适用于当前分支,即您所附加的分支。这不是取消设置的唯一方法,但通常是最好的方法。git branch --unset-upstream name
name
name
HEAD
要设置或更改分支的上游设置,请使用. 现在命名的分支有一个上游;上游是你给出的论点。与 一样,省略表示当前分支(您不能省略)。同样,这不是设置它的唯一方法,但通常它是最好的方法,因为该命令会在让您设置它之前验证参数是否合理。git branch --set-upstream-to=upstream name
name
upstream
--unset-upstream
name
upstream
git branch
upstream
有时分支机构从一开始就有上游设置,有时则没有。我们稍后会看看何时以及为什么。
1我已经到了尝试避免远程跟踪事物的分支一词的地步。我现在只调用远程跟踪名称,因为它们与本地分支名称非常不同。请注意git fetch -p
, 或git remote prune origin
或 设置fetch.prune
为true
仅影响这些远程跟踪名称。
究竟什么是上游?
上游只是另一个分支名称——在这里,分支名称是指本地分支,如master
or develop
,或远程跟踪名称,如origin/master
. 因此,如果您愿意,可以将上游develop
设置为 to或 to或 to 。该操作将让您设置任何存在的东西,并且在 Git 看来,这在这里是有意义的。master
origin/master
origin/develop
git branch --set-upstream-to
Git在这里有一个奇怪的缺陷。这部分是历史性的。回到古代,Git 没有遥控器——没有——所以origin
Git 也没有远程跟踪名称,如果没有origin
,就不可能有origin/master
。但部分原因是一个简单的事实,您可能有也可能没有,甚至origin/xyz
可能origin/xyz
在您在分支上努力工作时离开xyz
(因为 Bob认为您已经完成并xyz
在原点上删除了)。
简单地说,缺陷是,您设置的上游(在它存在时返回,git branch --set-upstream-to
因此让您设置它)现在可能已经消失了。当您: gone
在git branch -vv
输出中看到时就是这种情况。在过去的某个时候,您告诉您的Git,您的分支xyz
应该origin/xyz
作为其上游,并且origin/xyz
当时存在。因此git branch
验证一切都很好并进行了设置。但是现在名称已经消失了,因此该设置不再有效并git branch -vv
记下这一点。
实际上,分支的上游设置由两部分组成,您可以使用 配置其中一个或两个部分git config
,甚至可以将您的配置带入您选择的编辑器 ( git config --edit
) 并直接对其进行处理:
[branch "master"]
remote = origin
merge = refs/heads/master
在这个特定的存储库中,这个设置表示上游master
是origin/master
. 你可能认为你可以只取线中的origin
部分和线中的部分,但这是一种陷阱:有一个秘密的复杂映射。要查找某个分支的上游设置,请使用后缀:remote =
master
merge =
git rev-parse
@{upstream}
$ git rev-parse --symbolic-full-name master@{upstream}
refs/remotes/origin/master
这适用于上游也设置为另一个本地分支的分支。
不管怎样,因为它是这样的两个部分,你可以在正常git branch --set-upstream-to
机制之外乱用它,你可以打破上游设置。如果你确实破坏了它——如果你将它设置为无意义的东西——<code>git branch -vv 会将上游列为“已消失”,使用与正常时相同的技术,日常 Git 操作会破坏它,因为它确实消失了。Git 不关心它为什么坏了,只关心它现在坏了还是没坏:如果它现在坏了,Git 说“gone”,否则假装它没有设置。
请注意,这也意味着如果 Bob不小心xyz
从中删除origin
并且 Bob 修复了他的错误并xyz
放回了,您的 Git 可以从“消失”变为“没有消失,一切都很好” git fetch
。这也是你不应该让你的 Git 删除你的本地分支的另一个原因,因为有人在其他地方弄乱了其他Git。
上游有什么好处?
上游设置仅提供一些次要功能。有时,有些人真的很喜欢这些功能,但它们从来都不是必需的。所以从某种意义上说,上游一点也不好。只要你避免使用它们,你就不必使用它们git pull
。
但是,这些功能是:
更容易推送:如果你想在没有额外参数的情况下运行,标准
push.default
设置要求你的分支有一个上游。git push
更容易的合并和变基:
git merge
andgit rebase
命令可以使用它。包装器git pull
,你不必使用,我建议避免使用它,需要上游。包装器首先git fetch
为您运行,然后立即(在您有机会根据git fetch
所做的决定它是否是一个好主意之前)运行git merge
或git rebase
为您运行。更有用
git status
:第一行git status
告诉你是否处于分离 HEAD 模式,如果不是,你在哪个分支上。有一个上游意味着有第二条线,就在你所在的分支的那条线之后,当你在一个分支上时。第二行将分支与其上游进行比较,并告诉您它是否与其上游“最新”。
这就是上游的好处:它使一些事情变得更容易和/或更有用。但是您一次仅限于一个上游。有时,您可能希望获得与git status
任意一对名称相同的第二行输出。有一种方法可以做到这一点git rev-list --count
,但我们将把它留给其他 答案。
为什么有些分支已经有上游集,而有些则没有?
在 Git中有很多方法可以创建分支。每一种方法都与其他替代方法略有不同——这就是这些方法存在的原因,但也给你带来了这种混乱。
创建新分支的两个主要命令是git branch
和git checkout
。当您用于git branch
创建新分支时,您始终可以完全控制:
git branch --track newbranch origin/upstreamname
或者:
git branch --no-track newbranch origin/upstreamname
尽管 upstream 被称为upstream,但控制它的参数被拼写--track
——另一个历史事故或错误,真的。
如果您不使用--track
或--no-track
,git branch
请使用您在配置时选择的默认值branch.autoSetupMerge
。请参阅下文了解这意味着什么。
当你使用 时git checkout
,你可以使用--track
or --no-track
,但如果你不使用任何一个选项,它就会变得更加复杂。branch.autoSetupMerge
设置仍然很重要,但是......好吧:
git checkout -b newbranch
创建newbranch
,但从创建它HEAD
,所以它不设置上游。也就是说,新名称newbranch
现在标识了HEAD
在此之前标识的相同提交。git checkout -b newbranch origin/name
创建newbranch
并使用. 也就是说,新名称现在标识与. 这符合您的配置。origin/name
newbranch
origin/name
branch.autoSetupMerge
git checkout -b newbranch existing-branch
创建newbranch
,existing-branch
用作其起点。也就是说,新名称和现有名称现在标识相同的提交。这也符合您的branch.autoSetupMerge
配置,但请参阅下文了解我将其分开的原因。git checkout name
要么使用现有的name
,要么创建一个名为name
using的新分支。如果它创建一个新分支,它会服从.origin/name
branch.autoSetupMerge
请注意,这将永远不会使用本地分支名称创建新分支,即,它不能创建具有另一个本地分支作为其上游的本地分支。如果是这样的话,两个 *
name
* 将是相同的,所以定义的分支已经存在,所以它只是检查本地分支而不创建任何东西。git checkout --track origin/name
创建一个名为的新分支并name
设置其上游。git checkout --no-track origin/name
创建一个名为的新分支name
并确保它没有上游。
所以,如您所见,这很复杂!创建分支的确切方法部分确定它是否具有上游,其余的确定基于您的branch.autoSetupMerge
配置。此设置具有三个可能的值:
true
:当起点是远程跟踪名称时设置上游。false
: 不要设置上游。always
:当起点是远程跟踪名称或(本地)分支名称时设置上游。
如果您根本没有设置,默认设置branch.autoSetupMerge
是假装您将其设置为true
. 因此,默认情况下,所有这些分支创建选项的行为就像您所说的--track
,如果您给它们一个origin/*
名称或任何其他远程跟踪名称作为它们的起点。即使起点只是隐含的,也是如此,如:
git checkout develop
您没有本地但有远程跟踪的情况:这会从您的远程跟踪创建您的新本地,如果是- 包括如果您根本没有设置它 - 现在您的“轨道” - 已经作为它的上游——你的.develop
origin/develop
develop
origin/develop
branch.autoSetupMerge
true
develop
origin/develop
概括
您的一些分支机构设置了上游。哪些分支有上游,这些上游是什么,取决于您,由您的配置和/或命令行选项和/或附加git branch --set-upstream-to
或git branch --unset-upstream
命令控制。
那些确实设置了上游的分支将获得一些有用的功能。如果通过任何过程设置的上游“消失”,将git branch -vv
列出您当地的分支机构并说它们的上游“消失”。其他 Git 命令只会假装您取消设置它们的上游。如果上游再次回来,上游将恢复其用途。
仅因为其上游已消失而删除本地分支是错误的。删除它,因为你已经完成它很好。如果你已经完成了它们,你不需要有一个名为的本地分支develop
,甚至不需要一个名为的分支,即使它们仍然作为 upstream或names存在。你可以只使用来引用你的 Git 的记忆——你根本不需要拥有自己的记忆。master
origin/develop
origin/master
origin/master
master
origin
master
有时,由于某些潜在原因,您完成了一个分支,这也意味着上游将要消失或已经消失。在这种情况下,删除你的本地分支是好的——你删除它是因为你已经完成了它。它将被删除origin
或已经被删除的事实在origin
这里无关紧要!
推荐阅读
- tomcat - 我的 Tomcat RewriteRules 没有被正确读取
- networking - 用户的 IP 地址可以在浏览会话中使用吗?
- r - 与 R 中的“ifelse”相比,创建新变量的更好方法是什么?
- java - 有没有办法检查某些生成的代码在不使用 implements 关键字时是否遵守接口?
- docker - Docker 容器作为默认应用程序
- mongodb - 在集合中的两个数据之间查找两个日期
- php - 在运行在树莓派上的网站上使用 youtubes api
- amazon-web-services - 在 AWS Beanstalk 上运行 .net 核心 Web 应用程序 - 文件写入权限
- python - 磁力计的校准没有给出预期的结果
- haskell - 如何在 Haskell 中实现`assertFail`?