19

I had a three-way-merge branch merge:

git checkout master
git merge BranchA

>> Fast-forward merge

git merge BranchB

>> Three-way-merge (prompts for a merge commit message)

My questions are two:

  • How can I abort the merging? With the three-way-merge I'm showed the editor where to write the merge-commit message. But if I exit without saving, git will anyway proceed with the merge (just the merge-commit message will be the default one instead the one I could have written but aborted)

    commit 11111233
        Merge 'BranchB' into master
    

    while, obviously not having confirmed the commit message, I would expect the merge to not happen (as the same behaviour of when I do NOT confirm a normal commit message)

  • Will the commits from the two merged branches be sorted in chronological order? Or first (in the git log) will I see the commit from the BranchA, followed THEN from the commits of the BranchB?

EDIT

To explain better the second question I made a test: 2 branches (A and B) starting from the master branch. I made a commit on B, then on A, then again on B, and finally again on A. Then I merged BranchA into master. And then BranchB into master.

But when I git log on master, this is what has come out, and why I asked the second question:

commit 730fdd4d328999c86fa4d3b6120ac856ecaccab1
Merge: 7eb581b cc1085a
Author: Arthur Conandoyle <Arthur.Conandoyle@live.com>
Date:   Mon Feb 9 21:24:27 2015 +0100

    Merge branch 'BranchB' into master_COPY

commit 7eb581b39a8402e1694cc4bf4eab4a3feb1143f8
Author: Arthur Conandoyle <Arthur.Conandoyle@live.com>
Date:   Mon Feb 9 21:23:18 2015 +0100

    BranchA) - This should be the (second) last change of the branch, and be the
    most recent into the git log, even if I merge another branch into master,
    AFTER the one where we are committing this.

commit cc1085a6aaa2ee4b26d3c3fbb93bee863d9e7c28
Author: Arthur Conandoyle <Arthur.Conandoyle@live.com>
Date:   Mon Feb 9 21:20:29 2015 +0100

    (BranchB) - Add settings to the last new features

commit 5f5b846a2f89886d01244ba77af941f554233b51
Author: Arthur Conandoyle <Arthur.Conandoyle@live.com>
Date:   Mon Feb 9 21:18:54 2015 +0100

    (BranchA) - Add some changes

commit 92a57a56b6b7c9694fbedda71b8070fc58683dde
Author: Arthur Conandoyle <Arthur.Conandoyle@live.com>
Date:   Mon Feb 9 21:18:17 2015 +0100

    (BranchB) - Some changes

commit 221765476e348833cf8da73b1bf5239f3d4240e8
Author: Arthur Conandoyle <Arthur.Conandoyle@live.com>
Date:   Tue Feb 3 12:12:19 2015 +0100

    Change (this is the last commit of the parent 'master' branch)

(As Srdjan Grubor wrote) I would have been expected first (chronologically) all the commit from the merged BranchA and THEN all the commits from the merged BranchB, following the order of merging... .. but it's funny how the git log instead show them in chronological order and the commits are not shown as grouped in branches!

