我看过一些书籍和文章有一些非常漂亮的 Git 分支和提交图表。如何制作高质量的 Git 历史可打印图像?
36 回答
更新 2:我已经在 Git 问题的 Visualizing branch topology 中发布了这个答案的改进版本,因为它在那里更合适。该版本包括 lg3
,它显示了作者和提交者信息,所以你真的应该检查一下。出于历史原因(以及代表,我承认)留下这个答案,尽管我真的很想删除它。
我的两分钱:我通常在~/.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)' --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(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
lg = !"git lg1"
git lg
/git lg1
看起来像这样:
git lg2
看起来像这样
:
(注意:现在有更多适用于这个问题的答案,例如fracz's、Jubobs'或Harry Lee's!)
对于文本输出,您可以尝试:
git log --graph --abbrev-commit --decorate --date=relative --all
或者:
git log --graph --oneline --decorate --all
或者:这是用于绘制DAG图的Graphviz别名。
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);
或使用metro
模板:
或者使用提交消息、作者和标签:
使用JSFiddle对其进行测试。
使用@bsara的Git Grapher生成它。
建立在TikZ 和 PGF之上,gitdags
是一个小的 LaTeX 包,它允许您轻松地生成矢量图形提交图等等。
自动生成现有存储库的提交图不是; gitdags
它生成的图表仅用于教育目的。
我经常用它来为我对 Git 问题的回答生成图表,作为 ASCII 提交图的替代方案:
- 如何在 master 上进行错误修复并将其集成到我不太稳定的分支中?
- git commit --amend 究竟是如何工作的?
- 为什么在我运行“git checkout origin/<branch>”之后,Git 会告诉我“当前不在任何分支上”?
- 将master合并到分支和将分支合并到master有什么区别?
- Git rebase --preserve-merges 失败
这是一个演示简单变基效果的图表示例:
\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}
我刚刚编写了一个工具,它可以使用HTML/Canvas生成漂亮的 Git 提交图。
并提供一个 jQuery 插件,使其易于使用。
[GitHub] https://github.com/tclh123/commits-graph
预习:
Sourcetree是一个非常好的。它确实打印出一个好看的中等大小的历史和分支图:(以下是在一个实验性的 Git 项目上完成的,只是为了查看一些分支)。支持 Windows 7+ 和 Mac OS X 10.6+。
git-forest
是我使用了一年多的优秀 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 日志转换为漂亮的 SVG 图:
将输出git log --pretty='%h|%p|%d'
直接上传到工具中,然后单击“下载 graph.svg”链接。
该工具是纯客户端的,因此您的任何 Git 数据都不会与我的服务器共享。您还可以在本地保存 HTML + JavaScript 并使用“file:///” URL 运行它。它在Ubuntu 12.04 (Precise Pangolin)上的 Chrome 48 和 Firefox 43 上得到验证。
它生成的 HTML 可以直接发布到任何页面(包括 blogspot 博客引擎!)。看看这里的一些博客文章:
http://bit-booster.blogspot.ca/
这是该工具生成的示例 HTML 文件的屏幕截图:
根据我在相关问题的答案中找到的 Graphviz 脚本,我已经破解了一个 Ruby 脚本,该脚本创建了 Git 存储库的摘要视图。它省略了所有线性历史,只显示“有趣的”提交,即具有多个父级、多个子级或由分支或标签指向的提交。这是它为jQuery生成的图形片段:
git-big-picture和BranchMaster是类似的工具,它们试图仅显示图的高级结构,仅显示标签、分支、合并等如何相关。
这个问题有更多的选择。
我添加了三个自定义命令git tree
:git stree
和git 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 stree
and git 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);"'
[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 版本 1.9a。颜色值“auto”显然在此版本中首次亮相。这是一个很好的补充,因为分支名称将获得不同的颜色。例如,这使得区分本地和远程分支变得更容易。
用于 shell 的漂亮且干净的类似表格的 Git 图形输出
除了图树之外,通常使用散列
或在额外的列中
编辑:您想立即开始而不阅读所有解释吗?跳转到编辑 6。
信息:有关 shell 的更像分支的彩色版本,另请参阅我的第二个答案(https://stackoverflow.com/a/63253135/)。
到目前为止,在这个问题的所有答案中,没有一个显示出类似于表的干净的 shell 输出。最接近的是我开始的gospes的这个答案。
我的方法的核心是只计算向用户显示的树字符。然后用空格将它们填充到个人长度。
除了 Git,你还需要这些工具
- grep
- 粘贴
- 打印
- sed
- 序列
- tr
- 厕所
主要与任何 Linux 发行版一起使用。
代码片段是
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")
为了计算我们使用的所需空白
sed -nl1000 'l' <<< "$graph"
获取所有字符(每行 1000 个)而不是仅选择树字符:* | / \ _ 和空格用
grep -Eo '\\\\|\||\/|\ |\*|_'
最后计算它们并从我们选择的长度值中减去结果,在示例中为 9。
为了产生我们使用的计算出的空白数量
seq -s' ' $whitespaces
并用截断位置编号
tr -d '[:digit:]'
然后将它们添加到我们的图表线的末尾。而已!
Git 有一个很好的选项来格式化输出说明符的长度,它已经使用语法'%><(amount_of_characters,truncate_option)'
从左侧“>”或右侧“<”添加空格,并且可以从开头“ltrunc”、中间“mtrunc”或结束“截断”。
重要的是,上面的 printf cmd 对相应的 Git 列使用相同的长度值。
根据您的需要设计您自己的干净的类似表格的输出,玩得开心。
额外的:
要获得正确的长度值,您可以使用以下代码段
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:' ')
并使用 $max_chars 作为上面的正确长度值。
编辑 1:刚刚注意到下划线字符也用于 git 树并相应地编辑上面的代码片段。如果还有其他字符缺失,请发表评论。
编辑 2:如果你想去掉分支和标签条目周围的括号,只需在 git 命令中使用“%D”而不是“%d”,就像在编辑 3 中一样。
编辑 3:也许“自动”颜色选项是您最喜欢分支和标签条目的选项?
更改这部分 git 命令(颜色214)
%C(214)%>(15,trunc)%D%C(reset)
自动_
%C(auto)%>(15,trunc)%D%C(reset)
编辑4:或者你喜欢你自己的那部分颜色混合,一个带有闪烁头的奇特输出?
为了能够首先设置头部、分支名称和标签的样式,我们需要在我们的 git 命令中使用“自动”颜色选项,就像在 EDIT 3 中一样。
然后我们可以通过添加这 3 行来用我们自己的颜色值替换已知的颜色值
# 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}
就在行前
branch_all="$branch_all$(printf '%15s' "$branch")\n"
在我们的代码片段中。替换值产生上述颜色。
例如 head 的替换值为
3;5;1;38;5;196
哪里 3; 代表斜体,5;用于闪烁和 1;38;5;196 用于颜色。更多信息从这里开始。注意:此行为取决于您喜欢的终端,因此可能无法使用。
但是您可以选择您喜欢的任何颜色值。
git 颜色值和 ANSI 等效项的概述
您可以在此处找到带有git color/style 选项的列表。
如果您需要控制台上的输出以获得准确的颜色(上图由 Stack Overflow 按比例缩小),您可以使用
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
在您的 Git 项目路径中,该路径使用 Git 日志输出中的第一个提交。
编辑 5:正如成员“Andras Deak”所提到的,有一些方法可以使用此代码:
1)作为别名:
alias 不接受参数,但函数可以,因此只需在 .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 项目路径作为第一个参数的任何位置调用函数 git_table (源自类似表)。
2)作为一个shell脚本:
我将它与将 Git 项目目录作为第一个参数传递给它的选项一起使用,或者如果为空,则像正常行为一样采用工作目录。总的来说,我们有
# 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) 作为 git 别名:
也许最舒服的方法是在你的 .gitconfig 中添加一个 git 别名
[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\"); \
'"
不仅仅是git tably
在任何项目路径下调用。
Git 非常强大,您可以直接更改头部、标签等,如上图所示,取自此处。
另一个花哨的选择是选择您最喜欢的树颜色
[log]
graphColors = bold 160, blink 231 bold 239, bold 166, bold black 214, bold green, bold 24, cyan
这让你看起来很疯狂,但总是像表格一样的 git log 输出
眨眼太多!只是为了证明什么是可能的。指定颜色太少会导致颜色重复。
编辑 6: 由于您的积极投票,我改进了片段。现在,您几乎可以使用任何 git log 命令来提供它,而无需再调整代码。试试看!
它是如何工作的?
- 像往常一样在 .gitconfig 中定义 Git 日志命令(格式如下)
- 定义一个正的树列号,其中显示 git 图(可选)
然后打电话
git tably YourLogAlias
在任何 git 项目路径下或
git tably YourLogAlias TreeColNumber
其中 TreeColNumber 会覆盖上面始终定义的值。
git tably YourLogAlias | less -r
会将输出通过管道传输到 less 中,这对于庞大的历史非常有用。
您的 Git 日志别名必须遵循以下格式规则:
每列必须由您必须选择的列分隔符指示,如果不是唯一的,可能会导致问题
即生成树
^
、...format:'^%h^%cr^%s'
哈希、时间和提交列在您必须使用的日志命令中的每个提交占位符之前,使用
%><(<N>[,ltrunc|mtrunc|trunc])
trunc 选项之一(有关语法解释,请参阅https://git-scm.com/docs/pretty-formats),
但是任何换行符的最后一个提交占位符都可以在没有它的情况下使用
IE
...format:'^%<(7,trunc)%h^%<(12,trunc)%cr^%s'
(committer:
如果像,<
和>)
in这样的装饰需要额外的字符...%C(dim white)(committer: %cn% <%ce>)%C(reset)...
要获得类似表格的输出,它们必须直接在提交占位符之前和之后写入
IE
...%C(dim white)%<(25,trunc)(committer: %cn%<(25,trunc) <%ce>)%C(reset)...
使用列颜色喜欢
%C(white)...%C(rest)
需要--color
颜色输出的选项IE
...--color...format:'^%C(white)%<(7,trunc)%h%C(rest)...
如果您使用
--stat
选项或类似选项,%n
请在末尾添加换行符IE
...--stat...format:'...%n'...
只要不使用换行符或只使用空行,您就可以将 git 图放在每一列
format:'...%n'
对于非空换行符
...%n%CommitPlaceholder...
,只有当每行的所有第 n 列都存在并使用相同的宽度时,您才可以将 git 图放在每列 n+1您为特定日志别名定义的树列号的名称必须是
YourLogAlias-col
与普通的 git log 输出相比,这个输出很慢但很好。
现在将改进的代码段添加到您的 .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"
在表格的哪里
- 第一段将 delim(iter)、YourLogAlias 和 YourLogAlias-col 加载到 shell 变量中
- 第二个读出每列的长度
- 第三个计算最大值。树的长度
- 第四个将树加载到数组中
- 第五个组织和打印表格输出
结果:
或动态使用新的 TreeColNumber
再次:根据您的需要设计您自己的干净的类似表格的输出,玩得开心。
您还可以在评论中分享您首选的格式化 Git 日志别名。我会不时在上面的文字中包含评分最高的内容并添加图片。
有关更详细的文本输出,请尝试:
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
这取决于他们的样子。我使用gitx制作这样的图片:
您可以在 24 路章鱼合并上git log --graph
与gitk进行比较(最初来自http://clojure-log.n01se.net/date/2008-12-24.html):
这是我对这个问题的看法:
截屏:
用法:
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)'"
gitg:基于 gtk 的存储库查看器。这是新的,但有趣且有用。
我目前使用它。
虽然我有时会使用gitg,但我总是回到命令行:
[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
如您所见,它几乎是一个按键保存别名,基于:
- --color:清晰的外观
- --graph:可视化父母
- --date-order:最容易理解的 repo
- --装饰:谁是谁
- --oneline:很多时候你需要知道的关于提交的所有信息
- --simplify-by-decoration:初看的基础(只是标签、相关合并、分支)
- --all:使用和不使用此选项的所有别名保存击键
- --date=relative (%ar):了解 repo 中的活动(有时一个分支在 master 附近的提交很少,但几个月前来自他)
请参阅最新版本的 Git(1.8.5 及更高版本),您可以从装饰占位符 %d 中的 %C(auto) 中受益。
从这里开始,您需要对gitrevisions有一个很好的理解,以过滤您需要的任何内容(例如 master..develop,--simplify-merges
可以帮助您处理长期分支)。
命令行背后的强大功能是根据您的需要快速配置(了解存储库不是唯一的关键日志配置,因此有时需要添加--numstat、--raw 或--name-status。这里git log
和别名快速、强大并且(随着时间的推移)是您可以实现的最漂亮的图表。更重要的是,默认情况下通过寻呼机显示输出(少说),您始终可以在结果中快速搜索。不相信?您始终可以使用项目解析结果像gitgraph。
我建议tig
https://github.com/jonas/tig,这是一个更好的 Git 命令行工具。
您可以使用 Homebrew 在 macOS 上安装 tig:
$ brew install tig
$ tig
Visual Studio Code 有一个惊人的扩展——Git Graph:
稍微调整一下 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=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"
通过离开--all
你现在可以做
git lgBranch1 <branch name>
甚至
git lgBranch1 --all
尝试gitk
或gitk --all
。但是,它没有打印/保存 img 作为功能。
我有这个git log
别名~/.gitconfig
来查看图表历史:
[alias]
l = log --all --graph --pretty=format:'%C(auto)%h%C(auto)%d %s %C(dim white)(%aN, %ar)'
有了这个,git l
将输出如下内容:
在 Git 2.12 + 中,您甚至可以使用log.graphColors
配置选项自定义图表的线条颜色。
至于日志的格式,它类似于--oneline
,添加了作者姓名(尊重.mailmap
)和相对作者日期。请注意,在 Git >= 1.8.3%C(auto)
中支持告诉 Git 使用默认颜色进行提交哈希等的语法。
它会为您的 Git 存储库的提交历史生成 PNG 或 SVG 表示。
用于外壳的更像分支的彩色版本。
其他一些答案显示了由外部工具很好地着色的图形树,部分带有彩色线条信息。这是我的 shell 方法,它与我在此处的第一个答案相结合,用于类似表格的输出(https://stackoverflow.com/a/61487052)。
特征:
- 您可以定义所有的树颜色
- 您可以将每一列染成相应的分支颜色
- 您可以将树列放置在不同的位置
- 您可以使用各种
git log
别名 - 您可以为每个别名定义一个树列号
- 您可以将其导入
less -r
以获取巨大的历史
你如何使用它:
定义您的git log
别名,如显示的几个答案,例如,来自Slipp D.、albfan、kaoru ,使用下面提到的格式说明,并将其与代码片段一起粘贴到您的.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)'
(分支颜色中的哈希和时间) - 您必须
%><(<N>[,ltrunc|mtrunc|trunc])
使用其中一个 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 处YourLogAlias-col
如果您在文件.gitconfig中定义 TreeColumnNumber ,则必须是名称YourLogAlias
与正常
git log
输出相比,这个速度很慢,但很好
例子:
代码片段:
将以下行添加到您的.gitconfig文件中
[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"
也将 Bash 片段添加到您的.gitconfig文件中
# 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"
说明:
- 第一段将 delim(iter)、color-list 和 YourLogAlias 加载到 shell 变量中
- 第二个读出每一列的长度
- 第三个计算树的最大长度
- 第四个将树加载到数组中
- 第五个颜色树,基于案例分析
- 第六个着色非树列并打印类似表格的输出
最大的部分是设置树颜色的案例分析。其他部分在我的类似表的 shell 输出的链接答案中进行了解释。
请在评论中显示您最喜欢的格式化日志别名,因为我的只是示例。
文件~/.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。
转到存储库的图形视图,例如https://gitlab.com/gitlab-org/gitter/webapp/network/develop
将图表向下滚动到底部(它延迟加载提交!)
使用浏览器的检查器将 SVG 元素复制到新文件
在您选择的渲染器中打开它,例如Inkscape
作为Raphael Web 图形库的演示之一,有一个时髦的 Git 提交图。
该演示是静态的,但它应该很容易获取代码并将其静态数据换成一组实时数据——我认为它只是 JSON 格式的 Git 提交数据。
演示在这里:http ://dmitrybaranovskiy.github.io/raphael/github/impact.html
对于 OS X 用户,我采用了 @gospes 示例并针对 gsed (gnu-sed
通过Homebrew安装)稍微修改了它并调整了颜色(以使用黑色背景,不确定原始示例如何可能呈现它的方式该示例,因为它在具有黑色背景的终端上指定了黑色文本)。
[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
OS X 的关键是首先安装 GNU sed(具有 -r 选项)。使用 Homebrew 最容易完成,它不会覆盖系统安装的 sed,而是将 GNU sed 安装为“gsed”。我希望这对@SlippD.Thompson 有所帮助,他在上面评论过 OS X 无法正常工作。
我不知道直接工具,但也许您可以破解脚本以将数据导出为点格式并使用Graphviz进行渲染。
除了“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-cola
& git-dag
。
运行View->DAG...
并git-cola
替换Log: master --
with--all
显示了一个包含所有分支的漂亮图表。
这是我的社区别名: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 branch
git ls
# shows commits graph on the develop branch
git ls develop