漂亮的Git分支图

我看到一些书籍和文章有一些非常漂亮的Git分支和提交图表。我如何制作高质量的Git历史可打印图像?

1065319 次浏览

我不知道直接工具,但也许你可以破解一个脚本将数据导出为点格式并用Graphviz渲染。

尝试gitkgitk --all。但是,它没有打印/保存img作为函数。

这取决于它们的样子。我使用gitx来制作这样的图片:

简单图

您可以在24路章鱼合并中比较git log --graphgitk(最初来自http://clojure-log.n01se.net/date/2008-12-24.html):

24路Git章鱼合并。原始URLhttp://lwn.net/images/ns/kernel/gitk-octopus.png

对于文本输出,您可以尝试:

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

或:

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

或者:这是Graphviz别名用于绘制DAG图。

我个人使用#0gitk --all#2

gitg:基于gtk的存储库查看器。这是新的,但有趣且有用。

我现在用它。

有关更详细的文本输出,请尝试:

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

您可以在文件$HOME/. Gitconfig是否必填中添加别名:

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

有一个时髦的Git提交图作为拉斐尔 Web图形库的演示之一。

演示是静态的,但它应该很容易获取代码并将其静态数据交换为一组实时数据——我认为它只是JSON格式的Git提交数据。

演示在这里:http://dmitrybaranovskiy.github.io/raphael/github/impact.html

更新2:我已经发布了这个答案的改进版本在Git中可视化分支拓扑问题,因为它在那里更合适。该版本包括lg3,它显示了作者和提交者的信息,所以你真的应该检查一下。出于历史(&rep,我承认)原因留下这个答案,尽管我真的很想删除它。

我的两分钱:我有两个别名,我通常在我的~/.gitconfig文件中抛出:

[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)' --alllg2 = 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)' --alllg = !"git lg1"

git lg/git lg1看起来像这样:git lg1

git lg2看起来像这样:git lg2


(注意:现在有更适用于这个问题的答案,例如Jubobs',或Harry Lee's

基于我在对相关问题的回答中找到的Graphviz脚本,我破解了一个ruby脚本,它创建了Git存储库的摘要视图。它省略了所有线性历史,只显示“有趣”的提交,即具有多个父级、多个子级或由分支或标签指向的提交。这是它为jQuery生成的图的片段:

jQuery示例

大图删除支行是类似的工具,它们尝试只显示图的高级结构,只显示标记、分支、合并等之间的关系。

这个问题有更多的选择。

源树是一个非常好的。它确实打印出了一个好看的中等大小的历史记录和分支图:(以下是在一个实验性的Git项目上完成的,只是为了看看一些分支)。支持Windows 7+和Mac OS X 10.6+。

Sourcetree中的示例输出

Gitg是GNOME的Gitk和GitX的克隆(它也适用于KDE等),它显示了一个漂亮的彩色图表。

它是积极开发的(截至2012年)。它允许您按时间顺序或拓扑对提交(图节点)进行排序,并隐藏不导致选定分支的提交。

它适用于大型存储库和复杂的依赖关系图。

示例屏幕截图,显示linux-git和linux-2.6存储库:

linux-git

linux-2.6

稍微调整Slipp的精彩回答,您可以使用他的别名仅记录一个分支:

[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=relativelgBranch2 = 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-commitlg = !"git lg1"

通过离开--all你现在可以做

git lgBranch1 <branch name>

甚至

git lgBranch1 --all

#0是一个优秀的Perl脚本,我已经使用了一年多,我几乎不再直接使用git log命令。

这是我喜欢这个剧本的一些地方:

  • 它使用Unicode字符在图形中绘制线条,使图形线条看起来更连续。
  • 您可以将--reverse与图形输出结合起来,这是常规git log命令无法实现的。
  • 它在内部使用git log来获取提交列表,因此您传递给git log的所有选项也可以传递给此脚本。

我有一个使用git-forest的别名,如下所示:

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

这是终端上输出的样子:

在此输入图片描述

图表

它生成Git存储库提交历史记录的PNG或SVG表示。

我刚刚写了一个工具,可以使用超文本标记语言/画布生成一个漂亮的Git提交图。

并提供一个jQuery插件,使其易于使用。

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

预览:

预览

我添加了三个自定义命令:git treegit streegit vtree。我将按顺序介绍它们。

[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)'

在此输入图片描述


对于git streegit vtree,我使用Bash来帮助格式化。

[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


这适用于Git版本1.9a。颜色值'auto'显然在此版本中首次亮相。这是一个很好的补充,因为分支名称将获得不同的颜色。例如,这使得更容易区分本地和远程分支。

虽然我有时使用gitg,但我总是回到命令行:

[alias]# Quick look at all repositoriesloggsa = 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 repologga  = log --color --date-order --graph --oneline --decorate --all# Extend look at active branchlogg   = log --color --date-order --graph --oneline --decorate# Look with the datelogda  = log --color --date-order --date=local --graph --format=\"%C(auto)%h%Creset %C(blue bold)%ad%Creset %C(auto)%d%Creset %s\" --alllogd   = 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 datelogdra = log --color --date-order --graph --format=\"%C(auto)%h%Creset %C(blue bold)%ar%Creset %C(auto)%d%Creset %s\" --alllogdr = 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\" --alllogtsa = log --graph --color --format=\"%C(auto)%h %d %<|(100,trunc) %s\" --all --simplify-by-decoration

如您所见,它几乎是一个击键保存别名,基于:

  • --颜色:清晰外观
  • --graph:可视化父母
  • --装饰:谁是谁
  • --oneline:很多时候,你需要知道的关于提交的一切
  • --简化装饰:第一次看的基本(只是标签,相关合并,分支)
  • --all:使用和不使用此选项的所有别名保存击键

请参阅最新版本的Git(1.8.5及更高版本),您可以从装饰占位符%d中的%C(自动)中受益。

从这里开始,你所需要的只是对修改版本有很好的理解,以过滤你需要的任何东西(比如master…开发,其中--simplify-merges可以帮助处理长期分支)。

命令行背后的力量是基于您的需求的快速配置(了解存储库不是唯一的键日志配置,因此有时需要添加--numstat或--raw或--name-state。这里git log和别名快速、强大,并且(随着时间的推移)是您可以实现的最漂亮的图形。更重要的是,默认通过寻呼机显示输出(说更少),您可以始终在结果中快速搜索。不相信吗?您始终可以使用gitgraph这样的项目解析结果。

Gitgraph.js允许在没有存储库的情况下绘制漂亮的Git分支。只需编写一段JavaScript代码来配置您的分支和提交并在浏览器中呈现它。交互式文档可用。

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);

用Gitgraph.js生成的样本图

或者使用metro模板:

GitGraph.js地铁主题

或者使用提交消息、作者和标签:

带有提交消息的图形

JSFiddle测试它。

用@bsara的gitgrapher生成它。

构建在TikZ&PGF之上,#0是一个小型LaTeX包,可让您轻松生成矢量图形提交图等。

自动生成现有存储库的提交图是没有#0的目的;它产生的图只适用于教育目的

我经常用它来生成Git问题的答案图,作为ASCII提交图的替代品:

下面是这样一个图表的例子,展示了一个简单的rebase的效果:

输入图片描述

\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}

对于OS X用户,我采用了@gspes示例并对其进行了轻微修改(通过自制安装了gnu-sed)并调整了颜色(使用黑色背景,不确定原始示例如何可能呈现它在示例中的方式,因为它在具有黑色背景的终端上指定了黑色文本)。

[alias]# tree, vtree, stree supportlogx = 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 -rvtree = !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

OS X的关键是首先安装GNU ses(它有-r选项)。使用Homebrew最容易完成,它不会覆盖系统安装的ses,而是将GNU ses安装为“gses”。我希望这有助于@SlippD. Thompson谁上面评论关于OS X不工作。

git -c core.pager='less -SRF' log --oneline --graph --decorate

这是我的终端变体,类似于这里的许多答案。我喜欢调整传递给less的标志以防止换行。

示例输出

我将其设置为快速访问的别名,因为命令有点麻烦。

我写了一个Web工具,用于将Git日志转换为漂亮的SVG图:

Bit-Booster-离线提交图形绘制工具

git log --pretty='%h|%p|%d'的输出直接上传到工具中,然后单击“下载graph.svg”链接。

该工具是纯客户端的,因此您的Git数据不会与我的服务器共享。您还可以将超文本标记语言+JavaScript保存在本地,并使用“file:///”URL运行它。它在Chrome48和Ubuntu 12.04上的Firefox 43上进行了验证(精确穿山甲)。

它生成超文本标记语言,可以直接发布到任何页面(包括blogspot博客引擎!)。

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

以下是该工具生成的示例超文本标记语言文件的屏幕截图:

http://bit-booster.com/graph.html(工具)

这里的许多答案都很棒,但对于那些只想要简单的一行到一点的答案而无需设置别名或任何额外的答案的人来说,这里是:

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

不是每个人都会一直做git log,但是当你需要它的时候,只要记住:

"一只狗"=git log--一个ll--decate--oneline--graph

在此处输入图片描述

尝试ditaa。它可以将任何ASCII图转换为图像。虽然它的设计没有考虑到Git分支,但结果给我留下了深刻的印象。

来源(txt文件):

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

命令:

java -jar ditaa0_9.jar ascii-graph.txt

结果:

在此输入图片描述

它还支持背景颜色,虚线,不同的形状等等。

我在~/.gitconfig中有这个git log别名来查看图表历史:

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

有了这个,git l将输出如下内容:

在此处输入图片描述

在Git2.12+中,您甚至可以使用#0配置选项自定义图形的线条颜色。

至于日志的格式,它类似于#0,增加了作者姓名(尊重.mailmap)和相对作者日期。请注意,Git>=1.8.3支持%C(auto)语法,它告诉Git使用默认颜色进行提交哈希等。

这是我对这个问题的看法:

截图:

截图

用法:

git hist-显示当前分支的历史记录

git hist --all-显示所有分支(包括远程)的图表

git hist master devel-显示两个或多个分支之间的关系

git hist --branches-显示所有本地分支

添加--topo-order以拓扑方式对提交进行排序,而不是按日期(此别名中的默认值)

好处:

  • 看起来就像普通的--decorate,所以不同的分支名称有不同的颜色
  • 添加提交者电子邮件
  • 添加提交相对和绝对日期
  • 按日期排序提交

设置:

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)'"

我建议tighttps://github.com/jonas/tig,一个更好的Git命令行工具。

您可以使用Homebrew在macOS上安装tig:

$ brew install tig$ tig

在此输入图片描述

除了Slipp D. Thompson的答案之外,我建议您添加这个别名以具有相同的装饰,但在单行中通过提交:

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)'"

看着这段对话,我试着用我最喜欢的git-colagit-dag

git-cola运行View->DAG...并将日志:master --替换为--all显示了一个包含所有分支的漂亮图表。

文件~/. 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'

如果您的存储库位于GitLab上,您可以使用它的图形表示,因为它在浏览器中呈现为SVG。

在此输入图片描述

一个漂亮干净的类似表格的shell Git图输出

通常除了图树之外还有哈希

通常除了图树之外还有哈希

或者在额外的列中

或者在额外的专栏里

编辑:您想在不阅读所有解释的情况下立即开始?跳到编辑6

INFO:有关更像分支的shell彩色版本,请参阅我的第二个答案(https://stackoverflow.com/a/63253135/)。

到目前为止,在这个问题的所有答案中,没有一个显示了一个干净的类似表格的shell输出。最接近的是这个答案来自福音书,我从哪里开始。

我的方法的核心是只计算显示给用户的树字符。然后用空格将它们填充到个人长度。

除了Git,你还需要这些工具

  • grep
  • printf
  • ed
  • seq
  • 孩子们
  • wc

主要是在船上与任何Linux分布。

代码片段是

while IFS=+ read -r graph hash time branch message;do
# Count needed amount of white spaces and create themwhitespaces=$((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 columngraph_all="$graph_all$graph$whitespaces\n"hash_all="$hash_all$(printf '%7s' "$hash")  \n"
# Format all other columnstime_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 outputpaste -d' ' <(echo -e "$time_all") <(echo -e "$branch_all") <(echo -e "$graph_all") <(echo -e "$hash_all") <(echo -e "$message_all")

计算我们使用的所需空白

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

要获取所有字符(直到每行1000),而不是仅选择树字符: * | / \ _和空格

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

最后计算它们并将结果从我们选择的长度值中减去,在示例中为9。

生成我们使用的计算量的空白

  seq -s' ' $whitespaces

并将位置号截断为

  tr -d '[:digit:]'

然后将它们添加到我们的图表行的末尾。就是这样!

Git已经使用语法'%><(amount_of_characters,truncate_option)'格式化输出说明符的长度提供了不错的选项,它从左侧'>'或右侧'<'添加空格,并可以截断开头'ltrunc'、中间'mtrunc'或结尾'trunc'的字符。

上面的printf cmd对相应的Git列使用相同的长度值是重要

有乐趣的风格自己干净的表看输出到您的需求。

额外:

要获得正确的长度值,您可以使用以下代码段

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

并使用$max_chars作为上面的正确长度值。

编辑1:刚刚注意到git树中也使用了下划线字符,并相应地编辑上面的代码片段。如果缺少其他字符,请留下评论。

编辑2:如果您想去掉分支和标记条目周围的括号,只需在git命令中使用“%D”而不是“%d”,就像EDIT 3一样。

编辑3:也许“自动”颜色选项是你最喜欢的分支和标记条目?

Git无括号自动颜色头和标签表状shell输出

更改git命令的这一部分(颜色214

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

汽车

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

编辑4:或者你喜欢你自己的颜色组合,一个闪烁的头部的花哨输出?

Git树花式表样式输出

为了能够首先设置头部、分支名称和标签的样式,我们需要在我们的git命令中使用“自动”颜色选项,就像EDIT 3一样。

然后我们可以通过添加这3行来替换已知的颜色值

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

就在排队之前

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

在我们的代码片段中。替换值产生上面的颜色。

例如,头的替换值是

3;5;1;38;5;196

其中3;代表斜体字,5;代表闪烁,1; 38; 5; 196代表颜色。

但是您可以选择您喜欢的任何颜色值。

概述git颜色值和ANSI等价物

在此处输入图片描述

你找到一个带有git颜色/样式选项的列表。

如果您需要在控制台上输出准确的颜色(上图由Stack Overflow缩小),您可以使用

for ((i=0;i<=255;i++));dowhile IFS='+' read -r tree hash;doecho -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

在您的Git项目路径中,该路径使用您的Git日志输出中的第一次提交。

编辑5:正如成员“Andras Deak”所提到的,有一些方法可以使用此代码:

1)作为别名

别名不接受参数,但函数可以,因此只需在. 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" ###
}

并直接在您的git项目路径下或从您想要的任何地方调用函数git_tably(源自类似表格),并将您的git项目路径作为第一个参数。

2)作为shell脚本

