One Liner (for Bash/Zsh)
You can create a squash-all commit right from HEAD
, without rebase at all, just run:
git reset $(git commit-tree HEAD^{tree} -m "A new start")
Note: this requires a POSIX compatible shell like bash/zsh, or Git Bash on Windows.
Making an Alias in ~/.gitconfig
[alias]
squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} \"$@\");};f"
Then just run: git squash-all -m "a brand new start"
Note: Either provide the commit message from standard input, or via the -m
/-F
options, just like the git commit command. See git-commit-tree manual.
Alternatively, you can create the alias with the following command:
git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} "$@");};f'
Explain
create a single commit via
git commit-tree
What
git commit-tree HEAD^{tree} -m "A new start"
does is:Creates a new commit object based on the provided tree object and emits the new commit object id on stdout. The log message is read from the standard input, unless -m or -F options are given.
The expression
HEAD^{tree}
represents the tree object corresponding toHEAD
, namely the tip of your current branch. see Tree-Objects and Commit-Objects.reset the current branch to the new commit
Then
git reset
simply reset the current branch to the newly created commit object.This way, nothing in the workspace is touched, nor there's need for rebase/squash, which makes it really fast. And the time needed is irrelevant to the repository size or history depth.
Variation: New Repo from a Project Template
This is useful to create the "initial commit" in a new project using another repository as the template/archetype/seed/skeleton. For example:
cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")
This avoids adding the template repo as a remote (origin
or otherwise) and collapses the template repo's history into your initial commit.