864

I make new branch from master with:

git checkout -b testbranch

I make 20 commits into it.

Now I want to squash those 20 commits. I do that with:

git rebase -i HEAD~20

What about if I don't know how many commits? Is there any way to do something like:

git rebase -i all on this branch
Soviut
  • 88,194
  • 49
  • 192
  • 260
user3803850
  • 8,797
  • 3
  • 12
  • 6
  • 19
    You can do `git rebase -i 58333012713fc168bd70ad00d191b3bdc601fa2d` wich will do an interactive rebase where the commitnumber is the last commit that stays **unchanged** – denns Apr 03 '17 at 16:49
  • 2
    @denns Using this method with the last commit in the branch you are rebasing _from_ worked fantastic. Thanks so much! – Joshua Pinter Apr 16 '20 at 17:44
  • 7
    If someone was looking for how to squash the master/main branch: `git rebase -i --root master` – schmijos Jan 26 '22 at 08:51

23 Answers23

1049

Another way to squash all your commits is to reset the index to master:


Note: Git's default branch name is still master with Git version 2.41 (Q3 2023), as seen in git init man page.
Git version 2.28 (Q3 2020) introduced configurable default branch names, which means your remote repository may optionally use another default branch name such as main. In order to provide the most universally applicable examples, as well as avoid confusion, this answer shall assume Git's default configuration.

If you need the following commands to work for any default branch, replace master with ${defaultBranch}.
And define defaultBranch=$(git config --get init.defaultBranch || echo main).


Back to the solution: (to squash all your commit) reset the index to master:

git checkout yourBranch
git reset $(git merge-base master $(git branch --show-current))
git add -A
git commit -m "one commit on yourBranch"

This isn't perfect as it implies you know from which branch "yourBranch" is coming from.
Note: finding that origin branch isn't easy/possible with Git (the visual way is often the easiest, as seen here).

Note: git branch --show-current has been introduced with Git 2.22 (Q2 2019).


Or, as noted by Hiroki Osame in the comments:

git switch yourBranch
git reset --soft $(git merge-base master HEAD)
git commit -m "one commit on yourBranch"
  • no need for git branch --show-current since HEAD is already a reference to that branch.
  • no need for git add -A, since git reset --soft only moves HEAD, and leaves the index untouched (in other words, the files are already "added").

EDIT: you will need to use git push --force (or git push --force-with-lease)
See "git push --force-with-lease vs. --force"


Karlotcha Hoa adds in the comments:

For the reset, you can do

git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD)) 

