我观察的内容与我对git checkout
命令的了解不一致。在master
以外的分支上,我对跟踪文件进行了一些修改;没有暂存和提交这些更改,我运行
git checkout master
Git在没有击打眼睑的情况下顺从;但更令人惊讶的是,我在该分支上所做的所有修改仍然存在!以下是复制情况的示例:
mkdir myrepo
cd myrepo
git init
touch README # create a new file
git add .
git commit -m "initial commit"
git checkout -b new-branch
echo "foo" >> README
git checkout master
在此阶段,我工作树中的README
文件包含foo
行,即使我在另一个分支(new-branch
)上添加了该行。我希望README
为空,就像master
提示中记录的版本一样。在查看foo
之后,为什么master
行仍然存在?
答案 0 :(得分:5)
git checkout
并不像看起来那么简单。谢谢你问:)
据我了解,您的问题是:为什么在检出foo
后,未提交的更改(即添加的master
行)仍然存在于工作树中?如果您查找git-checkout
手册页,您将找到以下说明:
git checkout <branch>
To prepare for working on <branch>, switch to it by updating the
index and the files in the working tree, and by pointing HEAD at
the branch. Local modifications to the files in the working tree
are kept, so that they can be committed to the <branch>.
然而,这个描述似乎与你的例子中发生的事情相矛盾。你并不是第一个被它迷惑的人;见this discussion。在其中,Git的维护者Junio Hamano澄清了git checkout <commit-ish>
在存在局部修改时的作用:
原则是我们允许您查看不同的分支 当您对工作树和/或索引进行本地更改时, 只要我们可以使索引和工作树假装好像 从干净的状态开始,你达到了本地修改状态 您正在检查的分支机构。
发生的事情对我来说仍然不清楚,所以我进行了一些实验来解决问题,这是我对Junio Hamano回复的解释。首先,让我介绍一些术语:让
我的理解是,在为每个跟踪的文件调用时,git checkout
会获得以下差异,
git diff --staged
的输出中看到),git diff
的输出中看到),并检查这些更改是否完全适用于目标提交,Ct。如果存在任何冲突,则中止结账操作。否则,HEAD
移动到Ct,并保留暂存区域(Is)和工作树(Ws)的状态。
git checkout master
之前在行
之后git commit -m "initial commit"
在您的示例中,您的仓库看起来像这样:
提交,暂存区域和工作树旁边的页面在相应的三个&#34; Git区域&#34;中表示README
文件的内容。
git checkout master
然后你运行
git checkout master
所以,假设我对Junio的anwer的解释是正确的,这里会发生什么?
因为当前分支new-branch
和要签出的分支master
都指向同一个提交A
,所以Cs和Ct(使用我的术语)都对应于A
。在那种情况下,当然,diff(Cs,Is)和diff(Cs,Ws)干净地适用于Ct;这里没有冲突。
因此,执行结账操作:
HEAD
指向master
,git checkout master
由于在签出master
时没有出现混淆,因此保留了对工作树中README
的本地修改,以便可以将它们提交到master
分支。
答案 1 :(得分:3)
在进行更改之前(使用git add
),它只存在于工作目录中 - 它不会被git跟踪,因此将存在于您结帐的任何分支中。