How to remove selected commit log entries from a Git repository while keeping their changes?
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.
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)