How to remove selected commit log entries from a Git repository while keeping their changes?
Solution 1
git-rebase(1) does exactly that.
$ git rebase -i HEAD~5
git awsome-ness [git rebase --interactive] contains an example.
- Don't use
git-rebase
on public (remote) commits. - Make sure your working directory is clean (
commit
orstash
your current changes). - Run the above command. It launches your
$EDITOR
. - Replace
pick
beforeC
andD
bysquash
. It will meld C and D into B. If you want to delete a commit then just delete its line.
If you are lost, type:
$ git rebase --abort
Solution 2
# detach head and move to D commit
git checkout <SHA1-for-D>
# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>
# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>
# Re-apply everything from the old D onwards onto this new place
git rebase --onto HEAD <SHA1-for-D> master
Solution 3
Here is a way to remove a specific commit id knowing only the commit id you would like to remove.
git rebase --onto commit-id^ commit-id
Note that this actually removes the change that was introduced by the commit.
Solution 4
To expand on J.F. Sebastian's answer:
You can use git-rebase to easily make all kinds of changes to your commit history.
After running git rebase --interactive you get the following in your $EDITOR:
pick 366eca1 This has a huge file
pick d975b30 delete foo
pick 121802a delete bar
# Rebase 57d0b28..121802a onto 57d0b28
#
# 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
You can move lines to change the order of commits and delete lines to remove that commit. Or you can add a command to combine (squash) two commits into a single commit (previous commit is the above commit), edit commits (what was changed), or reword commit messages.
I think pick just means that you want to leave that commit alone.
(Example is from here)
Solution 5
You can non-interactively remove B and C in your example with:
git rebase --onto HEAD~5 HEAD~3 HEAD
or symbolically,
git rebase --onto A C HEAD
Note that the changes in B and C will not be in D; they will be gone.
Related videos on Youtube
xk0der
I love coding, spending time with my wife and daughter, and reading programming related books and articles.
Updated on October 16, 2020Comments
-
xk0der over 3 years
I would like to remove selected commit log entries from a linear commit tree, so that the entries do not show in the commit log.
My commit tree looks something like:
R--A--B--C--D--E--HEAD
I would like to remove the B and C entries so that they do not show in the commit log, but changes from A to D should be preserved. Maybe by introducing a single commit, so that B and C become BC and the tree looks like.
R--A--BC--D--E--HEAD
Or, ideally, after A comes D directly. D' representing changes from A to B, B to C and C to D.
R--A--D'--E--HEAD
Is this possible? if yes, how?
This is a fairly new project so has no branches as of now, hence no merges as well.
-
jfs almost 12 years@xk0der: "commits" is the right term here.
rebase
may remove old/create new commits. I don't know what "commit log entries" means. -
xk0der almost 12 years@J.F.Sebastian I don't see a problem with "commit log" - Log of all the commits. And I wanted to delete a few entries from the log - while keeping the actual changes (the commits).
-
jfs almost 12 years@xk0der: git commits are content-addressable i.e., if you change anything in a commit e.g., its log message; you create a new commit. You could read git's commit without git and see for yourself.
-
xk0der almost 12 years@J.F.Sebastian - Thanks for the links - I know that - But does that technicality really change the problem I was facing and how I put it forth? I guess not. In the end: I wanted to remove "the commit log messages" - without removing the "commit changes" - Please reread my question - specially the second paragraph. To add more
git log
shows the "commit log" git-scm.com/docs/git-log . And I wanted to get rid of two entries from that log - not the changes.
-
-
xk0der over 15 yearsThanks for the quick reply. So do I checkout A and do a rebase, something like
git rebase -i D [A]
? -
jfs almost 15 yearsThe OP wants to combine B,C,D commits, not to delete their changes.
-
tina Miller about 13 years
-
Frosty about 13 yearsThe extra HEAD in this command is will cause the rebase to finish with a 'detached HEAD' which is undesirable. It should be ommitted.
-
CB Bailey almost 13 yearsThis reverts the changes introduced my commit-id, the OP wants to retain the changes, just squash the commits.
-
Eray over 12 yearsHow can we do it on remote repos ?
-
jfs over 12 years@Eray: just
push -f
your changes. Don't do it if you're not working alone. -
jfs over 12 years
-
nalply over 12 years@J.F.Sebastian, thanks this makes sense. If we are a small team could we stop the world: everybody push, rebase, everybody delete local and clone? Would this work?
-
ripper234 over 12 yearsUpdated link to use wayback machine.
-
Mauricio Scheffer over 12 yearsI think you meant
reset --hard
, notrebase --hard
(which doesn't exist) -
jfs over 12 years@ripper234: I've fixed links to point
git-rebase
manual and wayback machine for the blog post. -
cgp about 12 yearsThis works too and helped me to understand what a soft reset is. Granted, the "top" answer is right too and shorter, but thanks for this answer as well.
-
Emil Styrke over 11 years-1 because it doesn't do what the OP asked (rather it destroys something he explicitly wanted to retain).
-
billrichards about 10 years<funfact> git rebase -i HEAD~5 followed by :q (from vim) results in --no-ff "Merge from..." commits being removed. </funfact>
-
Filip Bartuzi almost 9 years
@~5
is a shortcut forHEAD~5
-
Maggie S. over 8 years@J.F.Sebastian I am genuinely wanting to delete a commit and all its data/changes, but when I remove the commit line that I want to delete and exit the $EDITOR with
:wq
all I get is a message that sayscould not execute editor
. And them when I check undergit log
the commit I wanted to delete is still there. What does that error mean? -
jfs over 8 years@MaggieB.: these questions: "how to delete a line in my $EDITOR, how to save the changes to disk, how to exit the editor, how to specify another editor that you are more familiar with" should be asked separately. The answers depends on your
$EDITOR
(don't forget to mention what it is). See How to Ask -
Renan Bandeira almost 8 yearsif you do this you will lose the E commit as well, won't you? As I understood, you delete master and rename rework as master (considering the ABCDE flow is the master branch).
-
Max about 7 yearsSee here for more info: sethrobertson.github.io/GitFixUm/fixup.html#remove_deep
-
seeafish about 6 yearsJust to echo what @jfs said and add some more context, doing a rebase will rewrite the log shas! This is important to note, because if you've already pushed up, you'll need to force push to overwrite the upstream log. Problem there, as mentioned, anyone else working off that branch now can't push since the origin has changed.
git push --force-with-lease
is one thing to make note of, but in general, DON'T FORCE PUSH UNLESS YOU'RE WORKING ALONE! -
Edvins almost 5 yearsAlthough it doesn't do what the OP asked for, it was exactly what I needed, so +1 for a useful answer.