Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git revert deleted file and preserve file history

Suppose I have a file a.txt. One day, I deleted it, committed, and pushed.

The next day, I wanted like to revert the last commit, bringing back a.txt. I tried using git revert, but when I did git blame, all lines are showing the revert commit hash. The original blame history is lost.

Can I recover the file and preserve the file history, i.e., as if the file has not been deleted before? Note that I must not change the history as the commit has been pushed.

Thanks!

like image 845
fushar Avatar asked Aug 19 '15 17:08

fushar


2 Answers

You CAN do this! Here's how:

  1. Start a new branch from the commit preceding the delete that you want to undo.
  2. Merge the offending change with git merge <sha> -s ours.
  3. If the commit had changes besides the deletion that you want to keep:
    1. Reapply the changes to your working copy with git diff <sha>^..<sha> | git apply.
    2. Discard the deletions (many techniques are available; git checkout -p may work well for you).
  4. Merge this branch back into the main branch (e.g. master).

This produces a history with two branches; one in which the file was deleted, and one in which it was never deleted. As a result, git is able to track the file history without resorting to heroics such as -C -C -C. (In fact, even with -C -C -C, the file isn't "restored", because what git sees is that a new file was created as a copy of a previously existing file. With this technique, you are reintroducing the same file to the repository.)

like image 184
Matthew Avatar answered Oct 11 '22 17:10

Matthew


Run git blame with the -C option specified three times:

git blame -C -C -C

This causes git blame to look for content copied from files in previous commits.

From the documentation for git blame:

-C|<num>|

In addition to -M, detect lines moved or copied from other files that were modified in the same commit. This is useful when you reorganize your program and move code around across files. When this option is given twice, the command additionally looks for copies from other files in the commit that creates the file. When this option is given three times, the command additionally looks for copies from other files in any commit.

<num> is optional but it is the lower bound on the number of alphanumeric characters that Git must detect as moving/copying between files for it to associate those lines with the parent commit. And the default value is 40. If there are more than one -C options given, the <num> argument of the last -C will take effect.

like image 21
Ajedi32 Avatar answered Oct 11 '22 18:10

Ajedi32