一尘不染

被 git checkout 弄糊涂了

git

我是 git 新手,并试图围绕分支的工作方式进行思考。根据文档 git checkout

更新工作树中的文件以匹配索引或指定树中的版本。如果 >no 给出路径,git checkout 也会更新 HEAD 以将指定的分支设置为 >current 分支。

因此,据我了解,我工作的目录中的文件(我在其中执行 git init 的文件)应该根据我所在的分支而改变。我很困惑,因为当我在分支之间切换时不会发生这种情况。我在切换分支之前所做的编辑存在于我切换到的分支中。我做错了什么还是 git checkout 不能以这种方式工作而我只是误解了文档?


阅读 171

收藏
2022-05-07

共2个答案

一尘不染

Git 2.23 承认了这种混淆。
Git 2.23(2019 年第三季度)将替换git checkout为两个新命令

  • git switch
  • git restore

参见提交97ED685提交D16DC42提交BCBA406(2019年6月20日),提交4E43B7F提交1235875提交80F537F提交FC991B4提交FC991B4提交75F4C7C提交4DF3EC 提交4DF3EC 提交2F0896E ,提交A5E5E5 E5E5 E5E5 FIST 343,339,第339页,第3439页,第339页,第339页,第339页,第339页,第3439页,第3439页,第3439页,339.139139,339.339.339 ,第3391页。 ,提交 a6cfb9b提交 be8ed50提交 c9c935f提交 46e91b6(2019 年 4 月 25 日),和提交 328c6cb(2019 年 3 月 29 日),由Nguyễn Thái Ngọc Duy ( pclouds)撰写。
(由Junio C Hamano 合并 – gitster提交 f496b06中,2019 年 7 月 9 日)

checkout: 将其中的一部分拆分为新命令 ‘ switch

git checkout“做太多事情是许多用户困惑的根源(有时甚至会咬旧的计时器)。
为了解决这个问题,该命令将分为两个新命令:切换和恢复。旧的“ git checkout”命令仍然存在,直到所有(或大多数用户)都厌倦了它。

和:

switch:如果正在进行某些操作,则拒绝

除非您知道自己在做什么,否则切换到另一个分支做某事然后切换回来可能会令人困惑。更糟糕的是,你甚至可能忘记你正处于某事的中间。当您意识到时,您可能已经完成了大量工作,并且很难再回头。

一个新的选项--ignore-in-progress被考虑过,但被放弃了,因为不清楚应该发生什么。
有时您可以切换并安全返回并恢复操作。有时不是。
并且git-checkout行为是自动清除合并/恢复/樱桃挑选,这使它更加混乱。
请参阅此讨论

我们将来可能会重新访问并添加此选项。
但是现在要安全行事,不要允许它(你甚至不能用 跳过这个检查--force)。
建议用户自行取消操作(希望他们考虑后果,不要盲目输入命令),或者创建单独的工作树而不是切换。

第三个选项是好旧的“ git checkout”,但没有提到。


git switch手册页

描述

切换到指定分支。
更新工作树和索引以匹配分支。
所有新的提交都会被添加到这个分支的顶端。

可选地,可以使用 , 自动从同名的远程分支创建一个新分支-c-C请参阅),或者使用, 以及切换--guess将工作树与任何分支分离。--detach

切换分支不需要干净的索引和工作树(即与 相比没有差异HEAD)。
但是,如果操作导致本地更改丢失,则操作将中止,除非使用--discard-changesor另有说明--merge


例子

以下命令切换到“ main”分支:

$ git switch main

在错误的分支中工作后,将使用以下方法切换到正确的分支:

$ git switch mytopic

但是,您在本地修改的文件中的“错误”分支和正确的“ mytopic”分支可能会有所不同,在这种情况下,上述切换将失败,如下所示:

$ git switch mytopic error: You have local changes to 'frotz'; not switching branches.

您可以将-m标志提供给命令,该命令将尝试三向合并:

$ git switch -m mytopic Auto-merging frotz

在这种三向合并之后,本地修改不会在您的索引文件中注册,因此git diff会向您显示自新分支的尖端以来您所做的更改。

要切换回我们切换到之前的上一个分支mytopic(即“ main”分支):

$ git switch -

您可以从任何提交中增长一个新分支。
例如,切换到“ HEAD~3”并创建分支“ fixup”:

$ git switch -c fixup HEAD~3 Switched to a new branch 'fixup'

如果要从同名的远程分支启动新分支:

$ git switch new-topic Branch 'new-topic' set up to track remote branch 'new-topic' from 'origin' Switched to a new branch 'new-topic'

HEAD~3要在不创建新分支的情况下签出提交以进行临时检查或实验:

$ git switch --detach HEAD~3 HEAD is now at 9fc9555312 Merge branch 'cc/shared-index-permbits'

如果事实证明您所做的一切都值得保留,您可以随时为它创建一个新名称(无需切换):

$ git switch -c good-surprises