[That] automatically uses the branch you are currently on.
And if you use that, you can also use an alias, as the command doesn't rely on the branch name.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 4
    Better to checkout to commit where `YourBranch` currently is. This will keep `YourBranch` intact when you do `reset` – Eugen Konkov Apr 03 '18 at 10:40
  • On Windows just run "git merge-base master yourBranch" take the output and paste the output after "git reset" – Abdurrahim Jun 26 '18 at 11:34
  • 1
    @Abdurrahim Or open a git bash, and yo can copy-paste thos commands! – VonC Jun 26 '18 at 12:01
  • 12
    For the reset, you can do `git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD))` to automatically use the branch you are currently on. And if you use that, you can also use an alias, as the command doesn't rely on the branch name. – Karlotcha Hoa Aug 03 '18 at 20:53
  • @KarlotchaHoa Thank you, very good idea. I have included your comment in the answer for more visibility. – VonC Aug 03 '18 at 20:55
  • I've always used `git reset $(git merge-base origin/master @)` without issues. Is this error-prone? – Druska Sep 21 '18 at 14:30
  • 1
    @Druska For simlpe branching cases, no, it should work fine. – VonC Sep 21 '18 at 14:57
  • 1
    @Shimmy yes, provided you force push after the reset: `git push --force` (and warn your colleagues if you are several people working on that branch) – VonC Apr 28 '20 at 07:41
  • 1
    It works perfectly when you work with merged branches where you can't rebase your commits. Thanks! – yigidix Jan 26 '21 at 09:48
  • This only works on Git 2.22 and above. https://stackoverflow.com/a/6245587/5921427 – Sujay66 Jun 11 '21 at 21:53
  • @Sujay66 Good point. I have edited the answer to reference https://stackoverflow.com/a/55088865/6309, which is were I documented in 2019 the introduction of `git branch --show-current`. – VonC Jun 12 '21 at 05:05
  • This is pretty cool, but I'd rather reset to the tip of `origin/master` rather than merge-base. That way, the previous merges from master into the branch won't get in the way. – Dima Aug 13 '21 at 20:35
  • 1
    This is the only solution that worked slick for me, among the dozens of supervoted different stackoverflow threads like: https://stackoverflow.com/questions/37937984/git-refusing-to-merge-unrelated-histories-on-rebase and https://stackoverflow.com/questions/5189560/squash-my-last-x-commits-together-using-git – Eduardo Pignatelli Aug 17 '21 at 10:38
  • 1
    This is a great tip to use when the delta between a feature branch and trunk is clean (no conflicts, trunk merged into feature branch) but rebasing gives conflicts – antonagestam Oct 12 '21 at 08:50
  • Why is the `-force` flag necessary in this particular case ? – DrGregoryHouse Nov 18 '21 at 14:16
  • 1
    @DrGregoryHouse Because the history of the branch changes (HEAD reset to another commit, instead of new commits being added to the existing ones) – VonC Nov 18 '21 at 14:22
  • Well, this did not work at all, only the latest commit got affected and none of the previous ones – Anna T Dec 08 '21 at 18:30
  • @AnnaT OK. I would advise to present this (failed) use case in a separate question, to better understand what happened. – VonC Dec 08 '21 at 18:34
  • I fixed it some other way already - made a new branch off of main (b1), then did a hard reset on mainline, made new branch from main (b2 - in state without any of my committed but not pushed changes), then merge b1 into b2 with a squash – Anna T Dec 16 '21 at 16:24
  • And since my default branch is called main and my search had multi times brought me here. To copy it for my next time: `git reset $(git merge-base main $(git rev-parse --abbrev-ref HEAD))` – sschoof Feb 25 '22 at 09:30
  • @sschoof Good point, thank you. I have included your comment in the answer for more visibility. – VonC Feb 25 '22 at 11:06
  • You can simply replace the part `$(git rev-parse ..)` with `HEAD` or miss I something – niels Mar 09 '22 at 14:33
  • @niels I believe the goal is to get back the name of the branch for HEAD. But yes, HEAD should work. – VonC Mar 09 '22 at 14:37
  • @VonC I found the solution to complex and thing `rebase -i` is the way which is build in. – niels Mar 09 '22 at 15:04
  • I'm curious how this approach compares to `git reset --soft main` listed in subsequent upvoted answers. – Matthew Dean May 03 '22 at 16:58
  • @MatthewDean It is more or less the same, except i use `git merge-base` in order to reset to the right commit. – VonC May 03 '22 at 17:46
  • 1
    Gah -- the `-A` option needs to come with a warning – JizoSaves Jul 29 '22 at 17:25
  • 1
    I don't care how other people say,but this is the only way that work for me!!!! – William Aug 12 '22 at 21:25
  • git add -A hangs. – thang Oct 18 '22 at 16:41
  • @thang You need to ask a separate question. Comments are not the place to troubleshoot this. – VonC Oct 18 '22 at 19:03
  • If you've checked out the branch, you should be able to do: `git merge-base master HEAD`. And instead of `git reset`, I recommend `git reset --soft` so the `git add -A` isn't necessary. – Hiroki Osame Jan 29 '23 at 01:59
  • How would you squash all commits except the first commit? :D – Sandwich Feb 27 '23 at 20:05
  • 1
    @Sandwich You could reset to your first commit, then add and commit: that would create a second commit which would effectively squash all commits previously done after the first commit. – VonC Feb 27 '23 at 20:09
