问题描述
我是 git 的新手,并试图围绕分支的工作方式进行思考.根据文档 git checkout
I am new to git and trying to wrap my head around the way branches work. According to the documentation git checkout
更新工作树中的文件以匹配索引或指定树中的版本.如果>没有给出路径,git checkout 也会更新 HEAD 以将指定的分支设置为>当前分支.
据我所知,我工作的目录中的文件(我在其中执行 git init 的文件)应该根据我所在的分支而改变.我很困惑,因为当我在两者之间切换时不会发生这种情况分支.我在切换分支之前所做的编辑存在于我切换到的分支中.是我做错了什么还是 git checkout 不能这样工作而我只是误解了文档?
So as I understand it the files in my directory that I work in (the file I performed the git init in) would should change according to what branch I am in. I am confused because this does not happen when I change between branches. Edits I was working on before I switched branches are present in the branch I switched to. Am I doing something wrong or does git checkout not work this way and I am just misunderstanding the docs?
推荐答案
Git 有一个普遍的问题,就是将大约八到十个不同的东西塞进一个命令中.注意:Git 2.23 正在拆分其中的一些——当然,这很有帮助,但也是一个非常大的变化.(Git 2.23 应该被称为 Git 3.0 吗?Git 2.0 改变了 git add,在我看来这在程度上相似.)另见 VonC 的回答.
Git has this general issue of cramming about eight or ten different things into one command. Note: Git 2.23 is splitting some of these up—helpful, to be sure, but also a very big change. (Should Git 2.23 be called Git 3.0? Git 2.0 changed the behavior of git add
, which seems to me similar in degree.) See also VonC's answer.
git checkout
可以更新工作树,通常是这样.
git checkout
can update the working tree, and usually does.
它可以改变HEAD
指向的位置,有时会,有时不会.
It can change where HEAD
points, and sometimes does, sometimes doesn't.
它可以覆盖您对文件所做的工作,以防您想重置文件并撤消您的工作.或者它可以拒绝覆盖你对文件所做的工作,在改变HEAD
或不改变HEAD.
It can overwrite work you did to a file, in case you want to reset the file and undo your work. Or it can refuse to overwrite work you did to a file, leaving it unchanged while either changing HEAD
, or not changing HEAD
.
关于这一切的事情是,虽然描述起来非常困难,但实际上一切都有意义,一段时间后您会习惯这一点,并发现 one 命令在大多数情况下都能满足您的要求.(当然,大部分时间"可能是个问题......)
The thing about all this is that, while it's remarkably difficult to describe, it actually all makes sense and after a while you get used to this and find that the one command does what you mean, most of the time. (It's that "most of the time" that can be a problem, of course....)
无论如何,您所看到的特定行为是有意为之.假设您从分支 main
开始,就像大多数存储库一样:
Anyway, the particular behavior you're seeing is a deliberate feature. Let's say you start out on branch main
, as most repositories do:
$ git clone ...
$ git branch
* main
$
此时您可能会编辑一些文件,开始一些工作,然后才意识到:呸!我打算在分支 develop
!"
At this point you might edit some file(s), get some work going, and only then realize: "gah! I meant to do this on branch develop
!"
此时 Git 让你做的是切换到(或创建)分支 develop
,保留你的修改,在一个条件下:切换到 develop
不需要清除它们.假设您修改了文件 f1
并创建了一个新的 f2
,并且您现在想要创建并检出应该从以下位置开始的本地分支 develop
,并自动跟踪", origin/develop
:
What Git lets you do at this point is switch to (or create) branch develop
, keeping your modifications, under one condition: that switching to develop
does not require wiping them out. Let's say you modified file f1
and created a new f2
, and you now want to create and check out local branch develop
that should start from, and automatically "track", origin/develop
:
$ git checkout develop
(在非常旧的 git 版本中,你必须拼写这个 git checkout -b develop --track origin/develop
).
(in very old versions of git, you have to spell this git checkout -b develop --track origin/develop
).
假设文件f1
在分支main
和分支develop
的提示处是相同的. 对于 git 来说,这意味着它可以执行此结帐,因为它不必修改文件 f1
,因此它可以将您现有的更改保留到 f1
就位.
Let's also say that file f1
is the same at the tips of branch main
and branch develop
. What this means, to git, is that it can do this checkout, because it does not have to modify file f1
, so it can leave your existing changes to f1
in place.
如果文件 f2
在两次提交中 也 相同,或者(在这种情况下)在任一提交中都不存在,则不会破坏任何文件,并且git checkout
将创建您的新本地分支 develop
,根据需要修改工作树以匹配 origin/develop
——这不包括修改 f1
,也没有删除 f2
,所以你到目前为止所做的工作仍然完好无损.
If file f2
is also the same in both commits, or (as in this case) does not exist in either one, then no files will be clobbered, and git checkout
will create your new local branch develop
, modifying the work tree to match origin/develop
as needed—and this does not include modifying f1
, nor removing f2
, so the work you have done so far remains intact.
这允许您将新更改提交到本地 develop
.
This allows you to commit your new changes to your local develop
.
(如果您遇到 Git 确实 必须撤消更改,但仍想将它们移动"到另一个分支的情况,通常的技巧是使用 git stash
脚本.这听起来很简单,而 git stash
通常使用起来很简单,但实际上它是一个相当复杂的小野兽.在你知道之前不要担心这个不过需要它.)
(If you run into cases where Git does have to undo your changes, but still want to "move" them to another branch, the usual trick is to use the git stash
script. This sounds like a simple thing, and git stash
is often simple to use, but it is actually quite a complicated little beast under the covers. Don't worry about that until you need it, though.)
这种情况一直发生在我身上.很多时候想新建一个非跟踪分支,比切换到现有分支要简单一点,但原理还是一样的.
This happens to me all the time. Many times I want to create a new non-tracking branch, which is a bit simpler than switching to an existing branch, but the principle still applies.
这种自动跟踪使您可以更轻松地引入其他人所做的更改:一旦 Git 使用 git fetch
获取它们,Git 会通知您其他人所做的更改-people's-changes,并让您使用 git merge
或 git rebase
将您的更改与他们的更改结合起来,而无需进行大量额外的探索以找出谁的更改去了哪里.
This automatic tracking allows you to more easily bring in changes other people have done: once Git picks them up with git fetch
, Git will inform you about those other-people's-changes, and let you use git merge
or git rebase
to combine your changes with theirs, without a lot of extra poking-about to figure out whose changes go where.
由于您是 Git 的新手,因此将分支的尖端"(即特定提交)与分支"(实际上是模棱两可的)区分开来之类的概念存在是分支标签,然后是由提交树形成的分支结构——这是你最应该暂时忽略的其他东西.需要注意的主要事情是 Git 存储库中有一个名为 HEAD
的特殊文件,在该特殊文件中,git 写入字符串 ref: refs/heads/main
或ref: refs/heads/develop
,以便跟踪您所在的分支.所以git checkout X
一旦切换到分支X
,就会将ref:refs/heads/X
写入HEAD
.
Since you're new to Git, concepts like distinguishing "the tip of a branch", which is a specific commit, from "the branch", which is actually ambiguous—there are branch labels, and then there are branch structures formed by the commit tree—is something else you mostly should ignore for a while. The main thing to note is that there's a special file in the Git repository named HEAD
, and in that special file, git writes the string ref: refs/heads/main
or ref: refs/heads/develop
, in order to keep track of which branch you're on. So git checkout X
will write ref: refs/heads/X
into HEAD
once it switches to branch X
.
与此同时,存储库中的另一组特殊文件告诉 Git,分支 main
指的是那些丑陋的 SHA-1 之一,例如 c06f8d11b75e28328cdc809397eddd768ebeb533
.这是提示"main
的分支.当您在 main
上进行新提交时,Git 会创建新提交一个旧提示",然后将新的 SHA-1 写入分支文件,以便 main
现在是您的新提交.
Meanwhile, another set of special files in the repository tell Git that branch main
refers to one of those big ugly SHA-1s like c06f8d11b75e28328cdc809397eddd768ebeb533
. This is the "tip" of branch main
. When you make a new commit on main
, Git creates the new commit "one past the old tip", then writes the new SHA-1 into the branch files, so that main
is now your new commit.
精确的细节并不重要,因为 new 提交的想法只是推进了分支提示.
The precise details don't matter so much as the idea that new commits simply advance the branch-tip.
这篇关于被 git checkout 弄糊涂了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!