问题
This question follows this topic. I am trying to understand what merge do to avoid unwanted mistakes during it.
I have two branches:master,b. I saw an strange result of doing git merge. You can see output of git log before merging, here:
* 148c970 (HEAD, master) rename 1 in master to 1_master
| * ad18d9b (b) rename 1 in b to 1_b
|/
* 15cd89b add 1 in master
So I had a file with name 1 in master and b. Then rename it in master to 1_master and to 1_b in b. Then I did git merge:
git merge b
I guess it causes a conflict, because merge base must be 15cd89b and both branches introduce changes on 1, which they don't match.
But merging did not cause any conflict and after merging I saw both 1_b and 1_master in working directory.
Note:
I think both torek and twalberg in linked answers forecast conflict in above situation.
回答1:
If I attempt to reproduce your issue I get a rename/rename conflict, as I would expect. First, I created a repository and some files (with unique contents):
$ mkdir rename-exp
$ cd rename-exp/
$ git init
Initialized empty Git repository in /home/torek/tmp/rename-exp/.git/
$ cat > 1
This is file "1" in its initial state.
The file is being used
for a test of what happens with
a rename vs rename conflict
in Git.
The file needs some contents
so that git can detect the
rename when we actually
do the rename.
$ cat > 2
This is file "2".
We give it some contents
so that it has a unique SHA-1.
$ git add .
$ git commit -m initial
[master (root-commit) a4b6f52] initial
2 files changed, 12 insertions(+)
create mode 100644 1
create mode 100644 2
Next, I create branch b and rename. Note that it will not matter whether I do the rename with git mv or with mv followed by git rm --cached and git add (but git mv is easier, so I use it). It is, however, important that git be able to detect the rename. This requires that either the files match 100% exactly (the easy case) or that they match "at least 50%" (this threshold can be adjusted, but 50% is the default) when diff-ed and that the old name (1) is no longer present in both trees at the time of the git merge.
$ git checkout -b b
Switched to a new branch 'b'
$ git mv 1 1_b
$ git commit -m 'rename 1 to 1_b in branch b'
[b cc104b1] rename 1 to 1_b in branch b
1 file changed, 0 insertions(+), 0 deletions(-)
rename 1 => 1_b (100%)
Then I do the same rename, with a different name-target, in master:
$ git checkout master
Switched to branch 'master'
$ git mv 1 1_master
$ git commit -m 'rename 1 to 1_master in master'
[master b891757] rename 1 to 1_master in master
1 file changed, 0 insertions(+), 0 deletions(-)
rename 1 => 1_master (100%)
Finally, I run git merge:
$ git merge b
CONFLICT (rename/rename): Rename "1"->"1_master" in branch "HEAD" rename "1"->"1_b" in "b"
Automatic merge failed; fix conflicts and then commit the result.
$
You'll need to show your steps (and perhaps your git version as well) in order for me to see why your merge thought each change was delete-and-create (with non-conflicting creates) rather than rename.
Other variables that affect this:
- any argument to
-X rename-thresholdduring the merge (this is how you tune the 50% default); - the value from
git config --get merge.renameLimit - the value from
git config --get diff.renameLimit, if there is no setting formerge.renameLimit.
回答2:
I think that is because Git doesn't really know the concept of renaming a file. See the Git FAQ.
For Git it is just add 1_master followed by remove 1. What you did is
on branch master:
- add file
1_master - remove file
1
and on branch b:
- add file
1_b - remove file
1
So in summary (i.e. merge) this gives:
- add file
1_master - add file
1_b - remove file
1
No conflict. Both branches apply the same operation to file 1: removing it.
Things would change, if you'd edited file 1 on one of your branches. Then Git wouldn't know whether to apply the edit or the deletion.
来源:https://stackoverflow.com/questions/35969245/why-merge-does-not-cause-conflict