当存在同名文件时,如何在Git中切换分支

161

我在我的 Git 仓库中有一个名为 xyz 的文件。巧合的是,我还有一个名为 xyz 的分支。现在我在 master 分支上,但我想切换到 xyz 分支。需要使用的命令很简单:

$ git checkout xyz

但是这将会将文件 xyz 检出到当前 HEAD。我如何将我的分支更改为分支 xyz

4个回答

280

正如提交 a047faf所示(适用于 git 1.8.4.3+),你也可以尝试:

git checkout xyz --

(注意:自Git 2.21起,Q1 2019,错误消息将更清晰)

这将明确表明xyz部分是分支或提交,而--后的所有内容必须是路径(这里未提供路径)。有关“双破折号约定”的更多信息,请参见此处

如果您尝试不使用'--',那可能会或可能不会奏效,如“为什么git checkout <remote_branchname>不会创建新的跟踪分支?”中所示:

git checkout name执行以下操作:

  • 如果它是本地分支或显式远程分支,则切换到它。
  • 如果它是已跟踪的路径,则重置它
  • 如果它是远程分支,则创建跟踪分支并切换到它。

其行为并不总是相同的。因此需要'--'来提供明确定界。


更新于2019年8月,Git 2.23+

git checkout太令人困惑了,已被替换为:

  • git switch:意味着git switch xyz即使您有一个文件xyz也可以工作,
  • git restore:意味着git restore xyz即使您有一个分支xyz也可以工作。

此外,如我在“为什么我的Git存储库进入了分离的HEAD状态?”中所解释的,不再出现意外的分离的HEAD。


2
更好的解决方案,我认为是:https://dev59.com/jmkw5IYBdhLWcg3w9vJ-#9537923 - BobbyA
2
@BobbyA 我已经更新了答案,并提供了更好的回答。 - VonC
1
为什么不使用 git checkout -- docs 呢?OpenGroup Guideline 10 中提到了 -- 作为选项结束参数,但我不明白为什么它可以在该命令的末尾工作,而不是在 docs 之前 - Fernando Basso
2
@FernandoBasso 在答案中,xyz 是一个分支的名称,而不是路径,因此在 xyz 之后要加上 --。但现在,你不需要再问自己这个问题了:使用 git switch(仅限分支)或 git restore(仅限路径/文件)即可解决。git checkout 已经过时,不应再使用。 - VonC

10

VonC的解决方案是可行的,但我永远记不住语法,所以我通常使用更简单的解决方案:

$ (cd somedir && git checkout my-branch)

或者,如果您没有任何子目录:
$ (cd .git && git -C .. checkout my-branch)

这样更容易记住,而且它有效 ;-)


