我是 git 新手,并试图围绕分支的工作方式进行思考。根据文档 git checkout
更新工作树中的文件以匹配索引或指定树中的版本。如果 >no 给出路径,git checkout 也会更新 HEAD 以将指定的分支设置为 >current 分支。
因此,据我了解,我工作的目录中的文件(我在其中执行 git init 的文件)应该根据我所在的分支而改变。我很困惑,因为当我在分支之间切换时不会发生这种情况。我在切换分支之前所做的编辑存在于我切换到的分支中。我做错了什么还是 git checkout 不能以这种方式工作而我只是误解了文档?
Git 2.23 承认了这种混淆。 Git 2.23(2019 年第三季度)将替换git checkout为两个新命令:
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 日)
pclouds
gitster
checkout: 将其中的一部分拆分为新命令 ‘ switch‘ ” git checkout“做太多事情是许多用户困惑的根源(有时甚至会咬旧的计时器)。 为了解决这个问题,该命令将分为两个新命令:切换和恢复。旧的“ git checkout”命令仍然存在,直到所有(或大多数用户)都厌倦了它。
checkout
switch
” git checkout“做太多事情是许多用户困惑的根源(有时甚至会咬旧的计时器)。 为了解决这个问题,该命令将分为两个新命令:切换和恢复。旧的“ git checkout”命令仍然存在,直到所有(或大多数用户)都厌倦了它。
和:
switch:如果正在进行某些操作,则拒绝 除非您知道自己在做什么,否则切换到另一个分支做某事然后切换回来可能会令人困惑。更糟糕的是,你甚至可能忘记你正处于某事的中间。当您意识到时,您可能已经完成了大量工作,并且很难再回头。 一个新的选项--ignore-in-progress被考虑过,但被放弃了,因为不清楚应该发生什么。 有时您可以切换并安全返回并恢复操作。有时不是。 并且git-checkout行为是自动清除合并/恢复/樱桃挑选,这使它更加混乱。 请参阅此讨论。 我们将来可能会重新访问并添加此选项。 但是现在要安全行事,不要允许它(你甚至不能用 跳过这个检查--force)。 建议用户自行取消操作(希望他们考虑后果,不要盲目输入命令),或者创建单独的工作树而不是切换。 第三个选项是好旧的“ git checkout”,但没有提到。
除非您知道自己在做什么,否则切换到另一个分支做某事然后切换回来可能会令人困惑。更糟糕的是,你甚至可能忘记你正处于某事的中间。当您意识到时,您可能已经完成了大量工作,并且很难再回头。
一个新的选项--ignore-in-progress被考虑过,但被放弃了,因为不清楚应该发生什么。 有时您可以切换并安全返回并恢复操作。有时不是。 并且git-checkout行为是自动清除合并/恢复/樱桃挑选,这使它更加混乱。 请参阅此讨论。
--ignore-in-progress
git-checkout
我们将来可能会重新访问并添加此选项。 但是现在要安全行事,不要允许它(你甚至不能用 跳过这个检查--force)。 建议用户自行取消操作(希望他们考虑后果,不要盲目输入命令),或者创建单独的工作树而不是切换。
--force
第三个选项是好旧的“ git checkout”,但没有提到。
见git switch手册页
描述 切换到指定分支。 更新工作树和索引以匹配分支。 所有新的提交都会被添加到这个分支的顶端。 可选地,可以使用 , 自动从同名的远程分支创建一个新分支-c(-C请参阅),或者使用, 以及切换--guess将工作树与任何分支分离。--detach 切换分支不需要干净的索引和工作树(即与 相比没有差异HEAD)。 但是,如果操作导致本地更改丢失,则操作将中止,除非使用--discard-changesor另有说明--merge。
切换到指定分支。 更新工作树和索引以匹配分支。 所有新的提交都会被添加到这个分支的顶端。
可选地,可以使用 , 自动从同名的远程分支创建一个新分支-c(-C请参阅),或者使用, 以及切换--guess将工作树与任何分支分离。--detach
-c
-C
--guess
--detach
切换分支不需要干净的索引和工作树(即与 相比没有差异HEAD)。 但是,如果操作导致本地更改丢失,则操作将中止,除非使用--discard-changesor另有说明--merge。
HEAD
--discard-changes
--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
以下命令切换到“ main”分支:
main
$ git switch main
在错误的分支中工作后,将使用以下方法切换到正确的分支:
$ git switch mytopic
但是,您在本地修改的文件中的“错误”分支和正确的“ mytopic”分支可能会有所不同,在这种情况下,上述切换将失败,如下所示:
mytopic
$ git switch mytopic error: You have local changes to 'frotz'; not switching branches.
您可以将-m标志提供给命令,该命令将尝试三向合并:
-m
$ git switch -m mytopic Auto-merging frotz
在这种三向合并之后,本地修改不会在您的索引文件中注册,因此git diff会向您显示自新分支的尖端以来您所做的更改。
git diff
要切换回我们切换到之前的上一个分支mytopic(即“ main”分支):
$ git switch -
您可以从任何提交中增长一个新分支。 例如,切换到“ HEAD~3”并创建分支“ fixup”:
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 年第二季度)中更正。
-b/-B
-c/-C
请参阅Denton Liu ( ) 的commit 7c16ef7(2020 年 4 月 30 日)。(由Junio C Hamano 合并 – –在提交 f4675f3中,2020 年 5 月 8 日)Denton-L gitster
Denton-L
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评论-B对git switch. 对于引用 and 的错误消息,请-b改用-B格式字符串,以便在调用时可以打印-cand 。-C``git switch
报告人: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().
cmd_checkout()
checkout_main()
但是,在b7b5fce270(“ :和”switch的更好名称,2019-03-29,Git v2.23.0-rc0 –批次 #4中列出的合并)中,“ ”的分支创建和强制创建选项更改为and ,分别。-b``-B``switch``-c``-C
-b``-B``switch``-c``-C
因此,之前提到的错误消息和-b评论-B对git switch.
-b
-B
对于引用 and 的错误消息,请-b改用-B格式字符串,以便在调用时可以打印-cand 。-C``git switch
-C``git switch
Git 有一个普遍的问题,就是将大约八到十个不同的东西塞进一个命令中。 注意:Git 2.23 正在拆分其中的一些——这当然很有帮助,但也是一个非常大的变化。 (Git 2.23 是否应该被称为 Git 3.0?Git 2.0 改变了 的行为git add,在我看来这在程度上相似。)另见VonC 的回答。
git add
git checkout 可以更新工作树,通常会这样做。
它可以改变HEAD点的位置,有时会,有时不会。
它可以覆盖您对文件所做的工作,以防您想要重置文件并撤消您的工作。或者它可以拒绝覆盖您对文件所做的工作,使其在更改HEAD或不更改时保持不变HEAD。
关于这一切的事情是,虽然很难描述,但实际上这一切都是有道理的,一段时间后你会习惯这一点,并发现一个命令在大多数情况下都能做到你的意思。(当然,“大多数时候”可能是个问题......)
无论如何,您所看到的特定行为是故意的。假设您从 branch 开始main,就像大多数存储库一样:
$ git clone ... $ git branch * main $
此时您可能会编辑一些文件,开始进行一些工作,然后才意识到:“啊!我的意思是在分支上执行此操作develop!” 1
develop
Git 在这一点上让你做的是切换到(或创建)分支develop,在一个条件下保留你的修改:切换到develop不需要清除它们。假设您修改了文件f1并创建了一个新的2 f2,现在您想要创建并检查develop应该从2 origin/develop开始并自动“跟踪”的本地分支:
f1
f2
origin/develop
$ git checkout develop
(在非常旧的 git 版本中,您必须拼写 this git checkout -b develop --track origin/develop)。
git checkout -b develop --track origin/develop
假设文件在 branch和 branchf1的提示处是相同的。3 这对 git 来说意味着它可以执行此检查,因为它不必修改文件,因此它可以保留您现有的更改。main``develop``f1``f1
main``develop``f1``f1
如果两个提交中的文件也f2相同,或者(在这种情况下)任何一个都不存在,则不会破坏任何文件,并将创建新的本地分支,根据需要修改工作树以匹配- 这不包括修改,也不删除,所以到目前为止你所做的工作保持不变。git checkout``develop``origin/develop``f1``f2
git checkout``develop``origin/develop``f1``f2
这允许您将新更改提交到本地develop.
(如果您遇到 Git确实必须撤消您的更改,但仍想将它们“移动”到另一个分支的情况,通常的技巧是使用git stash脚本。这听起来很简单,而且git stash通常很容易使用,但它实际上是一个非常复杂的小野兽。不过,在你需要它之前不要担心。)
git stash
1这一直发生在我身上。很多时候我想新建一个非跟踪分支,这比切换到现有分支要简单一些,但原理仍然适用。
2这种自动跟踪使您可以更轻松地引入其他人所做的更改:一旦Gitgit fetch使用很多额外的探索,以找出谁的变化去哪里。git merge``git rebase
git 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
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就是您的新提交。
c06f8d11b75e28328cdc809397eddd768ebeb533
确切的细节并不重要,新提交只是推进分支提示的想法。