6

I'm having trouble understanding how a git merge works in terms of the commits created by the merge process. I've read the relevant sections in pro git and the git community book, but am still confused.

Consider this scenario: I have an "origin" git repo:

          master
            |
a0--a1--a2--a3
  \
   -b0--b1
         |
      branch2

I clone this repo to a local repo and then work only on the local repo. In branch2, I did a "git merge master". Now my local repo looks like this:

     master / origin/master
            |
a0--a1--a2--a3
  \           \
   -b0--b1-----merge
         |       |
  origin/branch2 |    
              branch2

So the merge created 1 commit, "merge", after the "b1" commit. "git log" for branch2 shows the expected graph:

> git log branch2 --graph --pretty=oneline --decorate
*   a7b69fc6759e1dd5463bab379ce101a6ad026c7b (HEAD, branch2) Merge branch 'master' into branch2
|\  
| * 482e4026f05e33395a9fc3c87f50a746f692406a (origin/master, origin/HEAD, master) a3
| * 8de57bdea2d316073af3b7055f8c28c56004ce94 a2
| * 1e991047996aad269f2c01b9a0b9a7d8293096a1 a1
* | 99955f66843df51fb9d40c7797156c32cad57415 (origin/branch2) b1
* | 30ca9b6363558322f2bb7810d75cda0d9c2ba3e0 b0
|/  
* 76a7c6d0eb54a9580841115ff2c3429360ab2ac9 a0

In addition, if I go one commit before the current head, I get to the b1 commit, as expected. (follow the branch2 line in the graph and go back 1 commit)

> git log branch2~ --graph --pretty=oneline --decorate
* 99955f66843df51fb9d40c7797156c32cad57415 (origin/branch2) b1
* 30ca9b6363558322f2bb7810d75cda0d9c2ba3e0 b0
* 76a7c6d0eb54a9580841115ff2c3429360ab2ac9 a0

Here comes my confusion. I haven't pushed my changes to the origin yet, but when I do a "git status", git says my local branch2 is ahead of the origin/branch2 by 4 commits. I thought the merge only resulted in 1 new "merge" commit, as seen by the graph / diagrams above? Why 4?

> git status
# On branch branch2
# Your branch is ahead of 'origin/branch2' by 4 commits.
#
nothing to commit (working directory clean)

Also, doing a "git log" from origin/branch2 to branch2 shows the 4 commits instead of the 1 I expected (going from "b1" to "merge").

> git log origin/branch2..branch2 --graph --pretty=oneline --decorate
* a7b69fc6759e1dd5463bab379ce101a6ad026c7b (HEAD, branch2) Merge branch 'master' into branch2
* 482e4026f05e33395a9fc3c87f50a746f692406a (origin/master, origin/HEAD, master) a3
* 8de57bdea2d316073af3b7055f8c28c56004ce94 a2
* 1e991047996aad269f2c01b9a0b9a7d8293096a1 a1

I understand the 4 commits are the 3 from master (a1,a2,a3) that the merge is supposed to bring over to branch 2, plus the "merge" commit. But why doesn't the graph show it that way? If it does, it would look like:

     master / origin/master
            |
a0--a1--a2--a3-----------
  \                      \
   -b0--b1--a1'--a2'--a3'--merge
         |                  |
  origin/branch2            |    
                         branch2

And branch2~ would bring me to a3' instead of b1.

Thanks in advance for any help.

digitalsky
  • 379
  • 4
  • 14

1 Answers1

6

As mentioned in "How to get the changes on a branch in git":

git log origin/branch2..branch2

means: all the commits on branch2 (positive reference) which aren't on origin/branch2 (negative reference)
(On the positive and negative references, see "Difference in 'git log origin/master' vs 'git log origin/master..'")

In your case, after the merge, you do have 4 commits on branch2 (the local one) that aren't on origin/branch2: a1, a2, a3 and merge.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Thanks for your quick response. So I misunderstood 2 things: 1) "Your branch is ahead of by x commits." means there are x commits in your current branch that doesn't exist in . These x commits does NOT mean there are 4 commits between your current branch and on a repo graph. 2) git log .. does NOT show what commits I would go through as I transverse from to in a repo graph. Instead, it can be thought of showing a "diff" of the commits in the history of and . – digitalsky Jun 17 '11 at 23:05
  • @digitalsky: `git log` takes a *range* of revision, and is about walking the graph of revisions, starting with the positive reference, going back through the revision history, stopping when it encounters revisions that are reachable from the negative reference. `git diff` takes *two* revisions (not a range of) and is about showing the diff between those two. Except for `diff A...B` which shows in `B` since it diverged from `A`. – VonC Jun 18 '11 at 07:56
  • @digitalsky: so four your 1), the "ahead" part is about walking back the revision graph, knowing that commits from another branch, once merge with your local branch, are now reachable from said local branch. For your 2), I would avoid the term "diff" ;) – VonC Jun 18 '11 at 07:59
  • That explanation's a keeper. Ta. – Philip Oakley Jun 18 '11 at 17:40