git divergent renaming

2020-02-28 03:01发布

I'd like to know how you handle a situation like this in Git:

  • create branch task001 from master
  • master: modify foo.c and rename it to bar.c
  • task001: modify foo.c and rename it to moo.c
  • merge task001 to master

What Git tells me is:

CONFLICT (rename/rename): Rename "foo.c"->"bar.c" in branch "HEAD" rename "foo.c"->"moo.c" in "task001"
Automatic merge failed; fix conflicts and then commit the result.

How should I solve it? I mean, I still want to merge the two files once the name conflict is resolved.

Thanks.

2条回答
叛逆
2楼-- · 2020-02-28 03:16

I initially understood your question to mean something different from what you have clarified in the comments, but the original answer may be useful, so I'm leaving that as the first part, but adding an alternative below:

1. Just resolving the conflict, so you only have the diverged moo.c and bar.c

Here I'm assuming that the result you want is to have bar.c and moo.c, with their changes from each branch, in the merged version. I would deal with this by resolving the conflict in the index and committing. The situation you describe looks like this:

$ git log --pretty=oneline --graph --decorate master task001
* fce127471ab5d1ef55b1d16412a75a7129782517 (task001) Rename to a different file on task001
* 8edbc1357a3c0484dc077f6f7ce43de91d21e794 A small change on the task001 branch
| * d10e9020d147a4bbd3688744823380322bf37718 (HEAD, master) Rename on master to bar.c
| * f952617645456a551df07f219bfdc95e00c8ac9b Added a small change in master
|/  
* e8602eef46af744defd4fb4073ecdb6a7afbfd28 Initial version of foo.c

If I then merge task001 into master, it produces the same error that you see:

$ git merge task001 
CONFLICT (rename/rename): Rename "foo.c"->"bar.c" in branch "HEAD" rename "foo.c"->"moo.c" in "task001"
Automatic merge failed; fix conflicts and then commit the result.

Then git status will show you a summary of problems:

$ git status
# On branch master
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#   added by us:        bar.c
#   both deleted:       foo.c
#   added by them:      moo.c
#
no changes added to commit (use "git add" and/or "git commit -a")

Now you just need to use git add and git rm to resolve the conflicts:

$ git add bar.c
$ git rm --cached foo.c
foo.c: needs merge
moo.c: needs merge
rm 'foo.c'
$ git add moo.c
$ git status
# On branch master
# Changes to be committed:
#
#   new file:   moo.c
#

(I used --cached for removing foo.c because it's no longer in the working copy, and --cached means the command only looks at the index -- otherwise you get an error about foo.c not existing.)

Then you just commit the results:

$ git commit
[ save the prepopulated commit message ]

And you've resolved the conflicts and have bar.c and moo.c in the merged version.

(I note in passing that git merge -s resolve works for me in the simple example situation describe here, but I hope this is more generally useful.)

2. Merging bar.c and moo.c back into one file

It seems from your comments below that really what you would like is to merge these files back into one again, with the changes to the file in both branches merged. If you want git's merge strategies to help you with this, the files on each branch must have the same path before merging, so you'll need to rename at least one of them before merging. Let's suppose you want the merged file to be called quux.c, although you could just as well make it foo.c again, of course. Then you could do the following steps, which rename the file on each branch before merging:

# Rename the file on master:

$ git checkout master
Already on 'master'
$ git mv bar.c quux.c
$ git commit -m "Rename bar.c to quux.c on branch master"
[master f9b3f49] Rename bar.c to quux.c on branch master
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename bar.c => quux.c (100%)

# Rename the file on task001:

$ git checkout task001 
Switched to branch 'task001'
$ git mv moo.c quux.c
$ git commit -m "Rename moo.c to quux.c as well on branch task001"
[task001 c71ad89] Rename moo.c to quux.c as well on branch task001
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename moo.c => quux.c (100%)

# Switch back to master, and merge in task001:

$ git checkout master
Switched to branch 'master'
$ git merge task001

If the changes didn't conflict, then at this point that merge should Just Work. In the example I tried they did conflict, so I needed to edit the file, git add the file and commit the result:

Renaming foo.c->quux.c
Auto-merging quux.c
CONFLICT (content): merge conflict in quux.c
Automatic merge failed; fix conflicts and then commit the result.
$ emacs -nw quux.c 
$ git add quux.c
$ git commit
[master 8baa7cb] Merge branch 'task001'
$ ls
quux.c
查看更多
兄弟一词,经得起流年.
3楼-- · 2020-02-28 03:20

Simple way to fix this First abort the current merge

git merge --abort

Now, decide which version of the file you want to use and use a merge strategy (with the flag -s)

You are on the branch master. If you want to keep the name you set in master then use this command

git merge -s ours task

If you want to use the version from task

git merge -s theirs task
查看更多
登录 后发表回答