我将它与将Git项目目录作为第一个参数传递给它的选项一起使用,或者如果为空,则像正常行为一样采用工作目录。在它的整体上,我们有

# Edit your color/style preferences here or use empty values for git auto styletag_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 treewhile IFS=+ read -r graph;dochars_count=$(sed -nl1000 'l' <<< "$graph" | grep -Eo '\\\\|\||\/|\ |\*|_' | wc -l)[[ $chars_count -gt ${max_chars:-0} ]] && max_chars=$chars_countdone < <(cd "${1:-"$PWD"}" && git log --all --graph --pretty=format:' ')
# Create the columns for your preferred table-like git graph outputwhile IFS=+ read -r graph hash time branch message;do
# Count needed amount of white spaces and create themwhitespaces=$(($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 columngraph_all="$graph_all$graph$whitespaces\n"hash_all="$hash_all$(printf '%7s' "$hash")  \n"
# Format all other columnstime_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 outputpaste -d' ' <(echo -e "$time_all") <(echo -e "$branch_all") <(echo -e "$graph_all") <(echo -e "$hash_all") <(echo -e "$message_all")

3)作为git别名

也许最舒服的方法是在. gitconfig中添加一个git别名

[color "decorate"]HEAD = bold blink italic 196branch = 214tag = 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\");                                          \'"

