573

Is it possible to do a git merge, but without a commit?

"man git merge" says this:

With --no-commit perform the merge but pretend the merge failed and do not autocommit,
to give the user a chance to inspect and further tweak the merge result before
committing.

But when I try to use git merge with the --no-commit it still auto-commits. Here's what I did:

$> ~/git/testrepo$ git checkout master
Switched to branch 'master'

$> ~/git/testrepo$ git branch
* master
  v1.0

$> ~/git/testrepo$ git merge --no-commit v1.0
Updating c0c9fd2..18fa02c
Fast-forward
 file1 |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

$> ~/git/testrepo$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)

A subsequent git log reveals all the commits from the v1.0 branch merged into master.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
selbie
  • 100,020
  • 15
  • 103
  • 173

7 Answers7

842

Note the output while doing the merge - it is saying Fast Forward.

In such situations, you want to do:

git merge <name-of-branch> --no-commit --no-ff

Important: If you do it this way, then you are not able to do any changes to the files in the staging area e.g. you can't remove/add files or make any changes to the files.

If you want to merge the changes and then commit as if you had manually typed all of the changes you merged in (as opposed to a traditional merge) you need to run rm .git/MERGE_HEAD afterward, which will force git to forget that the merge happened.

Wenfang Du
  • 8,804
  • 9
  • 59
  • 90
manojlds
  • 290,304
  • 63
  • 469
  • 417
  • 11
    what if there's a confict. – Jürgen Paul Jan 03 '15 at 05:06
  • 26
    @PineappleUndertheSea Fast forwards never cause conflicts. In case of "real" merge without fast forward the `--no-commit` switch is effective only if no conflict occurs, in case of conflict git will never auto-commit. – gronostaj Jan 05 '15 at 19:20
  • 54
    FYI: If you want to merge the changes and then commit _as if you had manually typed all of the changes you merged in_ (as opposed to a traditional merge) you need to run `rm .git/MERGE_HEAD` afterward, which will force git to forget that the merge happened. – Jonn Feb 27 '16 at 00:23
  • 10
    FYI: Here is sample output for a successful merge: `Automatic merge went well; stopped before committing as requested` – kevinarpe Mar 17 '17 at 11:24
  • 9
    Apparently `git merge BRANCHENAME --no-commit --no-ff` left my workspace in a git "MERGING" state. Not quite sure what this does exactly, but a simple `git stash save` and `git stash pop` cycle seemed to return everything to normal; with just the modified files from the target branch in place as intended, and no longer a MERGING status. – MoonLite Aug 15 '17 at 14:49
  • 6
    Wouldn't `git reset head` get rid of the MERGING status (based on [this](https://gist.github.com/katylava/564416))? – djvg Apr 17 '18 at 20:03
  • After using this command if there are conflicts I solve them, then use `git add .` to add the modified files. Conflicts or not, I use `git commit` (no parameters) to commit the merge. – pasx Mar 09 '20 at 13:48
  • 2
    Use ```git merge --abort``` to get rid of 'MERGING' state. It's more consistent and easier to remember. – user3739779 Mar 10 '20 at 14:58
  • 1
    In addition to @Jonn's comment, use `git restore --staged ` to unstage so your IDE shows you the changes. – Samir Apr 12 '20 at 12:19
  • Hi! Thanks Jonn and @Samir . What's does the var stand for in your comment, Samir? Just the normal project dir where .git sits in if I want to apply this on the whole project tree? – code_gamer Sep 24 '20 at 12:48
  • It'll be one or more arguments of the files you want to unstage. e.g. `git restore --staged file1.go somedir/file2.go app.yaml`. Use `git status` to see those files. – Samir Sep 24 '20 at 14:51
  • @manojlds Is the v1.0 still necessary? What is its purpose by the way? – user33276346 Jan 06 '21 at 02:30
  • Mine just says "Already up to date" even though the branches definitely aren't the same - any ideas? – Gamora Feb 23 '21 at 13:54
  • bash code to add alias `git mrg`: `git config --global alias.mrg 'merge --no-commit --no-ff'` – gndps Jul 25 '23 at 16:24
68

You're misunderstanding the meaning of the merge here.

The --no-commit prevents the MERGE COMMIT from occuring, and that only happens when you merge two divergent branch histories; in your example that's not the case since Git indicates that it was a "fast-forward" merge and then Git only applies the commits already present on the branch sequentially.

