1804

I have a remote Git server, here is the scenario which I want to perform:

  • For each bug/feature I create a different Git branch

  • I keep on committing my code in that Git branch with un-official Git messages

  • In top repository we have to do one commit for one bug with official Git message

So how can I merge my branch to remote branch so that they get just one commit for all my check-ins (I even want to provide commit message for this)?

M. Justin
  • 14,487
  • 7
  • 91
  • 130
SunnyShah
  • 28,934
  • 30
  • 90
  • 137
  • 1
    Do you want to keep the individual commits on those other branches? – poke Mar 15 '11 at 08:15
  • 36
    I typically use **git rebase -i** to collapse all my commits into one commit and re-write the commit message. Then I send it upstream. – Edward Falk Nov 27 '13 at 19:28
  • See also: [What to do with branch after merge](http://stackoverflow.com/q/14005854/562769) – Martin Thoma Dec 17 '15 at 09:31
  • 1
    @EdwardFalk What is the difference between `git rebase -i` and the (accepted) answer of abyx? – Martin Thoma Dec 17 '15 at 09:32
  • 38
    `git merge --squash` does it all on the command line in one shot and you just hope it works. `git rebase -i` brings up an editor and lets you fine-tune the rebase. It's slower, but you can see what you're doing. Also, there are difference between rebase and merge which are a little too involved to address in a comment. – Edward Falk Dec 17 '15 at 18:49
  • 12
    the problem with all these answers is that you have to be on the master branch locally and the run the merge --squash command... I want to run the merge --squash from the feature branch not the master branch..so that when I am done, I can push the feature branch to the remote and submit a PR, is that possible? – Alexander Mills Nov 01 '16 at 23:34
  • 11
    @AlexanderMills, I think you just need a second feature branch (cloned from the master branch). Do the `merge --squash` from the old to the new one, and then merge the new branch to master. The old branch becomes obsolete. – Gyromite Mar 28 '18 at 16:12
  • 1
    If you are moving these changes to an older branch, or branch from an old tag, many of these methods will include unwanted changes prior to the wanted branch commits! A way around this is to merge --squash the wanted branch to it's parent (locally is enough so it can be undone). Now you will have a single commit with only the branch changes you want. You can then cherry pick this single commit to an older branch without carrying lots of unwanted changes between the old branch and the parent of the new branch. – JStrahl Nov 03 '22 at 15:06

15 Answers15

2850

Say your bug fix branch is called bugfix and you want to merge it into master:

git checkout master
git merge --squash bugfix
git commit

This will take all the commits from the bugfix branch, squash them into 1 commit, and merge it with your master branch.


Explanation:

git checkout master

Switches to your master branch.

git merge --squash bugfix

Takes all commits from the bugfix branch and groups it for a 1 commit with your current branch.
(no merge commit appears; you could resolve conflicts manually before following commit)

git commit

Creates a single commit from the merged changes.

Omitting the -m parameter lets you modify a draft commit message containing every message from your squashed commits before finalizing your commit.

am0wa
  • 7,724
  • 3
  • 38
  • 33
abyx
  • 69,862
  • 18
  • 95
  • 117
  • 268
    If you want to keep references to the old commit messages you can write `git commit` (without `-m` param) and you will get to modify a drafted commit message containing all commit messages that you squashed. – Alex Aug 08 '13 at 15:16
  • 20
    You can achieve the same by doing `git commit --amend -m '...'` later on. – Janusz Lenar Feb 13 '14 at 13:21
  • 2
    @abyx I've been using your solution to move bugfixes and features from our develop to master as a single commit, but it appears that revert commits aren't being included in the merge squash. I'm cherry picking the revert commits as a workaround, but there's got to be a better solution for this corner case. Thoughts? – lowe0292 Apr 07 '14 at 16:26
  • 1
    See also: [Delete a Git branch both locally and remotely](http://stackoverflow.com/q/2003505/562769) – Martin Thoma Jan 22 '16 at 20:24
  • 1
    If you have `merge.ff=false` in your config make sure to set `--ff ` option – hdost Mar 02 '16 at 03:29
  • 31
    In case merge conflicts happen and you resolve these conflicts, `git commit` will no longer show the useful commit message containing all commit messages you squashed. In that case, try `git commit --file .git/SQUASH_MSG` (via http://stackoverflow.com/a/11230783/923560 ). – Abdull Jun 03 '16 at 16:02
  • 35
    Keep in mind that [squashing will by default attribute the commits to the squasher](http://git.661346.n2.nabble.com/Keep-original-author-with-git-merge-squash-td7625268.html). To keep the original author, you need to explicitly specify it like so: `git commit -a --author="Author" --message="Issue title #id"` – gaborous Aug 17 '16 at 17:16
  • 9
    `git merge --squash` allows you to create a single commit on top of the current branch whose effect is the same as merging another branch. But it won't produce the merge record, which means your pull-request as result would have no changes, yet won't be marked as merged! So, you will need just to delete that branch to be done. – am0wa Aug 02 '17 at 13:34
  • 6
    @am0wa This is a woefully under-mentioned aspect of `--squash`. When you do a `merge --squash`, you're NOT merging anything. You're creating a new commit, with the changes from the feature branch, but effectively _abandoning_ that feature branch. Aside from the commit message of your "squash" commit, there's no reference within Git to the branch that was being "merged" in. – Craig Otis May 19 '20 at 13:23
  • Would it be correct to say that `git merge --squash && git commit` does exactly the same as creating a merge commit, with the only difference that the resulting commit will only list one parent? – actual_panda Jul 05 '20 at 18:20
  • I think it would be more exactly to say that 'git merge --squash ' puts all the changes from into the STAGED area of the current branch. After that you have to commit them explicitly. – ka3ak Jul 09 '20 at 08:55
  • @Craig Otis of course. Rephrased the description. Just tried to kept it short. Many Thanks. – am0wa Jul 22 '20 at 17:27
  • Thanks @abyx, I just rolled out a production update with the help of this! – ba11b0y Apr 22 '21 at 18:21
  • Can I also do `git merge --ff-only --squash dev` ? – alper Jul 08 '21 at 00:06
  • But when I ran theses commands, it give me message: "Squash commit -- not updating HEAD" Whats wrong here? I checked git log in feature branch which has some commits then it is not merging into develop branch? Does it not work for fork branches? – Ashish Sharma Jan 07 '22 at 11:46
  • @CraigOtis that's a great point. Anyway to have both? By both I mean committing the squashed code AND having an indication that the branch was merged (for PR/back tracking purposes). – KidCrippler Feb 04 '22 at 23:08
  • Is it possible to have by default commit message like a normal merge ? (I mean `Merge branch 'feature/my' into main`), I don't want to commit all messages from other branch, useless for main branch history – Vincent Decaux Nov 15 '22 at 21:12
191

What finally cleared this up for me was a comment showing that:

git checkout main
git merge --squash feature

is the equivalent of doing:

git checkout feature
git diff main > feature.patch
git checkout main
patch -p1 < feature.patch
git add .

When I want to merge a feature branch with 105(!!) commits and have them all squashed into one, I don't want to git rebase -i origin/master because I need to separately resolve merge conflicts for each of the intermediate commits (or at least the ones which git can't figure out itself). Using git merge --squash gets me the result I want, of a single commit for merging an entire feature branch. And, I only need to do at most one manual conflict resolution.

Dan Kohn
  • 33,811
  • 9
  • 84
  • 100
  • 101
    I highly suggest performing the merge in the feature branch first `git merge master`, and only then `git merge --squash feature` in the master branch. – dotancohen Sep 10 '14 at 08:50
  • 2
    Yes, one of the things that's great about the `merge --squash` strategy is that you can continually merge origin/master into your branch and it makes the eventual merge easier. – Dan Kohn Sep 25 '14 at 01:10
  • 13
    @dotancohen Sorry to dredge up an old comment :) What is gained from merging in the feature branch before performing `git merge --squash feature` from the master branch? – bitsmack Jun 01 '15 at 22:04
  • 83
    You want to merge master into the feature branch first, and deal with any manual fixes in your feature branch. That also lets you run tests and make sure your feature branch works correctly. Then, you are guaranteed that you can do an automatic merge of your feature branch into master. – Dan Kohn Jun 02 '15 at 01:44
  • 7
    @dankohn I suggest you add the explanation in your above comment into your answer. – guntbert Dec 17 '15 at 15:29
  • 9
    @bitsmack: you would merge master into feature first. This give you the opportunity to resolve conflicts on the feature before merging the feature into master – Mike Jun 03 '16 at 12:41
  • Do you have a link to the git source code that shows it really works this way? I've looked briefly here https://github.com/git/git/blob/master/builtin/merge.c , but haven't found the relevant part there – gebbissimo May 19 '21 at 12:28
  • Regarding "is the equivalent of doing..". There is an important difference if I remember correctly. On applying a patch, it's much more complicated to resolve conflicts. Because usually, no merge tool is used then. – iuzuz Feb 21 '22 at 10:39
137

You want to merge with the squash option. That's if you want to do it one branch at a time.

git merge --squash feature1

If you want to merge all the branches at the same time as single commits, then first rebase interactively and squash each feature then octopus merge:

git checkout feature1
git rebase -i master

Squash into one commit then repeat for the other features.

git checkout master
git merge feature1 feature2 feature3 ...

That last merge is an "octopus merge" because it's merging a lot of branches at once.

starball
  • 20,030
  • 7
  • 43
  • 238
Adam Dymitruk
  • 124,556
  • 26
  • 146
  • 141
  • 3
    Why are you rebasing? – Umair A. Oct 11 '13 at 10:38
  • 13
    @UmairAshraf it's an interactive rebase which gives you the option to do a squash within your branch. – andho Oct 25 '13 at 02:19
  • 4
    Rebasing is a bad idea. Don't rebase already published commits – Sebi2020 Nov 16 '18 at 14:21
  • 2
    @Sebi2020 git merge --squash will rebase your already published commits in a way that's worse than an interactive rebase. An interactive rebase (on a feature branch) carry little to no adverse effects. – xiix Mar 05 '19 at 10:38
  • 2
    @xiix This only holds true if you the only one working with the feature branch. This is not an assumption you can make. I recommend to read the pages related to rebasing on [Git-SCM](https://git-scm.com/book/en/v2/Git-Branching-Rebasing). It states "**Do not rebase commits that exist outside your repository and people may have based work on them.**" And if you don't know for sure if people already based work on published commits (which you can't know because of the decentral nature of git) you shouln't do that. – Sebi2020 Mar 05 '19 at 14:19
  • 1
    @Sebi2020 - It's absolutely an assumption I can make. Not an assumption *everyone* can make, but at least in our company, we don't have massive amounts of people making uncoordinated changes off of feature branches. – xiix Mar 31 '19 at 15:50
  • 1
    @xiix @Sebi2020 Even when others have worked on the same branch, you can still rebase and force-push, at least in the case where their commits come *after* yours, and don't touch any lines on which you performed conflict resolution. When they `git pull` it will silently and successfully rebase their newer commits on top of your rebased ones. (Assuming they pull with the rebase option.) – Andrew Spencer Feb 26 '20 at 16:09
  • @Sebi2020 I believe it's a very concrete principle that people can follow when managing public commits. – tinystone Aug 19 '23 at 11:29
41

Suppose you worked in feature/task1 with multiple commits.

  1. Go to your project branch (project/my_project)

     git checkout project/my_project
    
  2. Create a new branch (feature/task1_bugfix)

     git checkout -b feature/task1_bugfix
    
  3. Merge with the --squash option

     git merge --squash feature/task1
    
  4. Create a single commit

     git commit -am "add single comments"
    
  5. Push your branch

     git push --set-upstream origin feature/task1_bugfix
    
spottedmahn
  • 14,823
  • 13
  • 108
  • 178
Farid Haq
  • 3,728
  • 1
  • 21
  • 15
30

Merge newFeature branch into master with a custom commit:

git merge --squash newFeature && git commit -m 'Your custom commit message';

If instead, you do

git merge --squash newFeature && git commit

you will get a commit message that will include all the newFeature branch commits, which you can customize.

I explain it thoroughly here: https://youtu.be/FQNAIacelT4

Vagelis Prokopiou
  • 2,285
  • 19
  • 14
25

If you have already git merge bugfix on main, you can squash your merge commit into one with:

git reset --soft HEAD^1
git commit
qwertzguy
  • 15,699
  • 9
  • 63
  • 66
  • `git reset --soft HEAD^1` seems to undo the last commit performed *before* the merge, at least in case of the merge being a fast-forward. – Jesper Matthiesen May 15 '18 at 14:21
  • @JesperMatthiesen in case of a fast-forward you don't get a merge commit, so then you would do `git reset --soft HEAD^`. – qwertzguy May 15 '18 at 20:17
  • This helped me to squash everything into a single commit after a downstream merge. – killjoy Aug 19 '18 at 21:52
20

I know this question isn't about Github specifically, but since Github is so widely used and this is the answer I was looking for, I'll share it here.

Github has the ability to perform squash merges, depending on the merge options enabled for the repository.

If squash merges are enabled, the "Squash and merge" option should appear in the dropdown under the "Merge" button.

Screenshot of "Squash and merge" Github feature

Aaron
  • 2,049
  • 4
  • 28
  • 35
5

To squash your local branch before pushing it:

  1. checkout the branch in question to work on if it is not already checked out.

  2. Find the sha of the oldest commit you wish to keep.

  3. Create/checkout a new branch (tmp1) from that commit.

    git checkout -b tmp1 <sha1-of-commit>

  4. Merge the original branch into the new one squashing.

    git merge --squash <original branch>

  5. Commit the changes which have been created by the merge, with a summary commit message.

    git commit -m <msg>

  6. Checkout the original branch you want to squash.

    git checkout <branch>

  7. Reset to the original commit sha you wish to keep.

    git reset --soft <sha1>

  8. Rebase this branch based on the new tmp1 branch.

    git rebase tmp1

  9. That's it - now delete the temporary tmp1 branch once you're sure everything is ok.

Jool
  • 1,706
  • 16
  • 14
2

For Git

Create a new feature

via Terminal/Shell:

git checkout origin/feature/<featurename>
git merge --squash origin/feature/<featurename>

This doesnt commit it, allows you to review it first.

Then commit, and finish feature from this new branch, and delete/ignore the old one (the one you did dev on).

  • @Melebius The only reference to "SourceTree" is in your sentence, if it was a tag or previous question: It doesn't exist anymore. – Jordan Stefanelli Feb 13 '19 at 14:47
  • 1
    @JordanStefanelli SourceTree was used in the [original version of this answer](https://stackoverflow.com/revisions/46588265/1). Thanks for notifying it’s fixed! – Melebius Feb 13 '19 at 15:05
2
git checkout YOUR_RELEASE_BRANCH
git pull
git checkout -b A_NEW_BRANCH
git merge --squash YOUR_BRANCH_WITH_MULTIPLE_COMMITS
git commit -am "squashing all commits into one"
git push --set-upstream origin A_NEW_BRANCH
izy
  • 1,085
  • 14
  • 18
  • 1
    Thank you for including the `pull`. All the other responses seem to assume that nothing has changed in the remote release branch since the last time you were hanging out on it.... – leerssej Apr 28 '21 at 18:10
0

if you get error: Committing is not possible because you have unmerged files.

git checkout master
git merge --squash bugfix
git add .
git commit -m "Message"

fixed all the Conflict files

git add . 

you could also use

git add [filename]
ResUta
  • 9
  • 6
0

Your feature branch is done and ready to commit to master, develop or other target branch with only one commit

  • Go to merge branch : git checkout master && git pull
  • Create a work branch from your clean local master : git checkout -b work
  • Merge squash your feature branch on work : git merge --squash your_feature_branch.
  • Commit with default or a new message : git commit (with a specific or default message)
  • Go back to your feature branch : git checkout your_feature_branch
  • Point your feature branch to work dir : git reset --hard work
  • Verify but you are ready to push : git push -f
  • Then clean up work branch if needed

Replace master with your target branch : develop and so on

  • No need to specify how many commit from your master to your feature branch. Git takes care*
Breton F.
  • 177
  • 1
  • 6
0

Assume the name of the branch where you made multiple commits is called bugfix/123, and you want to squash these commits.
First, create a new branch from develop (or whatever the name of your repo is). Assume the name of the new branch is called bugfix/123_up. Checkout this branch in git bash -

  • git fetch
  • git checkout bugfix/123_up
  • git merge bugfix/123 --squash
  • git commit -m "your message"
  • git push origin bugfix/123_up

Now this branch will have only one commit with all your changes in it.

-1

You can use tool I've created to make this process easier: git-squash. For example to squash all commits on feature branch that has been branched from master branch, write:

git squash master
git push --force
sheerun
  • 1,728
  • 14
  • 27
-1

Use

git status 

to check what's going on.

Then

git checkout master 
git merge --squash bugfix
git add (add which files you want or use wildcard command like ".")

Then

git commit -m "message"

And now last but not the least

git push -u origin master

Here origin can be other remote you prefer.

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135