我见过一些书籍和文章中有一些非常漂亮的Git分支和提交的图表。如何制作Git历史的高质量可打印图像?
当前回答
贝壳的颜色更像树枝。
其他一些答案显示了外部工具对图形树进行了很好的着色,部分带有彩色线条信息。这是我的shell方法,它与我在这里对类似表的输出的第一个答案相结合(https://stackoverflow.com/a/61487052).
特征:
您可以定义所有树的颜色你可以用相应的分支颜色染每一列可以将树列放置在不同的位置您可以使用各种git日志别名可以为每个别名定义树列编号你可以通过管道将其输入到较小的-r中,以获取巨大的历史记录
如何使用:
根据下面提到的格式说明,定义您的git日志别名,如所示的几个答案,例如Slipp D.、albfan、kaoru,并将其与代码片段一起粘贴到.gitconfig文件中。从项目路径调用它,通常使用
git-colord YourLogAlias或
git colored YourLogAlias TreeColumnNumber以动态放置树列。
格式化说明:
您的git日志别名必须遵循以下格式规则:
使用唯一字符作为每个提交占位符的列分隔符^…格式:“%h%cr%s”-->。。。格式:“^%h^%cr^%s”将整列用一种颜色着色,或将其留空以采用相应的分支颜色…格式:“^%h^%cr^%s”-->。。。格式:“^%h^%cr^%C(白色)%s%C(重置)”(哈希值和时间为分支颜色)必须使用trunc选项之一通过%><(<N>[,ltrunc|mtrunc|trunc])指定任何列的宽度,但是可以使用行上的任何最后一个提交占位符而不使用它…格式:“^%h^%cr^%C(白色)%s%C(重置)”-->。。。格式:“^%<(7,trunc)%h^%<如果需要额外的修饰字符,请将它们直接放置在提交占位符周围,即提交:…^%C(白色)%<(50,截断)%s%C(重置)…-->…^%C(白色)%<(50,trunc)提交:%s%C(重置)。。。如果使用换行符%n请将它们放在列分隔符之前或末尾…^%C(白色)%<(50,trunc)提交:%s%C(重置)'-->…%n ^%C(白色)%<(50,trunc)提交:%s%C(重置)%n'如果使用列颜色,如上面的%C(白色),则需要添加--color选项…格式:'^%<(7,trunc)%h.…-->--颜色格式:'^%<(7,trunc)%h。。。如果使用--stat选项或类似选项,请在末尾添加一个换行符%n…--stat..格式:“…”-->--stat..格式:“…%n”
其他:
对于具有非空换行符的git日志别名…%n%提交占位符。。。,只有当每行的所有第n列都存在并且使用相同的宽度时,才能将Git图放置在每列n+1处如果在文件.gitconfig中为YourLogAlias定义TreeColumnNumber,则YourLogAlias col必须是名称与正常的git日志输出相比,这个输出速度慢,但很好
示例:
git彩色lgc1
git彩色lgc2
git彩色lgc3
git彩色lgc4
代码段:
将以下行添加到.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)、颜色列表和YourLogAlias加载到shell变量中第二个读取每列的长度第三个计算树的最大长度第四个将树加载到数组中第五部分根据案例分析为树上色第六个为非树列着色,并打印类似表的输出
最大的部分是设置树颜色的案例分析。其他部分在我对类似于表的shell输出的链接答案中进行了解释。
请在评论中显示您最喜欢的格式化日志别名,因为我的只是示例。
其他回答
我添加了三个自定义命令:gittree、gitstree和gitvtree。我会按顺序检查它们。
[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)'
使用gitstree和gitvtree,我使用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”显然在这个版本中首次出现。这是一个很好的补充,因为分支名称将获得不同的颜色。例如,这使得区分本地分支和远程分支更加容易。
一个漂亮整洁的表,如外壳的Git图形输出
除了图树之外,通常使用哈希
或在额外的列中
编辑:你想在不阅读所有解释的情况下立即开始吗?跳转至EDIT 6。
信息:对于外壳的更像分支的彩色版本,请参见我的第二个答案(https://stackoverflow.com/a/63253135/).
在对这个问题的所有回答中,到目前为止,没有一个显示出类似于查找外壳输出的干净表格。最接近的答案是我刚开始时的小鹅。
我的方法的核心点是只计算显示给用户的树字符。然后用空格填充到个人长度。
除了Git,你还需要这些工具
希腊语粘贴输出函数已安装的序列号第三方厕所
大多数是在任何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”或结尾“trunk”截断字符。
重要的是,上面的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”,就像在EDIT 3中一样。
编辑3:也许对于分支和标记条目,“自动”颜色选项是您最喜欢的选项?
更改git命令的这部分(颜色214)
%C(214)%>(15,trunc)%D%C(reset)
自动
%C(auto)%>(15,trunc)%D%C(reset)
编辑4:或者你喜欢你自己的颜色组合,一个闪烁着脑袋的花哨输出?
为了能够首先设置头部、分支名称和标记的样式,我们需要在git命令中使用“auto”颜色选项,如EDIT3中所示。
然后,我们可以通过添加这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"
在我们的代码段中。替换值产生上述颜色。
例如,水头的替换值为
3;5;1;38;5;196
其中3;代表斜体,5;用于闪烁和1;38;5.196表示颜色。有关更多信息,请从这里开始。注意:此行为取决于您喜爱的终端,因此可能不可用。
但你可以选择任何你喜欢的颜色值。
数字颜色值和ANSI等效值概述
您可以在这里找到带有git颜色/样式选项的列表。
如果您需要控制台上的输出以获得准确的颜色(上面的图片由堆栈溢出缩小),您可以使用
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) 作为别名:
别名不接受参数,但函数可以,因此只需在.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项目路径下调用函数gittable(从类表中派生),或者从任何您想要的地方调用,将git项目的路径作为第一个参数。
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日志输出
眨眼太多!只是为了证明什么是可能的。指定的颜色太少会导致颜色重复。
只需单击一下即可获得完整的.gitconfig引用。
编辑6:由于你的支持,我改进了这个片段。现在,您可以用几乎任何gitlog命令来输入它,而不必再调整代码。试试看!
它是如何工作的?
一如既往地在.gitconfig中定义Git日志命令(格式如下)定义一个正树列编号,其中显示git图(可选)
那就打电话
git tably YourLogAlias
在任何git项目路径下或
git tably YourLogAlias目录号
其中TreeClNumber覆盖上面始终定义的值。
git tably YourLogAlias | less-r
将把输出管道输送到较少的位置,这对于巨大的历史记录非常有用。您的Git日志别名必须遵循以下格式规则:
每一列都必须由一个列分隔符表示,您必须选择该分隔符,如果不是唯一的,可能会导致问题即^ in。。。格式:“^%h^%cr^%s”生成树、哈希、时间和提交列在日志命令中必须使用的每个提交占位符之前%><(<N>[,ltrunc|mtrunc|trunk]),带有trunk选项之一(有关语法解释,请参见https://git-scm.com/docs/pretty-formats),但是,任何换行符的最后一个提交占位符都可以在没有它的情况下使用即…格式:“^%<(7,trunc)%h^%<如果装饰需要额外的字符,如(committer:,<and>)…%C(暗白色)(提交人:%cn%<%ce>)%C(重置)。。。要获得类似表的输出,必须在提交占位符之前和之后直接写入它们即…%C(暗淡的白色)%<(25,trunc)(提交人:%cn%<(25,trunk)<%ce>)%C(重置)。。。使用列颜色,如%C(白色)…%C(重置)需要彩色输出的--color选项即…--颜色…格式:'^%C(白色)%<(7,trunk)%h%C(重置)。。。如果使用--stat选项或类似选项,请在末尾添加一个换行符%n即…--stat.…格式:“…%n”。。。只要不使用换行符或仅使用空字符格式,就可以在每一列中放置git图形:'…%没有对于非空换行符…%n%提交占位符。。。只有当每行的所有第n列都存在并且使用相同的宽度时,才能将git图放置在每列n+1处为特定日志别名定义的树列编号的名称必须为YourLogAlias col
与正常的git日志输出相比,这个输出速度慢,但很好。
现在将改进的代码段添加到.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"
在tably
第一段将delim(iter)、YourLogAlias和YourLogAlias列加载到shell变量中第二个读取每列的长度第三个计算树的最大长度第四个将树加载到数组中第五个组织并打印类似表格的输出
结果:
或使用新的TreeColNumber
再次:尽情地设计自己的干净桌子,就像根据自己的需要寻找输出一样。
您还可以在评论中共享您首选的格式化Git日志别名。我会不时地在上面的文字中加入评分最高的,并添加图片。
稍微调整一下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"
你现在可以做的一切
git lgBranch1 <branch name>
甚至
git lgBranch1 --all
如果您正在使用macOS,可以尝试GitUp:
x轴:分支y轴:时间
我在~/.gitconfig中有这个git日志别名来查看图形历史:
[alias]
l = log --all --graph --pretty=format:'%C(auto)%h%C(auto)%d %s %C(dim white)(%aN, %ar)'
有了这一点,git l将输出如下内容:
在Git2.12+中,您甚至可以使用log.graphColors配置选项自定义图形的线条颜色。
至于日志的格式,它类似于--oneline,添加了作者名(尊重.mailmap)和相对作者日期。请注意,在Git>=1.8.3中支持%C(auto)语法,告诉Git使用提交散列等的默认颜色。
推荐文章
- 当git说它正在“解析delta”时,它实际上在做什么?
- Git命令将一个文件夹移动到另一个文件夹
- 在单个文件中重新启动/撤消冲突解决方案
- Visual Studio代码如何解决合并冲突与git?
- 无法推送到远程分支,无法解析到分支
- Git:如何将数据库重置为特定的提交?
- 如何在合并期间使用Git和命令行保存本地文件或远程文件?
- 能够用一个命令推到所有git遥控器?
- 重新基于Git合并提交
- 忽略已经签入目录的内容?
- 如何从windows cmd保存git提交消息?
- (Mac) -bash: __git_ps1:命令未找到
- 如何删除多个已删除的文件在Git仓库
- 使用vimdiff查看所有' git diff '
- 如何拉特定的目录与git