How to squash all git commits into one?

Viewed 381547

How do you squash your entire repository down to the first commit?

I can rebase to the first commit, but that would leave me with 2 commits. Is there a way to reference the commit before the first one?

21 Answers

In one line of 6 words:

git checkout --orphan new_root_branch  &&  git commit

create a backup

git branch backup

reset to specified commit

git reset --soft <#root>

then add all files to staging

git add .

commit without updating the message

git commit --amend --no-edit

push new branch with squashed commits to repo

git push -f

To do this, you can reset you local git repository to the first commit hashtag, so all your changes after that commit will be unstaged, then you can commit with --amend option.

git reset your-first-commit-hashtag
git add .
git commit --amend

And then edit the first commit nam if needed and save file.

Let's say you have 3 commits in your branch and it is already pushed to remote branch.

Example:

git log -4

Will display results like:

<your_third_commit_sha>
<your_second_commit_sha>
<your_first_commit_sha>
<master_branch_commit_sha - your branch created from master>

You want to squash your last 3 commits to one commit and push to remote branch. Here are the steps.

git reset --soft <master_branch_commit_sha>

Now all commits changes are integrated but uncommitted. Verify by:

git status

Commit all changes with a message:

git commit -m 'specify details'

Forcefully push the single commit to remote branch:

git push -f

For me it worked like this: I had 4 commits in total, and used interactive rebase:

git rebase -i HEAD~3

The very first commit remains and i took 3 latest commits.

In case you're stuck in editor which appears next, you see smth like:

pick fda59df commit 1
pick x536897 commit 2
pick c01a668 commit 3

You have to take first commit and squash others onto it. What you should have is:

pick fda59df commit 1
squash x536897 commit 2
squash c01a668 commit 3

For that use INSERT key to change 'insert' and 'edit' mode.

To save and exit the editor use :wq. If your cursor is between those commit lines or somewhere else push ESC and try again.

As a result i had two commits: the very first which remained and the second with message "This is a combination of 3 commits.".

Check for details here: https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit

This worked best for me.

git rebase -X ours -i master

This will git will prefer your feature branch to master; avoiding the arduous merge edits. Your branch needs to be up to date with master.

ours
           This resolves any number of heads, but the resulting tree of the merge is always that of the current
           branch head, effectively ignoring all changes from all other branches. It is meant to be used to
           supersede old development history of side branches. Note that this is different from the -Xours
           option to the recursive merge strategy.

I usually squash the entire tree when I restore a template from a git repository, to get a cleaner history and to ensure legal compliance. My workflow looks like this:

git clone https://git.invalid/my-awesome-template.git my-awesome-foo
cd !$
git branch -M master my-awesome-template/master
git checkout --orphan master
git rm -rf /
git commit --allow-empty --allow-empty-message -m 'Initial commit'
git merge --squash --allow-unrelated-histories my-awesome-template/master
git commit
git branch -D my-awesome-template/master
# you can now `drop' that "Initial commit":
git rebase -i --root

This squashes your entire history into a single large commit message.

In this particular example:

  • master is the working branch
  • my-awesome-template/master is an intermediate branch

Since I had some trouble with the solutions proposed here, I want to share a really simple solution (to squash all commits on a feature branch into one):

git merge origin/master && git reset --soft origin/master

The preceding merge cmd ensures, that no recent changes from master will go on your head when committing! After that, just commit the changes and do git push -f

I tried different commands with HEAD^{tree} but got this error from zsh:

zsh: no matches found: HEAD^{tree}

It was how ohmyzsh handles expansion, see this issue for more details: https://github.com/ohmyzsh/ohmyzsh/issues/449

Easiest fix is to run this command:

unsetopt nomatch
Related