请注意错误消息“ git switch”提及其创建新分支的选项,“ -b/-B”选项已显示,其中“ -c/-C”选项应该是,已在 Git 2.27(2020 年第二季度)中更正。

请参阅Denton Liu ( ) 的commit 7c16ef7(2020 年 4 月 30 日。(由Junio C Hamano 合并 – 提交 f4675f3中,2020 年 5 月 8 日)Denton-L
gitster

switch:修复与 -c 和 -C 相关的错误和注释

报告人:Robert Simpson
签字人:Denton Liu
审核人:Taylor Blau

d787d311db (” checkout: split part of it to new command ‘switch’“, 2019-03-29, Git v2.23.0-rc0 –批处理中列出的合并#4 ) 中,该git switch命令是通过提取 in 的通用功能创建cmd_checkout()checkout_main().

但是,在b7b5fce270(“ :和”switch的更好名称,2019-03-29,Git v2.23.0-rc0 –批次 #4中列出的合并)中,“ ”的分支创建和强制创建选项更改为and ,分别。-b``-B``switch``-c``-C

因此,之前提到的错误消息和-b评论-Bgit switch.

对于引用 and 的错误消息,请-b改用-B格式字符串,以便在调用时可以打印-cand 。-C``git switch

2022-05-07
一尘不染

Git 有一个普遍的问题,就是将大约八到十个不同的东西塞进一个命令中。 注意:Git 2.23 正在拆分其中的一些——这当然很有帮助,但也是一个非常大的变化。Git 2.23 是否应该被称为 Git 3.0?Git 2.0 改变了 的行为git add,在我看来这在程度上相似。)另见VonC 的回答

git checkout 可以更新工作树,通常会这样做。

可以改变HEAD点的位置,有时会,有时不会。

可以覆盖您对文件所做的工作,以防您想要重置文件并撤消您的工作。或者它可以拒绝覆盖您对文件所做的工作,使其在更改HEAD更改时保持不变HEAD

关于这一切的事情是,虽然很难描述,但实际上这一切都是有道理的,一段时间后你会习惯这一点,并发现一个命令在大多数情况下都能做到你的意思。(当然,“大多数时候”可能是个问题......)

无论如何,您所看到的特定行为是故意的。假设您从 branch 开始main,就像大多数存储库一样:

$ git clone ...
$ git branch
* main
$

此时您可能会编辑一些文件,开始进行一些工作,然后才意识到:“啊!我的意思是在分支上执行此操作develop!” 1

Git 在这一点上让你做的是切换到(或创建)分支develop,在一个条件下保留你的修改:切换到develop不需要清除它们。假设您修改了文件f1并创建了一个新的2 f2,现在您想要创建并检查develop应该从2 origin/develop开始并自动“跟踪”的本地分支:

$ git checkout develop 

(在非常旧的 git 版本中,您必须拼写 this git checkout -b develop --track origin/develop)。

假设文件在 branch和 branchf1的提示处是相同的。3 这对 git 来说意味着它可以执行此检查,因为它不必修改文件,因此它可以保留您现有的更改。main``develop``f1``f1

如果两个提交中的文件f2相同,或者(在这种情况下)任何一个都不存在,则不会破坏任何文件,并将创建新的本地分支,根据需要修改工作树以匹配- 这不包括修改,也不删除,所以到目前为止你所做的工作保持不变。git checkout``develop``origin/develop``f1``f2

这允许您将新更改提交到本地develop.

(如果您遇到 Git确实必须撤消您的更改,但仍想将它们“移动”到另一个分支的情况,通常的技巧是使用git stash脚本。这听起来很简单,而且git stash通常很容易使用,但它实际上是一个非常复杂的小野兽。不过,在你需要它之前不要担心。)


1这一直发生在我身上。很多时候我想新建一个非跟踪分支,这比切换到现有分支要简单一些,但原理仍然适用。

2这种自动跟踪使您可以更轻松地引入其他人所做的更改:一旦Gitgit fetch使用很多额外的探索,以找出谁的变化去哪里。git merge``git rebase

3由于您是 Git 新手,因此区分“分支的尖端”(即特定提交)和“分支”(实际上是模棱两可的)之类的概念 - 有分支标签然后有由提交树——是你暂时应该忽略的其他东西。主要需要注意的是,在 Git 存储库中有一个名为 的特殊文件,在该特殊文件中,git 会写入字符串or ,以跟踪您所在的分支。所以一旦切换到分支就会写入。HEAD``ref: refs/heads/main``ref: refs/heads/develop``git checkout X``ref: refs/heads/X``HEAD``X

同时,存储库中的另一组特殊文件告诉 Git,分支main指的是那些大而丑陋的 SHA-1 之一,例如c06f8d11b75e28328cdc809397eddd768ebeb533. 这是 branch 的“提示” main。当您在 上进行新提交时main,Git 会创建新的提交“超越旧提示”,然后将新的 SHA-1 写入分支文件,因此这main就是您的新提交。

确切的细节并不重要,提交只是推进分支提示的想法。

2022-05-07