检查出不同的分支后,为什么仍然存在未分级的更改?

Saj*_*gar 6 git git-checkout

我观察的东西与我对git checkout命令的了解不一致.在除了以外的分支上master,我对跟踪文件进行了一些修改; 没有暂存和提交这些更改,我跑了

git checkout master
Run Code Online (Sandbox Code Playgroud)

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  
Run Code Online (Sandbox Code Playgroud)

在这个阶段,README我的工作树中的文件包含该foo行,即使我在另一个分支(new-branch)上添加它.我期待README是空的,就像在笔尖中记录的版本一样master.foo退房后为什么线路还在那里master

jub*_*0bs 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>.
Run Code Online (Sandbox Code Playgroud)

但是,这个描述似乎与您的示例中发生的情况相矛盾.你不是第一个被它迷惑的人; 看到这个讨论.其中,Git的维护者Junio Hamano澄清了git checkout <commit-ish>在本地修改的情况下做了什么:

原则是,当您对工作树和/或索引进行本地更改时,我们允许您检出不同的分支,只要我们可以使索引和工作树假装您已达到本地修改状态,从你正在检查的分支的干净状态开始.


Junio Hamano的回应

发生了什么仍然不清楚,所以我进行了一些实验来解决问题,这是我对Junio Hamano的回答的解释.首先,让我介绍一些术语:让

  • Cs表示源提交,即HEAD在结账操作之前指向的提交,
  • 是表示集结区的状态,
  • Ws表示工作树的状态,
  • Ct表示目标提交,即我们试图检出的提交.

我的理解是,在调用时git checkout,对于每个被跟踪的文件,获取以下差异,

  • diff(Cs,Is)(你可以在输出中看到git diff --staged),
  • diff(Cs,Ws)(你可以在输出中看到git diff),

并检查这些更改是否完全适用于目标提交,Ct.如果存在任何冲突,则中止结账操作.否则,HEAD移动到Ct,并保留暂存区域(Is)和工作树(Ws)的状态.

应用到您的示例

之前 git checkout master

就行了

git commit -m "initial commit"
Run Code Online (Sandbox Code Playgroud)

在您的示例中,您的repo如下所示:

在此输入图像描述

提交,暂存区域和工作树旁边的页面README在相应的三个"Git区域"中表示文件的内容.

"中" git checkout master

然后你跑

git checkout master
Run Code Online (Sandbox Code Playgroud)

所以,假设我对Junio的anwer的解释是正确的,这里会发生什么?

因为当前分支new-branch和要检出的分支都master指向同一个提交A,所以Cs和Ct(使用我的术语)都对应A.在那种情况下,当然,diff(Cs,Is)和diff(Cs,Ws)干净地适用于Ct; 这里没有冲突.

因此,执行结账操作:

  • HEAD是指向master,
  • 保存区域的状态,
  • 工作树的状态得以保留.

git checkout master

因为在签出时没有出现混淆,所以保留了对工作树的master本地修改README,以便它们可以被提交到master分支.

在此输入图像描述