Git fast forward merge is FORWARD in terms of TIME. The pointer goes from older to newer commits.

Example (by ffwd merge master pointer is moved from commit D to commit G):

Before fast-forward merge:

                  master
                    |
        A<--B<--B<--D<--E<--F<--G
                                |
                           new_branch

After fast-forward merge:

                              master
                                |
        A<--B<--B<--D<--E<--F<--G
                                |
                           new_branch

But, since the commit pointers point from newer to older, in terms of these pointers strictly, the branch pointer goes backwards... upstream the commit pointers. So in that sense, it can be labeled a fast-reverse merge. Upstream (the term from ProGit book, chapter on merging) refers to reverse flow, up-the-stream, so explaining upstream flow as a fast forward thing can confuse newcomers. So, it's:

Upstream in terms of commit pointers.

Forward in terms of commit time.

Does this reasoning make sense?

2

There are 2 answers

6
J-16 SDiZ On

No, it don't move master to "G". It just start with "G" and ff to "D". master is just a name/label thingy (called ref). It is updated after merge, not "move" in steps.

To understand this, you can just try a merge with conflict. When the merge is awaiting manual resolve, the branches are still points to their old commit. Just the checkout tree and index are in the indeterminate state.

update: May be you can think in this way:

  1. find the merge base git merge-base D G, this is G
  2. Create a fake, temporary branch at G (Not really a branch, but lets pretend this for a moment).
  3. ff the fake branch to D.
  4. rename the fake branch to master, overwrite the old one.
6
wadesworld On

This would only be true if commits followed the path of the arrows.

I think that's what's confusing you. Remember, the arrows point to where you have come from, not where you're going.

The master pointer moved forward in time and forward along the branch. Remember, HEAD is at the tip of the branch. Anytime you move towards HEAD (assuming it hasn't been moved backwards) you're moving forward in time and commits.

Now, if you wanted to think of it as a linked list, then yes, typically A would be the head, and G would be the tail, EXCEPT.....we know that in Git our HEAD points to G. Besides that, I don't think newbies typically look at it at this low level and try to apply data structure concepts to it.

You're over thinking it.