4

I have source file A, which is getting long and contains two large classes. I want to split it into files A and B, preserving history and "blame" data.

In Subversion, this is very easy: do an svn copy A B, delete the lines from A that should only be in B and vice versa, then commit. But the project's owner sadly wants to switch to Git, and this is one of the workflows that I don't know how to do.

When you do svn log B, you get B's history from after the split, plus A's history from before the split. Additionally, svn blame B will attribute pre-split changes to the correct authors in the history of A, rather than attribute them to whomever did the split.

Myria
  • 3,372
  • 1
  • 24
  • 42
  • 1
    Possible duplicate of [How to "split" files with git](http://stackoverflow.com/questions/897707/how-to-split-files-with-git) – Geremia Jan 23 '16 at 06:05

3 Answers3

4

Git does not explicitly track renames. Instead where needed it calculates if a rename has occurred. For example, commands like git blame, git diff and git merge can make use of Git's rename detection machinery.

For this reason you should just make the change you need and commit it as normal.

So the correct steps for this case would be:

<make the needed changes to the files>
git add A B
git commit

Given that renaming is not explicitly tracked means that the rename detection algorithm sometimes needs a little bit of tuning to achieve what you need. For example, when doing a merge you might need to adjust the rename-threshold=<n> to get a better auto-merge.

If the similarity of the "renamed" files is below what Git detects, or can be configured to detect, then there is no way for Git to consider it a rename.

PeterSW
  • 4,921
  • 1
  • 24
  • 35
  • 1
    When splitting the file, nearly all the contents change. This question seems to suggest that what I'm talking about would not work, because the heuristic would consider the files unrelated: http://stackoverflow.com/questions/7938582/how-does-git-detect-similar-files-for-its-rename-detection – Myria Aug 07 '15 at 20:59
  • @Myria: that may well be the case. If so, the only way you could get git to recognize that B was copied from A—you'll be fine with respect to A itself, since the name did not change and therefore git's diff engine will just assume that file A is heavily modified—is to augment git's difference detector so that it *can* see that `B` was copied. Once you've "taught" git, this detection will apply retroactively to all earlier commits. – torek Aug 08 '15 at 02:17
0

First, copy the original file to a new filename:

$ cp A B

Next, delete unwanted lines from B and A, then add the new file to git and commit:

$ git add -A
$ git commit
mipadi
  • 398,885
  • 90
  • 523
  • 479
0

You don't have to do anything special when committing. Just commit the new and deleted files as usual, then use the -C option with git blame when you want to track copied file contents. git will figure everything out automatically. The same goes for moved files.

See also: Record file copy operation with Git

Community
  • 1
  • 1
Ajedi32
  • 45,670
  • 22
  • 127
  • 172