Suppose I have the following history:
A---B---C----------D------------E master
\ /\ /
W1--X1--Y1 W2--X2--Y2
topic1 topic2
Is it possible to remove all topic branches and their commits as following
A-B-C-D-E master
You have a few options for doing this.
One solution is to simply use a hard reset with a few squash merges:
git checkout master
git reset --hard C
git merge --squash topic1
git commit -m "Rewrite D"
git merge --squash topic2
git commit -m "Rewrite E"
# Verify that the new branch is no different from the old one
git diff sha_of_old_E
The idea here is that a squash merge will copy the final state of a topic branch (i.e. the last commit) into your current working copy, where you can then commit it. It effectively squashes a branch into a single commit.
Another method is to use an interactive rebase to squash the topic branches into a single commit. First, invoke the rebase
git rebase -i C
That will bring up the interactive rebase TODO list editor in your terminal. You'll see the following commits displayed:
pick sha W1
pick sha X1
pick sha Y1
pick sha W2
pick sha X2
pick sha Y2
What you want to do is something similar to the squash merge above. You can to squash the topic branches into single commits, so for each commit of a topic branch, squash (or "fixup") the descendant commit into its parent:
pick sha W1
squash sha X1
squash sha Y1
pick sha W2
squash sha X2
squash sha Y2
Then hit :wq
in the Vim editor to begin the interactive rebase. I won't go into detail about the next steps, because they're already adequately detailed in other numerous sources around the internet, such as in Pro Git § 6.4 Git Tools - Rewriting History - Squashing Commits.
You'll probably want to double check that you did the rebase correctly by verifying that the newly rewritten branch is no different from the previous one by using a simple diff:
git diff sha_of_old_E
Note that if you'd rather not bother editing the commit messages for each squash, you can use "fixup" instead, which will just reuse the commit message of the previous commit:
pick sha W1
fixup sha X1
fixup sha Y1
pick sha W2
fixup sha X2
fixup sha Y2
Note that you can also use s
or f
for squash and fixup, respectively.
Note that both of the above solutions will rewrite your commit history, of course, so your new commits will have different sha IDs. If you've already pushed the old version of your branch to your remote, then you'll need to force push to overwrite the old copy. This may not be something you want to do if you're sharing your branch with other people, for reasons which I won't detail here, since the possible dangers of force pushing are well documented in numerous other online sources, such as: