git rebase master feature gives (rename/delete) conflict, git rebase -i master feature does not

狂风中的少年 提交于 2019-12-12 13:45:23

问题


I encountered a strange situation with git in which I had a feature branch that modified some files and deleted one file "foo.js". When I rebased onto master via "git rebase master feature", I encountered the following type of conflict:

CONFLICT (rename/delete): src/main/resources/com/blah/bar.js deleted in Change some js and renamed in HEAD. Version HEAD of src/main/resources/com/blah/bar.js left in tree.

The odd thing is that neither neither the master branch nor the feature branch had even modified bar.js, let alone deleted it. What's more, executing "git rebase -i master feature" results in no conflict (when choosing all "pick").

One possible important clue is that foo.js and bar.js are similar but not identical files, and the slightly modified files are also similar to foo.js and bar.js. The only wild speculation that I can make is that some of the changes made to related js files somehow confused git into thinking that the offending commit in branch feature consisted of a delete of bar.js followed by a rename of foo.js (which was deleted) to bar.js. Is this possible/expected? Does anyone have any idea why this could happen? FYI, I'm using git version 1.8.3.2 on linux mint 16.


回答1:


That is a bit unusual, but your diagnosis is correct.

An interactive rebase uses a series of git cherry-pick commands. A non-interactive rebase uses git-merge-recursive (by default at least; see the git-rebase--merge script in the git-core directory, wherever that is on your system, or simply note the -s <strategy> argument to git rebase) to make each new commit from an old one. As the documentation for -m / --merge says (although it fails to mention that this is the default):

       Use merging strategies to rebase. When the recursive (default)
       merge strategy is used, this allows rebase to be aware of renames
       on the upstream side.
 
       Note that a rebase merge works by replaying each commit from the
       working branch on top of the <upstream> branch. Because of this,
       when a merge conflict happens, the side reported as ours is the
       so-far rebased series, starting with <upstream>, and theirs is the
       working branch. In other words, the sides are swapped.

You can tell for sure by using git diff -M --name-status1 to compare the suspect commit pair. If this shows bar.js as Deleted and foo.js as Renamed to bar.js, that's the culprit.

Annoyingly, there is no way to set the rename threshold for merge. Fortunately the workaround is simply to run an interactive rebase and make no changes in the command series, which you can short-cut by doing:

GIT_EDITOR=: git rebase -i ...

or by using the -p option to preserve merges (the latter is different if you have merges, but has the side effect of doing an "implied interactive" rebase, which simply sets GIT_EDITOR=: and also turns off autosquash).


1The -M option is not required if you have configured diff.renames to true (see git config documentation). Merge-recursive internally sets the rename but not copy detection, and sets the "rename limit" the first of whichever of these applies: your configured merge.renamelimit, if you have one; your diff.renamelimit if you have one; or the constant 1000.



来源:https://stackoverflow.com/questions/22951108/git-rebase-master-feature-gives-rename-delete-conflict-git-rebase-i-master-f

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!