33

I'm looking for a way to squash all git commits into a single big commit in master branch. I fully understand the consequences of what I'm trying to do, no need to explain that this is dangerous or that it's not the right way to go - I want to lose all my history and turn this repository into a single big commit.

The main problem is: I have no other living branches, no local commits, and all of the previous commits have already been pushed to remote master.

Hacky scripts are also welcome.

1
  • First thing that comes to my mind: git rebase -i <first-commit-hash>. Then use your editor's query replace functionality to replace all the pick by squashand save. Then git push --force. Commented Mar 24, 2019 at 16:33

2 Answers 2

76

I would use git reset --soft:

git reset --soft id-of-first-revision-of-master git commit --amend -m "single commit for master" 

Then you can git push --force wherever you need that new branch.

Update

I can think of another simple way to do it, with more git commands:

git checkout --orphan some-branch git commit -m "First commit" git branch -f master # move the local branch git checkout master git branch -d some-branch # delete the temp branch 

It could also be done like this, in a more hackish fashion:

git commit-tree -m "First commit" HEAD^{tree} 

That will write a revision.... if you check it out, you will have a single revision, content will be exactly like it is where you were standing before.... feel free to move the local branch (as explained in the previous recipe)

Sign up to request clarification or add additional context in comments.

4 Comments

@eftshift0 the git command git checkout --orphan -b some-branch is causing an error fatal: 'some-branch' is not a commit and a branch '-b' cannot be created from it. Did you actualy mean git checkout --orphan some-branch?
might make sense without the -b. I mean, if you are checking out an --orphan, then it's a new branch, right? Then no need to specify -b. Perhaps that's the logic.
I did first five commands here, and then 'git push --force-with-lease' - which did the trick. Only 1 commit on my remote, and my commits with sensitive data were gone.
5 years to push? Going over a slow dial-up?
17

You can still modify the history on the upstream by using git push --force-with-lease. However you have to be aware of the consequences.

Using git push --force will create a parallel tree on your upstream so all the developers may find themselves lost in a legacy branch.

In order to squash your history, simply do:

git rebase -i HEAD~10 

Where 10 is the number + 1 of commits you want to squash together. If you want to squash all the commits, then just refer your <first-commit-hash> instead of HEAD~10. Then on the editor you select squash for all the commits you want to group together. You can do search/replace: pick by squash

Once done, simply push your changes:

git push --force-with-lease 

I would never recommend to do --force because if another developer has pushed a commit in the meantime you will erase its move. By using --force-with-lease Git will prevent you to push if somebody else has pushed on the top of your last change (see this question for more details).

4 Comments

I believe instead of using the <first-commit-hash>, you can use git rebase -i --root to rebase all the way to the initial commit
The --root parametr does the trick for me. The solution whit HEAD~number or first commit hash does not work for me - they finish with two commits - not the only one.
Perfect @RuChernChong Thank you, using --root also did the trick for me
To be clear, it should be git push origin HEAD:main --force-with-lease

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.