Eric O. Lebigot
Eric O. Lebigot

Reputation: 94605

How to remove deletions and renames from the history?

In git, how to remove file deletions and renames, starting from a certain commit in a branch, while maintaining the history of changes for each file (both deleted and renamed)?

My use case is that I took a branch and started from there a new branch where I removed some files and renamed some others. I then modified the remaining (and often renamed) files (and also added some files). Now I want to revert back to the original names and recover the deleted files (that still exist at the common base), while keeping the history of everything. My final goal is to be able to merge back in the original branch (so without the renames and file deletions that I introduced).

Can this be done? I am wondering how easy this is, especially since the renamed files were modified (so naively removing the renames would sever the history link between the original files and the modifications, which I instead want to keep)…

PS: The changes since the branch diverged are extensive (at least on the "cleaned" branch).

Upvotes: 0

Views: 702

Answers (2)

Schwern
Schwern

Reputation: 165576

You don't have to rewrite history to make the merge work. You can revert the renames and reintroduce the deleted files, then commit and merge. Use git mv to rename the files back. Deleted files can be recovered using git checkout <rev-which-deleted-the-file>^ -- <filename>. See this answer for details.

Deleted and renamed files can be found using git-log's --diff-filter.

Git doesn't store renames, it calculates them on the fly with some heuristics to deal with small edits. git-log, git-diff, and git-blame all have options like -C and -M to control how hard Git tries to find copied and renamed (moved) files. So the continuity of history is not necessarily lost by the renames in the branch.


If you really want to rewrite your history, first find all the changes which delete files using git log --diff-filter=D master..branch. Then you can use git rebase -i to alter those commits and restore the deleted file.

Rewrites are a bit trickier because you'll have to undo the rename and then rename the file in each subsequent commit. This is a job for git-filter-branch which can apply the same change to a series of commits.

git filter-branch --tree-filter 'if [ -f new ]; mv new old; fi' master..branch

The --tree-filter runs the shell command on each commit and then alters the commit by adding and deleting files as necessary.

As before, to find your renames use git log --diff-filter=R master..branch.

Upvotes: 2

vonbrand
vonbrand

Reputation: 11831

You could try doing a git rebase -i for the offending branch, at the branching point. For security's sake, I'd first create a new branch at the tip of the branch you want to mangle, in case (hah! Murphy's law is relentless) something goes wrong.

If the changes are very extensive, there are ways to automate this, but that is more iffy. See the Pro git book for details.

Upvotes: 0

Related Questions