Kamafeather
  • 8,663
  • 14
  • 69
  • 99
  • 1
    Try to write _empty_ message to abort, i.e. remove everything and save empty file. – Alexey Ten Feb 09 '15 at 18:16
  • Nice advice. This workarounds the problem (I would say the _"bug"_) and allows to abort the _merging_! – Kamafeather Feb 09 '15 at 19:29
  • 2
    It’s not a bug. Empty commit messages abort the commit (unless explicitely allowed); that’s true for all commits: Normal ones, and merge commits. If you make your normal commit message template have some initial value, just exiting will not abort either. It’s the content of the commit, not the fact whether or not you have changed something. Otherwise, just accepting the default message wouldn’t work. – poke Feb 09 '15 at 19:32
  • Ok, good explanation. I didn't think about the use of a message template that could provoke this slightly different behaviour. Now I get it and has sense. Thanks! – Kamafeather Feb 09 '15 at 19:42
  • 1
    The phrase "three way merge" does not refer (in git anyway) to bringing *two* other branches into your current branch. Instead, it refers to the fact that when bringing *one* other branch into your current branch, the process is done by finding a "merge base" (nearest common ancestor) and then combining two sets of changes: merge-base vs `HEAD`, and merge-base vs other-branch-tip. In git, a "fast forward" merge occurs when `HEAD` is the merge-base. – torek Feb 09 '15 at 19:45
  • I would add that yes, putting an empty message makes the _merge_ to not happen. But this way the _merge_ will finish in an incomplete state. So it seems there is no option in _Git_ to abort a merge, after triggering `git merge `, without having to execute an additional command to come back to the pre-merge state. – Kamafeather Feb 09 '15 at 19:47
  • @torek: I was not anyway confusing the three-way-merge as a three-branches-merge. I know that this one is referred just to the second _merge_ operation. But good explanation anyway, thank :) – Kamafeather Feb 09 '15 at 19:50
  • 1
    @jthill: git will still do a two-way merge (aka fast-forward) in the case where the common ancestor is the current `HEAD`. It's called out thus in the documentation for `read-tree`'s `-m` option, at least. Not sure if anyone else still uses that terminology... – torek Feb 10 '15 at 01:36
  • Related post - [I ran into a merge conflict. How can I abort the merge?](https://stackoverflow.com/q/101752/465053) – RBT May 14 '18 at 09:45

4 Answers4

43

The branchB merge is perfectly ordinary, asking for an ordinary commit message. There's a default, if you quit without changing it the merge will complete. Since the merge itself has succeeded, the only way to stop it now is to supply a bad merge message (an empty one will do it absent hooks), edit: or have an editor that can error out like vim's :cq that I just learned about.

When a merge has stopped you can abort it with

git merge --abort
# or
git reset --merge

Backout for anything you just committed in error is

git reset --hard @{1}

There's no concept of branch "ownership" in git, all the ways you can refer to a commit are peers.

You can get a better idea of the structure git log is showing you with

git log --graph --decorate --oneline

Try it with with --date-order and --topo-order and --all.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • A three-way-merge is generated instead. Both branches come from _master_ and, if the first _merge_ will be a _fast-forward_, the second merge will be instead a _three-way-merge_ and will ask for a commit message; I tried on two different repositories. Your solutions are right, but I was looking for a way to **abort**, while you are suggesting to **undo** (that I usually do with a `git reset @{1}`, as you told). – Kamafeather Feb 09 '15 at 19:36
  • Anyway regarding your _edit2_: I tried on _Git_ _1.7.10.4_ and _1.9.3_, and both will confirm the _merge_ even if you quit from the editor without saving. To have the correct behaviour you need to provide an empty message _and commit it_ (as Alexey Ten suggested in the comments); THEN it will behave as expected and the merge will be incomplete. Just exiting the editor without saving is not enough and will confirm the merge anyway, using the default text as _merge_ message. – Kamafeather Feb 09 '15 at 19:37
  • @Kamafeather: jthill is talking about the *first* merge, the one done as a fast-forward. That merge completed already. Writing an empty commit message aborts the *second* merge, but the first one is done. – torek Feb 09 '15 at 19:42
  • You're offered a default merge message. Quitting without saving accepts that message and completes the merge. Edit: that's intentional, as the default message is by far the most common and best choiceI think you might be using a long-abandoned sense of "three-way merge". It's true that merge compares both tips against the original, so there's three files involved, but people assume it's in use because it's that much better. Counting only the tips is less misleading these days. – jthill Feb 09 '15 at 19:42
  • **@torek:** thanks for the clarification. However yes I was not expecting the abort of the second _merge_ to undo also the first one. I put the first _branch/merge_ just to make a concrete example of what is happening when I try to merge a second branch started from the same parent as the first one. **jthill:** thanks for the clarifications :) – Kamafeather Feb 09 '15 at 19:54
2

Regarding your edit, git log sorts its output. This can be surprising even in a linear history. There are flags to change the sorting method, and adding --graph changes the default sort to --topo-order.

The other item of note is that when git does a fast-forward of the branch, there is no merge commit:

      C---D   <-- branch
     /
A---B         <-- mainline

Allowing mainline to acquire branch via fast-forward results in the simple graph:

      C---D   <-- mainline, branch
     /
A---B

which is trivially drawn as a simple straight line, but forcing a merge commit (with git merge --no-ff) produces an actual two-parent merge commit:

      C---D   <-- branch
     /     \
A---B-------M <-- mainline

which (once generalized to have more commits) presents more interesting options for the commit-sorting process.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Thanks for the explanation and the link to the documentation. I should have checked that! I didn't know that `git log` had sorting options, and also a default sorting. – Kamafeather Feb 10 '15 at 11:24
0

You can "abort" the merge after you make you finish and use

git reflog

to return to your previous tree state. Usually merges are not sorted in chronological order but in branch commit order that is then sorted separately. This means that you would see your merge commit followed by all of the source branch commits (in chronological order) which are then followed by your main branch commits (in chronological order).

Srdjan Grubor
  • 2,605
  • 15
  • 17
  • What you say is the same I was expecting.... but I tried and found that the behaviour is different!... check the **EDIT** into my answer on the top! – Kamafeather Feb 09 '15 at 20:36
0

This command will help you to abort a local merging:

git merge --abort
Sambit Das
  • 131
  • 1
  • 5