5
Git 2.21 (Q1 2019, 4+ 年后) 将澄清错误信息并提出建议 "git checkout frotz" (最初我建议不加双破折号)通过确保 'frotz' 不能同时被解释为修订版本和路径来避免歧义
dwimming创建一个本地分支'frotz',基于远程跟踪分支'frotz'时,此安全性已更新,还会检查远程唯一的跟踪分支 'frotz'。
注:{{link3:"dwim"(下文中使用)是“做我想做的事”},当计算机系统尝试预测用户的意图时,自动纠正微不足道的错误而不是盲目执行用户的显式但可能不正确的输入。

查看 提交记录 be4908f (2018年11月13日) 由 Nguyễn Thái Ngọc Duy (pclouds) 提交。
(由 Junio C Hamano -- gitster -- 合并于 提交记录 8d7f9db, 2019年01月04日)

checkout: 消除模棱两可的跟踪分支和本地文件

When checkout dwim is added in commit 70c9ac2, it is restricted to only dwim when certain conditions are met and fall back to default checkout behavior otherwise.

It turns out falling back could be confusing.

One of the conditions to turn

git checkout frotz

to

git checkout -b frotz origin/frotz

is that frotz must not exist as a file.

But when the user comes to expect "git checkout frotz" to create the branch "frotz" and there happens to be a file named "frotz", git's silently reverting "frotz" file content is not helping.
This is reported in Git mailing list and even used as an example of "Git is bad" elsewhere.

We normally try to do the right thing, but when there are multiple "right things" to do, it's best to leave it to the user to decide.

Check this case, ask the user to to disambiguate:

  • "git checkout -- foo" will check out path "foo"
  • "git checkout foo --" will dwim and create branch "foo" 6

For users who do not want dwim, use --no-guess. It's useless in this particular case because "git checkout --no-guess foo --" will just fail.
But it could be used by scripts.

git checkout的man页面现在包括:

--no-guess:

Do not attempt to create a branch if a remote tracking branch of the same name exists.


在 Git 2.26 之前(2020 年第一季度),当 X 不是本地分支但可以命名多个远程跟踪分支时,“git checkout X”无法正确失败(即可作为创建相应本地分支的起点进行智能推测),这已得到纠正。

查看提交 fa74180提交2957709(2019年12月30日),由Alexandr Miloslavskiy (SyntevoAlex)进行修改。
(由Junio C Hamano -- gitster --合并于提交d0e70cd,2020年2月5日)

checkout: 不要在存在歧义的跟踪分支上恢复文件

Signed-off-by: Alexandr Miloslavskiy

为了更容易理解,这里列出了现有的好的场景:
1. 没有文件“foo”,没有本地分支“foo”,只有一个远程分支“foo”。 2. git checkout foo将创建本地分支foo,请参见commit 70c9ac2 abovediscussed here
以及
1. 有一个文件“foo”,没有本地分支“foo”,只有一个远程分支“foo”。 2. git checkout foo会报错,请参见commit be4908f above
此补丁防止以下情况发生:
1. 有一个文件“foo”,没有本地分支“foo”,有多个远程分支“foo”。 2. git checkout foo将成功...还原文件foo的内容!
也就是说,添加另一个远程分支会突然改变行为,最好的情况是让用户注意到这一点,最坏的情况是用户可能完全没有注意到这一点。
请参见commit be4908f above,其中提供了一些真实的抱怨。
据我所知,commit be4908f above中的修复(discussed here)忽略了多个远程分支的情况,并且从未打算回退到还原文件的整个行为:
1. commit 70c9ac2 above引入了意外的行为。
在此之前,从非ref到pathspec有回退。这是合理的回退。
之后,又从模糊的远程分支到pathspec有了另一个回退。
我知道这是一个复制和粘贴的疏忽。 2. commit ad8d510,来自“Can't do a checkout with multiple remotes”,以及discussed here,注意到了意外的行为,但选择了半文档化它而不是禁止它,因为补丁系列的目标集中在其他方面。 3. commit be4908f above添加了die(),当分支和文件之间存在歧义时。
多个跟踪分支的情况似乎被忽视了。
新的行为:如果没有本地分支并且有多个远程候选项,则只需die(),不要尝试还原文件,无论它是否存在(防止意外)或不存在(改进错误消息)。

在 Git 2.30 (2021年第一季度) 中, "git checkout"(man) 学会使用checkout.guess配置变量,并相应地启用/禁用其 "--[no-]guess"选项。

请查看 提交64f1f58 (2020年10月7日) 和 提交ef09e7d (2020年10月6日),作者为 Denton Liu (Denton-L)
(由Junio C Hamano -- gitster --提交0e41cfa中合并,2020年10月27日)

checkout: 学习尊重checkout.guess

Signed-off-by: Denton Liu

git checkout/switch的当前行为是默认启用--guess
然而,有些用户可能不希望自动发生这种情况。
不要强制用户每次手动指定--no-guess,而是教授这些命令checkout.guess配置变量,以便用户可以设置默认行为。

教授完成脚本识别新的配置变量,并在其设置为false时禁用DWIM逻辑。

git config现在在其手册页中包括:

checkout.guess

git checkoutgit switch中的--guess--no-guess选项提供默认值。请参见git switchgit checkout

git checkout现在在其手册页中包括:

--guess 是默认行为。使用 --no-guess 来禁用它。

可以通过 checkout.guess 配置变量设置默认行为。

git switch 现在在其手册页面中包含以下内容:

可以通过 checkout.guess 配置变量设置默认行为。


-3

你错了。它将检出分支xyz。

要检出文件,您需要使用命令git checkout -- xyz。 如果没有同名的分支,Git只允许您为文件提供快捷方式。

有关详细信息,请参见git checkout --help


11
如果这种情况没发生过,我为什么要问这个问题?这种情况正在发生在我身上。通常在检出一个分支时,会返回Switched to branch 'xyz'的响应,但是在我的情况下,没有任何响应。这与检出文件时的情况相同。此外,我查看了git branch -va的输出结果,得出结论没有发生这样的更改。 - venky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接