Re: How does git follow branch history across a merge commit?

3 messages, 3 authors, 2016-06-15 · open the first message on its own page

Re: How does git follow branch history across a merge commit?

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:47:20

Junio C Hamano [off-list ref] writes:
"Steven E. Harris" [off-list ref] writes:
quoted
Was it just luck that "HEAD^" referred to the predecessor that came from
branch "master" rather than branch "competition"?
Yes, if you want the second parent you would say HEAD^2.
Ahh, I misread your question.  No, it is not luck.  If you merge
competition into your master, the resulting commit will have your master
as its first parent.  If check out competition and merge master in your
example, the resulting merge will have compatition as the first parent.

Re: How does git follow branch history across a merge commit?

From: Steven E. Harris <hidden>
Date: 2016-06-15 22:47:20

Junio C Hamano [off-list ref] writes:
If you merge competition into your master, the resulting commit will
have your master as its first parent.  If check out competition and
merge master in your example, the resulting merge will have
compatition as the first parent.
I see, having run a few more experiments to confirm this.

I missed the point that merge commits are not "predecessor neutral";
they apparently have a bias indicating "/this branch/ received content
from /that branch/ (or /those branches/)".

To try to recreate my confusing scenario, I tried this:

,----
| git checkout competition
| git merge master
| # This fast-forwarded "competition" be equivalent to "master".
| git checkout 'HEAD^'
| # This wound up again at "master"'s predecessor, not "competition"'s.
`----

It seems that since fast-forward merges don't produce a commit, the
merge record remains in place recording that branch "competition" came
into branch "master". Even though we're checked out to branch
"competition" here, following its history back in time requires some
manual intervention. Do you concur, or is my example perhaps flawed?

-- 
Steven E. Harris

Re: How does git follow branch history across a merge commit?

From: Björn Steinbrink <hidden>
Date: 2016-06-15 22:47:20

On 2009.08.28 19:50:44 -0400, Steven E. Harris wrote:
I missed the point that merge commits are not "predecessor neutral";
they apparently have a bias indicating "/this branch/ received content
from /that branch/ (or /those branches/)".

To try to recreate my confusing scenario, I tried this:

,----
| git checkout competition
| git merge master
| # This fast-forwarded "competition" be equivalent to "master".
| git checkout 'HEAD^'
| # This wound up again at "master"'s predecessor, not "competition"'s.
`----

It seems that since fast-forward merges don't produce a commit, the
merge record remains in place recording that branch "competition" came
into branch "master".Even though we're checked out to branch
"competition" here, following its history back in time requires some
manual intervention. Do you concur, or is my example perhaps flawed?
As there is no merge commit, there's no "merge record" either.
"competition" just got updated to reference the same commit as "master".
Branch "competition" did not "come into" branch "master" either.
"competition" and "master" are just the names of the branch heads. And
those just reference commits, which actually form the history and have
no record of belonging to any branch head on their own.

IOW: "master" and "competition" aren't branches as in "a series of
commits with a fixed relation to each other", but just branch heads,
referencing the tips where the branches grow.

Scenario A:

Given this history:

A---B---C (master)
 \
  D---E (competition)

If you now merge "master" to "competition" you get:

A---B---C (master)
 \       \
  D---E---M (competition)

Where M is a merge commit with two parents, E being the first one, C
being the second one. And that's everything that git knows, that M is a
merged of C and E. That E is the first parent is just a smart choice,
nothing else.


Scenario B:

Given this history:

A (competition)
 \
  B---C (master)

If you ask git to merge "master" to "competition", it will see that
there aren't any commits reachable through "competition" that aren't
reachable through "master". So simply fast-forwarding "competition won't
make you lose anything. Thus you get:

A---B---C (master) (competition)

There's no trace of any merge, because it wasn't required. You can't
even tell that a fast-forward happened from that history. You could as
well just have created "competition".


That said, if you want to force a merge commit (which can sometimes be
useful), you can use the --no-ff flag:

git checkout competition
git merge --no-ff master

And this leads to:

A------M (competition)
 \    /
  B---C (master)


With M's first parent being A, and the second parent being C.

(Assuming that "competition" is a topic branch, this would be a bit
weird though, as you produce a totally pointless merge commit, before
you even started working on your topic branch. OTOH doing this the other way
around, i.e. forcing a merge commit when you merge a topic branch to
"master" _can_ be useful. Don't over do it though).

HTH
Björn
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help