2

In Java the name of a file is tied to the name of a class. Renaming one renames both.

The thing is, whenever I do this, bad things happen. History gets lost. Merge conflicts occur. People freak out.

How do I rename a file in git and handle whatever merge conflicts may arise from it?

Michael Lafayette
  • 2,972
  • 3
  • 20
  • 54

2 Answers2

1

In Git:

  1. History is attached to commits, not to files.
  2. Commits record a state, not a change.

The first item means that history is never lost, it's just cryptic. Which is not really much help, but git log --follow (as CodeWizard wrote in his answer) usually does the job (though --follow has some failings).

One consequence of the second item is that git does not keep track of directory operations like file renames. This means that during merge operations (whether from git merge, or from git rebase or git cherry-pick or git revert or whatever), git must guess which files were named what.

Git's guesses are based on its similarity index, whose computation is a bit complex. Your main guarantee here is that a file that is bit-for-bit identical to its previous version will be detected as a rename.

This is not necessarily enough by itself, because Git fires up the merge machinery later, at the time of the git merge or git rebase or whatever, and the rename (with bit-for-bit identical contents) may be buried in the history. For instance, suppose commit C0 creates the file, C1 modifies it some, C2 renames it, and C3 modifies it again. If you convince git to compare C1 vs C2, it finds the rename—but at the time of the merge operation, git compares C0 against C3, and if the file is not sufficiently similar, git misses the rename.

(We could modify Git so that it iterates through all the commits on the ancestry path from C0 to C3 looking for renames, which would solve this problem completely as long as you commit the rename as a separate operation. This would be somewhat expensive, computationally speaking, but is probably a good idea for some future version of Git. Of course, it also does not help you right now. There is another tool, git-imerge, available today that can help.)

TL;DR answer: try to commit the rename as a standalone commit

Or at least, if you make other changes, make them to other files. Keep the renamed file as similar as possible (bit-for-bit identical = guaranteed rename detection, anything else = similarity index comes into play).

This only helps if those merging know how to convince Git to do the right merges. In the worst case, three merges should do the trick: one up to the point of the rename, one to bring in the rename, and one from there to the end. If a future Git version offers an ancestry-path-rename-detect, use that in the future. Meanwhile the rename-only commit is as good as it gets.

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • I think what I'm going to do is instead of renaming a file, I'm just going to copy it and rename the copy. And then I'm going add a little note to the original file saying that it is being replaced with some other file so please don't use or modify it instead modify the copy. – Michael Lafayette Apr 26 '16 at 05:44
  • What exactly do you mean by "Commits record a state, not a change?" – Michael Lafayette Apr 26 '16 at 05:45
  • Well, definition by example: if it was 27 degrees yesterday, and it is 3 degrees warmer today, today's information is a change. If it was 27 degrees yesterday and 30 degrees now, today's information is a state. Changes are fine if you know some previous state, but you must start with at least one state. Knowing only states, you can *find* changes. Knowing only changes, you cannot find the actual state. So states seem better. But suppose I only tell you it is 30 today and was 25 last week, and then ask you what it was four days ago? If you had all the changes, you could answer. – torek Apr 26 '16 at 08:21
  • (continued) Hence, since git records *states*, it's easy to compute "last week vs today" (just subtract) but that tells you nothing about how you got here. You must walk through each day, computing each day's change, to find the *path by which you arrived* at today's state. That's what git could (but doesn't) do in order to find renames, provided you had committed the rename separately. – torek Apr 26 '16 at 08:22
0

Use the git rm

Once the file are renamed using the git mv you can view the history of the files with the git log --follow <path>

# Rename the desired files
git mv <old path> <new path>

# Add and commit your changes
git add .
git commit ...

# To view the history of the modified files use
git log --follow <path>
CodeWizard
  • 128,036
  • 21
  • 144
  • 167