606

Checkout the branch for which you would like to squash all the commits into one commit. Let's say it's called feature_branch.

git checkout feature_branch

Step 1:

Do a soft reset of your origin/feature_branch with your local main branch (depending on your needs, you can reset with origin/main as well). This will reset all the extra commits in your feature_branch, but without changing any of your file changes locally.

git reset --soft main

Step 2:

Add all of the changes in your git repo directory, to the new commit that is going to be created. And commit the same with a message.

# Add files for the commit.
git add ...
git commit -m "commit message goes here"
kevinarpe
  • 20,319
  • 26
  • 127
  • 154
shanky
  • 6,283
  • 1
  • 11
  • 15
  • 48
    This was the most reliable solution for me - not causing any rebase errors nor merge conflicts. – ANTARA Jul 27 '18 at 12:45
  • 14
    Warning: the git add -A add EVERYTHING you have in the local folder - to the branch. – David H Aug 24 '18 at 15:27
  • 7
    Best solution for a noob - non destructive and only oops moment may be checking in too much such as app secrets etc, which shouldn't matter if you have a proper gitignore file – Karan Harsh Wardhan May 31 '19 at 06:41
  • @NSduToit Short answer: No, you don't have to. After doing the above mentioned steps in my answer, you will end up with one commit with some code changes. You can think of it as just like any other commit with some code changes. You can push that to your remote branch without the `-f` flag. – shanky Jul 18 '19 at 16:38
  • this works only when the "feature_branch" is new branch – Bhimashankar Mantur Mar 17 '20 at 13:02
  • 9
    @BhimashankarMantur you can make it work if you push with "--force" to existing branch - because this "git reset --soft" is rewriting history. But of course you should push with "--force" only to branches which are used only by you - not shared ones - unless you notify all people which are using such branch about your force push (so they can retrieve those changes corerctly for example using: "git pull --rebase origin my-branch-name" ) – domis86 Apr 23 '20 at 11:49
  • git reset --soft master . master has to be main I guess – Shreyas Shetty Feb 18 '21 at 10:46
  • Beware, this overwrites changes of other poeple. – Caveman Sep 13 '21 at 01:30
  • better check log on your branch and reset to the desired commit 'cause main won't ensure the commit you want. Also with --soft tag, you needn't to `git add`, it's already staged. – Hieu Doan Nov 22 '21 at 09:52
  • 2
    Really nice solution. As i have already uploaded my changes, i need to force push `git push -f`, but worked like a charme. Thanks for sharing. – SAM Mar 07 '22 at 13:30
  • This worked for me! after trying rebase... reset... – x-code Jul 27 '22 at 13:59
  • Step3: --force push feature/working branch – x-code Jul 27 '22 at 14:00
  • Decent solution, I do suggest rebasing with master/main/develop before squashing your commits. – Vahid Amiri Sep 12 '22 at 08:29
  • This very a very nice explanation. I use the 'git reset --soft ' idea to work in a new branch and then I have one branch with the original commits and one with a squashed version. – WeakPointer Oct 28 '22 at 14:15
203

What you're doing is pretty error-prone. Just do:

git rebase -i master

which will automatically rebase only your branch's commits onto the current latest master.

