Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Telling git to follow moved content (not simply moved files)

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

like image 738
loopbackbee Avatar asked Dec 12 '13 10:12

loopbackbee


1 Answers

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)

like image 186
aronisstav Avatar answered Oct 21 '22 10:10

aronisstav