gitgithubgit-mergegit-rebase

Squash Git commits *non-interactively* with git rebase


I am looking for a way to squash commits with git rebase, but non-interactively. My question is, can we use git merge-base to find the common ancestor to "merge down to" and then squash all commits that are not shared?

E.g.:

git init
# make changes
git add . && git commit -am "first"
git checkout -b dev
# make changes to dev 
# *(in the meantime, someone else makes changes to remote master)*
git add . && git commit -am "second"
SHARED=$(git merge-base dev master)
git rebase ${SHARED}

above, because no changes to master happened in the meantime, I am not sure if this script would do anything. But what it definitely will not do, is squash commits. Is there anyway I can somehow squash all commits made on the dev branch, that are not in master?

Maybe the best thing to do would be to rebase, and then follow it with:

git reset --soft ${SHARED}

The reset --soft command should squash commits

To be clear, here is what I am looking for:

  1. clean linear history given by git rebase
  2. squash commits from feature branch without unnecessary interactivity

git rebase -i uses interactivity, which I want to avoid


Solution

  • The following will plop the dev tree into a new commit on master (note: this is not equivalent to a rebase, as @torek kindly points out below):

    git checkout dev         && \
    git reset --soft master  && \
    git commit
    

    Note that you should not have uncommitted pages or untracked files when doing this.

    Here's how it works:

    1. checkout dev will update HEAD, your index (staging area), and working tree to match the state of the repository at dev,
    2. reset --soft master will not affect your index or working tree (which means that all the files in your staging area will reflect exactly the state of the repository at dev), but will point HEAD at master, and
    3. commit will commit your index (which corresponds to dev) and walk master forward.

    The &&s ensure that the script does not continue if anything fails.