而不是在任何项目路径下调用git tably

Git非常强大,您可以直接更改head、tags…,如上图所示和从这里带走

另一个花哨的选择是选择你最喜欢的树的颜色

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

它给你疯狂的外观,但总是像表一样的git日志输出

fanciest_git_tree_tablelike_image

闪烁太多!只是为了演示什么是可能的。指定的颜色太少会导致颜色重复。

只需单击一下即可完成. gitconfig参考。

编辑6:由于您的积极投票,我改进了片段。现在你几乎可以使用任何git log命令来提供它,并且不必再调整代码。试试看!

它是如何工作的?

  • 一如既往地在. gitconfig中定义您的Git日志命令(格式如下)
  • 定义一个正树列号,其中显示git图(可选)

那就打电话

    git tably YourLogAlias

在任何git项目路径下或

    git tably YourLogAlias TreeColNumber

其中TreeColNumber从上面覆盖始终定义的值。

    git tably YourLogAlias | less -r

将输出管道到更少,这对巨大的历史很有用。

您的Git日志别名必须遵循以下格式规则:

  • 每个列都必须由一个列分隔符指示,您必须选择它,如果不是唯一的,可能会导致问题

    ...format:'^%h^%cr^%s'中的^导致树、哈希、时间和提交列

  • 在日志命令中的每个提交占位符之前,您必须使用%><(<N>[,ltrunc|mtrunc|trunc]),其中一个trunc选项

    (有关语法解释,请参阅https://git-scm.com/docs/pretty-formats),

    但是,任何换行符的最后一个提交占位符都可以在没有它的情况下使用

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

  • 如果需要额外的字符来装饰,例如(committer: <>)

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

    要获得类似表格的输出,它们必须直接写在提交占位符之前和之后

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

  • 使用像%C(white)...%C(rest)这样的列颜色需要--color选项来进行彩色输出

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

  • 如果您使用--stat选项或类似选项,请在末尾添加换行符%n

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

  • 您可以将git图放置在每一列,只要您不使用换行符或仅使用空format:'...%n'

    对于非空换行符...%n%CommitPlaceholder...,只有当每行的所有第n列都存在并使用相同的宽度时,您才能将git图放置在每列n+1处

  • 为特定日志别名定义的树列号的名称必须是YourLogAlias-col

与普通的git日志输出相比,这个很慢但很好。

现在将改进的代码段添加到您的. gitconfig

[color "decorate"]HEAD   = bold blink italic 196branch = 214tag    = bold 222
[alias]
# Delimiter used in every mylog alias as column seperatordelim     = ^
# Short overview about the last hashes without graphmylog     = 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 treemylog2    = 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 datamylog3    = 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"

在哪里在桌子上

  • 第一段将delm(iter)、YourLogAlias和YourLogAlias-cols加载到shell变量中
  • 第二个读出每列的长度
  • 第三个计算树的最大长度
  • 第四个将树加载到数组中
  • 第五个组织和打印类似表格的输出

结果:

在此处输入图片描述

在此处输入图片描述

在此处输入图片描述

或在飞行中使用新的TreeColNumber

在此处输入图片描述

再次:有乐趣的风格自己干净的桌子一样的输出,以满足您的需求。

您还可以在评论中分享您首选的格式化Git日志别名。我不时会在上面的文本中包含评分最高的日志,并添加图像。

一个更像树枝的贝壳彩色版本。

e

其他一些答案显示图形树被外部工具很好地着色,部分带有彩色线信息。这是我的shell方法,它与我在这里的第一个答案相结合,用于类似表格的输出(https://stackoverflow.com/a/61487052)。

产品特点:

  • 你可以定义所有的树的颜色
  • 你可以把每一列都染成相应的树枝颜色
  • 你可以把树放在不同的位置
  • 您可以使用各种git log别名
  • 您可以为每个别名定义一个树列编号
  • 您可以将其导入less -r以获取巨大的历史

你如何使用它:

定义您的git log别名,如所示的几个答案,例如,来自Slipp D.albfankaoru,使用下面提到的格式化说明,并将其与代码片段一起粘贴到您的. gitconfig文件中。从您的项目路径调用它,通常使用

git colored YourLogAlias

git colored YourLogAlias TreeColumnNumber动态放置树列。

格式说明:

您的git log别名必须遵循以下格式规则:

  • 使用唯一字符作为每个提交占位符的列分隔符,即^
    ...format:'%h%cr%s'-->
    ...format:'^%h^%cr^%s'
  • 用一种颜色为整个列着色,或者将其留空以采用相应的分支颜色
    ...format:'^%h^%cr^%s'-->
    ...format:'^%h^%cr^%C(white)%s%C(reset)'(分支颜色中的哈希和时间)
  • 您必须使用trunc选项之一通过%><(<N>[,ltrunc|mtrunc|trunc])指定任何列的宽度,但行上的任何最后一个提交占位符都可以在没有它的情况下使用
    ...format:'^%h^%cr^%C(white)%s%C(reset)'-->
    ...format:'^%<(7,trunc)%h^%<(12,trunc)%cr^%C(white)%<(50,trunc)%s%C(reset)'
  • 如果您需要额外的装饰字符,请将它们直接放在提交占位符周围,即Commit:
    ...^%C(white)%<(50,trunc)%s%C(reset)...-->
    ...^%C(white)%<(50,trunc)Commit:%s%C(reset)...
  • 如果您使用换行符%n,请将它们放在列分隔符之前或末尾
    ...^%C(white)%<(50,trunc)Commit:%s%C(reset)'-->
    ...%n^%C(white)%<(50,trunc)Commit:%s%C(reset)%n'
  • 如果您使用像上面%C(white)这样的列颜色,则需要添加--color选项
    ...format:'^%<(7,trunc)%h...-->
    ...--color...format:'^%<(7,trunc)%h...
  • 如果您使用--stat选项或类似选项,请在末尾添加换行符%n
    ...--stat...format:'...'-->
    ...--stat...format:'...%n'

杂项:

  • 对于git log别名和非空换行符...%n%CommitPlaceholder...,只有当每行的第n列都存在并使用相同的宽度时,您才能将Git图放置在每列n+1处

  • 如果您在文件. gitconfig中为YourLogAlias定义了一个TreeLaynNumber,则YourLogAlias-col必须是名称

  • 与正常的git log输出相比,这个很慢,但很好

示例:

git colored lgc1e

git colored lgc2e

git colored lgc3e

git colored lgc4e

代码片段:

将以下行添加到您的. gitconfig文件

[alias]
# Define your unique column separatordelim      = ^
# Define your 'git log' aliases and optional tree column numberslgc1       = 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 listcolor-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"

将Bash代码段也添加到您的. gitconfig文件中

# This is the Bash snippet which does all the magiccolored = !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"

解释:

  • 第一个段落将delm(iter)、Color-list和YourLogAlias加载到shell变量中
  • 第二个读出每列的长度
  • 第三个计算树的最大长度
  • 第四个将树加载到数组中
  • 第五种颜色的树,基于案例分析
  • 第六个为非树列着色并打印类似表格的输出

最大的部分是设置树颜色的案例分析。其他部分在我的链接回答中解释了类似表格的shell输出。

请在评论中显示您最喜欢的格式化日志别名,因为我的只是示例。

如果您使用的是macOS,您可以尝试GitUp

在此输入图片描述

  • x轴:分支
  • y轴:时间

Visual Studio Code有一个惊人的扩展-图表管理工具

Git Graph

这里是我的社区别名:git ls。使用git ls,您可以查看图表,每个提交仅涵盖一行。所有内容都着色并包含有用的信息。您还可以检查其他分支的提交历史记录:

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

用法:

# shows commits graph on the current branchgit ls
# shows commits graph on the develop branchgit ls develop

这是图表视图:输入图片描述