简体   繁体   中英

Why does `git checkout -m` succeed without merge?

Git Pocket Guide says

Git ignores untracked files while switching branches, unless the file exists in the target branch ; then it aborts, even if the versions in the working tree and destination branch are the same. You can use the --merge option to get around this without having to delete the untracked file , only to have Git restore it a moment later. The merge operation results in the same file, in this case.

On branch master , I have a tracked file hellofile

$ git branch 
  feature2
* master
$ cat hellofile 
hello
$ git status
On branch master
nothing to commit, working tree clean

On branch feature2 , it has no file hellofile , and I create it but leave it untracked

$ git checkout feature2
$ ls
common  reader  README  writer
$ echo "world" > hellofile

I then try to checkout master . It is understandable that git checkout will fail, but with -m succeed. But why does git checkout -m succeed without merge? (I am expecting a file hellofile with marked conflict)

$ git checkout master
error: The following untracked working tree files would be overwritten by checkout:
    hellofile
Please move or remove them before you switch branches.
Aborting
$ git branch
* feature2
  master

$ git checkout -m master
error: Dirty index: cannot merge (dirty: f2f hellofile)
Switched to branch 'master'
$ cat hellofile 
hello

The problem here is that hellofile is not tracked in feature2 , yet exists in master . -m is designed for both branches having some change on a tracked file. Now, this change may or may not be staged, but is tracked in our working tree. Contrarily, I hope it makes sense that if both branches has added and committed some version of the file, we would have standard conflict.

If the file is not at least tracked in both branches, then the 3-Way merge seems to resolve the conflict as a git checkout --ours ... more on this in the discussion section.

That is, in doing this in your example,

$ echo "world" > hellofile
$ git checkout -m master

you are effectively (not actually) saying to disregard changes in the current working directories' un-tracked file. If however, you had been tracking hellofile on both branches and did your modification,

$ `echo "world" > hellofile"
$ `git add hellofile`

you would have gotten a conflict which looked more like this:

<<<<<<< master
hello
=======
world
>>>>>>> local

I am going to assume that is what you were going for; it was correctly marked as a merge conflict. Yet, your change was brought across both branches without being committed.


Discussion

The documentation doesn't say this is intended, but that your problem is clearly the behavior. I think this is probably an oversight/bug on their part. What they seem to mean, is

"However, with this option, a three-way merge between the current branch, your indexed files , and the new branch is done, and you will be on the new branch."

After reading this post: Can I use git diff on untracked files? , I am going to assume that what is actually happening in the merge scheme is that the working directory file doesn't actually have a valid blob in the index to be considered something to merge, and so is for all intents and purposes, "disregarded".

Edit: Here is a question that was just asked, with a similar sort of conundrum: Why does git checkout <<file>> not work when the same file is in index?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM