• Git系列,自定义 git 命令,用 shell 脚本帮助你更好的实现 git 版本控制


    一、问题引出

    在实际的生产当中,无论是 git、小乌龟 git 、idea git 插件,都满足不了我们生产中遇到的一些常见的问题,例如:

    • 工作任务重的时候,手头上可能有若干个分支,每个分支对应着不同的业务,这时我们怎么区分哪个分支对应着哪个任务呢?
    • 我只想看到当前分支是哪个业务的分支,还不想输入烦人的超长命令,怎么办?
    • 我想在任意分支上查询最近六个月来自己提交过哪些文件,改动了多少行,每次改动具体修改了什么,怎么办?
    • ......

    二、解决问题的思路

    如果你从未有或者几乎没有接触过脚本编程,你或许会很烦那些进行命令操作的人,会觉得他们在装逼,在耍酷,GUI有多爽,多简单,为何非要输那些命令呢?这很正常,我也理解,因为每个人都是这么走过来的,就像你刚学 Linux 和用了三年 Linux 后的你一样;你会发现入门的时候有多么痛苦,但你也会发现,当你真正迈入 Shell 的世界之后,原来曾经的痛苦是值得的!

    我以一个过来人的身份告诉你无论是 cmd、bat、linux shell、python shell、vb 还是其他的任何脚本编程语言,他们的价值远远大于你的想象,学会了它们的任何一种,你的工作效率可以最少提高 30% 以上,甚至翻倍!!!下面我说下原因:

    • 一个再好的软件都是针对普罗大众的,不是为私人定制的,它不可能做到让所有人都满意,拿 git 来说,我个人觉得 git 是目前最优秀的版本控制工具,没有之一,曾经有个同事跟我说,学会了 git 你就相当于掌握了项目的时间法则,可以买到后悔药,可以分身,可以不限条件的回忆之前发生的点点滴滴 ......,但是它依旧有它的不足,比如我在 一 提出的问题,我可以毫无疑问的告诉你,我提出的那些问题 git 可以很完美的做到,但是代价也很大——命令太长,需要记忆很多参数,不可复用,下次还得再敲一遍,所以我们需要用我们喜欢的命令,参数来简化它,改造它
    • 任何一款软件,它的 Gui 功能相比于它的 命令模式,至少阉割了 30%,换句话说就是,同一个软件,它在 GUI 上做不了的事,不代表它在 命令行模式下 完不成
    • 如果你已经走入 Shell 世界大门超过两年,你会毫不犹豫的承认在某些特定的情形下 命令行 效率要比 点点点 的 GUI操作 高很多,而这样的情形会每天都出现,这条只有亲身体验才能感受到,所以不要和 GUI 党争论,没有意义

    下面我们开门见山的说本篇论文的重点——Git,用到的技术是 Linux Shell,但是注意,Wiindows 操作系统支持,因为 Git Windows 版也提供了 Shell 解析系统——不得不承认,Git 的作者太顶了,不然我们还得将 shell 命令转为 cmd bat 脚本

    三、实战操作

    1. 为分支添加注释

    1️⃣ 在 git 安装目录下的 /etc/gitconfig 配置文件中添加如下代码

    1. [alias]
    2. # adddesc 可以自定义自己喜欢的名字
    3. # adddesc.sh 是我们之后需要新建的 shell 脚本
    4. adddesc = !sh adddesc.sh

    2️⃣ 在 git 安装目录下的 usr/bin 目录下新建自己的命令脚本 adddesc.sh,并且编辑如下代码

    1. #! /bin/bash
    2. typeset all_branches=`git branch -a`
    3. typeset obj_branch=$1
    4. typeset obj_desc=$2
    5. typeset is_exist="0"
    6. init_arg(){
    7. if [ -z "$obj_branch" ] || [ -z "$obj_desc" ]; then
    8. echo "分支名、分支注释内容不可为空"
    9. exit 1
    10. fi
    11. for curr_branch in $all_branches
    12. do
    13. if [ $obj_branch == $curr_branch ]; then
    14. is_exist="1"
    15. break
    16. fi
    17. done
    18. if [ "$is_exist" == "0" ]; then
    19. echo "目标分支不存在, 核实后重试"
    20. exit 1
    21. fi
    22. if [ ${#obj_desc} -le 0 ] || [ ${#obj_desc} -ge 51 ]; then
    23. echo "注释内容长度(1-50)不合适,请重新配置"
    24. exit 1
    25. fi
    26. }
    27. add_desc(){
    28. git config branch."$obj_branch".description $obj_desc
    29. }
    30. init_arg
    31. add_desc

    3️⃣ 使用命令为自己的分支添加注释

    git adddesc <分支名> <分支注释内容>

    2. 查看所有分支的注释

    1️⃣ 在 git 安装目录下的 /etc/gitconfig 配置文件中添加如下代码

    1. [alias]
    2. descs = !sh descs.sh

    2️⃣ 在 git 安装目录下的 usr/bin 目录下新建自己的命令脚本 descs.sh,并且编辑如下代码

    1. #! /bin/bash
    2. typeset all_branches=$(git for-each-ref --format='%(refname)' refs/heads/ | sed 's|refs/heads/||')
    3. show_descs(){
    4. for curr_branch in $all_branches
    5. do
    6. typeset curr_desc=`git config branch."$curr_branch".description`
    7. echo "$curr_branch ------> $curr_desc"
    8. done
    9. }
    10. show_descs

    3️⃣ 使用命令查看所有分支的注释

    git descs

    3. 查看当前分支及其注释

    1️⃣ 在 git 安装目录下的 /etc/gitconfig 配置文件中添加如下代码

    1. [alias]
    2. curr = !sh curr.sh

    2️⃣ 在 git 安装目录下的 usr/bin 目录下新建自己的命令脚本 curr.sh,并且编辑如下代码

    1. #! /bin/bash
    2. typeset curr_branch=`git rev-parse --abbrev-ref HEAD`
    3. typeset curr_desc=`git config branch."$curr_branch".description`
    4. show_desc(){
    5. echo "$curr_branch ------> $curr_desc"
    6. }
    7. show_desc

    3️⃣ 使用命令查看当前所在分支及其注释

    git curr

    4. 自定义 git log 命令

    1. 笔者封装的这个命令可谓相当强大,可以根据以下条件筛选 git log 日志

    1. 分支名

    2. 提交者

    3. 提交过的文件名

    4. 提交过的文件中包含的内容

    5.提交注释

    6. 起始日期,结束日期

    2. 筛选出来的 git log 日志会显示 谁在什么时候提交了哪些文件,是修改了还是新增了还是删除了,每个文件改动多少行,具体改动内容是什么

    3. 可以对比某个分支(或commit点)相对与某个分支(或commit点)多出了哪些提交,这在发版时非常需要,可以防止合并错代码,提交了不必要的提交

    1️⃣ 在 git 安装目录下的 /etc/gitconfig 配置文件中添加如下代码

    1. [alias]
    2. find = !sh find.sh

    2️⃣ 在 git 安装目录下的 usr/bin 目录下新建自己的命令脚本 find.sh,并且编辑如下代码

    1. #! /bin/bash
    2. # @author huhai
    3. # @skill linxu shell
    4. # @message git 日志查看脚本
    5. # 命令及参数
    6. typeset command="git log"
    7. typeset argv=" --no-merges --date=format:'%Y-%m-%d %H:%M:%S'"
    8. typeset pretty=" --pretty=\"%n%n%n%Cred[%cd]%Cgreen<%cn %ce>%C(yellow)[%H]%n%Creset%s\""
    9. # 输出文件路径
    10. typeset outfile="~/Desktop/lanyue.log"
    11. # 入参
    12. typeset branch
    13. typeset username
    14. typeset email
    15. typeset file
    16. typeset context
    17. typeset message
    18. typeset startdate
    19. typeset enddate
    20. typeset basepoint
    21. typeset standpoint
    22. # -a 代表数组
    23. typeset -a all_branches
    24. typeset is_detail="0"
    25. typeset is_out="0"
    26. typeset is_print="0"
    27. # 帮助信息
    28. showhelp(){
    29. echo "-h [无参] help:帮助命令"
    30. echo "-d [无参] detail:将每次提交的文件修改详细列出"
    31. echo "-a [无参] about:将每次提交的文件修改行数列出"
    32. echo "-o [无参] out:输出结果到桌面的 lanyue.log 文件"
    33. echo "-p [无参] print:将完整的命令打印而不是执行"
    34. echo "\n"
    35. echo "-b [有参] branch:匹配分支名"
    36. echo "-u [有参] user:匹配作者"
    37. echo "-e [有参] email:匹配email"
    38. echo "-f [有参] file:匹配提交文件"
    39. echo "-c [有参] context:匹配提交文件所包含的内容"
    40. echo "-m [有参] message:匹配提交注释"
    41. echo "-x [有参] (获取 分支|commit 之间的commit历史) 基点"
    42. echo "-y [有参] (获取 分支|commit 之间的commit历史) 变点"
    43. echo "-S [有参] Start:匹配开始日期"
    44. echo "-E [有参] End:匹配结束日期"
    45. exit 1
    46. }
    47. # 报错信息
    48. errorinfo(){
    49. echo "出错可能是以下原因:"
    50. echo "1. 未知参数,请使用 -h 查看帮助信息"
    51. echo "2. 未给有参子命令提供参数值"
    52. exit 1
    53. }
    54. # 入参定义
    55. while getopts ":hadopb:u:e:f:c:m:x:y:S:E:" option
    56. do
    57. case $option in
    58. b)
    59. branch=$OPTARG
    60. ;;
    61. u)
    62. username=$OPTARG
    63. ;;
    64. e)
    65. email=$OPTARG
    66. ;;
    67. f)
    68. file=$OPTARG
    69. ;;
    70. c)
    71. context=$OPTARG
    72. ;;
    73. m)
    74. message=$OPTARG
    75. ;;
    76. x)
    77. basepoint=$OPTARG
    78. ;;
    79. y)
    80. standpoint=$OPTARG
    81. ;;
    82. S)
    83. startdate=$OPTARG
    84. ;;
    85. E)
    86. enddate=$OPTARG
    87. ;;
    88. a)
    89. is_detail="1"
    90. ;;
    91. d)
    92. is_detail="2"
    93. ;;
    94. o)
    95. is_out="1"
    96. ;;
    97. p)
    98. is_print="1"
    99. ;;
    100. h)
    101. showhelp
    102. ;;
    103. ?)
    104. errorinfo
    105. ;;
    106. esac
    107. done
    108. # 初始化分支信息
    109. init_branch(){
    110. # 判断目标分支是否真实存在的标志
    111. typeset is_exist="0"
    112. # 如果没有输入分支,则默认当前分支为操作对象
    113. if [ -z "$branch" ]; then
    114. branch=`git symbolic-ref --short HEAD`
    115. fi
    116. # 判断输入分支是否合法(存在)
    117. all_branches=`git branch -a`
    118. for curr_branch in $all_branches
    119. do
    120. if [ $curr_branch == $branch ]; then
    121. is_exist="1"
    122. break
    123. fi
    124. done
    125. if [ $is_exist == "0" ]; then
    126. echo "目标分支 [-b 参数] 不存在,请核实后重试"
    127. exit 1
    128. fi
    129. command=$command" "$branch
    130. }
    131. # 初始化比较信息,用于得到 standpoint 相较于 basepoint 多了的提交历史
    132. init_compare(){
    133. if [ ! -z "$basepoint" ]; then
    134. if [ -z "$standpoint" ]; then
    135. standpoint=`git symbolic-ref --short HEAD`
    136. fi
    137. fi
    138. if [ ! -z "$standpoint" ]; then
    139. if [ -z "$basepoint" ]; then
    140. basepoint=`git symbolic-ref --short HEAD`
    141. fi
    142. fi
    143. if [ ! -z "$basepoint" ] && [ ! -z "$standpoint" ]; then
    144. command="git log"
    145. command=$command" "$basepoint".."$standpoint
    146. fi
    147. }
    148. # 初始化开始日期信息
    149. init_startdate(){
    150. if [ ! -z "$startdate" ]; then
    151. typeset date_type=`echo $startdate | grep -v '[^0-9]' > /dev/null && /dev/null && echo "number" || echo "string"`
    152. if [ "$date_type" == "string" ]; then
    153. echo "开始日期不合法,必须为数字类型"
    154. exit 1
    155. elif [ "$date_type" == "number" ]; then
    156. typeset date_length=`echo ${#startdate}`
    157. if [ "$date_length" -ne 8 ]; then
    158. echo "开始日期长度不合法,必须为合法8位日期"
    159. exit 1
    160. fi
    161. else
    162. echo "未知错误,异常退出"
    163. exit 1
    164. fi
    165. # 格式化日期
    166. typeset year=${startdate:0:4}
    167. typeset month=${startdate:4:2}
    168. typeset day=${startdate:6:2}
    169. typeset startdate_final=$year"-"$month"-"$day
    170. argv=$argv" --after=""$startdate_final"
    171. fi
    172. }
    173. # 初始化结束日期信息
    174. init_enddate(){
    175. if [ ! -z "$enddate" ]; then
    176. typeset date_type=`echo $enddate | grep -v '[^0-9]' > /dev/null && /dev/null && echo "number" || echo "string"`
    177. if [ "$date_type" == "string" ]; then
    178. echo "结束日期不合法,必须为数字类型"
    179. exit 1
    180. elif [ "$date_type" == "number" ]; then
    181. typeset date_length=`echo ${#enddate}`
    182. if [ "$date_length" -ne 8 ]; then
    183. echo "结束日期长度不合法,必须为合法8位日期"
    184. exit 1
    185. fi
    186. else
    187. echo "未知错误,异常退出"
    188. exit 1
    189. fi
    190. # 格式化日期
    191. typeset year=${enddate:0:4}
    192. typeset month=${enddate:4:2}
    193. typeset day=${enddate:6:2}
    194. typeset enddate_final=$year"-"$month"-"$day
    195. argv=$argv" --before=""$enddate_final"
    196. fi
    197. }
    198. # 初始化 作者 和 email 信息
    199. init_author_email(){
    200. typeset is_set="0"
    201. if [ ! -z "$username" ]; then
    202. argv="$argv"" --committer=""$username"
    203. is_set="1"
    204. fi
    205. if [ "$is_set" == "0" ] && [ ! -z "$email" ]; then
    206. argv="$argv"" --committer=""$email"
    207. fi
    208. }
    209. # 是否显示每次提交的详细信息
    210. init_show_detail(){
    211. if [ "$is_detail" == "1" ]; then
    212. argv="$argv"" --numstat"
    213. elif [ "$is_detail" == "2" ]; then
    214. argv="$argv"" -p"
    215. else
    216. argv="$argv"" --name-status"
    217. fi
    218. }
    219. # 匹配提交文件名
    220. init_commit_file(){
    221. if [ ! -z "$file" ]; then
    222. argv="$argv"" --*""$file""*"
    223. fi
    224. }
    225. # 匹配提交内容
    226. init_commit_context(){
    227. if [ ! -z "$context" ]; then
    228. argv="$argv"" -S""\"""$context""\""
    229. fi
    230. }
    231. # 匹配提交注释
    232. init_commit_message(){
    233. if [ ! -z "$message" ]; then
    234. argv="$argv"" --grep ""$message"
    235. fi
    236. }
    237. # 执行命令
    238. exec_command(){
    239. if [ "$is_out" == "1" ]; then
    240. cmd="$command""$argv""$pretty"" > ""$outfile"
    241. else
    242. cmd="$command""$argv""$pretty"
    243. fi
    244. if [ "$is_print" == "1" ]; then
    245. echo "$cmd"
    246. else
    247. eval "$cmd"
    248. fi
    249. }
    250. # 调用函数
    251. init_branch
    252. init_compare
    253. init_startdate
    254. init_enddate
    255. init_author_email
    256. init_show_detail
    257. init_commit_file
    258. init_commit_context
    259. init_commit_message
    260. exec_command

    3️⃣ 使用命令查看日志

    git find [可选参数]

    4️⃣ 简单示例

     

     

  • 相关阅读:
    检查OpenGL的版本
    MySQL触发器
    曝 15 寸 iPad 或将变身 Mac?谷歌:大屏设备应具备智能手机体验
    python: 用百度API读取增值税发票信息
    【云原生】基于Kubernetes开发的阿里云ACK之存储管理
    冰达ROS机器人快速使用指南
    4.Linux系统管理(组的管理,系统操作)
    基于.NetCore开发博客项目 StarBlog - (30) 实现评论系统
    Selenium--常用元素操作方法
    Android Gradle插件与Gradle的区别
  • 原文地址:https://blog.csdn.net/ITlanyue/article/details/128160540