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 配置文件中添加如下代码

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

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

#! /bin/bash

typeset all_branches=`git branch -a`
typeset obj_branch=$1
typeset obj_desc=$2
typeset is_exist="0"

init_arg(){
	if [ -z "$obj_branch" ] || [ -z "$obj_desc" ]; then
		echo "分支名、分支注释内容不可为空"
		exit 1
	fi

	for curr_branch in $all_branches
	do
		if [ $obj_branch == $curr_branch ]; then
			is_exist="1"
			break
		fi
	done

	if [ "$is_exist" == "0" ]; then
		echo "目标分支不存在, 核实后重试"
		exit 1
	fi

	if [ ${#obj_desc} -le 0 ] || [ ${#obj_desc} -ge 51 ]; then
		echo "注释内容长度(1-50)不合适,请重新配置"
		exit 1
	fi
}


add_desc(){	
	git config branch."$obj_branch".description $obj_desc
}

init_arg
add_desc

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

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

2. 查看所有分支的注释

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

[alias]
    descs = !sh descs.sh

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

#! /bin/bash

typeset all_branches=$(git for-each-ref --format='%(refname)' refs/heads/ | sed 's|refs/heads/||')

show_descs(){
	for curr_branch in $all_branches
	do
		typeset curr_desc=`git config branch."$curr_branch".description`
		echo "$curr_branch ------> $curr_desc"
	done
}

show_descs

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

git descs

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

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

[alias]
    curr = !sh curr.sh

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

#! /bin/bash

typeset curr_branch=`git rev-parse --abbrev-ref HEAD`
typeset curr_desc=`git config branch."$curr_branch".description`

show_desc(){
	echo "$curr_branch ------> $curr_desc"
}

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 配置文件中添加如下代码

[alias]
    find = !sh find.sh

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

#! /bin/bash
# @author		huhai
# @skill		linxu shell
# @message		git 日志查看脚本

# 命令及参数
typeset command="git log"
typeset argv=" --no-merges --date=format:'%Y-%m-%d %H:%M:%S'"
typeset pretty=" --pretty=\"%n%n%n%Cred[%cd]%Cgreen<%cn %ce>%C(yellow)[%H]%n%Creset%s\""

# 输出文件路径
typeset outfile="~/Desktop/lanyue.log"

# 入参
typeset branch
typeset username
typeset email
typeset file
typeset context
typeset message
typeset startdate
typeset enddate
typeset basepoint
typeset standpoint
# -a 代表数组
typeset -a all_branches
typeset is_detail="0"
typeset is_out="0"
typeset is_print="0"



# 帮助信息
showhelp(){
	echo "-h [无参]	help:帮助命令"
	echo "-d [无参]	detail:将每次提交的文件修改详细列出"
	echo "-a [无参]	about:将每次提交的文件修改行数列出"
	echo "-o [无参]	out:输出结果到桌面的 lanyue.log 文件"
	echo "-p [无参] print:将完整的命令打印而不是执行"

	echo "\n"

	echo "-b [有参] branch:匹配分支名"
	echo "-u [有参] user:匹配作者"
	echo "-e [有参] email:匹配email"
	echo "-f [有参] file:匹配提交文件"
	echo "-c [有参] context:匹配提交文件所包含的内容"
	echo "-m [有参] message:匹配提交注释"
	echo "-x [有参] (获取 分支|commit 之间的commit历史) 基点"
	echo "-y [有参] (获取 分支|commit 之间的commit历史) 变点"
	echo "-S [有参] Start:匹配开始日期"
	echo "-E [有参] End:匹配结束日期"
	exit 1
}

# 报错信息
errorinfo(){
	echo "出错可能是以下原因:"
	echo "1. 未知参数,请使用 -h 查看帮助信息"
	echo "2. 未给有参子命令提供参数值"
	exit 1
}

# 入参定义
while getopts ":hadopb:u:e:f:c:m:x:y:S:E:" option
do
	case $option in
		b)
			branch=$OPTARG
			;;
		u)
			username=$OPTARG
			;;
		e)
			email=$OPTARG
			;;
		f)
			file=$OPTARG
			;;
		c)
			context=$OPTARG
			;;
		m)
			message=$OPTARG
			;;
		x)
			basepoint=$OPTARG
			;;
		y)
			standpoint=$OPTARG
			;;
		S)
			startdate=$OPTARG
			;;
		E)
			enddate=$OPTARG
			;;
		a)
			is_detail="1"
			;;
		d)
			is_detail="2"
			;;
		o)
			is_out="1"
			;;
		p)
			is_print="1"
			;;
		h)
			showhelp
			;;
		?)
			errorinfo
			;;
	esac
done



