Pretty Git branch graphs
Asked Answered
L

39

1899

I've seen some books and articles have some really pretty looking graphs of Git branches and commits. How can I make high-quality printable images of Git history?

Lepidopteran answered 29/6, 2009 at 10:12 Comment(6)
I have created a python script to create a graphiz graph! Take a look. github.com/chode/git-graphKayleigh
If you want high-quality and printable, my tool (bit-booster.com/graph.html) converts "git log" into SVG. For more information, see my answer.Townscape
Are you looking for a tool to visualize your own git history - or - a charting tool which has a way to draw pretty "Git branches"?Wilfredwilfreda
Possible duplicate of Visualizing branch topology in gitRandolf
try tig, github.com/jonas/tigGuyenne
If you use VS Code ..... https://mcmap.net/q/12492/-pretty-git-branch-graphsThorny
L
2354

Update: I've posted an improved version of this answer to the Visualizing branch topology in Git question, since it's far more appropriate there. Leaving this answer for historical (& rep, I'll admit) reasons, though I'm really tempted to just delete it.

My two cents: I have two aliases I normally throw in my ~/.gitconfig file:

[alias]
lg1 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --all
lg2 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(auto)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
lg = lg1

git lg/git lg1 looks like this: git lg1

and git lg2 looks like this: git lg2


(Note: There now exists much more applicable answers to this question, such as fracz's, Jubobs', or Harry Lee's!)

Lydell answered 31/1, 2012 at 4:22 Comment(25)
Yeah, I do. Normal and bright/bold colors are: Black #202020/#555555, Red: #5d1a14/#da4939, Green: #424e24/#a5c261, Yellow: #6f5028/#ffc66d, Blue: #263e4e/#6d9cbe, Magenta: #3e1f50/#a256c7, Cyan: #234e3f/#62c1a1, and White: #979797/#ffffff.Lydell
@Turbo: For me, the colors are changeable in the profile settings for my terminal app (Terminal.app). The terminal app you're using may or may not support changing which colors are displayed for given ANSI colors. Also, the dash (em dash, accurately) was created with option-shift-[hyphen-minus key]. I suppose I wrongly assumed that all current platforms were up-to-snuff with Unicode.Lydell
@slipp-d-thompson, --decorate option uses the short ref names.Breve
Your --date=relative and --abbrev-commit are redundant because you explicitly use %cr and %h, respectively.Abandoned
@RobertDailey I don't know how that would be possible. These commands are just additional aliases; they don't affect the existing behavior of any git functionality (by design). I suspect something else is the culprit— one easy way to check is to stub out lg1 as !"echo 'ran lg1'" and lg2 as !"echo 'ran lg2'".Lydell
@RohitJain That depends on what terminal app you're using. Look in its settings for “ANSI Colors”. If you can't find it, check the documentation. If it doesn't support it, look for a different terminal app. I'm using Terminal.app on OS X; it's under Preferences›Settings»Text›ANSI Colors.Lydell
@Jason Goemaat: Hey, sorry for the revert— I just think that stackoverflow.com/revisions/9074343/5 is outside of the scope of the Q and this A. It's GIT 102, covered well in the git manual(s), and easily found via a Google/SO search for “set git config” or similar.Lydell
@JasonGoemaat I really do think 95% of the audience for this suggestion already knows how to use git-config. And for the 5% that don't— they really should be focused more on learning git and have a GUI for visualizations like this this rather than customizing their CLI. Honestly, I suggest anyone not already familiar with their .gitconfig file shouldn't be putting snippets found on the interwebs in there.Lydell
Here's how to get the refs to be colorized like --decorateDualistic
I'd add the %C(auto) modifier to the refnames (%d) to get nicer colors. See https://mcmap.net/q/12731/-color-in-git-log/…Floyfloyd
Great answer. I've modified the command to look more like the output of --oneline --decorate with lg = log --graph --abbrev-commit --decorate --format=format:'%C(yellow)%h%C(reset)%C(auto)%d%C(reset) %C(normal)%s%C(reset) %C(dim white)%an%C(reset) %C(dim blue)(%ar)%C (reset)' --allStandby
@hbogert Similarly, I maintain a Gist of my own ~/.gitconfig file here: gist.github.com/capnslipp/859701Lydell
modified one for "actual dates, than relative" : git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)%aD%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --allDunker
combine this with github.com/theZiz/aha and you got a wonderful html git log, you just have to append --color to the gitlog commandColon
this is the command to create an alias called lg1: git config --global alias.lg1 "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all"Trump
You can use glog alias if on zsh and oh-my-zshLionize
Go to the terminal and paste this to configure the alias in git config: 1) git config --global alias.lg1 "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all" 2) git config --global alias.lg2 "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all"Beetner
Can we also complete the commit message under each one?Crustal
Vs code extension 'Git Graph' does all of this including many more functions like cherry-pick, merge, revert etc.Soar
What's the purpose of ! in lg = !"git lg1"?Legislate
@Legislate It tells Git to run it as a standard shell command. IIRC, you can't make an alias to another alias (only to a built-in git command), so the !"…" syntax jumps over that limitation (as well as allowing you to use any combination of CLI stuff you want, like sed or grep).Lydell
Run git init to reload the ~/.gitconfig so that you can run git <alias-cmd>Gaines
I've found that %C(dim white) doesn't work for me so I'm replacing it with %C(brightblack)Barghest
@Gaines I'm not sure how that fixed anything for you, but you definitely shouldn't do that. git init creates a new repository in the working directory. Also, all git commands reload ~/.gitconfig automatically. If you do want to make sure Git has picked up changes to your ~/.gitconfig, try checking the results of git config --global --list instead.Lydell
About the use of %an %ae: you ignore mailmap entries in this way. Usually they are set for good reason, namely authors/committers changed name or email and want to point users to the correct current information. It would be better to use %aN %aE here, which is also default behaviour for git log.Hammerhead
P
2046

Many of the answers here are great, but for those that just want a simple one-line-to-the-point answer without having to set up aliases or anything extra, here it is:

git log --all --decorate --oneline --graph

Not everyone would be doing a git log all the time, but when you need it just remember:

"A Dog" = git log --all --decorate --oneline --graph

Enter image description here

If you enter

git config --global alias.adog "log --all --decorate --oneline --graph"

at the command prompt once, you can use

git adog

from that prompt even if you close and reopen it.

Pupil answered 29/1, 2016 at 0:50 Comment(18)
git config --global alias.adog "log --all --decorate --oneline --graph"Bootee
I've been looking for the --all for so long I'm about to cry (T_T) THANK YOU!M
Summary of what the different options are for: --all = Pretend as if all the refs in refs/ are listed on the command line as commit>. --no-decorate, --decorate[=short|full|no] = Print out the ref names of any commits that are shown. If short is specified, the ref name prefixes refs/heads/, refs/tags/ and refs/remotes/ will not be printed. If full is specified, the full ref name (including prefix) will be printed. --oneline = This is a shorthand for "--pretty=oneline --abbrev-commit" used together. --graph= Draw a text-based graphical representation of the commit historyDamaraland
--oneline was introduced in Git 1.6.3: github.com/git/git/blob/… --pretty=oneline will work with Git versions before 1.6.3Moonstone
Great answer, but I think it's better without "--oneline" =]Botticelli
I think "--decorate" is now included by default. But I'll remember the acronym this way anyway!Antinomian
Since I read your answer a long time ago, whenever I need to use git log, the only thing that pops up in my mind is this image.Kt
GOAD git into showing a pretty branch graph: --graph --oneline --all --decorate.Laufer
I prefer "All Dogs" git log --all --decorate --oneline --graph --statAuricle
I've been looking for the --all for an emberassing amount of time but didn't know it exists...Bovill
As mentioned below by @shuaihanhungry, in oh-my-zsh this is available by default as gloga. (the decorate is not longer needed, so oga is enough)Reflect
We still need the --decorate when we pass git log to a pager e.g. watch git logTonisha
@KevinWheeler because its the easiest way to remember this vs the other answers.Adair
For everyone that uses git test (and you definitely should!), the test notes cache comes up as noise when using --all so they needs to be excluded: git config --global alias.adog "log --exclude=refs/notes/tests/* --all --decorate --oneline --graph" (NB, any --exclude pattern needs to come before --all).Tunstall
Although decorate is no longer needed as I noted earlier, if you are piping this command into less -R, (because it is part of a larger script), you should still include --decorate and also --color But how do I git a C dog? :-)Antinomian
I saw this answer years ago and I could neither find it nor use the right keywords to arrive here, but searching for git "adog" brought me here without delay. AwesomeCustom
I'm quite happy without the --all option as that gives me just the commits relevant to my current branch as I would see if I run gitk. This also nicely reduces it down to git dog 🐶Laurent
--all option is explained by man git-rev-listCondiment
R
435

For textual output you can try:

git log --graph --abbrev-commit --decorate --date=relative --all

Or:

git log --graph --oneline --decorate --all

Or: here's a Graphviz alias for drawing the DAG graph.

I personally use gitx, gitk --all and gitnub.

Rameriz answered 29/6, 2009 at 22:25 Comment(2)
I like these two as they split nicely between 'git log' (short) and 'git log' (long), so I can call the short (oneline) version most of the time, but if I need more details use the long version with full commit details. Then I have two nice mappings of <leader>gl (short) and <leader>gll (long) in Vim.Laurent
it it possible to ignore Author section?Crustal
B
307

Gitgraph.js allows to draw pretty Git branches without a repository. Just write a JavaScript code that configures your branches and commits and render it in the browser. Interactive docs are available.

var gitGraph = new GitGraph({
   template: "blackarrow",
   mode: "compact",
   orientation: "horizontal",
   reverseArrow: true
});

var master = gitGraph.branch("master").commit().commit();
var develop = gitGraph.branch("develop").commit();
master.commit();
develop.commit().commit();
develop.merge(master);

sample graph generated with Gitgraph.js

Or with metro template:

GitGraph.js metro theme

Or with commit messages, authors, and tags:

GitGraph with commit messages

Test it with JSFiddle.

Generate it with Git Grapher by @bsara.

Bootee answered 8/6, 2014 at 14:40 Comment(12)
Yay, that's totally amazing! Posted it into fiddle jsfiddle.net/guan1oz1 so you can test it out right away.Treasurehouse
The arrows should point to parent(s), though, not to children.Coyle
@Jubobs, I'm reading this graph from right to left, which arguably is equally weird.Tiki
@Jubobs: Good point. That's a common hurdle for people trying to understand Git: they think about the sequence of time instead of inheritance. Making it clear that (nearly) everything in git is relative to something prior helps all the other pieces fall into place.Lydell
@fracz: this is really cool. Thanks. One suggestion, however: please mention that even though the test webpage shows only no text, gitgraph.js does display commit messages, tags etc. if one download and open it locally. -- I suggest this because, at first, I thought it cannot display text and hence did not meet my needs. Fortunately, I didn't give up and downloaded gitgraph.js to my laptop. Turned out the actual output is pretty amazing and exactly what I want. :)Indigested
Regarding arrow direction, from the docs: * @param {Boolean} [options.reverseArrow = false] - Make arrows point to ancestors if trueElectrothermal
FYI, after seeing this post and playing with gitgraph.js, I decided to create a little tool that basically puts a UI to gitgraph.js. It's not finished, and the UI isn't where I want it to be yet, but contributions are welcome! take a look: github.com/bsara/git-grapherGroupie
The gitgraph.min.js link no longer works in the jsfiddle. There are other hostings of the script, at your own risk: https://mcmap.net/q/22389/-gitgraph-js-not-loading-from-cdn/521799Hayes
Only complaint with this tool is that it orients history top to bottom when in vertical mode. This is in contrast to majority of other tools that orient it from bottom to top for newer commits.Snout
This is just for presentations not for generating a graph or a real git history, which was the initial question.Unipod
Seems like the link is dead. The repo is at github.com/nicoespeon/gitgraph.js and they have a new website at nicoespeon.com/gitgraph.js/#0Outpatient
@PedroGarcíaMedina: Actually, the question doesn't say anything about a real git history.Juetta
C
145

