How to understand git log --graph

回眸只為那壹抹淺笑 提交于 2019-12-05 10:44:07

问题


I am quite confused with the output of graphic git log.

I do understand that each * means a commit, whether it is a diverge, common or merge commit. I do understand that pipes means branch.

Let's look at a simple graph log:

First of all, which branch does the red pipe (the most left-handed one) represent for? I don't think it is the current branch that I am on, because after I checkout to other branch, the graph looks the same. Furthermore, it doesn't represent master branch neither.

Second of all, if the most left-handed branch represents a single branch, why it changes color after commit "0e5b5"?

I searched for a tutorial on how to read git log graphs, unfortunately, I got nothing. If there are some awesome tutorials on this topic, please feel free to share.


回答1:


Git works from the current commit looking at ancestors. Branches are not "entities", they are (moving) references. There is no way for git log (or gitk which has a different color scheme but is analoguous to git log --graph or tig) to know if the current branch is the descendant of branch A or branch B. It only knows parents. From man git-log:

   git log -p -m --first-parent
       Shows the history including change diffs, but only from the "main 
       branch"   perspective, skipping commits that come from merged
       branches, and showing full diffs of changes introduced by the merges. 
       This makes sense only when following a strict policy of merging
       all topic branches when staying on a single integration branch.

Would somewhat address your concern. git log by default use current checked out commit as a reference (identical to executing git log HEAD

While I personnaly think the man page is quite clear for git, you may want to take a look at gitk or tig. The former is a graphical interface the later is a terminal-like minimal gitk tool. I use both depending on what I want to do.




回答2:


With Git 2.25 (Q1 2020), The implementation of "git log --graph" got refactored and then its output got simplified.

That in turn can fix the color for some cases.
The following provides an illustration on how colors and edges are managed with git log --graph.

See commit d784d97 (12 Nov 2019) by Denton Liu (Denton-L).
See commit bbb13e8, commit 92beecc, commit 479db18, commit 0195285, commit d62893e, commit 0f0f389, commit 458152c, commit ee7abb5, commit 46ba2ab, commit a551fd5, commit 9157a2a, commit 210179a, commit fbccf25 (15 Oct 2019) by James Coglan (jcoglan).
(Merged by Junio C Hamano -- gitster -- in commit 0be5caf, 01 Dec 2019)

graph: fix coloring of octopus dashes

Signed-off-by: James Coglan

In 04005834ed ("log: fix coloring of certain octopus merge shapes", 2018-09-01, Git v2.20.0-rc0 -- merge listed in batch #6), there is a fix for the coloring of dashes following an octopus merge.
It makes a distinction between the case where all parents introduce a new column, versus the case where the first parent collapses into an existing column:

| *-.           | *-.
| |\ \          | |\ \
| | | |         |/ / /

The latter case means that the columns for the merge parents begin one place to the left in the new_columns array compared to the former case.

However, the implementation only works if the commit's parents are kept in order as they map onto the visual columns, as we get the colors by iterating over new_columns as we print the dashes.
In general, the commit's parents can arbitrarily merge with existing columns, and change their ordering in the process.

For example, in the following diagram, the number of each column indicates which commit parent appears in each column.

| | *---.
| | |\ \ \
| | |/ / /
| |/| | /
| |_|_|/
|/| | |
3 1 0 2

If the columns are colored (red, green, yellow, blue), then the dashes will currently be colored yellow and blue, whereas they should be blue and red.

To fix this, we need to look up each column in the mapping array, which before the GRAPH_COLLAPSING state indicates which logical column is displayed in each visual column.
This implementation is simpler as it doesn't have any edge cases, and it also handles how left-skewed first parents are now displayed:

| *-.
|/|\ \
| | | |
0 1 2 3

The color of the first dashes is always the color found in mapping two columns to the right of the commit symbol. Because commits are displayed after all edges have been collapsed together and the visual columns match the logical ones, we can find the visual offset of the commit symbol using commit_index.


Regarding edges (still with Git 2.25, Q1 2020):

graph: smooth appearance of collapsing edges on commit lines

Signed-off-by: James Coglan

When a graph contains edges that are in the process of collapsing to the left, but those edges cross a commit line, the effect is that the edges have a jagged appearance:

*
|\
| *
|  \
*-. \
|\ \ \
| | * |
| * | |
| |/ /
* | |
|/ /
* |
|/
*

We already takes steps to smooth edges like this when they're expanding; when an edge appears to the right of a merge commit marker on a GRAPH_COMMIT line immediately following a GRAPH_POST_MERGE line, we render it as a \:

* \
|\ \
| * \
| |\ \

We can make a similar improvement to collapsing edges, making them easier to follow and giving the overall graph a feeling of increased symmetry:

*
|\
| *
|  \
*-. \
|\ \ \
| | * |
| * | |
| |/ /
* / /
|/ /
* /
|/
*

To do this, we introduce a new special case for edges on GRAPH_COMMIT lines that immediately follow a GRAPH_COLLAPSING line.
By retaining a copy of the mapping array used to render the GRAPH_COLLAPSING line in the old_mapping array, we can determine that an edge is collapsing through the GRAPH_COMMIT line and should be smoothed.


More generally:

graph: commit and post-merge lines for left-skewed merges

Signed-off-by: James Coglan

Following the introduction of "left-skewed" merges, which are merges whose first parent fuses with another edge to its left, we have some more edge cases to deal with in the display of commit and post-merge lines.

The current graph code handles the following cases for edges appearing to the right of the commit (*) on commit lines.

A 2-way merge is usually followed by vertical lines:

| | |
| * |
| |\ \

An octopus merge (more than two parents) is always followed by edges sloping to the right:

| |  \          | |    \
| *-. \         | *---. \
| |\ \ \        | |\ \ \ \

A 2-way merge is followed by a right-sloping edge if the commit line immediately follows a post-merge line for a commit that appears in the same column as the current commit, or any column to the left of that:

| *             | * |
| |\            | |\ \
| * \           | | * \
| |\ \          | | |\ \

This commit introduces the following new cases for commit lines. If a 2-way merge skews to the left, then the edges to its right are always vertical lines, even if the commit follows a post-merge line:

| | |           | |\
| * |           | * |
|/| |           |/| |

A commit with 3 parents that skews left is followed by vertical edges:

| | |
| * |
|/|\ \

If a 3-way left-skewed merge commit appears immediately after a post-merge line, then it may be followed the right-sloping edges, just like a 2-way merge that is not skewed.

| |\
| * \
|/|\ \

Octopus merges with 4 or more parents that skew to the left will always be followed by right-sloping edges, because the existing columns need to expand around the merge.

| |  \
| *-. \
|/|\ \ \

On post-merge lines, usually all edges following the current commit slope to the right:

| * | |
| |\ \ \

However, if the commit is a left-skewed 2-way merge, the edges to its right remain vertical.
We also need to display a space after the vertical line descending from the commit marker, whereas this line would normally be followed by a backslash.

| * | |
|/| | |

If a left-skewed merge has more than 2 parents, then the edges to its right are still sloped as they bend around the edges introduced by the merge.

| * | |
|/|\ \ \

To handle these new cases, we need to know not just how many parents each commit has, but how many new columns it adds to the display; this quantity is recorded in the edges_added field for the current commit, and prev_edges_added field for the previous commit.

Here, "column" refers to visual columns, not the logical columns of the columns array.
This is because even if all the commit's parents end up fusing with existing edges, they initially introduce distinct edges in the commit and post-merge lines before those edges collapse.

For example, a 3-way merge whose 2nd and 3rd parents fuse with existing edges still introduces 2 visual columns that affect the display of edges to their right.

| | |  \
| | *-. \
| | |\ \ \
| |_|/ / /
|/| | / /
| | |/ /
| |/| |
| | | |

This merge does not introduce any logical columns; there are 4 edges before and after this commit once all edges have collapsed. But it does initially introduce 2 new edges that need to be accommodated by the edges to their right.


The classic output has been simplified:

graph: example of graph output that can be simplified

Signed-off-by: James Coglan

The commits following this one introduce a series of improvements to the layout of graphs, tidying up a few edge cases, namely:

  • merge whose first parent fuses with an existing column to the left
  • merge whose last parent fuses with its immediate neighbor on the right
  • edges that collapse to the left above and below a commit line

This test case exemplifies these cases and provides a motivating example of the kind of history I'm aiming to clear up.

The first parent of merge E is the same as the parent of H, so those edges fuse together.

* H
|
| *-.   E
| |\ \
|/ / /
|
* B

We can "skew" the display of this merge so that it doesn't introduce additional columns that immediately collapse:

* H
|
| *   E
|/|\
|
* B

The last parent of E is D, the same as the parent of F which is the edge to the right of the merge.

* F
|
 \
. \   E
 \ \
 / /
| /
|/
* D

The two edges leading to D could be fused sooner: rather than expanding the F edge around the merge and then letting the edges collapse, the F edge could fuse with the E edge in the post-merge line:

* F
|
 \
. | E
 \|
 /
|
* D

If this is combined with the "skew" effect above, we get a much cleaner graph display for these edges:

* F
|
| E
|
|
* D

Finally, the edge leading from C to A appears jagged as it passes through the commit line for B:

| * | C
| |/
* | B
|/
* A

This can be smoothed out so that such edges are easier to read:

| * | C
| |/
* / B
|/
* A


来源:https://stackoverflow.com/questions/20200226/how-to-understand-git-log-graph

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!