Matthieu Vergne's Homepage

Last update: 06/01/2022 17:50:20

How to Squash Several Git Commits into a Single One?

Context

Several of your commits contain changes that you want to keep in a single commit. For example, the addition of a new feature in a commit A and some fixes to this feature in a commit B. You want them to be in a single commit to deliver the new feture already fixed.

Here, we target a fine grained modification of our commits. If you prefer to forget your history and rewrite it completely, prefer this way.

Question

How to Squash Several Git Commits into a Single One?

Method

Rewriting a Git history can be done in plenty of ways. Unfortunately, messing it up can be done as well. If you feel unsafe about rewriting the history, give a look here first. Better feel safe than sorry.

All you need is to squash your commits into a single one that you can split later if required. Be aware that you will be the sole author of this commit, which might be unwanted. Either provide authors information in the commit details or, after splitting, amend the relevant commits with the right authors.

For squashing your commits, you need first to have them in a sequence. If some commits that you want to squash are mixed with commits you don't want to squash, first reorder your commits. The commits to squash can be in any order, so order them as you want as long as they are together.

Once your commits are properly ordered, here is the information you need to prepare:


COMMIT_LAST=$(git rev-parse HEAD) # Identify the last commit
COMMIT_START=<commit SHA-1>       # Identify the first commit to squash
COMMIT_STOP=<commit SHA-1>        # Identify the last commit to squash
MESSAGE="<message>"               # Message of the squashed commit

Once ready, just squash the sequence into a single commit:


git reset --hard ${COMMIT_START}~1                   # Place the branch on the commit before the sequence
git cherry-pick -n ${COMMIT_START}~1..${COMMIT_STOP} # Reproduce the sequence without commiting
git commit -m "${MESSAGE}"                           # Commit the result with the squash message
git cherry-pick ${COMMIT_STOP}..${COMMIT_LAST}       # Apply the remaining commits

Answer

To squash a set of Git commits, first ensure they are ordered into a sequence. You can then use git reset --hard to restart the branch just before the sequence to squash. The main command to retrieve your commits is git cherry-pick. Use it to retrieve the commits you need to reproduce as is. For the sequence to squash, pick them with the -n option to retrieve only there changes. You can commit all of them at once with git commit.

Bibliography