Meaning of git log --oneline --graph output
Asked Answered
E

2

8

I'm learning about relative commit references and trying to understand the following git log --oneline --graph output provided in a lesson.

git graph

In the lesson it says that given HEAD points to the 9ec05ca commit, HEAD^^^ (meaning the great-grandparent commit) is the 0c5975a commit. But it seems to me 4c9749e should be the great grandparent, if each SHA is a direct descendant of the one below it. Any clarification appreciated.

Eyla answered 20/5, 2018 at 0:39 Comment(5)
You have eight great grandparents, but only one mother's mother's mother. git log by default shows the entire ancestry in order by birthdate (where timestamp weirdities don't make that contradict ancestry). Try it with git log --oneline --graph --decorate --first-parent.Wesle
^ or ^1 means the first parent. ^n means the n-th parent. So when it comes to 4c9749e, it's HEAD^^^2. If a merge commit is created after merging B to A, A's original head is its first parent and B's head is the 2nd parent.Incestuous
I think I understand now. In the lesson it says "With a merge commit ... The first parent is the branch you were on when you ran git merge while the second parent is the branch that was merged in." Since 796ddb0 is on branch master, its first parent is the one also on branch master (so, 0c5975a), and the second parent of 796ddb0 is the one (4c9749e) on a different branch (branch heading-update).Eyla
"each SHA is a direct descendant of the one below it" This premise is incorrect, if the history diverges, there are "sibling"/"cousin" commits that don't have ancestor/descendant relation, but are still show one below the other. Btw, gitk is usually a nicer alternative to log --graph, the graph is a bit more readable than ascii one, and it can show a lot of details, like the list of parents if selected commit.Conduplicate
@NatalieCardot yes, that's it. Don't make the mistake of reading much into the "branch", or any, abstraction, Git is extremely concrete. This unsettles people who want abstractions to go beyond how Git uses them, as nothing more than ways to help understand what's possible. The commit graph is real. All else is ephemera, ways of referring to or constructing currently-particular commits in it.Wesle
A
2

Commit can have more than one parent. ^ 1 means first parent. ^2 means second parent and so on. Just ^ defaults to ^1 which is first parent.

Similarly ~ give access to traverse up for an ancestor. For example if you want 3 generation up ~3. If you want 7th last commit in same branch favouring first parent while traversing.

Any merge will have two parents with merge to branch becoming first parent. Merge from branch becoming second parent.

Absalom answered 20/5, 2018 at 9:55 Comment(2)
I'm not clear on what you mean by "...merge to branch becoming first parent. Merge from branch becoming second parent." In the lesson it says "The first parent is the branch you were on when you ran git merge while the second parent is the branch that was merged in," is that what you're saying?Eyla
Yes exactly. I mean “ merge to” branch and “merge from” branchAbsalom
M
6

setia_'s answer remains the most appropriate but your question is meaningful because a git history can be considered from two distinct perspectives: either you totally view it as a (mathematical) graph in which parent's order is supposed to be non significant, OR you consider a merge operation as the integration of an external branch into a common trunk (i.e. your current branch, very often "master"). This is also the assumption made by git merge.

This is important not only because browsing an exponentially growing tree rapidly becomes a pain, but also because having a branch "master" that contains a finished product and integrating external submissions is a model followed by many workflows.

Since both these points of view are valid, they cause --first-parent to be a frequently used option, though not a main command nor a default behavior.

For example, browsing the Linux kernel main repository (for which Git was first designed) with a simple git log --graph can take up to one minute before displaying something, but git log --graph --first-parent will show you the main branch and let you observe that it's mainly composed of merges, with occasional direct commits.

Another thing one have to keep it mind is that you can ask to have your commits displayed by chronological order using --date-order or topological order with --topo-order. Let's assume you have two distinct branches and alternatively commit to the one or the other before eventually merging them. Depending on the order, the resulting graph would look like one of these :

Chronological order                     Topological order

*   ec9a124 Merge branch 'B' into A     *   ec9a124 Merge branch 'B' into A
|\                                      |\
* | e5314f2 Ninth                       | * e3e2435 Eighth
| * e3e2435 Eighth                      | * af3bac5 Sixth
* | 308228b Seventh                     | * 3a2f0b9 Fourth
| * af3bac5 Sixth                       | * d901c9f Second
* | ab11578 Fifth                       * | e5314f2 Ninth
| * 3a2f0b9 Fourth                      * | 308228b Seventh
* | 344bd0f Third                       * | ab11578 Fifth
| * d901c9f Second                      * | 344bd0f Third
|/                                      |/
* 0f029bc First                         * 0f029bc First

All commits remain on their respective line but the latter is a depth-first search. And since git log (so does git rev-list) displays a collection of pre-gathered revisions, this order will be the same whether you're using --graph or displaying them as a flat list (actually, if not specified, git log use reverse chronological order by default, and topological one when using --graph).

Because of that, you can't simply rely on the first row to decide which parent to choose.

This can also cause some older commits to appear before the new ones, which can be very confusing when beginning with Git, and give you the impression that your work has disappeared (until it comes to one's mind to perform a search, then retrieve it buried somewhere in history).

Margemargeaux answered 20/5, 2018 at 15:23 Comment(0)
A
2

Commit can have more than one parent. ^ 1 means first parent. ^2 means second parent and so on. Just ^ defaults to ^1 which is first parent.

Similarly ~ give access to traverse up for an ancestor. For example if you want 3 generation up ~3. If you want 7th last commit in same branch favouring first parent while traversing.

Any merge will have two parents with merge to branch becoming first parent. Merge from branch becoming second parent.

Absalom answered 20/5, 2018 at 9:55 Comment(2)
I'm not clear on what you mean by "...merge to branch becoming first parent. Merge from branch becoming second parent." In the lesson it says "The first parent is the branch you were on when you ran git merge while the second parent is the branch that was merged in," is that what you're saying?Eyla
Yes exactly. I mean “ merge to” branch and “merge from” branchAbsalom

© 2022 - 2024 — McMap. All rights reserved.