13

I am refactoring a single-file PHP script to declare functions and classes in separate files. How does one move a block of code from one file to another file yet preserve the Git history for each individual line? I would like the ability to use at the very least git blame on the code. Comparing to older versions would also be helpful.

Note that I am not interested in 'workaround' solutions that would require additional commands or flags (such as --follow) on the code to view its 'old' history, for which the person viewing the history would have to know that the file needs special treatment. I am looking for a solution which writes the necessary metadata such that normal git commands such as blame, log, diff, and such 'just work' without presenting to them additional flags or arguments.

I have read quite a few posts looking for solutions to similar problems, but none that address the issue of git blame on individual lines. One solution that I think would work would be to copy the file and its entire history, then work off of that. However, that question remains without a satisfactory answer.

Community
  • 1
  • 1
dotancohen
  • 30,064
  • 36
  • 138
  • 197
  • 1
    Note that `git blame` already tracks lines of code across files, but unless the files was renamed, you still have to pass additional options to tell Git to do the move/copy detection, perhaps because it's an expensive operation. –  Jul 17 '13 at 12:16
  • Suppose "Stas" writes a block of code and checks it into Git, and then I cut and paste the block into a different file. Now `git blame` will show that I've written that block of code. I am looking for a solution which will allow me to move the code, but it should still show that Stas wrote it, and when. – dotancohen Jul 17 '13 at 12:25
  • 2
    Have you read the [`git blame` documentation](https://www.kernel.org/pub/software/scm/git/docs/git-blame.html) to see if it already does what you're looking for? –  Jul 17 '13 at 13:08
  • 2
    in particular, the `-C` thing is probably what you want (i've deleted my answer because while it's technically correct that git doesn't track this, in practice `-C` is probably good enough for what you need). – andrew cooke Jul 17 '13 at 13:15
  • Thank you, I am aware of `--follow` and `-C1` but I'm really looking for a solution that 'rewrites' the history of the file to add the information for the original function author to the new location. – dotancohen Jul 17 '13 at 14:34
  • I find this to be very relevant. It could be expanded to a much broader question "How can I work on git as an **editor** and keep the original **author** as such?". Just like we can do with posts here on SEN. Answer is: we can't. But I wish we could. – cregox Jul 23 '13 at 15:29

1 Answers1

6

Warning: This assumes that rewriting history is acceptable. Do not use this unless you know the implications of rewriting history.

To split a file into multiple files while maintaining history use git filter-branch:

git filter-branch --tree-filter 'if [ -f original.php ]; then 
    echo part1.php part2.php part3.php | xargs -n 1 cp original.php; fi' HEAD

Then delete the lines that you do not want from each file (leaving only the desired functions and classes) and commit the result!

powtac
  • 40,542
  • 28
  • 115
  • 170
onionjake
  • 3,905
  • 27
  • 46
  • 4
    Note that the linked document is the git user manual, I didn't know about it until just now (I guess it has a low search ranking or something) but it's very detailed and seems like it will be really useful. I try to avoid "Thanks!" comments but I really would like to emphasize how important that link is. I bought a whole darn book in Git and that page still has some information that the book doesn't. – jrh Oct 25 '17 at 19:24