# 初始化分支信息
init_branch(){
	# 判断目标分支是否真实存在的标志
	typeset is_exist="0"

	# 如果没有输入分支,则默认当前分支为操作对象
	if [ -z "$branch" ]; then
		branch=`git symbolic-ref --short HEAD`
	fi

	# 判断输入分支是否合法(存在)
	all_branches=`git branch -a`
	for curr_branch in $all_branches
	do
		if [ $curr_branch == $branch ]; then
			is_exist="1"
			break
		fi
	done

	if [ $is_exist == "0" ]; then
		echo "目标分支 [-b 参数] 不存在,请核实后重试"
		exit 1
	fi

	command=$command" "$branch
}

# 初始化比较信息,用于得到 standpoint 相较于 basepoint 多了的提交历史
init_compare(){
	if [ ! -z "$basepoint" ]; then
		if [ -z "$standpoint" ]; then
			standpoint=`git symbolic-ref --short HEAD`
		fi
	fi

	if [ ! -z "$standpoint" ]; then
		if [ -z "$basepoint" ]; then
			basepoint=`git symbolic-ref --short HEAD`
		fi
	fi

	if [ ! -z "$basepoint" ] && [ ! -z "$standpoint" ]; then
		command="git log"
		command=$command" "$basepoint".."$standpoint
	fi
}

# 初始化开始日期信息
init_startdate(){
	if [ ! -z "$startdate" ]; then
		typeset date_type=`echo $startdate | grep -v '[^0-9]' > /dev/null && /dev/null && echo "number" || echo "string"`

		if [ "$date_type" == "string" ]; then
			echo "开始日期不合法,必须为数字类型"
			exit 1
		elif [ "$date_type" == "number" ]; then
			typeset date_length=`echo ${#startdate}`
			if [ "$date_length" -ne 8 ]; then
				echo "开始日期长度不合法,必须为合法8位日期"
				exit 1
			fi
		else
			echo "未知错误,异常退出"
			exit 1
		fi
		
		# 格式化日期
		typeset year=${startdate:0:4}
		typeset month=${startdate:4:2}
		typeset day=${startdate:6:2}

		typeset startdate_final=$year"-"$month"-"$day

		argv=$argv" --after=""$startdate_final"
	fi
}

# 初始化结束日期信息
init_enddate(){
	if [ ! -z "$enddate" ]; then
		typeset date_type=`echo $enddate | grep -v '[^0-9]' > /dev/null && /dev/null && echo "number" || echo "string"`

		if [ "$date_type" == "string" ]; then
			echo "结束日期不合法,必须为数字类型"
			exit 1
		elif [ "$date_type" == "number" ]; then
			typeset date_length=`echo ${#enddate}`
			if [ "$date_length" -ne 8 ]; then
				echo "结束日期长度不合法,必须为合法8位日期"
				exit 1
			fi
		else
			echo "未知错误,异常退出"
			exit 1
		fi
		
		# 格式化日期
		typeset year=${enddate:0:4}
		typeset month=${enddate:4:2}
		typeset day=${enddate:6:2}

		typeset enddate_final=$year"-"$month"-"$day

		argv=$argv" --before=""$enddate_final"
	fi
}

# 初始化 作者 和 email 信息
init_author_email(){
	typeset is_set="0"

	if [ ! -z "$username" ]; then
		argv="$argv"" --committer=""$username"
		is_set="1"
	fi

	if [ "$is_set" == "0" ] && [ ! -z "$email" ]; then
		argv="$argv"" --committer=""$email"
	fi
}

# 是否显示每次提交的详细信息
init_show_detail(){
	if [ "$is_detail" == "1" ]; then
		argv="$argv"" --numstat"
	elif [ "$is_detail" == "2" ]; then
		argv="$argv"" -p"
	else
		argv="$argv"" --name-status"
	fi
}

# 匹配提交文件名
init_commit_file(){
	if [ ! -z "$file" ]; then
		argv="$argv"" --*""$file""*"
	fi
}

# 匹配提交内容
init_commit_context(){
	if [ ! -z "$context" ]; then
		argv="$argv"" -S""\"""$context""\""
	fi
}

# 匹配提交注释
init_commit_message(){
	if [ ! -z "$message" ]; then
		argv="$argv"" --grep ""$message"
	fi
}

# 执行命令
exec_command(){
	if [ "$is_out" == "1" ]; then
		cmd="$command""$argv""$pretty"" > ""$outfile"
	else
		cmd="$command""$argv""$pretty"
	fi

	if [ "$is_print" == "1" ]; then
		echo "$cmd"
	else
		eval "$cmd"
	fi
}



# 调用函数
init_branch
init_compare
init_startdate
init_enddate
init_author_email
init_show_detail
init_commit_file
init_commit_context
init_commit_message
exec_command

3️⃣ 使用命令查看日志

git find [可选参数]

4️⃣ 简单示例

 

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT蓝月

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值