2

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.

1
  • Imagine you have 6 commits, c1<--c2<--c3<--c4<--c5<--c6, and c6 is the latest commit. What do you mean by the 2nd to last commit to the 5th last commit? I did not get you.
    – Chuck Lu
    Commented Oct 13, 2020 at 8:12

2 Answers 2

3

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

2
  • I get the error: git: 'ls' is not a git command. See 'git --help'. How can I view my git history?
    – Chris You
    Commented Oct 12, 2020 at 14:31
  • ls is a custom macro i have, sorry. I will replace it with git log :)
    – zrrbite
    Commented Oct 12, 2020 at 14:33
0

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.

2
  • What GUI tool do you recommend?
    – Chris You
    Commented Oct 12, 2020 at 14:39
  • I use SourceTree for this specific use-case. GitHub has a nice one too. The command-line is usually most effective when in a bind. For whatever reason I can't seem to fall in love with any Git integrations within my IDEs.
    – benhorgen
    Commented Oct 12, 2020 at 16:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.