26

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.

phd
  • 82,685
  • 13
  • 120
  • 165
milosmns
  • 3,595
  • 4
  • 36
  • 48
  • First thing that comes to my mind: `git rebase -i `. Then use your editor's query replace functionality to replace all the `pick` by `squash`and save. Then `git push --force`. – JB Nizet Mar 24 '19 at 16:33
  • https://stackoverflow.com/search?q=%5Bgit%5D+squash+all+commits – phd Mar 24 '19 at 17:03
  • Hm there are many solutions so this, not sure which one is right – milosmns Mar 25 '19 at 10:48

2 Answers2

59

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)

vvvvv
  • 25,404
  • 19
  • 49
  • 81
eftshift0
  • 26,375
  • 3
  • 36
  • 60
  • @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`? – Boris Mar 25 '21 at 17:46
  • 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. – eftshift0 Mar 25 '21 at 17:56
13

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).

nowox
  • 25,978
  • 39
  • 143
  • 293
  • 19
    I believe instead of using the ``, you can use `git rebase -i --root` to rebase all the way to the initial commit – Ru Chern Chong Mar 24 '19 at 17:06
  • 2
    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. – eNca Oct 18 '20 at 20:41
  • 1
    Perfect @RuChernChong Thank you, using `--root` also did the trick for me – Fernando Torres Apr 12 '23 at 05:37