Reputation: 95
I would like to squash commits X to Y (let's say the 2nd to last commit to the 5th last commit) that have already been pushed to my remote repository. I see answers on Stackoverflow for squashing X last commits, but I am not interested in squashing the last X commits, but commits behind the last few commits.
Upvotes: 2
Views: 1082
Reputation: 1260
What you want is an "interactive rebase" (git rebase -i
) which you can use to rebase a branch onto itself. The command will provide you with a list of commits that you've specified in your range which you can then ask to be edited, squashed together, left alone - For instance in the middle of a range of commits.
https://git-scm.com/docs/git-rebase
-i --interactive Make a list of the commits which are about to be rebased. Let the user edit that list before rebasing. This mode can also be used to split commits (see SPLITTING COMMITS below).
Example:
15:49 $ git log --oneline -5
ffdad47 2020-10-12 (HEAD -> master) fourth commit [Martin KJELDSEN]
60b7363 2020-10-06 third commit [Martin KJELDSEN]
a72eea4 2019-03-28 second commit [Martin KJELDSEN]
b9b64b8 2019-03-28 first commit [Martin KJELDSEN]
Then run the rebase command to rebase all commits onto b9b64b8
.
git rebase -i b9b64b8
Git presents me with the following list in an editor and i'll select to squash one of the middle commits (fixup
= squash and use existing commit message. squash
= let the user merge all the commit messages together before proceeding with rebase).
pick a72eea4 second commit
fixup 60b7363 third commit
<There could be more commits here>
pick fourth commit
# Rebase b9b64b8..ffdad47 onto b9b64b8 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
When saving this configuration and continuing with the rebase you'll have rewritten history according to your rebase -i
configuration
Upvotes: 3
Reputation: 1975
I have found it easy to use the reverse-commit workflow. To execute that I start with the most recent commit I want to back out and work my way down the commit history using these commands (or your favorite GUI tool):
git revert [commit_hash]
There are some useful flags such as --no-edit
and --no-commit
depending on how you like to manage your commit messages and where you are in your commit index.
Upvotes: 0