为什么在检出不同的分支后仍然存在未分离的更改? [英] Why are unstaged changes still present after checking out a different branch?

查看:178
本文介绍了为什么在检出不同的分支后仍然存在未分离的更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在观察与我对 git checkout 命令所了解的内容不一致的内容。在除 master 之外的分支上,我对被跟踪的文件进行了一些修改;没有登台并提交这些更改,我运行

  git checkout master 

Git遵守而不打眼皮;但更令人惊讶的是,我对该分支所做的所有修改仍然存在!这是一个重现情况的例子:

  mkdir myrepo 
cd myrepo
git init
触摸README#创建一个新文件
git add。
git commit -m初始提交
git checkout -b新分支
回显foo>> README
git checkout master

在这个阶段, README 文件在我的工作树中包含 foo 行,尽管我在另一个分支上添加了它( new-branch )。我希望 README 为空,就像记录在 master 中的版本一样。为什么在检出 master

后, foo h2_lin>解决方案

乍一看,你的问题似乎很无趣,但它让我意识到 git checkout 不是一个简单的操作看起来好像。感谢您提出:)



据我所知,您的问题是:为什么未提交更改添加了 foo 这行,在检查 master 之后仍然存在于工作树中。如果您查看 git-checkout 手册页,您会发现以下说明:

  git checkout<分支> 

要准备在< branch>上工作,可以通过更新
索引和工作树中的文件并将HEAD指向
分支来切换到它。保留工作树
中的文件的局部修改,以便它们可以被提交给< branch> ;.

然而,这个描述似乎与你的例子中发生的事情相矛盾。你不是第一个被它弄糊涂的人;请参阅这个讨论。其中,Git的维护者Junio Hamano澄清了在本地修改的情况下 git checkout< commit-ish> 的作用:


原则是,当您对工作树和/或索引进行本地更改时,我们允许您检出另一个分支

只要我们可以让索引和工作树假装成你
达到了本地修改状态,从你正在检出的分支的干净状态
开始。






Junio Hamano的回应的解释



我仍然不清楚发生了什么,所以我进行了一些实验来修复想法,这里是我对Junman Hamano的回复的解释。首先,让我介绍一些条款:让


  • Cs表示源提交,即HEAD在签出操作之前指向的提交

  • 表示暂存区域的状态,
  • W表示工作树的状态,

  • Ct表示目标提交,即我们试图检出的提交。



我的理解是,调用时 git checkout ,对于每个跟踪的文件,得到以下差异,




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


    这些变化是否适用于目标提交Ct。如果有任何冲突,结帐操作将中止。否则, HEAD 移动到Ct,并保留暂存区域(Is)和工作树状态(Ws)的状态。



    应用程序到您的示例



    之前 git checkout master



    在行后面

      git commit -m初始提交




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

    期间 git checkout master



    然后运行

     git checkout master 

    因此,假设我的解释Junio的饮料是正确的,这里会发生什么?



    因为现在的麸皮ch, new-branch ,并且要检出的分支 master ,指向相同的提交 A ,C和Ct(使用我的术语)对应于 A 。在那种情况下,diff(Cs,Is)和diff(Cs,Ws)当然适用于Ct;这里没有冲突。

    因此,结帐操作将执行:


    • HEAD 被指向 master

    • 暂存区域的状态被保留,


    • 之后 git checkout master

      因为在检出 master 时没有发生冲突,工作树中的 README 已保存,以便它们可以被提交给 master 分支。




      I'm observing something that is not consistent with what I know about the git checkout command. While on a branch other than master, I make some modifications to a tracked file; without staging and committing those changes, I run

      git checkout master
      

      Git complies without batting an eyelid; but what is even more surprising is that all the modifications I made on that branch are still present! Here is an example reproducing the situation:

      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  
      

      At this stage, the README file in my working tree contains the foo line, even though I added it while on the other branch (new-branch). I was expecting README to be empty, like the version recorded in the tip of master. Why is the foo line still there after checking out master?

      解决方案

      At first sight, your question seemed pretty uninteresting, but it made me realize that git checkout is not as simple an operation as it seems. Thanks for asking it :)

      As I understand it, your question is: why are the uncommitted changes, i.e. the added foo line, still present in the working tree after checking out master? If you look up the git-checkout man page, you'll find the following description:

      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>.
      

      However, this description seems to contradict what's happening in your example. You're not the first one to be confused by it; see this discussion. In it, Junio Hamano, the maintainer of Git, clarifies what git checkout <commit-ish> does in the presence of local modifications:

      The principle is that we allow you to check out a different branch when you have local changes to the working tree and/or to the index, as long as we can make the index and the working tree pretend as if you reached that locally modified state, starting from a clean state of the branch you are checking out.


      Exegesis of Junio Hamano's response

      What happens still wasn't clear to me, so I conducted a few experiments to fix ideas, and here is my interpretation of Junio Hamano's reply. First, let me introduce some terms: let

      • Cs denote the source commit, i.e. the commit that HEAD points to before the checkout operation,
      • Is denote the state of the staging area,
      • Ws denote the state of the working tree,
      • Ct denote the target commit, i.e. the commit that we're attempting to check out.

      My understanding is that, when invoked, git checkout, for each tracked file, gets the following diffs,

      • diff(Cs,Is) (which you can see in the output of git diff --staged),
      • diff(Cs,Ws) (which you can see in the output of git diff),

      and checks whether those changes apply cleanly on the target commit, Ct. If there is any conflict, the checkout operation is aborted. Otherwise, HEAD moves to Ct, and the states of the staging area (Is) and working tree (Ws) are preserved.

      Application to your example

      Before git checkout master

      Right after the line

      git commit -m "initial commit"
      

      in your example, your repo looks like this:

      The pages next to the commit, staging area, and working tree, symbolizes the contents of your README file in the correspondings three "Git areas".

      "During" git checkout master

      Then you run

      git checkout master
      

      So, under the assumption that my interpretation of Junio's anwer is correct, what happens here?

      Because both the current branch, new-branch, and the branch to checked out, master, point to the same commit A, both Cs and Ct (using my terminology) correspond to A. In that case, of course, diff(Cs,Is) and diff(Cs,Ws) apply cleanly to Ct; no conflict here.

      Therefore, the checkout operation is carried out:

      • HEAD is made to point to master,
      • the state of the staging area is preserved,
      • the state of the working tree is preserved.

      After git checkout master

      Because no conflit arose when checking out master, local modifications to README in the working tree have been kept, so that they can be committed to the master branch.

      这篇关于为什么在检出不同的分支后仍然存在未分离的更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