repo 导出本地 git tag 给他人

使用 repo 管理了多个 git 仓库,有时需要将本地仓库的tag同步给其他人,但又不能直接推到远程(例如权限问题)。

实际场景举例

本地复现了一个问题,需要让其他人回退到相同环境来排查。

本地集成验证好了一个版本需要发布,打好tag却没有权限推送,得告知各个仓库负责人在同样的commit上打tag并推送到远程仓库。

仓库少的话,简单告知下各个仓库对应的commit号就可以了,对方手工找到对应的commit号进行操作。

涉及的仓库数量多或者本地 tag 可能发生变更需要多次同步的时候,手工操作就比较麻烦了。

自动化脚本

让我们来考虑下如何让同步本地 tag 这个事情变得简单些。(不看实现过程的话,可直接拉到最后总结部分)

后续演示基于一个简单的repo环境

mkdir test-repo; cd test-repo; repo init -u https://github.com/zqb-all/zqb-manifest repo sync #打上tag方便后续测试 repo forall -c git tag test-v1 基础命令

tag名是已知的,要提取的关键信息就只有 仓库 和 commit号。

repo可以帮我们遍历所有仓库,在每个仓库下执行git命令,使用方式是repo forall -c git xxx。

已知tagname,要获取commit号,可以通过git log tagname列出对应的commit,我们只需要一个commit,于是可以加上-1参数只列出一个提交。

组合一下就得到了

#!/bin/bash # v1 tag=$1 repo forall -c git log -1 $tag

试试效果,

$ ./repo_share_tag.sh test-v1 commit e9e78ee6df545fb057eb6baaaf9446327cabdfa7 Author: zhuangqiubin <zhuangqiubin@gmail.com> Date: Mon Apr 6 00:14:54 2020 +0800 fix typo commit 059c803e9f1d0df8e5c89aec11340224c1d85f0e Author: zqb-all <zhuangqiubin@gmail.com> Date: Fri Aug 30 10:11:51 2019 +0800 fix save name, support vim 以下省略多个commit信息

得到的结果是每个仓库对应这个tag的commit打印。

有几个问题。

没有打印仓库名

对于没有打上该tag的仓库,git log会有报错信息

打印的冗余信息太多,例如时间,commit信息等,都无关紧要,只需要唯一的commit号即可

定制格式

问题1和2可以通过为repo forall 加上-p参数来一并解决。

使用repo forall -p -c git xxx,会打印出仓库路径,并忽略错误。

问题3可以通过定制git log的格式来解决。

我是想到了平时一直在使用的一个git的alias,它可以定制git log的显示格式。

$cat ~/.gitconfig | grep "lg" lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

明显看出用--pretty=format就可以指定格式,各个参数的含义对照执行结果也容易猜测出来,不想猜就通过man git log来确认下。

如果平时没用过定制的git log输出,只要有这个想法,搜索一下也有很多介绍。

既然有git原生提供的功能,就不要自己费力气去过滤处理了。

所以问题3的解决方式是,加上--pretty=format:'%h'参数。

修改后为

#!/bin/bash # v2 tag=$1 repo forall -p -c git log -1 $tag --pretty=format:'%h'

此时就没有冗余信息了,输出格式清爽多了。

$ ./repo_share_tag.sh test-v1 project python/convertfb/ 774ddb6 project rust/cut-trailing-bytes/ e9e78ee project shell/EasierMinicom/ 059c803 project shell/PathMarker/ 4b6e219 project shell/pop-up-task-diary/ 5d85ed2 project shell/smartbc/ 9d7bc06 生成脚本

导出轻松了,但接收方还是得手工打tag。

能不能直接生成一个脚本,给到接收方运行,自动打tag呢 ?

观察下这个输出,规律很简单,一行仓库路径,一行commit号。如果每两行合为一行,再适当插入一些shell命令,应该就可以得到shell脚本了。

两行合并为一行,根据经验sed和awk应该都能做,具体命令就得搜索下了,简单搜索可得到

sed -n '{N;s/\n/\t/p}' test //sed的方法 awk '{tmp=$0;getline;print tmp"\t"$0}' test //awk方法

观察下,awk似乎更方便进一步定制,那就选awk吧

#!/bin/bash # v3 tag=$1 repo forall -p -c git log -1 $tag --pretty=format:'%h' | awk '{tmp=$0;getline;print tmp"\t"$0}'

得到的结果

$ ./repo_share_tag.sh test-v1 project python/convertfb/ 774ddb6 project rust/cut-trailing-bytes/ e9e78ee project shell/EasierMinicom/ 059c803 project shell/PathMarker/ 4b6e219 project shell/pop-up-task-diary/ 5d85ed2 project shell/smartbc/ 9d7bc06

以上的project我们是不要的,只要保留 仓库path 和 commit。这一点可以将awk命令中的$0改成$2来实现,$0是整行,$1对应project,$2则刚好是我们需要的path。

另外得再插入一些固定的字符,将 <path> <commit> 变成 cd <path> ; git tag <commit> tagname,考虑处理完一个仓库后还得要退回源目录,方便处理下一个仓库,那再加个 cd -。cd -表示回到上一个目录,很实用的命令。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgzzwp.html