tags:

views:

316

answers:

1

I having one confusion about a particular git behavior:

Following are the steps and situation (the list of commands are also given later):

  1. I have two branches: master and XBranch
  2. There is a file src/a.txt in both of them. It's content is "Old Content"
  3. In XBranch I rename src/a.txt to src/b.txt, using: mv, git rm, git add.
  4. In master rename the file a.txt. During commit I did git rm src/a.txt but forgot to do git add src/b.txt In master I do: git rm src/a.txt and git commit

  5. In master, I edit the content of the file b.txt to "New Content

  6. In master I do git add src/b.txt and git commit
  7. In master I do: git merge XBranch

The file src/b.txt conflicts, which is perfectly understandable. But the content is "Old Content". Why?

Why not is it something like:

<<<<<<< HEAD
New Content
=======
Old content
>>>>>>> XBranch

List of Commands:

sabya@SABYA-PC d:/merge_temp/test/case2
$ mkdir source

sabya@SABYA-PC d:/merge_temp/test/case2
$ git init
Initialized empty Git repository in d:/merge_temp/test/case2/.git/

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ mkdir src

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ vi src/a.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ cat src/a.txt
Old Content

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git add src/

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git commit
[master (root-commit) 148500e] added src/a.txt
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 src/a.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git branch XBranch

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git checkout XBranch
Switched to branch 'XBranch'

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ mv src/a.txt src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ git rm src/a.txt
rm 'src/a.txt'

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ git add src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ git commit
[XBranch b3ff8fa] changed a.txt to b.txt in XBranch
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename src/{a.txt => b.txt} (100%)

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ git checkout master
Switched to branch 'master'

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ mv src/a.txt src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git rm src/a.txt
rm 'src/a.txt'

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git commit
[master bfeaecb] removed src/a.txt
 1 files changed, 0 insertions(+), 1 deletions(-)
 delete mode 100644 src/a.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ vi src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ cat src/b.txt
New Content

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git add src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git commit
[master 2361d5e] changed content of b.txt
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git merge XBranch
CONFLICT (rename/delete): Rename src/a.txt->src/b.txt in XBranch and deleted in HEAD
Automatic merge failed; fix conflicts and then commit the result.

sabya@SABYA-PC d:/merge_temp/test/case2 (master|MERGING)
$ cat src/b.txt
Old Content
+2  A: 

There is a conflict, but not about the file content. It is about the tree content.

  • In one tree, the case2 directory (in master), there is a new file b.txt
  • in the same directory (in XBranch), there is a renamed file a.txt => b.txt

When you are resolving the conflict, you are in effect choosing one file or the other (not one line within the file).
Hence the "Old Content" in the resulting file.


The OP adds in the comments:

But then how logically is it different from the following situation:

  1. I add a file a.txt in master with "Old Content" and commit it.
  2. I add a file a.txt in XBranch with "New Content" and commit it.
  3. I merge XBranch into master.

This time it is showing both contents in that file!

This time, both trees (the case2 directory in branches master and XBranch) reference a new file a.txt: its content get merged, with conflict resolution.
Before, there was a conflict between a a.txt (renamed as b.txt) and a new b.txt: both files cannot exist in the same branch, a choice (of file, not of file content) had to be made.

In step 4 of my question, if I do "git rm" and "git add" in a single commit, it works as I expect! I fail to understand that now.
How can I predict when the file will have both contents?
When it will just have the content of XBranch and when will it have just the content of master?

That means that:

  • instead of merging XBranch (a.txt renamed as b.txt) to master commit with a new b.txt from step 6 (conflict of tree),
  • you would merge XBranch (a.txt renamed as b.txt) with master from new step 4 (a.txt also renamed as b.txt): same tree content, but different blob content: conflict of lines.

That being said, the OP still thinks there must be a bug:

VonC
But then how logically is it different from the following situation:1. I add a file a.txt in master with "Old Content" and commit it.2. I add a file a.txt in XBranch with "New Content" and commit it.3. I merge XBranch into master.This time it is showing both contents in that file!
Sabya
@Sabya: this time, both trees (the `case2` directory in branches `master` and `XBranch`) reference a *new* file `a.txt`: its content get merged, with conflict resolution. Before, there was a conflict between a **`a.txt`** (renamed as `b.txt`) and a new **`b.txt`**: both files cannot exist in the same branch, a choice (of file, not of file content) had to be made.
VonC
In step 4 of my question, if I do "git rm" and "git add" in a single commit, it works as I expect!I fail to understand that now. How can I predict when the file will have both contents? When it will just have the content of XBranch and when will it have just the content of master?
Sabya
@That means that, instead of merging `XBranch` (`a.txt` renamed as `b.txt`) to master commit with a *new* `b.txt` from step 6 (conflict of tree), you would merge `XBranch` (`a.txt` renamed as `b.txt`) with master from new step 4 (`a.txt` also renamed as `b.txt`): **same tree content, but different blob content**: conflict of lines.
VonC
I reported this to git mailing list. One person from there said this could be a bug. The content of both the files being present in this case can be an expected behavior.
Sabya
@Sabya: right: http://ns.spinics.net/lists/git/msg133831.html. I stand by my original explanations. http://support.github.com/discussions/repos/3438-can-anybody-answer-this-confusion-about-git-deleterename GitHub support explanation seems reasonable too.
VonC
As this answer and its comments provide all required information, I'm marking the answer as accepted.
Sabya