pfabri
  • 885
  • 1
  • 9
  • 25
Samus_
  • 2,903
  • 1
  • 23
  • 22
  • 14
    That wouldn't (imo) necessarily clear up the confusion; I think this is one (relatively rare) time the docs are actually clear: `git help merge` => "With `--no-commit` perform the merge but pretend the merge failed and do not autocommit, to give the user a chance to inspect and further tweak the merge result before committing." The key of course is using it in conjunction with `--no-ff` – michael Feb 12 '13 at 00:58
  • 6
    ...maybe it would be less confusing to break from strict terminology and describe it this way: a "git merge" that does a fast-forward doesn't have a merge commit because there isn't actually a merge at all. This is in fact the ideal situation: fast-forwards are a Good Thing, and not having this extra "merge commit" Makes Sense. This is good default behavior and shouldn't be disabled. (In proper parlance, a fast-forward is a type of merge, but it isn't a "true merge".) – michael Mar 27 '13 at 08:32
  • 4
    it's relative to the policies of the project, in some cases it's useful to have/force those extra "merge commits" even when it's a ff because you need to mark the inclusion of the feature into the main branch. – Samus_ Jun 22 '13 at 01:28
  • 10
    ...what. All right, I think git is pretty much unsalvageable. This answer _in particular_ has convinced me to try Mercurial. – Rag Apr 01 '15 at 02:18
41

If you only want to commit all the changes in one commit as if you typed yourself, --squash will do too

$ git merge --squash v1.0
$ git commit
Adrian Li
  • 501
  • 4
  • 2
  • 1
    Is this the same effect as `git merge v1.0 --no-commit --no-ff` – jpierson Aug 18 '17 at 13:30
  • 3
    No, different effect. Squash creates a new commit with a new hash. It combines all the commits in a branch into one commit for the merge. – Kavi Siegel Jan 17 '18 at 22:49
  • Can you explain a little bit more about the difference? – Muhammed Bera Koç Mar 16 '21 at 16:30
  • @KaviSiegel `--no-squash` will not create a commit automatically, user has to do that. In fact, `--commit` is not even allowed if `--squash` is used. So, `merge --squash` is kind of equivalent to copying all changes (from all commits) from the other branch and doing `git add` on those. – Mohnish Oct 08 '21 at 15:38
34

I prefer this way so I don't need to remember any rare parameters.

git merge branch_name

It will then say your branch is ahead by "#" commits, you can now pop these commits off and put them into the working changes with the following:

git reset @~#

For example if after the merge it is 1 commit ahead, use:

git reset @~1

Note: On Windows, quotes are needed. (As Josh noted in comments) eg:

git reset "@~1"
Will Ediger
  • 893
  • 9
  • 17
Pellet
  • 2,254
  • 1
  • 28
  • 20
  • 6
    On windows, quotes are needed: `git reset "@~1"` – Josh May 29 '18 at 22:33
  • 1
    Way better than the accepted answer! Very logical and easy to follow. Tip for GIT GUI'ers: In the Vizualize All Branch, _merge_ the target branch, right-click the commit you were and _Reset main branch to here_ in default mode (AKA "Mixed, leave working tree untouched, reset index") – adelriosantiago Jan 19 '23 at 03:39
5

When there is one commit only in the branch, I usually do

git merge branch_name --ff
Sithu
  • 4,752
  • 9
  • 64
  • 110
1

You could also do

git cherry-pick <commit hash> 

for each commit if you want to preserve the commit history...

I'm not really seeing a "nice" way to merge multiple commits from another branch with the git merge command without it adding a merge commit at some point (i.e. only having the commits you want to include)

Adam Dunmars
  • 361
  • 1
  • 11
0

Old question with many answers, but this is too big for a comment.


As another answer mentioned, merging v1.0 into master resulted in a fast-forward merge. In fact, there really was no merge. The v1.0 tag had a commit whose parent commit was the tip of master. Got just advanced the pointer for master ahead one commit.

If doing that introduces an bad merge, what you *really" gave us a bad commit at the v1.0 tag.

The more appropriate solution is to do the fast forward merge of v1.0 into master, the add a commit to master correcting the bad code. After that either delete the v1.0 tag and recreate it, or retag v1.0 and force push the tag. Better yet, create a v1.0.1 tag from the commit that fixes v1.0.

Every other answer points you too the wrong solution from a coding standpoint.

Greg Burghardt
  • 17,900
  • 9
  • 49
  • 92