Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to squash a number of commits non-interactively?

People also ask

How could you squash multiple commits together without using?

You can do this fairly easily without git rebase or git merge --squash . In this example, we'll squash the last 3 commits. Both of those methods squash the last three commits into a single new commit in the same way. The soft reset just re-points HEAD to the last commit that you do not want to squash.

Can I squash specific commits?

There is no explicit Git squash command. Instead, to squash git commits, the interactive git rebase is used. To squash all commits on a single branch, the interactive git rebase command must be passed one of two arguments: the id of the commit from which the branch split from its parent.


Make sure your working tree is clean, then

git reset --soft HEAD~3
git commit -m 'new commit message'

I personally like wilhelmtell's solution:

git reset --soft HEAD~3
git commit -m 'new commit message'

However, I made an alias with some error checking so that you can do this:

git squash 3 'my commit message'

I recommend setting up aliases that actually run scripts so that it is easier to (a) code up your scripts and (b) do more complex work with error checking. Below is a script that does the work of squash and then below that is a script for setting up your git aliases.

Script for squashing (squash.sh)

#!/bin/bash
#

#get number of commits to squash
squashCount=$1

#get the commit message
shift
commitMsg=$@

#regular expression to verify that squash number is an integer
regex='^[0-9]+$'

echo "---------------------------------"
echo "Will squash $squashCount commits"
echo "Commit message will be '$commitMsg'"

echo "...validating input"
if ! [[ $squashCount =~ $regex ]]
then
    echo "Squash count must be an integer."
elif [ -z "$commitMsg" ]
then
    echo "Invalid commit message.  Make sure string is not empty"
else
    echo "...input looks good"
    echo "...proceeding to squash"
    git reset --soft HEAD~$squashCount
    git commit -m "$commitMsg"
    echo "...done"
fi

echo
exit 0

Then to hook up that squash.sh script to a git alias, make another script for setting up your git aliases like so (create_aliases.command or create_aliases.sh):

#!/bin/sh
echo '-----------------------'
echo 'adding git aliases....'
echo '-----------------------'
echo
git config --global alias.squash "!bash -c 'bash <path to scripts directory>/squash.sh \$1 \$2' -"
#add your other git aliases setup here
#and here
#etc.
echo '------------------------------------'
echo 'here is your global gitconfig file:'
echo '------------------------------------'
more ~/.gitconfig
echo 
echo
echo '----------------'
echo 'end of script...'
echo '----------------'

To add to the answer by wilhelmtell I find it convenient to soft reset to HEAD~2 and then amending the commit of HEAD~3:

git reset --soft HEAD~2
git commit --all --amend --no-edit    

This will merge all commits to the HEAD~3 commit and use its commit message. Be sure to start from a clean working tree.


I used:

EDITOR="sed -i '2,/^$/s/^pick\b/s/'" git rebase -i <ref>

Worked quite fine. Just don't try to have a commit log with a line that starts with "pick" :)


Use the following command to squash the last 4 commits within the last commit:

git squash 4

With the alias:

squash = !"f() { NL=$1; GIT_EDITOR=\"sed -i '2,$NL s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'\"; git rebase -i HEAD~$NL; }; f"
sq = !git squash $1
sqpsf = !git squash $1 && git psf 

From https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig