Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
How to simplify the graph produced by git log --graph

Ideas for improvements to git log --graph

I will maybe someday get around to dusting off my C and making these changes myself unless someone else does it first.

Make the graph for --topo-order less wiggly

Imagine a long-running development branch periodically merges from master. The git log --graph --all --topo-order is not as simple as it could be, as of git version 1.7.10.4.

It doesn't seem like a big deal in this example, but when you're trying to follow the history trails in ASCII and you've got several different branches displayed at once, it gets difficult quickly.

To simulate:

git init example
cd example
git commit --allow-empty -m "initial empty commit"
git branch dev
for x in `seq 4`; do
    echo 1 >> 1.txt
    git add 1.txt
    git commit -m "commit"
    git checkout dev
    git merge --no-ff --no-edit master
    git checkout master
done

The result:

$ git log --graph --all --topo-order --decorate --oneline --boundary
*   a9f8d93 (dev) Merge branch 'master' into dev
|\
| * 5f32650 (HEAD, master) commit
* |   b511501 Merge branch 'master' into dev
|\ \
| |/
| * 4e6810e commit
* |   2cd55b4 Merge branch 'master' into dev
|\ \
| |/
| * 4f74695 commit
* |   372799e Merge branch 'master' into dev
|\ \
| |/
| * 076669f commit
|/
* 7382440 initial empty commit

What I would like it to display:

$ git log --graph --all --topo-order --decorate --oneline --boundary
*   a9f8d93 (dev) Merge branch 'master' into dev
|\
| * 5f32650 (HEAD, master) commit
* | b511501 Merge branch 'master' into dev
|\|
| * 4e6810e commit
* | 2cd55b4 Merge branch 'master' into dev
|\|
| * 4f74695 commit
* | 372799e Merge branch 'master' into dev
|\|
| * 076669f commit
|/
* 7382440 initial empty commit

Let me specify which branches sink to the left.

Sometimes I'm faced with a very complex mess of merges and branches. I'd like to be able to ask git log to show me the graph, but to always set commits from specific branches into specific columns in the output. This might make for more line-drawing to connect the commits, but that's okay in this situation.

Using the very same repo above, I'd like to say "make left-most columns for master and dev, in that order" and see:

$ git log --graph --all --topo-order --decorate --oneline --boundary --force-branch-columns=master,dev

.-- master
| .-- dev
v v

  * a9f8d93 (dev) Merge branch 'master' into dev
 /|
* | 5f32650 (HEAD, master) commit
| * b511501 Merge branch 'master' into dev
|/|
* | 4e6810e commit
| * 2cd55b4 Merge branch 'master' into dev
|/|
* | 4f74695 commit
| * 372799e Merge branch 'master' into dev
|/|
* | 076669f commit
 \|
  * 7382440 initial empty commit

Maybe that doesn't seem like it's of much value, but let's throw another branch into the mix and see what it might look like.

Branch from somewhere in the middle of dev, create two commits, then merge from master:

git checkout -b newbranch dev~3
echo 2 >> 2.txt; git add 2.txt; git commit -m "commit"
echo 2 >> 2.txt; git add 2.txt; git commit -m "commit"
git merge --no-ff --no-edit master

The unmodified result:

$ git log --graph --all --topo-order --decorate --oneline --boundary
*   f745bf5 (HEAD, newbranch) Merge branch 'master' into newbranch
|\
* | 7031537 commit
* | 416ab2c commit
| | *   a9f8d93 (dev) Merge branch 'master' into dev
| | |\
| | |/
| |/|
| * | 5f32650 (master) commit
| | *   b511501 Merge branch 'master' into dev
| | |\
| | |/
| |/|
| * | 4e6810e commit
| | *   2cd55b4 Merge branch 'master' into dev
| | |\
| |/ /
|/| /
| |/
| * 4f74695 commit
* |   372799e Merge branch 'master' into dev
|\ \
| |/
| * 076669f commit
|/
* 7382440 initial empty commit

What's most striking to me about the as-is unmodified output is the frequency with which we see this cross-legged pattern:

  *   b511501 Merge branch 'master' into dev
  |\
  |/
 /|
* | 4e6810e commit
  *   2cd55b4 Merge branch 'master' into dev

Is the output perhaps intentionally like this to show which parent of a merge commit is the "first" parent? If so, that may be useful sometimes, so I wouldn't want to see that style completely removed in favor of my suggestion.

With different line-drawing logic and forced columns, it might look like this:

$ git log --graph --all --topo-order --decorate --oneline --boundary --force-branch-columns=master,dev

