Telling git to follow moved content (not simply mo

2019-03-12 21:53发布

While refactoring source code, sometimes you need to move big blocks of text inside a file, or even to a new file. You create a branch refactored and commit away:

$git checkout master
$git branch refactored
$git checkout refactored
<move code around>
$git commit -m "refactored code"

However, people may commit on top of the old pre-refactor branch, changing the code that was moved:

$git checkout master
<change code that was moved elsewhere on branch refactored>
$git commit -m "bugfix"

On branch refactored, you then want to incorporate changes made in master:

$git checkout refactored
$git merge master
<giant merge conflict>

This leads to a large merge conflict. If there was a way to tell git that the content was simply moved, it should be possible to merge automatically.

The worse part is that, even after resolving the conflict and commiting it, git still can't use the resolution to figure out further merges:

<fix conflicts>
$git commit -m "merge master into refactored"
$git checkout master
<change more code>
$git commit -m "bugfix2"
$git checkout refactored
$git merge master
<another giant merge conflict>

Is this avoidable at all? I've tried git rerere and it can't resolve the conflicts here. Is there any way git can see moving a block of text as a actual move, instead of a deletion and insertion? If it can't, what's the best approach to minimizing merge conflicts, if you need to keep the two parallel branches for a while?

While this is easy enough for moving the contents of a complete file, I couldn't find information on moving only part of it, or moving inside the same file.

Also, if there's a solution for this, what would be the behaviour of git blame on the refactored code? Would it point to the refactoring commit, or ignore it? Is there a way to achieve the later?

In case anyone's interested, I've put a base64 encoded tar.gz of the (very minimal) repository I'm using for testing on pastebin

Potential Solutions

One potential solution might be performing the merge by applying a (automatically) edited patch with the changes in the pre-refactored branch. Is there software developed to do this? Using this approach I guess that, since this is transparent to git, git blame would point to the refactoring commit.

I've found the same question, applied to diff. There's no mention to any existing non-proprietary implementation, but there mention to a algorithm that tracks block movement

2条回答
神经病院院长
2楼-- · 2019-03-12 22:22

It is not possible to avoid this extra effort, but then again that is how Git is supposed to work:

The other fundamentally smart design decision is how Git does merges. The merging algorithms are smart but they don't try to be too smart. Unambiguous decisions are made automatically, but when there's doubt it's up to the user to decide. This is the way it should be. You don't want a machine making those decisions for you. You never will want it. That's the fundamental insight in the Git approach to merging: while every other version control system is trying to get smarter, Git is happily self-described as the "stupid content manager", and it's better for it.

(From Wincent Colaiuta's blog)

查看更多
一纸荒年 Trace。
3楼-- · 2019-03-12 22:28

Unfortunately you can't replace the built in git merge strategies as far as I can tell. This means you can't stop the conflicts, however you can use an intelligent tool to resolve them.

This one Semantic Merge looks interesting, it can also be used by git

查看更多
登录 后发表回答