Search code examples
gitgit-mv

Late-rename file after commit in git


Someone changed a file name and its content in a way that git was unable to detect that it was the same file.

They also didn't use git mv, so when I got the pull request I saw a new file being added and an old file being deleted, which makes it impracticable for reviewing.

Being a nice guy I pulled their code and tried to do a late git mv, so I'd be able to add a commit to their pull request and see things beautifully on Github review page, but that didn't work.

Is there a way to do a posthumous rename of a file?


Solution

  • Git doesn't track file identity: there's nothing in the repository that says that file bar in revision n was renamed/copied/moved from file foo in revision (n-1). Doing git mv is the same as doing plain mv followed by git add on the new name and git rm on the old. The repository just stores a snapshot of the directory tree at each commit, and it's up to the tools examining the repository to make decisions about how the files in different commits relate to each other.

    When you're looking at the revision history and git says a file was moved or renamed, it's determining that locally, as a guess based on the similarity of the old and new files' contents. Many git commands support a -M option that lets you specify the similarity threshold for deciding that a delete and an add in the same commit should be regarded as a rename. The default threshold is 50%.

    If you want git to treat the change as a rename by default, without having to specify a lower -M threshold every time you examine the repository, you can split the change into two commits: one to change the contents while keeping the name, and one to rename the file while keeping the contents unchanged (or at least, less than 50% changed).

    Doing this "posthumously" will, of course, require resetting the branch head to before the old commit, replacing it with the two new commits, force-pushing, and contacting anyone who might have pulled the original version to let them know you've changed history. (This is no different from making any other kind of change to a commit that's been published to others.)