.-- master
| .-- dev
v v

    * f745bf5 (HEAD, newbranch) Merge branch 'master' into newbranch
   /|
  / * 7031537 commit
 /  * 416ab2c commit
| * | a9f8d93 (dev) Merge branch 'master' into dev
|/| |
* | | 5f32650 (master) commit
| * | b511501 Merge branch 'master' into dev
|/| |
* | | 4e6810e commit
| * | 2cd55b4 Merge branch 'master' into dev
|/|/
| /
|/|
* | 4f74695 commit
| * 372799e Merge branch 'master' into dev
|/|
* | 076669f commit
 \|
  * 7382440 initial empty commit

I think that it is much easier with that visualization to track which commits are in master and dev, and see the points at which other branches forked from and merged with them.

@gsscoder

It would be cool :+1: !

@nvie

:+1:

Somewhat two years ago, I had an idea for a pet project that resembled this feature a lot. I never pursued it, though :(

I wanted to use that for git-flow based projects, where you typically have two "fixed" branches (develop and master), and the rest of the branches lives somewhere in between, or "to the left of" develop. Basically, I would love to use this option:

--force-branch-columns="*,develop,release*,hotfix*,master"

This would basically draw git logs laid out as the branching model's main picture.

I think having such a feature would tremendously simplify reading your git logs, as it renders branches the way you would love to think about them.

@MiroRadenovic

yes,that would be great feature

@vidia

Maybe I am resurrecting a dead thread, but I love this idea. Just throwing that out there.

@pkoch

I'd like to be able to ask git log to show me the graph, but to always set commits from specific branches into specific columns in the output.

I'm not really sure on how this would work. The branch is a pointer to a commit, not more. While it's definitely possible to order the "lane position" of the current commit of a branch, git has no way to tell if a commit "belongs to a branch" further past in history.

@staltz

I would love to see this too, and I've been wondering how to develop it (let's call it "git flog"? Flow + log). pkoch pointed out the main problem, and probably to accomplish "git flog", one would need to modify git further.

@mdeady

Now I'm definitely resurrecting an old thread...

@pkoch:

git has no way to tell if a commit "belongs to a branch" further past in history

I think you could base this off of the parent order. For merge commits, the first parent would stay in the same column. Ambiguity arises from deciding which column to place a 'branching' commit (a commit that is the first parent of multiple commits). You could probably just have those commits aligned into the left-most column of all the branches that are involved. So in the last snippet in OP's post, 7382440 initial empty commit would instead be in the left column as master is the left-most column of the two columns that split from it.

@drachlyznardh

It may be late to post this, but I'm very interested in the matter.

git has no way to tell if a commit "belongs to a branch" further past in history

Wouldn't it be possible to force the columns using tags instead of branches? Tags don't move, so they can mark a point in history as needed, and their name can be conventionally prefixed to show their desired column.

Something like --force-tag-columns="hotfix-*,release-*,*" could turn

*   9e8966d (HEAD, tag: release-0.b, master) Merge branch 'devel'
|\  
| * 53c17b8 (devel) A devel commit.
| * 1a7201b A devel commit.
| * f709752 A devel commit.
| *   c54a11c Merge branch 'master' into devel
| |\  
| |/  
|/|   
* |   42a126d (tag: release-0.a-000) Merge branch 'hotfix'
|\ \  
| * | 5a13312 (tag: hotfix-000, hotfix) Fixing bug #000
|/ /  
* |   8ff7de1 (tag: release-0.a) Merge branch 'devel'
|\ \  
| |/  
| * 6984067 A devel commit.
| * f1213d4 A devel commit.
| * 3c075a4 A devel commit.
|/  
* 3ffe4fe (tag: release-base) First commit.

into

  *   9e8966d (HEAD, tag: release-0.b, master) Merge branch 'devel'
  |\  
  | * 53c17b8 (devel) A devel commit.
  | * 1a7201b A devel commit.
  | * f709752 A devel commit.
  | * c54a11c Merge branch 'master' into devel
  |/|   
  * | 42a126d (tag: release-0.a-000) Merge branch 'hotfix'
 /| |  
* | | 5a13312 (tag: hotfix-000, hotfix) Fixing bug #000
 \| |  
  * | 8ff7de1 (tag: release-0.a) Merge branch 'devel'
  |\|  
  | * 6984067 A devel commit.
  | * f1213d4 A devel commit.
  | * 3c075a4 A devel commit.
  |/  
  *   3ffe4fe (tag: release-base) First commit.
@martinda

Anyone knows how difficult this is to implement?

@datagrok
Owner

Shrug, it's not a dead thread until somebody gets around to implementing it. If/when I do get a chance to work on it I'll first re-read all the comments left here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.