peterh
peterh

Reputation: 1

How to retroactively delete a commit from a git repository?

I want to remove a commit from a git repository. Not the last one, thus a git reset won't work.

I have this: A->B->C->D->...

And now I want to have only

A->B->D->...

Thus, I want to change the past on a way as if C never had been existed.

How can I do that?

The possible inconsistencies with the remote repositories are a non-issue (I have full control over them). It is not a problem if the commit ids change, too.

Upvotes: 2

Views: 194

Answers (2)

torek
torek

Reputation: 488463

If you have a simple, linear set of changes to copy to new commits, use git rebase -i as in Alejandro C.'s answer. If not, do not mix git rebase -i with git rebase -p: it really won't work well.

Instead, first, use git replace to construct an alternative history: make a replacement for the commit that comes after the one(s) you want removed, where the replacement's parent is the next-earlier commit you want Git to "see" when it uses replacements (which it does by default). Then, once you have the desired history, run an otherwise-no-operation git filter-branch to copy the commits. The copied commits will, like the rest of Git, use the "pretend history" from the replacement, so they will in fact have that as their real history, and when git filter-branch makes the branch names point to the newly copied branch tips, the replacement history will now be the actual history.

(Then, as with any git filter-branch operation, you must clean away the refs/original/ references. It's also wise to all of this in a temporary spare repository in case you goof it up. :-) )

Upvotes: 1

Alejandro C.
Alejandro C.

Reputation: 3801

Use git rebase -i B then squash the commit that you don't want (but whose changes you want to keep; delete it if you don't want the changes) (where B is the ref of the parent of the commit you want to delete).

You'll get something like the following

pick B Good commit
squash C Commit message I don't want, but whose changes I do want
pick D Good commit 

# Rebase B..D onto B
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Upvotes: 2

Related Questions