Eevee
  • 47,412
  • 11
  • 95
  • 127
  • 22
    Agreed this is your best solution. but follow this [link](https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit) as it better explains what you need to do. – Christo Aug 14 '16 at 18:22
  • 5
    Instead of squashing commits, you could merge the branch to master and do a git reset to origin/master to unstage all commits. That would let you commit your existing unstaged code with `commit -am "the whole thing!"` – nurettin Sep 12 '17 at 10:37
  • 4
    @nurettin I think the `reset origin/master` method is really bad as it's just the same as making commits directly on master - there is not 'merge branch' history, no pull request option. The answer by @WaZaA is much more in keeping with normal git workflow I think – Drenai Dec 13 '17 at 10:04
  • 2
    Actually i think the `git merge --squash feature-branch` does the same thing!. There is a GitHub merge pull request squash option, think that's the route I'll go – Drenai Dec 13 '17 at 10:30
  • @Brian that's what I started doing afterwards. – nurettin Dec 13 '17 at 11:43
  • 1
    @nurettin Did you notice that after doing a Squash and Merge on your own repositories, that the branch still says `7 commits ahead of master`, even after the merge – Drenai Dec 13 '17 at 11:44
  • @Brian I haven't noticed that, but I've had `not fully merged` errors while deleting branches which I merge/squashed. Perhaps your message is talking about origin/master before a push ? – nurettin Dec 13 '17 at 12:35
  • @nurettin I've added it as a question, because I'm stuck on it https://stackoverflow.com/questions/47791622/github-merge-pull-request-with-squash-commits-branch-still-says-7-commits – Drenai Dec 13 '17 at 13:13
  • [Here's a really good overview of the merging and rebasing workflows](https://randyfay.com/content/rebase-workflow-git), and [in this comment on the same page](https://randyfay.com/comment/1107#comment-1107) you'll find some really helpful visualisation of the different ways of doing roughly the same thing. – pfabri Jun 01 '19 at 19:21
  • 1
    This solution did not work for me. It basically broke my branch. I got a bunch of errors. `error: could not apply 271a11a...` – Sergey Yarotskiy Jun 16 '22 at 14:56
  • Thank you. This is the simplest answer that just worked for me. – Dark Star1 Oct 19 '22 at 08:03
167

Another simple way to do this: go on the origin branch and do a merge --squash. This command doesn't do the "squashed" commit. when you do it, all commit messages of yourBranch will be gathered.

$ git checkout master
$ git merge --squash yourBranch
$ git commit # all commit messages of yourBranch in one, really useful
 > [status 5007e77] Squashed commit of the following: ...
Appulus
  • 18,630
  • 11
  • 38
  • 46
WaZaA
  • 1,840
  • 1
  • 11
  • 9
  • 4
    True. I mentioned the difference between merge --squash and rebase -i in http://stackoverflow.com/a/2427520/6309 – VonC Sep 21 '16 at 14:42
  • 7
    This works if you don't wanna squash into the parent branch, just create and switch to a new branch based off the parent branch and do the squash merge into that. – Belladonna Sep 22 '16 at 16:47
  • 7
    nice! i create a "temp" branch off "master" first to squash "yourBranch" into, then merge "temp" into "master". – lazieburd Sep 25 '19 at 16:43
  • 1
    How this is not the most voted answer. This exactly answers the question and more. First no mater what is the parent branch. Second it does what OP asked. Third It uses `merge` so no matter how many commits could be done on the destination branch (you wont pick a commit to rebase !). Nice tip. – Anddo Jan 17 '23 at 22:11
68

Assuming you were branching from the master, you don't need to enter yourBranch into the reset step all the time:

git checkout yourBranch
git reset --soft HEAD~$(git rev-list --count HEAD ^master)
git add -A
git commit -m "one commit on yourBranch"

Explanation:

  • git rev-list --count HEAD ^master counts the commits since you made your feature branch from the master, f.ex. 20.
  • git reset --soft HEAD~20 will make a soft reset of the last 20 commits. This leaves your changes in the files, but removes the commits.

Usage:

In my .bash_profile I have added an alias for gisquash to do this with one command:

# squash all commits into one
alias gisquash='git reset --soft HEAD~$(git rev-list --count HEAD ^master)'

After reseting and committing you need to do a git push --force.

Hint:

If you're using Gitlab >= 11.0 you don't need to do this anymore as it has a squashing option when merging branches. Gitlab Squashing option

mles
  • 4,534
  • 10
  • 54
  • 94
34

Solution - 1

A. Pull master into your feature branch (Make sure to update your Master)

git pull origin master  

B. Do soft reset to master

git reset --soft master

C. Commit your changes

git commit -m “commit message"

D. Do git push

git push --force  

Solution - 2

Squashing Commit using git rebase

A.

$git rebase -i HEAD~3  (HEAD~<no. of commits you want to squash>)

B. You will get one interactive prompt where you need to Pick the top commit and insert squash or s in front of those which you want to combine/squash.

Note: Make sure do changes in insert mode and save the file ; (wq in VI Editor)

C. Now you will get another interactive prompt where you need to put # in front of commits message that you don't want, and or add your own message. Again save the file and your commits will successfully rebase.

Cheers!

Alok Tripathi
  • 874
  • 10
  • 9
  • 1
    Solution #1 worked for me when interactive rebasing was too brutal - e.g. a really old branch with 122 commits on it. Interactive rebase was nasty, stepping through commit-by-commit on terribly old files with more conflicts than not. I wanted to just squash all the changes, rebase and then review the changes manually to see what was worth keeping, what needed to be discarded and what needed to be updated. Thanks! – Joshua Pinter Dec 15 '21 at 21:13
  • That's true. Solution 2 is handy if you have less no. of commits in the branch. – Alok Tripathi May 31 '22 at 17:42
28

Since I had some trouble with the solutions proposed here, I want to share a really simple solution (which really works regardless):

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 (inverted) when committing! After that, just commit the changes and do git push -f

seebi
  • 488
  • 5
  • 9
25

Based on reading several Stackoverflow questions and answers on squashing, I think this is a good one liner to squash all commits on a branch:

git reset --soft $(git merge-base master YOUR_BRANCH) && git commit -am "YOUR COMMIT MESSAGE" && git rebase -i master

This is assuming master is the base branch.

Travis Reeder
  • 38,611
  • 12
  • 87
  • 87
  • 2
    Thanks a lot, company has a lot of restrictions in place and could not rebase the usual way with an editor as was not aloud to save. Also could not use squash and merge feature in git as this branch goes to Lead dev for merging and he does not like it. This 1 liner worked and saved headaches. Awesome job. – L1ghtk3ira Oct 24 '17 at 15:25
19

How

You need to get the merge base of your branch

git merge-base master your-branch
# 566f8438e0cd0e331ceb49a9cb0920143dfb065c

Then you can rebase to it

git rebase -i 566f8438e0cd0e331ceb49a9cb0920143dfb065c
# then squash/pick/do commit messages

or just do a soft-reset and commit everything

git reset --soft 566f8438e0cd0e331ceb49a9cb0920143dfb065c
git add .
git commit -m "The only commit"

Automate

If you do this often you can automate it by putting these in your .bashrc using.

g-rebase-branch() {
  git branch --show-current | xargs git merge-base master | xargs git rebase -i
}

g-one-commit() {
  local last_commit_message=`git show -s --format=%s`
  git branch --show-current | xargs git merge-base master | xargs git reset --soft
  git add -A
  git commit -m "$last_commit_message"
  git commit --amend
}

and then do these directly in the terminal.

g-one-commit

but if you're merging against a different branch than master then you can replace master with "$1" to do this

g-one-commit staging
Caveman
  • 2,527
  • 1
  • 17
  • 18
12

To refine Caveman's answer a bit, use git reset --soft <commit>. From the documentation, this command:

Does not touch the index file or the working tree at all (but resets the head to <commit>, just like all modes do). This leaves all your changed files "Changes to be committed", as git status would put it.

In other words, it undoes all of your commits up to <commit>. But it does not change the working directory. You end up with all of the changes, unstaged and uncommitted. It's as if those intervening commits never happened.

Example:

# on master
git checkout -b testbranch
# make many commits
git reset --soft master
git add .
git commit -m 'The only commit.'

At this point, you're still on testbranch, which has a single commit. Merge into master as you would ordinarily do.

The first part of Caveman's answer (git rebase -i) did not in my hands squash commits.

Rich Apodaca
  • 28,316
  • 16
  • 103
  • 129
10

If you use JetBrains based IDE like IntelliJ Idea and prefare using GUI over command line:

  1. Go to Version control window (Alt + 9/Command + 9) - "Log" tab.
  2. Choose a point in the tree from which you created your branch
  3. Right click on it -> Reset current branch to here -> Pick Soft (!!!) (it's important for not to lose your changes)
  4. Push the Reset button in the bottom of the dialog window.

That's it. You uncommited all your changes. Now if you'll make a new commit it will be squashed

Eduard Streltsov
  • 1,754
  • 20
  • 19
10

In previous answers, I have not seen any information on how to deal with "messy branches" and "self conflicts". E.g. I often end up having master commits on my feature branch (call it feature) that cause conflicts against themselves. This I found to be one of the most annoying issues to deal with.

How to squash messy branches? Use a temporary branch!

I found Felix Rieseberg's solution to be the best. This is my slightly shorter transcription of his advice:

  1. Create a local tmp branch of off master
    • git checkout master && git pull && git checkout -b tmp
  2. Merge all feature changes into tmp (without any commits, only staged file changes).
    • git merge --squash $feature
  3. Manually solve all remaining "real conflicts"
    • (This is the only step you cannot have a script do for you)
  4. Commit. tmp is now master + 1 commit (containing all changes).
    • git commit ...
  5. Checkout feature and git reset --hard tmp (feature's original contents are gone, and it is now basically tmp, but renamed)
    • git checkout $feature && git reset --hard tmp
  6. Ignore and override origin/feature (then clean up)
    • git push -f && git branch -D tmp

Felix points out that this is going to produce the cleanest possible merge, without any weird self-conflicts coming from a messy/complicated relationship between master and feature:

you might be getting a smaller number of unavoidable merge conflicts. Have faith that this is the smallest possible number of conflicts as you're skipping the many in-between commits you've originally created.

Domi
  • 22,151
  • 15
  • 92
  • 122
8

You can do this with subcommands ie

$ git rebase -i HEAD~$(git rev-list --count HEAD ^master)

This will run first count the commits since you diverged from master and then rebase back to that exact length.

Rob Lopez
  • 111
  • 1
  • 1
6

Assuming you are on feature branch:

  1. Find the first commit in the feature branch. You can view it in the branch directly if you are using gitlab or github and copy the hash from there or you can use following command:

git log <source_branch>..<feature_branch> --pretty=format:%h

  1. Execute following commands:
git reset --soft <base_commit_hash>

git commit --amend --no-edit

Now at this stage, on your local, you have 1 commit which includes changes done in all the previous commits.

Review it and you need to force push it. After force push, all the changes will be combined in one commit and your branch will have only 1 commit.

  1. Force push in the feature branch
git push --force 
user
  • 867
  • 9
  • 21
3

You can use tool I've created specifically for this task:

https://github.com/sheerun/git-squash

Basically you need to call git squash master and you're done

sheerun
  • 1,728
  • 14
  • 27
3
git checkout -b temp
git checkout yourbranch
git fetch
git reset --hard origin/master
git merge --squash temp
git commit -m "new message" 

most easiest way to do.

This creates a new branch , then reset your branch to base branch and then we squash the changes and creates a new commit before merging back temp branch to our branch

PDHide
  • 18,113
  • 2
  • 31
  • 46
3

The shortest way to squash commits done since master on the current branch is:

git rebase -i master

If you want to squash1 all commits into one and your Git editor is Vim2, then issue this Vim command:

:2,$s/pick/fixup/

Then save and quit (:wq) Vim.


1 fixup means to discard additional commit messages of squashed commits. To be able to further process commit messages of squashed commits, replace it with squash.

2 You can switch your editor just for the single command by setting the EDITOR environment variable:

EDITOR=vim git rebase -i master
Melebius
  • 6,183
  • 4
  • 39
  • 52
2

Another solution would be to save all commit logs to a file

git log > branch.log

Now branch.log will have all commit ids since beginning.. scroll down and take the first commit (this will be difficult in terminal) using the first commit

git reset --soft

all commits will be squashed

pranav
  • 499
  • 5
  • 6
2

All this git reset, hard, soft, and everything else mentioned here is probably working (it didn't for me) if you do the steps correctly and some sort of a genie.
If you are the average Joe smo, try this:
How to use git merge --squash?


Saved my life, and will be my go to squash, been using this 4 times since I found out about it. Simple, clean and basically 1 comamnd. In short:


If you are on a branch lets call it "my_new_feature" off develop and your pull request has 35 commits (or however many) and you want it to be 1.

A. Make sure your branch is up to date, Go on develop, get latest and merge and resolve any conflicts with "my_new_feature"
(this step really you should take as soon as you can all the time anyway)

B. Get latest of develop and branch out to a new branch call it "my_new_feature_squashed"

C. magic is here.
You want to take your work from "my_new_feature" to "my_new_feature_squashed"
So just do (while on your new branch we created off develop):
git merge --squash my_new_feature

All your changes will now be on your new branch, feel free to test it, then just do your 1 single commit, push, new PR of that branch - and wait for repeat the next day.
Don't you love coding? :)

ItaiRoded
  • 142
  • 7
1

Git reset, as mentioned in many answers before, is by far the best and simplest way to achieve what you want. I use it in the following workflow:

(on development branch)

git fetch
git merge origin/master  #so development branch has all current changes from master
git reset origin/master  #will show all changes from development branch to master as unstaged
git gui # do a final review, stage all changes you really want
git commit # all changes in a single commit
git branch -f master #update local master branch
git push origin master #push it
Marcus
  • 617
  • 3
  • 8
1

I know this question is already answered but I went and wrote a bash function around the accepted answer to allow you to do it in one command. It starts by creating a backup branch in case the squash fails for some reason. Then squashes and commits.

# Squashes every commit starting after the given head of the given branch.
# When the squash is done, it will prompt you to commit the squash.
# The head of the given parent branch must be a commit that actually exists
# in the current branch.
#
# This will create a backup of the current branch before it performs the squash.
# The name of the backup is the second argument to this function.
#
# Example: $ git-squash master my-current-branch-backup
git-squash() {
  PARENT_BRANCH=$1
  BACKUP_BRANCH=$2

  CURRENT_BRANCH=$(git branch --show-current)

  git branch $BACKUP_BRANCH
  BACKUP_SUCCESS=$?

  if [ $BACKUP_SUCCESS -eq 0 ]; then
    git reset $(git merge-base $PARENT_BRANCH $CURRENT_BRANCH)
    git add -A
    git commit
    echo "Squashed $CURRENT_BRANCH. Backup of original created at $BACKUP_BRANCH$"
  else
    echo "Could not create backup branch. Aborting squash"
  fi
}
Ian Kirkpatrick
  • 1,861
  • 14
  • 33
0

The only generic solution I found so far.

git reset $(git reflog show --no-abbrev $(git branch --show-current) | grep "branch: Created from" | awk '{print $1;}')
git add .
git commit -m "Squashed commit"
Mircea Sirghi
  • 310
  • 1
  • 6
-1

In case you are okay with an answer involving another branch, try git checkout --orphan <new_branch> It allowed me to simply commit ALL files from previous branch as one commit.

This is something like a git merge squash but not quite the same.

user1889992
  • 355
  • 3
  • 7
  • This seems to squash the entire repository rather than just the current branch. – yohosuff Mar 01 '22 at 23:21
  • This is the most ingenious solution. Don't take me wrong, it is so dumb but it is also so genial!!! It has to be rebased onto the branch you want to merge afterward. Nevertheless, it is just the simplest of all solutions. Kudos!!! – Mircea Sirghi Aug 30 '23 at 18:40