Built on top of TikZ & PGF, gitdags is a little LaTeX package that allows you to effortlessly produce vector-graphics commit graphs, and more.

Automatic generation of an existing repository's commit graph is not the purpose of gitdags; the graphs it produces are only meant for educational purposes.

I often use it to produce graphs for my answers to Git questions, as an alternative to ASCII commit graphs:

Here is an example of such a graph demonstrating the effects of a simple rebase:

enter image description here

\documentclass{article}

\usepackage{subcaption}
\usepackage{gitdags}

\begin{document}

\begin{figure}
  \begin{subfigure}[b]{\textwidth}
    \centering
    \begin{tikzpicture}
      % Commit DAG
      \gitDAG[grow right sep = 2em]{
        A -- B -- { 
          C,
          D -- E,
        }
      };
      % Tag reference
      \gittag
        [v0p1]       % node name
        {v0.1}       % node text
        {above=of A} % node placement
        {A}          % target
      % Remote branch
      \gitremotebranch
        [origmaster]    % node name
        {origin/master} % node text
        {above=of C}    % node placement
        {C}             % target
      % Branch
      \gitbranch
        {master}     % node name and text 
        {above=of E} % node placement
        {E}          % target
      % HEAD reference
      \gitHEAD
        {above=of master} % node placement
        {master}          % target
    \end{tikzpicture}
    \subcaption{Before\ldots}
  \end{subfigure}

  \begin{subfigure}[b]{\textwidth}
    \centering
    \begin{tikzpicture}
      \gitDAG[grow right sep = 2em]{
        A -- B -- { 
          C -- D' -- E',
          {[nodes=unreachable] D -- E },
        }
      };
      % Tag reference
      \gittag
        [v0p1]       % node name
        {v0.1}       % node text
        {above=of A} % node placement
        {A}          % target
      % Remote branch
      \gitremotebranch
        [origmaster]    % node name
        {origin/master} % node text
        {above=of C}    % node placement
        {C}             % target
      % Branch
      \gitbranch
        {master}      % node name and text 
        {above=of E'} % node placement
        {E'}          % target
      % HEAD reference
      \gitHEAD
        {above=of master} % node placement
        {master}          % target
    \end{tikzpicture}
    \subcaption{\ldots{} and after \texttt{git rebase origin/master}}
  \end{subfigure}
  \caption{Demonstrating a typical \texttt{rebase}}
\end{figure}

\end{document}
Coyle answered 24/8, 2014 at 4:14 Comment(11)
@That looks great! I would also like a few line on how to use it: consider a Windows user who has no LaTeX installed at all. How to produce a graph from scratch?Posticous
@Posticous I'm not sure, but if you don't want to install LaTeX, you might be able to produce your graphs on ShareLatex and WriteLaTeX, and the likes. I will look into it and expand the wiki when I have more time... Feel free to promote the package :)Coyle
This is great stuff! I'll write up a tutorial at some point, but for now, I just wanted to mention that you can post-process your graphs using the documentclass standalone (I use the crop feature), use latex input.tex to generate a dvi, and then finally use dvisvgm input.dvi to generate an SVG with transparency. Converting from the SVG to a raster format like PNG is easy enough with convert -antialias -density 300 -background none input.svg output.png. By the way, these images look amazing with full transparency. Still working on the font issue... i.imgur.com/1Xu2Ry5.pngSingle
@Single Thanks. Don't hesitate to upvote this answer :) You can use the standalone class, but, if I were you, I'd go the pdflatex route, because it produces a PDF directly. Also, no need to rasterize it; just import it wherever as a PDF. Which font are you using?Coyle
@Jubobs The default font, Latin Modern Typewriter, specified in the gitdags package. The goal I had was to export these images with transparency enabled. When extracting them from the pdf, there tend to be artifacts I haven't been able to get rid of: i.imgur.com/fMvv1Gx.png. Note the fill on the arrows.Single
@Single Those artefacts are probably created somewhere during the dvi -> svg -> png conversion. Stick to the PDF format: use pdflatex. I can see no such artefacts on my PDF output (in Mac OS X Preview).Coyle
@Jubobs The problem with that method is the lack of transparency. Extraction from the PDF via imagemagick, convert -channel rgba -density 600 -alpha on input.pdf output.png, results in artifacts. The DVI->SVG->PNG route doesn't produce them. Likewise, they're not present in the Tex->PDF process.Single
It took me a while to get this working so I wrote a step-by-step guide how to get gitdags working from scratch on Ubuntu 14.04Wedded
@Wedded Thanks for that. I'm partly to blame for why getting this to work is complicated; once I successfully submit gitdags and xcolor-solarized to CTAN, they will become part of your TeX distribution and you won't need to install them "manually".Coyle
@Jubos many thanks for releasing gitdas. I cannot find an example of a merge, can you show me how to include it in my graphs?Yecies
@AndreaPolci See github.com/Jubobs/gitdags/issues/3 for an example of a merge. The documentation for gitdags is on the way!Coyle
R
87

Gitg is a clone of Gitk and GitX for GNOME (it also works on KDE etc.) which shows a pretty colored graph.

It is actively developed (as of 2012). It lets you sort the commits (graph nodes) either chronologically or topologically, and hide commits that don't lead to a selected branch.

It works fine with large repositories and complex dependency graphs.

Sample screenshots, showing the linux-git and linux-2.6 repositories:

linux-git

linux-2.6

Rilda answered 1/11, 2012 at 23:35 Comment(0)
R
69

I just wrote one tool that can generate a pretty Git commits graph using HTML/Canvas.

And provide a jQuery plugin which makes it easy to use.

[GitHub] https://github.com/tclh123/commits-graph

Preview:

Preview

Reverberate answered 14/1, 2014 at 15:7 Comment(2)
Looks nice, how do you get preformatted data to draw this graph?Solly
@Solly I just add the backend code to my repo. You can view it on github.Reverberate
C
65

A nice and clean looking table-like Git graph output for shells

With hashes as usually besides the graph tree

With hashes as usually besides the graph tree

Or in an extra column

Or in an extra column

THX!: This answer is now among the top 10 most rated and even has its own GitHub repository.

EDIT: You want to start right away without reading all explanations? Jump to EDIT 7.

INFO: For a more branch-like colored version for shells, see also my second answer (https://stackoverflow.com/a/63253135/).

In all the answers to this question none showed a clean table-like looking output for shells so far. The closest was this answer from gospes where I started from.

The core point in my approach is to count only the tree characters shown to the user. Then fill them to a personal length with white spaces.

Other than Git, you need these tools

  • grep
  • paste
  • printf
  • sed
  • seq
  • tr
  • wc

Mostly on board with any Linux distribution.

The code snippet is

while IFS=+ read -r graph hash time branch message;do

  # Count needed amount of white spaces and create them
  whitespaces=$((9-$(sed -nl1000 'l' <<< "$graph" | grep -Eo '\\\\|\||\/|\ |\*|_' | wc -l)))
  whitespaces=$(seq -s' ' $whitespaces|tr -d '[:digit:]')

  # Show hashes besides the tree ...
  #graph_all="$graph_all$graph$(printf '%7s' "$hash")$whitespaces \n"

  # ... or in an own column
  graph_all="$graph_all$graph$whitespaces\n"
  hash_all="$hash_all$(printf '%7s' "$hash")  \n"

  # Format all other columns
  time_all="$time_all$(printf '%12s' "$time") \n"
  branch_all="$branch_all$(printf '%15s' "$branch")\n"
  message_all="$message_all$message\n"
done < <(git log --all --graph --decorate=short --color --pretty=format:'+%C(bold 214)%<(7,trunc)%h%C(reset)+%C(dim white)%>(12,trunc)%cr%C(reset)+%C(214)%>(15,trunc)%d%C(reset)+%C(white)%s%C(reset)' && echo);

# Paste the columns together and show the table-like output
paste -d' ' <(echo -e "$time_all") <(echo -e "$branch_all") <(echo -e "$graph_all") <(echo -e "$hash_all") <(echo -e "$message_all")

To calculate the needed white spaces we use

  sed -nl1000 'l' <<< "$graph"

to get all characters (till 1000 per line) than select only the tree characters: * | / \ _ and white spaces with

  grep -Eo '\\\\|\||\/|\ |\*|_'

Finally count them and substract the result from our chosen length value, which is 9 in the example.

To produce the calculated amount of white spaces we use

  seq -s' ' $whitespaces

and truncate the position numbers with

  tr -d '[:digit:]'

Then add them to the end of our graph line. That's it!

Git has the nice option to format the length of the output specifiers already with the syntax '%><(amount_of_characters,truncate_option)', which adds white spaces from the left '>' or right '<' side and can truncate characters from the start 'ltrunc', middle 'mtrunc' or end 'trunc'.

It is important that printf cmd's above use the same length values for the corresponding Git column.

Have fun to style your own clean table-like looking output to your needs.

Extra:

To get the right length value you can use the following snippet

while read -r graph;do
    chars=$(sed -nl1000 'l' <<< "$graph" | grep -Eo '\\\\|\||\/|\ |\*|_' | wc -l)
    [[ $chars -gt ${max_chars:-0} ]] && max_chars=$chars
done < <(git log --all --graph --pretty=format:' ')

and use $max_chars as the right length value above.

EDIT 1: Just noticed that the underline character is also used in the git tree and edit the code snippets above accordingly. If there are other characters missing, please leave a comment.

EDIT 2: If you want to get rid of the brackets around branch and tag entries, just use "%D" instead of "%d" in the git command, like in EDIT 3.

EDIT 3: Maybe the "auto" color option is the one you prefer most for branch and tag entries?

Git bracketless auto color head and tag tablelike shell output

Change this part of the git command (color 214)

%C(214)%>(15,trunc)%D%C(reset)

to auto

%C(auto)%>(15,trunc)%D%C(reset)

EDIT 4: Or you like your own color mix for that part, a fancy output with blinking head?

Git tree fancy styled tablelike output

To be able to style the head, branch names and tags first we need the "auto" color option in our git command like in EDIT 3.

Then we can replace the know color values with our own by adding these 3 lines

 # branch name styling
 branch=${branch//1;32m/38;5;214m}
 # head styling
 branch=${branch//1;36m/3;5;1;38;5;196m}
 # tag styling
 branch=${branch//1;33m/1;38;5;222m}

just before line

 branch_all="$branch_all$(printf '%15s' "$branch")\n"

in our code snippet. The replacement values produce the colors above.

For example the replacement value for head is

3;5;1;38;5;196

where 3; stands for italic, 5; for blinking and 1;38;5;196 for the color. For more infos start here. Note: This behavior depends on your favorite terminal and may therefore not be usable.

BUT you can choose any color value you prefer.

OVERVIEW of the git color values and ANSI equivalents

enter image description here

You find a list with git color/style option here.

If you need the output on your console for accurate colors (the picture above is scaled down by Stack Overflow) you can produce the output with

for ((i=0;i<=255;i++));do
  while IFS='+' read -r tree hash;do
    echo -e "$(printf '%-10s' "(bold $i)") $hash  $(sed -nl500 'l' <<< "$hash"|grep -Eom 1 '[0-9;]*[0-9]m'|tr -d 'm')"
  done < <(git log --all --graph --decorate=short --color --pretty=format:'+%C(bold '$i')%h%C(reset)'|head -n 1)
done

in your Git project path which uses the first commit from your Git log output.

EDIT 5: As member "Andras Deak" mentioned, there are some ways how to use this code:

1) as a Bash alias:

alias does not accept parameters but a function can, therefore just define in your .bashrc

   function git_tably () {
     unset branch_all graph_all hash_all message_all time_all max_chars

     ### add here the same code as under "2) as a shell script" ###

   }

and call the function git_tably (derived from table-like) directly under your git project path or from wherever you want with your git project path as first parameter.

2) as a shell script:

I use it with the option to pass a Git project directory as first parameter to it or if empty, take the working directory like the normal behavior. In it's entirety we have

# Edit your color/style preferences here or use empty values for git auto style
tag_style="1;38;5;222"
head_style="1;3;5;1;38;5;196"
branch_style="38;5;214"

# Determine the max character length of your git tree
while IFS=+ read -r graph;do
  chars_count=$(sed -nl1000 'l' <<< "$graph" | grep -Eo '\\\\|\||\/|\ |\*|_' | wc -l)
  [[ $chars_count -gt ${max_chars:-0} ]] && max_chars=$chars_count
done < <(cd "${1:-"$PWD"}" && git log --all --graph --pretty=format:' ')

# Create the columns for your preferred table-like git graph output
while IFS=+ read -r graph hash time branch message;do

  # Count needed amount of white spaces and create them
  whitespaces=$(($max_chars-$(sed -nl1000 'l' <<< "$graph" | grep -Eo '\\\\|\||\/|\ |\*|_' | wc -l)))
  whitespaces=$(seq -s' ' $whitespaces|tr -d '[:digit:]')

  # Show hashes besides the tree ...
  #graph_all="$graph_all$graph$(printf '%7s' "$hash")$whitespaces \n"

  # ... or in an own column
  graph_all="$graph_all$graph$whitespaces\n"
  hash_all="$hash_all$(printf '%7s' "$hash")  \n"

  # Format all other columns
  time_all="$time_all$(printf '%12s' "$time") \n"
  branch=${branch//1;32m/${branch_style:-1;32}m}
  branch=${branch//1;36m/${head_style:-1;36}m}
  branch=${branch//1;33m/${tag_style:-1;33}m}
  branch_all="$branch_all$(printf '%15s' "$branch")\n"
  message_all="$message_all$message\n"

done < <(cd "${1:-"$PWD"}" && git log --all --graph --decorate=short --color --pretty=format:'+%C(bold 214)%<(7,trunc)%h%C(reset)+%C(dim white)%>(12,trunc)%cr%C(reset)+%C(auto)%>(15,trunc)%D%C(reset)+%C(white)%s%C(reset)' && echo);

# Paste the columns together and show the table-like output
paste -d' ' <(echo -e "$time_all") <(echo -e "$branch_all") <(echo -e "$graph_all") <(echo -e "$hash_all") <(echo -e "$message_all")

3) as a Git alias:

Maybe the most comfortable way is to add a git alias in your .gitconfig

[color "decorate"]
    HEAD = bold blink italic 196
    branch = 214
    tag = bold 222

[alias]
    count-log = log --all --graph --pretty=format:' '
    tably-log = log --all --graph --decorate=short --color --pretty=format:'+%C(bold 214)%<(7,trunc)%h%C(reset)+%C(dim white)%>(12,trunc)%cr%C(reset)+%C(auto)%>(15,trunc)%D%C(reset)+%C(white)%s%C(reset)'
    tably     = !bash -c '"                                                                                                    \
                  while IFS=+ read -r graph;do                                                                                 \
                    chars_count=$(sed -nl1000 \"l\" <<< \"$graph\" | grep -Eo \"\\\\\\\\\\\\\\\\|\\||\\/|\\ |\\*|_\" | wc -l); \
                    [[ $chars_count -gt ${max_chars:-0} ]] && max_chars=$chars_count;                                          \
                  done < <(git count-log && echo);                                                                             \
                  while IFS=+ read -r graph hash time branch message;do                                                        \
                    chars=$(sed -nl1000 \"l\" <<< \"$graph\" | grep -Eo \"\\\\\\\\\\\\\\\\|\\||\\/|\\ |\\*|_\" | wc -l);       \
                    whitespaces=$(($max_chars-$chars));                                                                        \
                    whitespaces=$(seq -s\" \" $whitespaces|tr -d \"[:digit:]\");                                               \
                    graph_all=\"$graph_all$graph$whitespaces\n\";                                                              \
                    hash_all=\"$hash_all$(printf \"%7s\" \"$hash\")  \n\";                                                     \
                    time_all=\"$time_all$(printf \"%12s\" \"$time\") \n\";                                                     \
                    branch_all=\"$branch_all$(printf \"%15s\" \"$branch\")\n\";                                                \
                    message_all=\"$message_all$message\n\";                                                                    \
                  done < <(git tably-log && echo);                                                                             \
                  paste -d\" \" <(echo -e \"$time_all\") <(echo -e \"$branch_all\") <(echo -e \"$graph_all\")                  \
                                <(echo -e \"$hash_all\") <(echo -e \"$message_all\");                                          \
                '"

Than just call git tably under any project path.

Git is so powerful that you can change head, tags, ... directly as shown above and taken from here.

Another fancy option is to select tree colors you prefer the most with

[log]
    graphColors = bold 160, blink 231 bold 239, bold 166, bold black 214, bold green, bold 24, cyan

that gives you crazy looking but always table-like git log outputs

fanciest_git_tree_tablelike_image

Too much blinking! Just to demonstrate what is possible. Too few specified colors leads to color repetitions.

A complete .gitconfig reference is just one click away.

EDIT 6: Due to your positive votes I improved the snippet. Now you can feed it with almost any git log command and don't have to adapt the code any more. Try it!

How does it work?

  • define your Git log commands in your .gitconfig as always (formatted like below)
  • define a positive tree column number, where the git graph is shown (optional)

Then just call

    git tably YourLogAlias

under any git project path or

    git tably YourLogAlias TreeColNumber

where TreeColNumber overwrites an always defined value from above.

    git tably YourLogAlias | less -r

will pipe the output into less which is useful for huge histories.

Your Git log alias must follow these format rules:

  • each column has to be indicated by a column delimiter which you have to choose and may cause problems if not unique

    i.e. ^ in ...format:'^%h^%cr^%s' results in a tree, a hash, a time and a commit column

  • before every commit placeholder in your log command you have to use %><(<N>[,ltrunc|mtrunc|trunc]) , with one of the trunc options

    (for syntax explanations see https://git-scm.com/docs/pretty-formats),

    however the last commit placeholder of any newline can be used without it

    i.e. ...format:'^%<(7,trunc)%h^%<(12,trunc)%cr^%s'

  • if extra characters are needed for decoration like (committer: , < and >) in

    ...%C(dim white)(committer: %cn% <%ce>)%C(reset)...

    to get a table-like output they must be written directly before and after the commit placeholder

    i.e. ...%C(dim white)%<(25,trunc)(committer: %cn%<(25,trunc) <%ce>)%C(reset)...

  • using column colors like %C(white)...%C(reset) needs the --color option for a colored output

    i.e. ...--color...format:'^%C(white)%<(7,trunc)%h%C(reset)...

  • if you use the --stat option or similar, add a newline %n at the end

    i.e. ...--stat...format:'...%n'...

  • you can place the git graph at every column as long as you use no newline or only empty ones format:'...%n'

    for non-empty newlines ...%n%CommitPlaceholder... you can place the git graph at every column n+1 only if all n-th columns of each line exist and use the same width

  • the name of your defined tree column number for a specific log alias have to be YourLogAlias-col

Compared to normal git log output this one is slow but nice.

Now the improved snippet to add to your .gitconfig

[color "decorate"]
    HEAD   = bold blink italic 196
    branch = 214
    tag    = bold 222

[alias]

    # Delimiter used in every mylog alias as column seperator
    delim     = ^

    # Short overview about the last hashes without graph
    mylog     = log --all --decorate=short --color --pretty=format:'^%C(dim white)%>(12,trunc)%cr%C(reset)^%C(bold 214)%<(7,trunc)%h%C(reset)' -5

    # Log with hashes besides graph tree
    mylog2    = log --all --graph --decorate=short --color --pretty=format:'%C(bold 214)%<(7,trunc)%h%C(reset)^%C(dim white)%>(12,trunc)%cr%C(reset)^%C(auto)%>(15,trunc)%D%C(reset)^%C(white)%<(80,trunc)%s%C(reset)'
    mylog2-col= 3

    # Log with hashes in an own column and more time data
    mylog3    = log --all --graph --decorate=short --color --pretty=format:'^%C(dim white)%>(12,trunc)%cr%C(reset)^%C(cyan)%<(10,trunc)%cs%C(reset)^%C(bold 214)%<(7,trunc)%h%C(reset)^%C(auto)%<(15,trunc)%D%C(reset)^%C(white)%s%C(reset)'
    mylog3-col= 4

    tably     = !bash -c '" \
                \
                \
                declare -A col_length; \
                apost=$(echo -e \"\\u0027\"); \
                delim=$(git config alias.delim); \
                git_log_cmd=$(git config alias.$1); \
                git_tre_col=${2:-$(git config alias.$1-col)}; \
                [[ -z "$git_tre_col" ]] && git_tre_col=1; \
                [[ -z "$git_log_cmd" ]] && { git $1;exit; }; \
                \
                \
                i=0; \
                n=0; \
                while IFS= read -r line;do \
                  ((n++)); \
                  while read -d\"$delim\" -r col_info;do \
                    ((i++)); \
                    [[ -z \"$col_info\" ]] && col_length[\"$n:$i\"]=${col_length[\"${last[$i]:-1}:$i\"]} && ((i--)) && continue; \
                    [[ $i -gt ${i_max:-0} ]] && i_max=$i; \
                    col_length[\"$n:$i\"]=$(grep -Eo \"\\([0-9]*,[lm]*trunc\\)\" <<< \"$col_info\" | grep -Eo \"[0-9]*\" | head -n 1); \
                    [[ -n \"${col_length[\"$n:$i\"]}\" ]] && last[$i]=$n; \
                    chars_extra=$(grep -Eo \"trunc\\).*\" <<< \"$col_info\"); \
                    chars_extra=${chars_extra#trunc)}; \
                    chars_begin=${chars_extra%%\\%*}; \
                    chars_extra=${chars_extra%$apost*}; \
                    chars_extra=${chars_extra#*\\%}; \
                    case \" ad aD ae aE ai aI al aL an aN ar as at b B cd cD ce cE ci cI cl cL cn cN cr \
                            cs ct d D e f G? gd gD ge gE GF GG GK gn gN GP gs GS GT h H N p P s S t T \" in \
                      *\" ${chars_extra:0:2} \"*) \
                        chars_extra=${chars_extra:2}; \
                        chars_after=${chars_extra%%\\%*}; \
                        ;; \
                      *\" ${chars_extra:0:1} \"*) \
                        chars_extra=${chars_extra:1}; \
                        chars_after=${chars_extra%%\\%*}; \
                        ;; \
                      *) \
                        echo \"No Placeholder found. Probably no tablelike output.\"; \
                        continue; \
                        ;; \
                    esac; \
                    if [[ -n \"$chars_begin$chars_after\" ]];then \
                      len_extra=$(echo \"$chars_begin$chars_after\" | wc -m); \
                      col_length["$n:$i"]=$((${col_length["$n:$i"]}+$len_extra-1)); \
                    fi; \
                  done <<< \"${line#*=format:}$delim\"; \
                  i=1; \
                done <<< \"$(echo -e \"${git_log_cmd//\\%n/\\\\n}\")\"; \
                \
                \
                git_log_fst_part=\"${git_log_cmd%%\"$apost\"*}\"; \
                git_log_lst_part=\"${git_log_cmd##*\"$apost\"}\"; \
                git_log_tre_part=\"${git_log_cmd%%\"$delim\"*}\"; \
                git_log_tre_part=\"${git_log_tre_part##*\"$apost\"}\"; \
                git_log_cmd_count=\"$git_log_fst_part$apost $git_log_tre_part$apost$git_log_lst_part\"; \
                col_length[\"1:1\"]=$(eval git \"${git_log_cmd_count// --color}\" | wc -L); \
                \
                \
                i=0; \
                while IFS=\"$delim\" read -r graph rest;do \
                  ((i++)); \
                  graph_line[$i]=\"$graph\"; \
                done < <(eval git \"${git_log_cmd/ --color}\" && echo); \
                \
                \
                i=0; \
                l=0; \
                while IFS= read -r line;do \
                  c=0; \
                  ((i++)); \
                  ((l++)); \
                  [[ $l -gt $n ]] && l=1; \
                  while IFS= read -d\"$delim\" -r col_content;do \
                    ((c++)); \
                    [[ $c -le $git_tre_col ]] && c_corr=-1 || c_corr=0; \
                    if [[ $c -eq 1 ]];then \
                      [[ \"${col_content/\\*}\" = \"$col_content\" ]] && [[ $l -eq 1 ]] && l=$n; \
                      count=$(wc -L <<< \"${graph_line[$i]}\"); \
                      whitespaces=$(seq -s\" \" $((${col_length[\"1:1\"]}-$count))|tr -d \"[:digit:]\"); \
                      col_content[$git_tre_col]=\"${col_content}$whitespaces\"; \
                    else \
                      col_content[$c+$c_corr]=\"$(printf \"%-${col_length[\"$l:$c\"]}s\" \"${col_content:-\"\"}\")\"; \
                    fi; \
                  done <<< \"$line$delim\"; \
                  for ((k=$c+1;k<=$i_max;k++));do \
                    [[ $k -le $git_tre_col ]] && c_corr=-1 || c_corr=0; \
                    col_content[$k+$c_corr]=\"$(printf \"%-${col_length[\"$l:$k\"]:-${col_length[\"${last[$k]:-1}:$k\"]:-0}}s\" \"\")\"; \
                  done; \
                  unset col_content[0]; \
                  echo -e \"${col_content[*]}\"; \
                  unset col_content[*]; \
                done < <(eval git \"$git_log_cmd\" && echo); \
                "' "git-tably"

where in tably

  • the first paragraph loads the delim(iter), YourLogAlias and YourLogAlias-col into shell variables
  • the second reads out the length for each column
  • the third counts the max. length of the tree
  • the fourth loads the tree into an array
  • the fifth organizes and print the table-like output

Results:

Enter image description here

Enter image description here

Enter image description here

or with new TreeColNumber on the fly

Enter image description here

AGAIN: Have fun to style your own clean table-like looking output to your needs.

EDIT 7: A more simple and fast table-like approach with almost Git-like speed but without a moving tree column (EDIT 6 has that feature).

How does it work?

  • define your Git log aliases in your .gitconfig as always

Then just call

    git table YourGitLogAlias

under any Git project path.

Your Git log alias only needs to follow one offical Git log rule:

  • in your format part, each commit placeholder that should lead to a column needs a width limit

       %<>(N,ltrunc,mtrunc,trunc)%CommitPlaceholder

where in %<>(N,ltrunc,mtrunc,trunc)

  • N sets the column width to N characters, with N >= 2
  • <> place it on the < - left, <> - middle or > - right
  • ltrunc,mtrunc,trunc truncate longer contents from the ltrunc - left, mtrunc - middle or trunc - right

and is optional for every last commit placeholder of a format line or every commit placeholder that always expands to the same length.

To recognize your format part in the snippet below, format:'' must be used and nowhere else in your Git log alias.

Example:

log --all --graph --color --pretty=format:'%Cblue%h %Cgreen%cr %Creset%s' -10

becomes

log --all --graph --color --pretty=format:'%Cblue%<(7,trunc)%h %Cgreen%<(15,trunc)%cr %Creset%s' -10

where

  • %<(7,trunc) is optional as every abbrev commit %h has length 7
  • %s is the last commit placeholder of the format line

Explanation:

The key point to count the tree characters is still the same approach as in the whole answer. The resulting tree length is then appended to the beginning of each format line in a special format. The advantage of this approach is that any Git log alias can also be used as normal.

Snippet: Add this bash snippet that only uses the external commands wc and of course git to your .gitconfig.

[color "decorate"]
    HEAD   = blink bold italic 196
    branch = 214
    tag    = bold 222

[alias]
    # change alias names to give them a more meaningfull name or add your own versions here
    tlog0 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) %C(bold green)%<(15,trunc)%ar%C(reset) %C(dim white)%<(22,trunc)%an%C(auto)%<(15,trunc)%d %C(white)%s%C(reset)' --all
    tlog1 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%<(31,trunc)%aD%C(reset) %C(bold green)(%<(22,trunc)%ar)%C(reset)%C(auto)%d%C(reset)%n%<(10,trunc)%x20%C(white)%s%C(reset)%n%<(10,trunc)%x20%C(dim white)%<(31,trunc)%an %ae%C(reset)'
    tlog2 = log --all --color --date='format:%Y-%m-%d %H:%M:%S' --decorate=short --graph --pretty=format:'%C(bold dim white)%ad%C(reset) %C(bold dim cyan)%<(20,trunc)%an%C(reset) %C(bold cyan)%h%C(reset)%C(auto)%d%C(reset)%n%C(dim white)%<(19,trunc)%ar%C(reset) %C(dim cyan)%<(20,trunc)%ae%C(reset) %C(bold white)Commit:%C(reset) %C(white)%s%C(reset)%n'

    table = !bash -c '" \
            alias=$1; \
            apost=$(echo -e \"\\u0027\"); \
            shift; \
            log_cmd=\"$(git config alias.$alias) $@\"; \
            [[ \"$log_cmd\" == \" $@\" ]] && { git $alias $@; exit; }; \
            \
            \
            log_fst_prt=\"${log_cmd%%\"format:$apost\"*}format:\"; \
            log_tre_prt=\"${log_cmd#\"$log_fst_prt$apost\"}\"; \
            log_tre_prt=\"${log_tre_prt%%$apost*}\"; \
            log_lst_prt=\"${log_cmd#\"$log_fst_prt$apost$log_tre_prt$apost\"}\"; \
            log_cmd_tre=\"${log_fst_prt}$apost%x20$apost${log_lst_prt}\"; \
            \
            \
            for opt_dis in \"--color\" \"--stat\";do \
              log_cmd_tre=\"${log_cmd_tre//\" $opt_dis\"}\"; \
            done; \
            tre_width=$(eval git \"${log_cmd_tre}\" | wc -L); \
            \
            \
            i=0; \
            log_tre_new=; \
            while IFS= read -r line;do \
              ((i++)); \
              if [[ $i -eq 1 ]];then \
                log_tre_new+=\"%<|($tre_width,trunc)%x20${line}\"; \
              else \
                log_tre_new+=\"%n%<|($(($tre_width-1)),trunc)%x20${line}\"; \
              fi; \
            done <<< \"$(echo -e \"${log_tre_prt//\\%n/\\\\n}\")\"; \
            [[ \"${log_tre_prt%\"%n\"}\" != \"$log_tre_prt\" ]] && log_tre_new+=\"%n\"; \
            \
            \
            log_cmd=\"${log_fst_prt}${apost}${log_tre_new}${apost}${log_lst_prt}\"; \
            eval git \"$log_cmd\"; \
            "' "git-table"

where the

  • first section loads your alias and your optional parameters into variables
  • second prepares your alias for counting
  • third disables some options for counting and counts the tree length
  • fourth adds the tree length in an appropriate format to any format line
  • fifth calls Git with your prepared table-like alias

enter image description here

enter image description here

enter image description here

Thanks for all your support and upvotes. Make some nice table-like logs ;)

Clarsach answered 28/4, 2020 at 18:10 Comment(9)
You should explain in your answer how these bash snippets will turn into fancy git log-like commands. One can figure out uses looking at the answer you linked, but answers should be self-containedCareer
You mean I should explain the git log cmd in detail? Or could you give me an example what you are missing, please.Clarsach
Note: The output of the awesome git log command is used by this snippet to receive the tablelike output on a terminal. So, the other way around as you mentioned ;)Clarsach
I figured you're not typing 20 lines of bash each time you need this. It makes sense to define this as a bash function or a git alias. Most readers won't bother trying to complete your code to make it easily usable. That's what I meant. If you just put the code in a random sh file on your path you can ignore me.Career
I see. Thanks for your advise. I will edit my answer and add such an alias. Normally I use files for such "long" commands as you mentioned. But to have both ways written here is much more comfortable, I agree.Clarsach
It's possible this is the longest Stackoverflow answer everBibelot
@Clarsach , Sir kindly please create a public Git project for this work, so that we can formalize it there, provide a guide in chapters and also discuss issues/improvements. Or would you like me to do it for you?Cartie
@DmitryMikushin Dmitry, thank you very much for your interest. Please, feel free to do that as long as it remains opensource. It would also be nice if you post the link to the repo here. Have fun ;)Clarsach
@Clarsach , thanks! Here is the repo: github.com/dmikushin/tablyCartie
G
62

Sourcetree is a really good one. It does print out a good looking and medium size history and branch graph: (the following is done on an experimental Git project just to see some branches). Supports Windows 7+ and Mac OS X 10.6+.

Example output in Sourcetree

Gerous answered 17/9, 2012 at 0:52 Comment(4)
It is also available in App Store, so update should work automatically.Craquelure
I love sourcetree's graph, but i'd rather use the command line, and sourcetree's defaults always mess with my repos.Antipyretic
SourceTree would insist you create Atlassian account (or use your google account and grant Atlassian some permissions to get your email and profile info), and after install on Mac (OS X El Capitan v 10.11.5) it fails on 'Clonning' step: "fatal: no submodule mapping found in .gitmodules for path '<path skipped>'" and also a strange warning: "templates not found /usr/local/git/share/git-core/templates". Very obscure messages, not so great.Thud
And then after uninstall don't forget to tidy up your Google security privileges you granted earlier: myaccount.google.com/security -> Connected apps & sites -> Apps connected to your account -> Manage AppsThud
T
62

I wrote a web tool for converting Git logs into pretty SVG graphs:

Bit-Booster - Offline Commit Graph Drawing Tool

Upload output from git log --pretty='%h|%p|%d' directly into the tool and then click on the "download graph.svg" link.

The tool is pure-client-side, and so none of your Git data is shared with my server. You can also save the HTML + JavaScript locally and run it using "file:///" URLs. It was verified on Chrome 48 and Firefox 43 on Ubuntu 12.04 (Precise Pangolin).

It generates HTML that can be posted directly into any page (including the blogspot blogging engine!). Take a look at some of the blog posts here:

http://bit-booster.blogspot.ca/

Here's a screenshot of a sample HTML file generated by the tool:

http://bit-booster.com/graph.html (the tool)

Townscape answered 25/1, 2016 at 8:17 Comment(2)
@Jay it appears the color reflects the indentation level of that particular branch, and that branches may move over to another column and therefore change color.sHusted
It would be great to make a CLI tool from this code, so we could just install it with npm/yarn.Flowerdeluce
W
61

git-forest is an excellent Perl script I've been using for more than a year and I hardly use the git log command directly any more.

These are some of the things I love about this script:

  • It uses Unicode characters to draw the lines in the graph giving a more continuous look to the graph lines.
  • You can combine --reverse with the graph output, which is not possible with the regular git log command.
  • It uses git log internally to grab the list of commits, so all options that you pass to git log can also be passed to this script as well.

I have an alias using git-forest as follows:

[alias]
tree = "forest --pretty=format:\"%C(red)%h %C(magenta)(%ar) %C(blue)%an %C(reset)%s\" --style=15 --reverse"

This is how the output looks like on a terminal:

Enter image description here

Welltodo answered 22/3, 2013 at 4:50 Comment(5)
@void.pointer - Yes it won't because git-forest is a perl script and has perl module dependencies. Running git under cygwin with the required perl modules installed might be the best alternative you could get if you really want this on Windows :)Welltodo
Wow, that repo has a lot of great tools. Thanks!Forevermore
Works perfectly fine @MinGW(MSYS) under Win$; install CPANM; then Git.pm; create an alias and you are ready to go.Bosch
the link you give is one version, the original is in a git repo as well, and then there is also this fork with many adaptations. Someone should probably examine these and merge all their corner-case fixes together.Impasse
Here: I ended up rebasing all those random forks onto each other, so that it becomes possible to view their diffs. I also integrated this into vim-flog for viewing and issuing git commands from within vim.Impasse
T
46

Based on a Graphviz script I found in an answer to a related question, I've hacked up a Ruby script that creates a summary view of a Git repository. It elides all linear history and just shows "interesting" commits, i.e. those with multiple parents, multiple children, or pointed to by a branch or tag. Here's a snippet of the graph it generates for jQuery:

jQuery sample

git-big-picture and BranchMaster are similar tools that try to show only the high-level structure of a graph, by only displaying how tags, branches, merges, etc. are related.

This question has some more options.

Timoteo answered 11/6, 2012 at 1:19 Comment(2)
I tried this, but couldn't get dot to work correctly with the output for our repo (42 branches, 175 tags, 42.000 commits)... Too bad... That's exactly what I was looking for!Ancona
@XavierNodet, if your repo is public and/or you have an error message etc., please file an issue on GitHub. Thanks!Timoteo
S
45

I've added three custom commands: git tree, git stree and git vtree. I'll go over them in that order.

[alias]
    tree = log --all --graph --decorate=short --color --format=format:'%C(bold blue)%h%C(reset) %C(auto)%d%C(reset)\n         %C(black)[%cr]%C(reset)  %x09%C(black)%an: %s %C(reset)'

Enter image description here


With git stree and git vtree, I've use Bash to help with the formatting.

[alias]
    logx = log --all --graph --decorate=short --color --format=format:'%C(bold blue)%h%C(reset)+%C(dim black)(%cr)%C(reset)+%C(auto)%d%C(reset)++\n+++       %C(bold black)%an%C(reset)%C(black): %s%C(reset)'
    stree = !bash -c '"                                                                             \
        while IFS=+ read -r hash time branch message; do                                            \
            timelength=$(echo \"$time\" | sed -r \"s:[^ ][[]([0-9]{1,2}(;[0-9]{1,2})?)?m::g\");     \
            timelength=$(echo \"16+${#time}-${#timelength}\" | bc);                                 \
            printf \"%${timelength}s    %s %s %s\n\" \"$time\" \"$hash\" \"$branch\" \"\";          \
        done < <(git logx && echo);"'

git_stree


[alias]
    logx = log --all --graph --decorate=short --color --format=format:'%C(bold blue)%h%C(reset)+%C(dim black)(%cr)%C(reset)+%C(auto)%d%C(reset)++\n+++       %C(bold black)%an%C(reset)%C(black): %s%C(reset)'
    vtree = !bash -c '"                                                                             \
        while IFS=+ read -r hash time branch message; do                                            \
            timelength=$(echo \"$time\" | sed -r \"s:[^ ][[]([0-9]{1,2}(;[0-9]{1,2})?)?m::g\");     \
            timelength=$(echo \"16+${#time}-${#timelength}\" | bc);                                 \
            printf \"%${timelength}s    %s %s %s\n\" \"$time\" \"$hash\" \"$branch\" \"$message\";  \
        done < <(git logx && echo);"'

git_vtree


This works with Git version 1.9a. The color value 'auto' is apparently making its debut in this release. It's a nice addition because branch names will get a different color. This makes it easier to distinguish between local and remote branches for instance.

Stebbins answered 18/3, 2014 at 14:0 Comment(6)
fatal: bad color value 'auto' for variable '--pretty format' :(Maniple
Turned out to be an old version of git. Yum has a pretty outdated version of Git in its repo. Compiled from source (1.9) and it works great. It's beautiful too! Thanks @gospes!Maniple
No go on OS X: sed: illegal option -- rLydell
@SlippD.Thompson: I'm using linux :). The -r is for extended regular expressions. Apparently the OSX version of sed doesn't have it. Perhaps you could update sed. Otherwise, you can just rewrite the sed command without extended regex.Stebbins
For the Mac OS X sed, use -E instead of -rWestmoreland
Is this resilient to commit messages containing +?Glossematics
T
39

Visual Studio Code has an amazing extension - Git Graph:

Git Graph

Thorny answered 1/12, 2020 at 9:21 Comment(1)
Oh, it's called Git Graph 😅, I always confuse it with Git Lens.Compulsion
S
37

For more detailed textual output, try:

git log --graph --date-order -C -M --pretty=format:"<%h> %ad [%an] %Cgreen%d%Creset %s" --all --date=short

You can add an alias in file $HOME/.gitconfig:

[alias]
    graph = log --graph --date-order -C -M --pretty=format:\"<%h> %ad [%an] %Cgreen%d%Creset %s\" --all --date=short
Sordino answered 2/6, 2011 at 8:52 Comment(0)
M
37

This is my take on this matter:

Screenshot:

Screenshot

Usage:

git hist - Show the history of current branch

git hist --all - Show the graph of all branches (including remotes)

git hist master devel - Show the relationship between two or more branches

git hist --branches - Show all local branches

Add --topo-order to sort commits topologically, instead of by date (default in this alias)

Benefits:

  • Looks just like plain --decorate, so with separate colors for different branch names
  • Adds committer email
  • Adds commit relative and absolute date
  • Sorts commits by date

Setup:

git config --global alias.hist "log --graph --date-order --date=short \
--pretty=format:'%C(auto)%h%d %C(reset)%s %C(bold blue)%ce %C(reset)%C(green)%cr (%cd)'"
Morgen answered 1/9, 2017 at 0:55 Comment(0)
H
36

It depends on what they looked like. I use gitx which makes pictures like this one:

Simple plot

You can compare git log --graph vs. gitk on a 24-way octopus merge (originally from http://clojure-log.n01se.net/date/2008-12-24.html):

24-way Git octopus merge. The original URL was https://static.mcmap.net/file/mcmap/ZG-Ab5ovKRY1ai2QX73/images/ns/kernel/gitk-octopus.png

Holna answered 29/6, 2009 at 15:37 Comment(5)
It's funny... I'd have sworn I heard you say "24-way octopus merge"!Ringler
Out of curiosity, has anyone attempted to extract GitX's (or another GUI git tool's) drawing routines into a standalone executable? If I'm not mistaken, getting Cocoa to draw into a vector PDF file wouldn't be difficult, and would satisfy the OP's need for high-Q printable imagery.Lydell
It was on S3 via skitch before they redid their thing. I wish I still had it. :(Holna
Just replaced it with a gitk version from lwn.net/images/ns/kernel/gitk-octopus.png, linked from clojure-log.n01se.net/date/2008-12-24.html. @Dustin: hope that's ok. It's not the same image, but it serves a similar purpose. From the screen shot, it looks like that's part of the linux kernel, so I guess you could find that commit and re-take an equivalent gitx screenshot....Merino
Isn't gitx for MacOS only? I could not find it for Linux.Crider
F
29

gitg: a gtk-based repository viewer. That's new, but interesting and useful.

I use it currently.

Fascist answered 3/4, 2011 at 6:39 Comment(1)
It seems to be a clone of GitX and a pretty good one at that. RecommendSheena
S
29

Although I sometimes use gitg, I always come back to the command line:

[alias]
    # Quick look at all repositories
    loggsa = log --color --date-order --graph --oneline --decorate --simplify-by-decoration --all
    # Quick look at active branch (or refs pointed)
    loggs  = log --color --date-order --graph --oneline --decorate --simplify-by-decoration
    # Extend look at all repo
    logga  = log --color --date-order --graph --oneline --decorate --all
    # Extend look at active branch
    logg   = log --color --date-order --graph --oneline --decorate
    # Look with the date
    logda  = log --color --date-order --date=local --graph --format=\"%C(auto)%h%Creset %C(blue bold)%ad%Creset %C(auto)%d%Creset %s\" --all
    logd   = log --color --date-order --date=local --graph --format=\"%C(auto)%h%Creset %C(blue bold)%ad%Creset %C(auto)%d%Creset %s\"
    # Look with the relative date
    logdra = log --color --date-order --graph --format=\"%C(auto)%h%Creset %C(blue bold)%ar%Creset %C(auto)%d%Creset %s\" --all
    logdr = log --color --date-order --graph --format=\"%C(auto)%h%Creset %C(blue bold)%ar%Creset %C(auto)%d%Creset %s\"

    loga   = log --graph --color --decorate --all

    # For repositories without subject body commits (Vim repository, git-svn clones)
    logt  = log --graph --color --format=\"%C(auto)%h %d %<|(100,trunc) %s\"
    logta  = log --graph --color --format=\"%C(auto)%h %d %<|(100,trunc) %s\" --all
    logtsa = log --graph --color --format=\"%C(auto)%h %d %<|(100,trunc) %s\" --all --simplify-by-decoration

As you can see, it is almost a keystroke saving aliases, based on:

  • --color: clear look
  • --graph: visualize parents
  • --date-order: most understandable look at repo
  • --decorate: who is who
  • --oneline: Many times all you need to know about a commit
  • --simplify-by-decoration: basic for a first look (just tags, relevant merges, branches)
  • --all: saving keystrokes with all alias with and without this option
  • --date=relative (%ar): Understand activity in repo (sometimes a branch is few commits near master but months ago from him)

See in recent version of Git (1.8.5 and above) you can benefit from %C(auto) in decorate placeholder %d.

From here all you need is a good understanding of gitrevisions to filter whatever you need (something like master..develop, where --simplify-merges could help with long term branches).

The power behind command line is the quickly configuration based on your needs (understand a repository isn't a unique key log configuration, so adding --numstat, or --raw, or --name-status is sometimes needed. Here git log and aliases are fast, powerful and (with time) the prettiest graph you can achieved. Even more, with output showed by default through a pager (say less) you can always search quickly inside results. Not convinced? You can always parse the result with projects like gitgraph.

Scent answered 5/4, 2014 at 0:32 Comment(1)
Very nice. Adding these to my config. But I recommend changing %Cred%d%Creset to be %C(auto)%d%Creset which will give different colors for remote or local branch namesDualistic
B
25

I suggest tig https://github.com/jonas/tig, a much much better command line tool for Git.

You can use Homebrew to install tig on macOS:

$ brew install tig
$ tig

Enter image description here

Beasley answered 4/1, 2018 at 7:3 Comment(3)
can we use tig in linux?Crustal
@alper, yes it's available on Linux (see installation instructions). Even Git for Windows bundle installs it.Amentia
The screenshot doesn't do tig justice, tig is outstanding at rendering git graphs compactly but this example just used a flat sequential history.Buffoon
N
19

Very slightly tweaking Slipp's awesome answer, you can use his aliases to log just one branch:

[alias]
lgBranch1 = log --graph --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(bold white)— %an%C(reset)%C(bold yellow)%d%C(reset)' --abbrev-commit --date=relative
lgBranch2 = log --graph --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(bold white)— %an%C(reset)' --abbrev-commit
lg = !"git lg1"

By leaving off the --all you can now do

git lgBranch1 <branch name>

or even

git lgBranch1 --all
Narayan answered 16/1, 2013 at 22:20 Comment(2)
what's the purpose of ! in lg = !"git lg1"?Legislate
I'm using your lgBranch2 approach but I changed the date format to --date=format-local:'%Y-%m-%d %H:%M:%S' and removed the newline. Thanks!Hubsher
H
15

Try gitk or gitk --all. However, it doesn't have a print/save img as a function.

Healthy answered 29/6, 2009 at 13:14 Comment(2)
gitk is efficient but not very beautiful.Cystoscope
The fact that it comes built-in makes it pleasant and hassle-free for me. Especially --all shows you all of the branches.Only
M
15

I have this git log alias in ~/.gitconfig to view the graph history:

[alias]
l = log --all --graph --pretty=format:'%C(auto)%h%C(auto)%d %s %C(dim white)(%aN, %ar)'

With this in place, git l will output something like:

enter image description here

In Git 2.12+ you can even customize the line colors of the graph using the log.graphColors configuration option.

As for the logs' format, it's similar to --oneline, with the addition of the author name (respecting .mailmap) and the relative author date. Note that the %C(auto) syntax, which tells Git to use the default colors for commit hash, etc. is supported in Git >= 1.8.3.

Machinery answered 5/10, 2016 at 15:46 Comment(1)
git log --graph --oneline just to make sure oneliner didn't get lostMccloud
C
14

A more branch-like colored version for shells.

e

Some other answers show graph trees nicely colored by external tools, partly with colored line information. This is my approach for shells, which is a combination with my first answer here for a table-like output (https://stackoverflow.com/a/61487052).

Features:

  • You can define all the tree colors
  • You can dye every column in the corresponding branch color
  • You can place the tree column at different positions
  • You can use various git log aliases
  • You can define a tree column number for each alias
  • You can pipe it into less -r for huge histories

How you use it:

Define your git log alias as in several answers shown, e.g., from Slipp D., albfan, kaoru, with the formatting instructions mentioned below and paste it into your .gitconfig file along with the code snippet. Call it from your project path, as usually with

git colored YourLogAlias or with

git colored YourLogAlias TreeColumnNumber to place the tree column on the fly.

Formatting Instructions:

Your git log alias must follow these format rules:

  • use a unique character as the column separator for every commit placeholder, i.e., ^
    ...format:'%h%cr%s' -->
    ...format:'^%h^%cr^%s'
  • color a whole column in one color or leave it blank to adopt the respective branch color
    ...format:'^%h^%cr^%s' -->
    ...format:'^%h^%cr^%C(white)%s%C(reset)' (hashes and time in branch color)
  • you have to specify the width of any column by %><(<N>[,ltrunc|mtrunc|trunc]) with one of the trunc options, but any last commit placeholder on a line can be used without it
    ...format:'^%h^%cr^%C(white)%s%C(reset)' -->
    ...format:'^%<(7,trunc)%h^%<(12,trunc)%cr^%C(white)%<(50,trunc)%s%C(reset)'
  • if you need extra decoration characters, place them directly around the commit placeholder, i.e., Commit:
    ...^%C(white)%<(50,trunc)%s%C(reset)... -->
    ...^%C(white)%<(50,trunc)Commit:%s%C(reset)...
  • if you use newlines %n put them before a column separator or at the end
    ...^%C(white)%<(50,trunc)Commit:%s%C(reset)' -->
    ...%n^%C(white)%<(50,trunc)Commit:%s%C(reset)%n'
  • if you use column colors like %C(white) above you need to add the --color option
    ...format:'^%<(7,trunc)%h... -->
    ...--color...format:'^%<(7,trunc)%h...
  • if you use the --stat option or similar, add a newline %n at the end
    ...--stat...format:'...' -->
    ...--stat...format:'...%n'

Miscellaneous:

  • for your git log aliases with non-empty newlines ...%n%CommitPlaceholder..., you can place the Git graph at every column n+1 only if all n-th columns of each line exist and use the same width

  • YourLogAlias-col has to be the name if you define a TreeColumnNumber in file .gitconfig for YourLogAlias

  • compared to the normal git log output, this one is slow, but nice

Examples:

git colored lgc1 e

git colored lgc2 e

git colored lgc3 e

git colored lgc4 e

Code-Snippet:

Add the following lines to your .gitconfig file

[alias]

# Define your unique column separator
delim      = ^

# Define your 'git log' aliases and optional tree column numbers
lgc1       = log --all --graph --color --pretty=format:'^%<(7,trunc)%h^%C(white)%<(15,trunc)- %ar -%C(reset)^%<(35,trunc)%s^%C(white)%an%C(reset)'

lgc2       = log --all --graph --color --pretty=format:'%D^%<(7,trunc)%h^%<(35,trunc)%s^%C(white)%<(20,trunc)%an%C(reset)^%C(white) (%ar)%C(reset)'
lgc2-col   = 2

lgc3       = log --all --graph --color --pretty=format:'%<(7,trunc)%h%d^%<(11,trunc)%cs%C(reset)^%s%n^%C(white)%<(11,trunc)%cr%C(reset)^%C(white)%<(25,trunc)From %an%C(reset)^%C(white)%ae%C(reset)%n'
lgc3-col   = 2

lgc4       = log --all --graph --color --pretty=format:'%h^%C(white)%<(25,trunc)%an%C(reset)^%C(white)%<(31,trunc)%aD%C(reset)^%s%n^%C(dim white)%<(25,trunc)%ae%C(reset)^%>(31,trunc)%D%C(reset)%n'
lgc4-col   = 3

# Define your whitespace seperated tree color list
color-list = "1;38;5;222 1;38;5;69 1;38;5;250 1;38;5;70 1;31 1;38;5;93 1;33 2;38;5;11 1;38;5;48 1;35 1;32 1;38;5;111 1;38;5;160 1;38;5;130 1;36 38;5;21"

Add the Bash snippet to your .gitconfig file too

# This is the Bash snippet which does all the magic
colored = !bash -c '" \
  \
  \
  declare -A col_length col_colored; \
  apost=$(echo -e \"\\u0027\"); \
  delim=$(git config alias.delim); \
  git_log_cmd=$(git config alias.$1); \
  graph_col=${2:-$(git config alias.$1-col)}; \
  color_list=( $(git config alias.color-list) ); \
  [[ -z \"$graph_col\" ]] && graph_col=1; \
  [[ -z \"$git_log_cmd\" ]] && { git $1;exit; }; \
  \
  \
  i=0; \
  n=0; \
  while IFS= read -r line; do \
    ((n++)); \
    while read -d\"$delim\" -r col_info;do \
      ((i++)); \
      [[ -z \"$col_info\" ]] && col_length[\"$n:$i\"]=${col_length[\"${last[$i]:-1}:$i\"]} && ((i--)) && continue; \
      [[ $i -gt ${i_max:-0} ]] && i_max=$i; \
      [[ \"${col_info:1:1}\" = \"C\" ]] && col_colored[\"$n:$i\"]=1; \
      col_length[\"$n:$i\"]=$(grep -Eo \"\\([0-9]*,[lm]*trunc\\)\" <<< \"$col_info\" | grep -Eo \"[0-9]*\" | head -n 1); \
      [[ -n \"${col_length[\"$n:$i\"]}\" ]] && last[$i]=$n; \
      chars_extra=$(grep -Eo \"\\trunc\\).*\" <<< \"$col_info\"); \
      chars_extra=${chars_extra#trunc)}; \
      chars_begin=${chars_extra%%\\%*}; \
      chars_extra=${chars_extra%$apost*}; \
      chars_extra=${chars_extra#*\\%}; \
      case \" ad aD ae aE ai aI al aL an aN ar as at b B cd cD ce cE ci cI cl cL cn cN cr \
              cs ct d D e f G? gd gD ge gE GF GG GK gn gN GP gs GS GT h H N p P s S t T \" in \
        *\" ${chars_extra:0:2} \"*) \
          chars_extra=${chars_extra:2}; \
          chars_after=${chars_extra%%\\%*}; \
          ;; \
        *\" ${chars_extra:0:1} \"*) \
          chars_extra=${chars_extra:1}; \
          chars_after=${chars_extra%%\\%*}; \
          ;; \
        *) \
          echo \"No Placeholder found. Probably no table-like output.\"; \
          continue; \
          ;; \
      esac; \
      if [[ -n \"$chars_begin$chars_after\" ]];then \
        len_extra=$(echo \"$chars_begin$chars_after\" | wc -m); \
        col_length[\"$n:$i\"]=$((${col_length[\"$n:$i\"]}+$len_extra-1)); \
      fi; \
    done <<< \"${line#*=format:}$delim\"; \
    i=1; \
  done <<< \"$(echo -e \"${git_log_cmd//\\%n/\\\\n}\")\"; \
  \
  \
  git_log_fst_part=\"${git_log_cmd%%\"$apost\"*}\"; \
  git_log_lst_part=\"${git_log_cmd##*\"$apost\"}\"; \
  git_log_tre_part=\"${git_log_cmd%%\"$delim\"*}\"; \
  git_log_tre_part=\"${git_log_tre_part##*\"$apost\"}\"; \
  git_log_cmd_count=\"$git_log_fst_part$apost $git_log_tre_part$apost$git_log_lst_part\"; \
  col_length[\"1:1\"]=$(eval git \"${git_log_cmd_count// --color}\" | wc -L); \
  \
  \
  i=0; \
  while IFS=\"$delim\" read -r graph rest;do \
    ((i++)); \
    graph_line[$i]=\"$graph\"; \
  done < <(eval git \"${git_log_cmd/ --color}\" && echo); \
  \
  \
  i=0; \
  l=0; \
  msg_err=; \
  color_list_ind=-1; \
  color_list_num=${#color_list[*]}; \
  color_repeat_ind=1; \
  if [[ $color_list_num -eq 0 ]];then \
    echo \"No tree colors specified via color-list under section [alias] in your .gitconfig\"; \
    echo \"Therefore collecting available Git colors, which may take a while ...\"; \
    while read -d\"[\" -r char;do \
      color=$(sed -nl99 \"l\" <<< \"$char\"); \
      case \"$color\" in \
        *\"m\"*) \
          color=${color%%m*}; \
          ;; \
        *) \
          continue; \
          ;; \
      esac; \
      case \" $color_list \" in \
        *\" $color \"*) \
          continue; \
          ;; \
        *) \
          color_list=\"$color_list$color \"; \
          ;; \
      esac; \
    done <<< \"$(git log --all --color --graph --pretty=format:)\"; \
    echo -e \"Temporary used color-list = \\\"${color_list% }\\\"\\n\"; \
    color_list=( ${color_list% } ); \
    color_list_num=${#color_list[*]}; \
  fi; \
  while IFS= read -r line;do \
    ((i++)); \
    j=-1; \
    case_off=; \
    graph_colored=; \
    graph_line_last=\"${graph_line[$i-1]}\"; \
    graph_line=\"${graph_line[$i]}\"; \
    graph_line_next=\"${graph_line[$i+1]}\"; \
    while IFS= read -r char;do \
      ((j++)); \
      case \"$case_off$char\" in \
        [^\\ \\_\\*\\/\\|\\\\]|\"case_off\"*) \
          graph_colored=\"${graph_colored}\\033[${point_color}m$char\\033[0m\"; \
          case_off=\"case_off\"; \
          ;; \
        \" \") \
          graph_colored=\"${graph_colored}$char\"; \
          case \"$char_last\" in \
            \" \") \
              unset color_ind[$j]; \
              ;; \
          esac; \
          ;; \
        \"*\") \
          case \"${graph_line_last:$j:1}\" in \
            \"*\") \
              :; \
              ;; \
            \"|\") \
              case \"${graph_line_last:$(($j-1)):1}\" in \
                \"\\\\\") \
                  color_ind[$j]=${color_ind_last[$j-1]:-${color_ind[$j-1]}}; \
                  ;; \
                *) \
                  :; \
                  ;; \
              esac; \
              ;; \
            \" \") \
              case \"${graph_line_last:$(($j-1)):1}\" in \
                \"\\\\\") \
                  color_ind[$j]=${color_ind_last[$j-1]:-${color_ind[$j-1]}}; \
                  ;; \
                \"/\") \
                  case \"${graph_line_last:$(($j+1)):1}\" in \
                    \"/\") \
                      color_ind[$j]=${color_ind[$j+1]}; \
                      ;; \
                    \" \") \
                      new_col_ind=${#color[*]}; \
                      while true;do \
                        ((color_list_ind++)); \
                        [[ $color_list_ind -ge $color_list_num ]] && color_list_ind=$color_repeat_ind; \
                        [[ $color_list_ind -ge $color_list_num ]] && break; \
                        new_color=${color_list[$color_list_ind]}; \
                        case \"$new_color\" in \
                          \"\"|[\\ ]*) \
                            continue; \
                            ;; \
                          \"${color[${color_ind[$j-1]}]}\") \
                            [[ $(($color_list_num-$color_repeat_ind)) -gt 1 ]] && continue; \
                            ;;& \
                          *) \
                            color[$new_col_ind]=$new_color; \
                            color_ind[$j]=$new_col_ind; \
                            last_new_colored_line=$i; \
                            break; \
                            ;; \
                        esac 2>/dev/null; \
                      done; \
                      ;; \
                    *) \
                      [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                      ;; \
                  esac; \
                  ;; \
                \" \") \
                  case \"${graph_line_last:$(($j+1)):1}\" in \
                    \"/\") \
                      color_ind[$j]=${color_ind[$j+1]}; \
                      ;; \
                    *) \
                      new_col_ind=${#color[*]}; \
                      while true;do \
                        ((color_list_ind++)); \
                        [[ $color_list_ind -ge $color_list_num ]] && color_list_ind=$color_repeat_ind; \
                        [[ $color_list_ind -ge $color_list_num ]] && break; \
                        new_color=${color_list[$color_list_ind]}; \
                        case \"$new_color\" in \
                          \"\"|[\\ ]*) \
                            continue; \
                            ;; \
                          \"${color[${color_ind[$j-1]}]}\") \
                            [[ $(($color_list_num-$color_repeat_ind)) -gt 1 ]] && continue; \
                            ;;& \
                          *) \
                            color[$new_col_ind]=$new_color; \
                            color_ind[$j]=$new_col_ind; \
                            last_new_colored_line=$i; \
                            break; \
                            ;; \
                        esac 2>/dev/null; \
                      done; \
                      ;; \
                  esac; \
                  ;; \
                *) \
                  [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                  ;; \
              esac; \
              ;; \
            \"\"|[^\\ \\_\\*\\/\\|\\\\]) \
              new_col_ind=${#color[*]}; \
              while true;do \
                ((color_list_ind++)); \
                [[ $color_list_ind -ge $color_list_num ]] && color_list_ind=$color_repeat_ind; \
                [[ $color_list_ind -ge $color_list_num ]] && break; \
                new_color=${color_list[$color_list_ind]}; \
                case \"$new_color\" in \
                  \"\"|[\\ ]*) \
                    continue; \
                    ;; \
                  \"${color[${color_ind[$j-1]}]}\") \
                    [[ $(($color_list_num-$color_repeat_ind)) -gt 1 ]] && continue; \
                    ;;& \
                  *) \
                    color[$new_col_ind]=$new_color; \
                    color_ind[$j]=$new_col_ind; \
                    last_new_colored_line=$i; \
                    break; \
                    ;; \
                esac 2>/dev/null; \
              done; \
              ;; \
            *) \
              [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
              ;; \
          esac; \
          graph_colored=\"${graph_colored}\\033[${color[${color_ind[$j]}]}m$char\\033[0m\"; \
          point_color=${color[${color_ind[$j]}]}; \
          ;; \
        \"|\") \
          case \"${graph_line_last:$j:1}\" in \
            \" \") \
              case \"${graph_line_last:$(($j-1)):1}\" in \
                \"/\") \
                  color_ind[$j]=${color_ind[$j+1]}; \
                  ;; \
                \"\\\\\") \
                  color_ind[$j]=${color_ind_last[$j-1]:-${color_ind[$j-1]}}; \
                  ;; \
                *) \
                  case \"${graph_line_last:$(($j+1)):1}\" in \
                    \"/\") \
                      color_ind[$j]=${color_ind[$j+1]}; \
                      ;; \
                    *) \
                      [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                      ;; \
                  esac; \
                  ;; \
              esac; \
              ;; \
            \"|\") \
              case \"${graph_line_last:$(($j-1)):1}\" in \
                \"\\\\\") \
                  case \"${graph_line:$(($j+1)):1}\" in \
                    \"\\\\\") \
                       :; \
                       ;; \
                    \" \") \
                      color_ind[$j]=${color_ind_last[$j-1]}; \
                      ;; \
                    *) \
                      [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                      ;; \
                  esac; \
                  ;; \
                *) \
                  :; \
                  ;; \
              esac; \
              ;; \
            \"*\") \
              case \"${graph_line:$(($j-1)):1}\" in \
                \"/\") \
                  if [[ $last_new_colored_line -eq $(($i-1)) ]];then \
                    new_col_ind=${#color[*]}; \
                    while true;do \
                      ((color_list_ind++)); \
                      [[ $color_list_ind -ge $color_list_num ]] && color_list_ind=$color_repeat_ind; \
                      [[ $color_list_ind -ge $color_list_num ]] && break; \
                      new_color=${color_list[$color_list_ind]}; \
                      case \"$new_color\" in \
                        \"\"|[\\ ]*) \
                          continue; \
                          ;; \
                        \"${color[${color_ind[$j-1]}]}\") \
                          [[ $(($color_list_num-$color_repeat_ind)) -gt 1 ]] && continue; \
                          ;;& \
                        *) \
                          color[$new_col_ind]=$new_color; \
                          color_ind[$j]=$new_col_ind; \
                          break; \
                          ;; \
                      esac 2>/dev/null; \
                    done; \
                  else \
                    color_ind[$j]=${color_ind_last[$j]}; \
                  fi; \
                  ;; \
                *) \
                  :; \
                  ;; \
              esac; \
              ;; \
            \"/\") \
              color_ind[$j]=${color_ind[$j]}; \
              ;; \
            *) \
              [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
              ;; \
          esac; \
          graph_colored=\"${graph_colored}\\033[${color[${color_ind[$j]}]}m$char\\033[0m\"; \
          ;; \
        \"/\") \
          case \"${graph_line_last:$(($j)):1}\" in \
            \"|\") \
              case \"${graph_line_last:$(($j+1)):1}\" in \
                \"/\") \
                  case \"${graph_line_next:$j:1}\" in \
                    \"|\") \
                      color_ind[$j]=${color_ind[$j+1]}; \
                      ;; \
                    \" \") \
                      color_ind[$j]=${color_ind[$j]}; \
                      ;; \
                    *) \
                      [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                      ;; \
                  esac; \
                  ;; \
                *) \
                  color_ind[$j]=${color_ind[$j]}; \
                  ;; \
              esac; \
              ;; \
            *) \
              case \"${graph_line_last:$(($j+2)):1}\" in \
                \"/\"|\"_\") \
                  color_ind[$j]=${color_ind[$j+2]}; \
                  ;; \
                *) \
                  case \"${graph_line_last:$(($j+1)):1}\" in \
                    \"/\"|\"_\"|\"|\") \
                      color_ind[$j]=${color_ind[$j+1]}; \
                      ;; \
                    \"*\") \
                      case \"${graph_line:$(($j+1)):1}\" in \
                        \"|\") \
                          if [[ $last_new_colored_line -eq $(($i-1)) ]];then \
                            color_ind[$j]=${color_ind_last[$j+1]}; \
                          else \
                            new_col_ind=${#color[*]}; \
                            while true;do \
                              ((color_list_ind++)); \
                              [[ $color_list_ind -ge $color_list_num ]] && color_list_ind=$color_repeat_ind; \
                              [[ $color_list_ind -ge $color_list_num ]] && break; \
                              new_color=${color_list[$color_list_ind]}; \
                              case \"$new_color\" in \
                                \"\"|[\\ ]*) \
                                  continue; \
                                  ;; \
                                \"${color[${color_ind[$j-1]}]}\") \
                                  [[ $(($color_list_num-$color_repeat_ind)) -gt 1 ]] && continue; \
                                  ;;& \
                                *) \
                                  color[$new_col_ind]=$new_color; \
                                  color_ind[$j]=$new_col_ind; \
                                  break; \
                                  ;; \
                              esac 2>/dev/null; \
                            done; \
                          fi; \
                          ;; \
                        *) \
                          color_ind[$j]=${color_ind_last[$j+1]}; \
                          ;; \
                      esac; \
                      ;; \
                    *) \
                      case \"${graph_line_last:$j:1}\" in \
                        \"\\\\\") \
                          :; \
                          ;; \
                        \" \") \
                          case \"${graph_line_last:$(($j+1)):1}\" in \
                            \"*\") \
                              color_ind[$j]=${color_ind[$j+1]}; \
                              ;; \
                            *) \
                              [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                              ;; \
                          esac; \
                          ;; \
                        *) \
                          [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                          ;; \
                      esac; \
                      ;; \
                  esac; \
                  ;; \
              esac; \
              ;; \
          esac; \
          graph_colored=\"${graph_colored}\\033[${color[${color_ind[$j]}]}m$char\\033[0m\"; \
          ;; \
        \"\\\\\") \
          case \"${graph_line_last:$(($j-1)):1}\" in \
            \"|\"|\"\\\\\") \
              color_ind[$j]=${color_ind_last[$j-1]:-${color_ind[$j-1]}}; \
              ;; \
            \"*\") \
              new_col_ind=${#color[*]}; \
              while true;do \
                ((color_list_ind++)); \
                [[ $color_list_ind -ge $color_list_num ]] && color_list_ind=$color_repeat_ind; \
                [[ $color_list_ind -ge $color_list_num ]] && break; \
                new_color=${color_list[$color_list_ind]}; \
                case \"$new_color\" in \
                  \"\"|[\\ ]*) \
                    continue; \
                    ;; \
                  \"${color[${color_ind[$j-1]}]}\") \
                    [[ $(($color_list_num-$color_repeat_ind)) -gt 1 ]] && continue; \
                    ;;& \
                  *) \
                    color[$new_col_ind]=$new_color; \
                    color_ind[$j]=$new_col_ind; \
                    break; \
                    ;; \
                esac 2>/dev/null; \
              done; \
              ;; \
            \" \") \
              case \"${graph_line_last:$(($j-2)):1}\" in \
                \"\\\\\"|\"_\") \
                  color_ind[$j]=${color_ind_last[$j-2]:-${color_ind[$j-2]}}; \
                  ;; \
                *) \
                  case \"${graph_line_last:$j:1}\" in \
                    \"|\") \
                      color_ind[$j]=${color_ind_last[$j]:-${color_ind[$j]}}; \
                      ;; \
                    *) \
                      [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                      ;; \
                  esac; \
                  ;; \
              esac; \
              ;; \
            *) \
              [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
              ;; \
          esac; \
          graph_colored=\"${graph_colored}\\033[${color[${color_ind[$j]}]}m$char$char\\033[0m\"; \
          ;; \
        \"_\") \
          case \"${graph_line:$(($j-2)):1}\" in \
            \"\\\\\"|\"_\") \
              color_ind[$j]=${color_ind[$j-2]}; \
              ;; \
            \" \"|\"/\") \
              k=2; \
              while [[ \"${graph_line:$(($j+$k)):1}\" = \"_\" ]];do \
                k=$(($k+2)); \
              done; \
              case \"${graph_line:$(($j+$k)):1}\" in \
                \"/\") \
                  case \"${graph_line_last:$(($j+$k+1)):1}\" in \
                    \"*\") \
                      color_ind[$j]=${color_ind[$j+$k+1]}; \
                      ;; \
                    \" \") \
                      case \"${graph_line_last:$(($j+$k)):1}\" in \
                        \"\\\\\") \
                          color_ind[$j]=${color_ind[$j+$k]}; \
                          ;; \
                        *) \
                          [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                          ;; \
                      esac; \
                      ;; \
                    \"|\") \
                      case \"${graph_line:$(($j+$k+1)):1}\" in \
                        \"|\") \
                          color_ind[$j]=${color_ind[$j+$k+2]}; \
                          ;; \
                        \" \") \
                          color_ind[$j]=${color_ind[$j+$k+1]}; \
                          ;; \
                        *) \
                          [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                          ;; \
                      esac; \
                      ;; \
                    *) \
                      [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                      ;; \
                  esac; \
                  ;; \
                *) \
                  [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
                  ;; \
              esac; \
              ;; \
            *) \
              [[ -n \"$msg_err\" ]] && echo -e \"Unknown case in graph_line $i: $graph_line for char $char at position $j\nwith the former graph_line $(($i-1)): $graph_line_last\"; \
              ;; \
          esac; \
          graph_colored=\"${graph_colored}\\033[${color[${color_ind[$j]}]}m$char\\033[0m\"; \
          ;; \
      esac; \
      char_last=$char; \
    done <<< \"$(grep -Eo \".\" <<< \"${graph_line%%$delim*}\")\"; \
    for key in ${!color_ind[*]};do \
      color_ind_last[$key]=${color_ind[$key]}; \
    done; \
    \
    \
    c=0; \
    ((l++)); \
    [[ $l -gt $n ]] && l=1; \
    while IFS= read -d\"$delim\" -r col_content;do \
      ((c++)); \
      [[ $c -le $graph_col ]] && c_corr=-1 || c_corr=0; \
      if [[ $c -eq 1 ]];then \
        [[ \"${col_content/\\*}\" = \"$col_content\" ]] && [[ $l -eq 1 ]] && l=$n; \
        whitespaces=$(seq -s\" \" $((${col_length[\"1:1\"]}-$j))|tr -d \"[:digit:]\"); \
        col_content[$graph_col]=\"${graph_colored}$whitespaces\"; \
      elif [[ ${col_colored[\"$l:$c\"]:-0} -eq 0 ]];then \
        col_content[$c+$c_corr]=\"\\033[${point_color:-0}m$(printf \"%-${col_length[\"$l:$c\"]}s\" \"${col_content:-\"\"}\")\\033[0m\"; \
      else \
        col_content[$c+$c_corr]=\"$(printf \"%-${col_length[\"$l:$c\"]}s\" \"${col_content:-\"\"}\")\"; \
      fi; \
    done <<< \"$line$delim\"; \
    for ((k=$c+1;k<=$i_max;k++));do \
      [[ $k -le $graph_col ]] && c_corr=-1 || c_corr=0; \
      col_content[$k+$c_corr]=\"$(printf \"%-${col_length[\"$l:$k\"]:-${col_length[\"${last[$k]:-1}:$k\"]:-0}}s\" \"\")\"; \
    done; \
    unset col_content[0]; \
    echo -e \"${col_content[*]}\"; \
    unset col_content[*]; \
  done < <(git $1 && echo); \
  "' "git-colored"

Explanations:

  • The first paragraph loads the delim(iter), color-list and YourLogAlias into shell variables
  • The second reads out the length for every column
  • The third counts the maximum length of the tree
  • The fourth loads the tree into an array
  • The fifth colors the tree, based on case analysis
  • The sixth colorizes non-tree columns and print the table-like output

The biggest part is the case analysis for setting the tree colors. The other parts are explained in my linked answer for table-like shell outputs.

Please show your favorite formatted log alias in the comments, as mine are only examples.

Clarsach answered 4/8, 2020 at 18:35 Comment(2)
Thank you very much for your answer. I see that in all your example the commit (the * character) is also colorized (in 99% percents of what I saw in Google it is always white). Can you please explain how you did it? I have my own git log alias and I just what to add commit colorization.Chekhov
At time of writing my answer, there was not such an option for colorization you ask for. You can try format your git log cmd as mentioned so that it fits in and can be used by the code above. Within this every tree line is analysed and colored due to the users settings. This is mainly done in the 5. paragraph. Infos about colorization techniques you can find under EDIT 4 in my first answer. Follow the link there. I think there are different ways how to colorize the asterix than mine but it can be quiet a lot of work, depends what exactly you want to reach. Thanks for voting up.Clarsach
I
13

GitGraph

It generates a PNG or SVG representation of your Git repository's commit history.

Infantryman answered 1/4, 2013 at 14:3 Comment(0)
E
12
git -c core.pager='less -SRF' log --oneline --graph --decorate

This is my terminal variation, similar to many answers here. I like to adjust the flags passed to less to prevent word wrapping.

example output

I set this to an alias for quick access since the command is a bit cumbersome.

Eddins answered 6/1, 2016 at 2:53 Comment(0)
B
9

Try ditaa. It can transform any ASCII diagram into an image. Although it was not designed with Git branches in mind, I was impressed by the results.

Source (txt file):

        +--------+
        | hotfix |
        +---+----+
            |
--*<---*<---*
       ^
       |
       \--*<---*
               |
           +---+----+
           | master |
           +--------+

Command:

java -jar ditaa0_9.jar ascii-graph.txt

Result:

Enter image description here

It also supports background colors, dashed lines, different shapes and more. See the examples.

Bootee answered 25/3, 2016 at 19:37 Comment(1)
In a similar vein, casual-effects.com/markdeep is very powerful to spruce up hand-arranged ascii art diagrams.Buffoon
O
9

Some aliases in file ~/.oh-my-zsh/plugins/git/git.plugin.zsh:

gke='\gitk --all $(git log -g --pretty=%h)'
glg='git log --stat'
glgg='git log --graph'
glgga='git log --graph --decorate --all'
glgm='git log --graph --max-count=10'
glgp='git log --stat -p'
glo='git log --oneline --decorate'
glog='git log --oneline --decorate --graph'
gloga='git log --oneline --decorate --graph --all'
glol='git log --graph --pretty='\''%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'\'' --abbrev-commit'
glola='git log --graph --pretty='\''%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'\'' --abbrev-commit --all'
Overlive answered 18/6, 2018 at 2:45 Comment(1)
gloga is the one.Reflect
S
9

If your repository sits on GitLab, you can use its graph representation as that is rendered as an SVG in your browser.

Enter image description here

Strigil answered 5/2, 2019 at 10:49 Comment(2)
Wow such a lazy sneaky copy, very convenient to keep users familiar with gitlab. Should add it in a gitlab-ci job to print into README.mdContra
Should be higher up. It is hands-on and comes in a much nicer design than any command prompt can output. But of course, it is bound to GitLab...Bellebelleek
P
8

Here my alias for the community: git ls. With git ls you can view the graph and each commit covers just one line. Everything coloured and with useful information. You can also check the commit history on other branches:

git config --global alias.ls '!f() { git log $1 --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cgreen\\ [%ae,%ar]" --decorate --graph; }; f'

Usage:

# shows commits graph on the current branch
git ls

# shows commits graph on the develop branch
git ls develop 

Here is the graph view: enter image description here

Pentacle answered 20/12, 2021 at 9:15 Comment(1)
on my side it looks different. I'm missing the non-linear graph structure that you are showing here. using git version 2.17.1 (Ubuntu 18.04)Stupefaction
M
7

There's a funky Git commit graph as one of the demos of the Raphael web graphics library.

The demo is static, but it should be easy enough to take the code and swap out their static data for a live set of data -- I think it's just Git commit data in JSON format.

The demo is here: http://dmitrybaranovskiy.github.io/raphael/github/impact.html

Magaretmagas answered 2/6, 2011 at 9:8 Comment(3)
That's the same graph code used on GitHub's impact graphs, no? (e.g. github.com/DmitryBaranovskiy/raphael/graphs/impact)Lydell
@Sven: Thank you for pointing that out. I have corrected the broken links for you, although please bear in mind that this answer is five years old, and thus there may be a better solution more recently.Magaretmagas
@SlippD.Thompson this code is now at github.com/DmitryBaranovskiy/raphaeljs.com/tree/master/githubSynodic
U
5

For OS X users, I've taken the @gospes example and slightly modified it for gsed (gnu-sed installed via Homebrew) and adjusted the colors (to work with a black background, not sure how the original example could possibly render the way it does in the example since it specifies black text on a terminal with a black background).

[alias]
    # tree, vtree, stree support
    logx = log --all --graph --decorate=short --color --format=format:'%C(bold blue)%h%C(reset)+%C(bold black)(%cr)%C(reset)+%C(auto)%d%C(reset)++\n+++       %C(bold black)%an%C(reset)%C(bold black): %s%C(reset)'
    tree = log --all --graph --decorate=short --color --format=format:'%C(bold blue)%h%C(reset) %C(auto)%d%C(reset)\n         %C(bold black)[%cr]%C(reset)  %x09%C(bold black)%an: %s %C(reset)'
    stree = !bash -c '" \
    while IFS=+ read -r hash time branch message; do \
        timelength=$(echo \"$time\" | gsed -r \"s:[^ ][[]([0-9]{1,2}(;[0-9]{1,2})?)?m::g\"); \
        timelength=$(echo \"16+${#time}-${#timelength}\" | bc); \
        printf \"%${timelength}s    %s %s %s\n\" \"$time\" \"$hash\" \"$branch\" \"\"; \
    done < <(git logx && echo);"' | less -r
    vtree = !bash -c '" \
    while IFS=+ read -r hash time branch message; do \
      timelength=$(echo \"$time\" | gsed -r \"s:[^ ][[]([0-9]{1,2}(;[0-9]{1,2})?)?m::g\"); \
      timelength=$(echo \"16+${#time}-${#timelength}\" | bc); \
      printf \"%${timelength}s    %s %s %s\n\" \"$time\" \"$hash\" \"$branch\" \"$message\"; \
    done < <(git logx && echo);"' | less -r

The key for OS X is to first install GNU sed (which has the -r option). It is most easily done with Homebrew, which will not overwrite the system-installed sed, but will instead install GNU sed as "gsed". I hope this helps @SlippD.Thompson who commented above about OS X not working.

Uri answered 5/10, 2014 at 0:48 Comment(0)
B
5

If you are using macOS, you can try GitUp:

Enter image description here

  • x-axis: Branches
  • y-axis: time
Betook answered 11/10, 2020 at 8:26 Comment(1)
This is my favorite tool for visualizing Git graphs. I wish there was something similar that I could use when I'm working on Windows or Linux.Stadtholder
F
4

I don't know about a direct tool, but maybe you can hack a script to export the data into dot format and render it with Graphviz.

Flying answered 29/6, 2009 at 10:57 Comment(2)
Try this one github.com/gugod/bin/blob/master/git-graphviz . I didn't have all the dependencies in my corporate environment, so changing those io commands to simple perl `git log [...]` commands worked for me.Pascal
If you're on a mac and you want to try this script, you can grab perl with brew install perl dot and then cpan common::sense IO::all to get the dependencies. Then, just pipe the output to an appropriate command, like git-graphviz | dot -Tpng -o repo.png. However, the output isn't much different than git-big-picture.Tamarin
S
4

Looking at this conversation, I tried to use my favorite git-cola & git-dag.

Running View->DAG... from git-cola and replacing Log: master -- with --all shows a pretty graph with all branches.

Saltzman answered 22/3, 2018 at 1:50 Comment(0)
P
3

In addition to the answer of 'Slipp D. Thompson', I propose you to add this alias to have the same decoration, but in a single line by commit:

git config --global alias.tre "log --graph --decorate --pretty=oneline --abbrev-commit --all --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)'"
Pokeweed answered 6/3, 2018 at 13:34 Comment(0)
G
3

I find git-sim visualization clear.

Although the project goal is to simulate and visualize git commands you can use it to visualize commits as well:

git sim -n 10 log --all

git sim

Greaten answered 7/3 at 14:23 Comment(0)
O
0

An improvement from 'Slipp D. Thompson' answer:

Most of us don't need "stash record" in our git log, which makes it redundant. Instead of doing --all and then trying to filter out the stashes, we only need branches, remotes and tags:

git log --graph --abbrev-commit --decorate --format=format:\'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)\' --branches --remotes --tags

Or alias

[alias]
lg = log --graph --abbrev-commit --decorate --format=format:\'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)\' --branches --remotes --tags
Outnumber answered 12/6, 2023 at 5:44 Comment(0)
N
0

I have a perl script that prints pretty git graphs to the console that even make sense! It uses the normal git command line tool to get the log data so it doesn't rely on any non-standard perl plugins (in fact, the only plugins it uses are some standard ones for date handling)

You can find it here - http://knockknock.org.uk/git-graph

'git-graph -h' will print option details

Nellynelms answered 24/10, 2023 at 13:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.