Can Git really track the movement of a single function from 1 file to another? If so, how?
This functionality is provided through git blame -C <file>
.
The -C
option drives git into trying to find matches between addition or deletion of chunks of text in the file being reviewed and the files modified in the same changesets. Additional -C -C
, or -C -C -C
extend the search.
Try for yourself in a test repo with git blame -C
and you'll see that the block of code that you just moved is originated in the original file where it belonged to.
From the git help blame
manual page:
The origin of lines is automatically followed across whole-file renames (currently there is no option to turn the rename-following off). To follow lines moved from one file to another, or to follow lines that were copied and pasted from another file, etc., see the
-C
and-M
options.
As of Git 2.15, git diff
now supports detection of moved lines with the --color-moved
option. It works for moves across files.
It works, obviously, for colorized terminal output. As far as I can tell, there is no option to indicate moves in plain text patch format, but that makes sense.
For default behavior, try
git diff --color-moved
The command also takes options, which currently are no
, default
, plain
, zebra
and dimmed_zebra
(Use git help diff
to get the latest options and their descriptions). For example:
git diff --color-moved=zebra
As to how it is done, you can glean some understanding from this email exchange by the author of the functionality.
A bit of this functionality is in git gui blame
(+ filename). It shows an annotation of the lines of a file, each indicating when it was created and when last changed. For code movement across a file, it shows the commit of the original file as a creation, and the commit where it was added to the current file as last change. Try it.
What I really would want is to give git log
as some argument a line number range additionally to a file path, and then it would show the history of this code block. There is no such option, if the documentation is right. Yes, from Linus' statement I too would think such a command should be readily available.