Keep git history when splitting a file
GitHistoryGit SvnGit Problem Overview
I want to take a function out of one file and put it into another, but keep the blame history.
cp a.php b.php
vim b.php
# delete everything but 1 function
vim a.php
# delete the 1 function
git add a.php b.php
git commit
But if I run git blame b.php
I only see it blaming to this new commit.
Git Solutions
Solution 1 - Git
The general rule to maintaining blame history is to make a separate move commit first before any edits. It has been my experience that this allows git blame
to work without the need for the -C
option. So in the case of splitting the file up into new files, this can be done in two commits:
- Duplicate the original to the new destinations, making sure to delete the original
- Remove the extra sections from the duplicated files
In the example provided, this would be:
cp a.php b.php
mv a.php c.php
git add a.php b.php c.php
git commit
vim b.php # delete everything but 1 function
vim c.php # delete the 1 function
git add b.php c.php
git commit
Solution 2 - Git
I've slightly modified Peter's answer to another question here to create a reusable, non-interactive shell script called git-split.sh
:
#!/bin/sh
if [[ $# -ne 2 ]] ; then
echo "Usage: git-split.sh original copy"
exit 0
fi
git mv $1 $2
git commit -n -m "Split history $1 to $2"
REV=`git rev-parse HEAD`
git reset --hard HEAD^
git mv $1 temp
git commit -n -m "Split history $1 to $2"
git merge $REV
git commit -a -n -m "Split history $1 to $2"
git mv temp $1
git commit -n -m "Split history $1 to $2"
It simply copies the source file into a new file, and both files have the same history. An explanation why this works can be seen in that other answer
Solution 3 - Git
Perhaps this previous SO question could be informative:
https://stackoverflow.com/questions/1728922/how-does-git-track-source-code-moved-between-files
To paraphrase the accepted answer: essentially, Git doesn't actually "store" moved code; when generating things like blames for moved code, that's done ex post facto by examining the state of the entire repository from commit to commit.
Solution 4 - Git
try git blame -C -C b.php