git pull 每次拉代码自动发送到钉钉群

钉钉群的关于机器人的官网开发文档,我们可以知道,核心的代码就是 curl 一句。

curl 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxx' \
   -H 'Content-Type: application/json' \
   -d '{"msgtype": "text", 
        "text": {
             "content": "我就是我, 是不一样的烟火"
        }
      }'

获取 token 所在的URL 的办法,就是在群设置里面有个只能群助手,添加一个自定义机器人即可,这里面的核心是关键字的设置,要求发送的文本内容里必须包含关键字才能触发机器人。我们把关键字定义为 gitpull,所以只要发送的消息里有gitpull 关键字,机器人就会自动发送,钉钉会把消息发送到群里。

我们把原生的 git 修改为 /usr/bin/git.orig 重新写一个新的 /usr/bin/git 的脚本如下:

#!/bin/bash
TOKEN="xxx"
URL="https://oapi.dingtalk.com/robot/send?access_token=$TOKEN"
TEXT="[gitpull] User: "$(id -un)" pulling code in dir: "$(pwd)
/usr/bin/git.orig $*
if [ $? == 0 -a "$1" == "pull" ]
then
        # echo "Pulling Code"
        curl $URL -H 'Content-Type: application/json' \
                -d '{"msgtype": "text","text": {"content": "'"$TEXT"'" }}'
        echo
fi

这样每次拉取代码,我们就能在钉钉群里得到消息,知道是谁在拉什么代码

关于代码开发中的 Changelog

因为我们在做一个项目的自动版本更新(让用户手动点击更新 SaaS 软件的版本),开发中混乱的版本管理和 Commit 注释,有时候让人抓狂。

这里有两个链接或许值得阅读:
https://keepachangelog.com/en/1.0.0/
https://co-pilot.dev/changelog#best-practices-release-dates-apply

  • Changelog 的正式文件名就叫 CHANGELOG.md
  • 必须是倒排序的
  • 用 ISO 格式(YYYY-MM-DD)来写日期,并和版本号一起写在每个 Change 的开头
  • 对不同的修改进行归类
  • 高亮重大的修改和功能废弃

这篇文章里有比较好的例子: https://depfu.com/blog/what-makes-a-good-changelog
另外可以参考 github 上 MD 写作指引: https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax

git tag 的理解和版本管理的自动整合

微博中有很多 hash tag,其实来源于 Twitter,部分微信用户也会在自己的朋友圈文章中打 Hash tag,当然只是自己搜索有用,没有其他用处。

开发里有个说法:代码即文章,文章即代码;那当然是要把代码写得非常优雅才可以。 本文旨在通过 git tag 相关命令 ,对版本打标签的做法予以自动化集成到代码的 Web 界面,并能在 SaaS 情形下,让客户自己决定是否更新版本,一个鼠标点击即可完成版本升级。

先来讲一下 git 里面的两种 tag,一个叫 Annotation, 一个叫 Lightweight,我们姑且称为注释标签和轻量标签,前者带有很多 MetaData,后者则没有任何 MetaData,是跟随当前 commit 而来的。 我们先讲这个简单,也在刚开始把我们弄糊涂的轻量标签。

简单而言, 打标签是需要在代码 commit 完, push 之前做的一个步骤。 git tag -a TAGNAME 就是注释标签,没有 -a 就是轻量标签。举例

$ git commit README.md -m "先 commit 再  git tag v2.0.11"
$ git tag v2.0.11  // 添加轻量标签
$ git show v2.0.11  // 验证
commit 9cc9c4a32d581e1aed98b2378104f2d5e29c02bd (HEAD -> edu1.1, tag: v2.0.11)
$ git describe
v2.0.10-1-g9cc9c4a3
$ git show-ref --tags v2.0.11
9cc9c4a32d581e1aed98b2378104f2d5e29c02bd refs/tags/v2.0.11
$ git describe --tags
v2.0.11
$ git push  // push 代码 
$ git push origin tag v2.0.11  // push 标签

这里有一个困惑的地方就是 git describe 的输出, 没有 –tags 参数的时候,输出的其实是 v2.0.10-1-g9cc9c4a3,这是从上一个注释标签开始以来的标签。我们看下 git describe 的解释

The command finds the most recent tag that is reachable from a commit. If the tag points to the commit, then only the tag is shown. Otherwise, it suffixes the tag name with the number of additional commits on top of the tagged object and the abbreviated object name of the most recent commit. The result is a “human-readable” object name which can also be used to identify the commit to other git commands.

By default (without –all or –tags) git describe only shows annotated tags. For more information about creating annotated tags see the -a and -s options to git-tag(1).

有了对以上命令的理解,注释标签就很好解释了, 添加注释标签类似对代码 commit ,就是需要 -m 用来添加对标签的注释。 其他就是 push 的时候需要把标签一起 push 出去。

如果我们在以上一个完整的周期完成后,继续提交代码,但是遗忘了打标签,我们用 git describe 加和不加 --tags 可以看到区别:
$ git describe // 针对注释标签
v2.0.10-2-g54a3d4ca
$ git describe --tags  // 针对任意类型标签
v2.0.11-1-g54a3d4ca

我们可以用 $ git tag -l -n 3 列出所有的标签 ,3 表示输出最多3行注释
在 git 的新版本里,支持 sort
我们可以使用

git tag -l -n --sort="v:refname"

来对 v2.01 之类的版本号标签,根据版本号排序。在 sort 后面的变量前面加一个 减号,我们可以倒排序,这样,我们就可以自动生成 Release Notes 了

git tag -l -n --sort=-"v:refname"

删除远程标签:

$ git push --delete origin tagname

Vuejs 的版本管理, 可以直接用 npm version v1.x.x -m “版本注释” 直接推送, npm 会直接管理 git 版本号,然后用 $ git push origin master –follow-tags 就可以把代码和版本一并推送到代码库,然后在相应的代码文件里,直接调用 config.version 即可读取到 package.json 文件里,自定义的软件包的版本号了。

同样的对于小程序项目,没有 package.json 文件,我们可以手工创建一个:

然后,我们用同样的 npm version v1.2.3 -m “注释” 之类的打标签,然后用 git push origin master –follow-tags 把所有标签都 push 出去

后记, 每次打完标签, 要打很多字,而且 branch 的名字各不相同,写了一个 alias,放到 profile 里, 以后每次 commit 好代码,打完标签,只要敲 .push 就可以推送带标签的代码了:

alias .push='git push $(git remote|tail -1) $(git branch|awk '"'"'/^\*/ {print $NF}'"'"') $(git describe --tags)'
另外如果要查找当前目录下的版本库的顶层目录用:
$ git rev-parse --show-toplevel 

Go 语言动态追踪 git 的版本号,需要在编译时,传入版本号的变量:

ver=$(git describe --tags)
go install -ldflags "-X main.file_v=$ver" myprog.go
这里 file_v 是 main 函数里定义的变量 

git-shell 介绍一下

github 也好, 其他国内的一些 什么云也好, 基本上做私仓的话, 是要收费的。
既然 git 支持 ssh , 所以, 用自己的服务器, 其实也不算难事。
为了让 git 服务器真正成为 只能 远程 git , 不能直接 ssh 登录的话, 我们需要限制用户的 shell,用 /bin/noshell 肯定不行。 git 提供了 git-shell, 可以完成此功能。 所以我们 man git-shell 就可以知道怎么玩了。 很简单。
创建用户, 并 su – user 以后
$ chsh -s /usr/bin/git-shell
$ mkdir $HOME/git-shell-commands
$ cat > $HOME/git-shell-commands/no-interactive-login <<EOF
#!/bin/sh
printf ‘%s\n’ “你好 $USER,欢迎使用 git 管理代码库”
printf ‘%s\n’ “但是你不能使用 ssh 直接登录 git 服务器哦!”
exit 128
EOF
# chmod +x $HOME/git-shell-commands/no-interactive-login

这样用户能依旧通过 ssh 提交代码,但是不能直接登录服务器了。

git 点滴

把本地创建好的分支,强行推送到远程库创建
git push -u origin <branch>
Stackoverflow 上一个去掉特定 hash 之前的 commit 历史的脚本,实测成功!-2019/12/26
#!/bin/bash
git checkout --orphan temp $1 # create a new branch without parent history
git commit -m "Truncated history" # create a first commit on this branch
git rebase --onto temp $1 master # now rebase the part of master branch that we want to keep onto this branch
git branch -D temp # delete the temp branch

# The following 2 commands are optional - they keep your git repo in good shape.
git prune --progress # delete all the objects w/o references
git gc --aggressive # aggressively collect garbage; may take a lot of time on large repos

查看修改过的代码:
$ git status -uno –porcelain
$ git diff --name-only <starting SHA> HEAD

来自: https://git-scm.com/book/en/v2/Git-Basics-Tagging
为 git 加版本号:
$ git tag -a v1.4 -m "my version 1.4"

带 tag push 代码
$ git push origin branchname --follow-tags

查看标签指定的版本:
$ git show v1.4

为某个指定的提交后续添加版本标签:
$ git tag -a v1.2 9fceb02
提交代码:
 1. git commit -a -m "msg"  
 2. git tag v0.1.0    
 3. git push origin tag v0.1.0


正确的流程:
按照常规修改代码, commit 代码,然后 git tag -a v2.0.8 -m “…”, 然后 git describe 验证查看, git push origin tag v2.0.8 ,去另外的 git 客户端 git pull 就可以看到新的标签下载, 用 git describe 验证当前 commit 是否是正确的 v2.0.8 标签

git bash 的妙用

Git for Windows 随带了 mingw 环境,可以在 windows 下执行 Linux 的命令。当然这些命令只是 Windows 的 exe 文件,只不过有一个 Linux 的外壳。

在 git 环境下, 我们经常需要命令行下运行 git 命令,而方便的 Linux 环境,就能提供和 Linux 一致的体验。
我们甚至可以结合 putty 的 puttygen 生成的 Key 和 git bash 下的 ssh-keygen 使用相同的 key 文件,来无缝切换 windows 和 Linux 的环境。

假设 Windows 用户的用户名是 abc, 那么在 git bash 里面,默认生成的 key 在 /c/Users/abc/.ssh 下,我们可以用 puttygen 把生成的 openssh 的 key 放到这个目录下,这样子, 无论是用 putty 连接到 Linux 服务器,还是 git bash 下连接,都能有相同的 key。


设置 ssh 到 github

  1. 去 github.com 创建个人账户
  2. 在个人账户下,创建 Orgnization (可选)
  3. 同样去右上角头像,下拉进入设置(setting),点击 “SSH and GPG keys”,添加自己想添加的 SSH 公钥 ( 粘贴 ~/.ssh/id_rsa.pub 文件的内容)
  4. 选用 ssh 方式 git clone
  5. 之后就可以用 ssh 方式 git push 了

git fetch/pull 非常慢的解决办法

某同学把一些很多很大的文件 push 进入了 repo。导致后面的 pull 非常慢。
在本地删除了这些文件后,强制 push 到一个新的 Branch:
$ git push -u mzhanhui zhanhui2.1:zhanhui2.1

在生产机上 fetch branch 依旧非常缓慢,用如下命令fetch:

$ git fetch mzhanhui -u –depth 1

Usage: git fetch [<options>] [<repository> [<refspec>…]]
or: git fetch [<options>] <group>
or: git fetch –multiple [<options>] [(<repository> | <group>)…]
or: git fetch –all [<options>]

-v, –verbose be more verbose
-q, –quiet be more quiet
–all fetch from all remotes
-a, –append append to .git/FETCH_HEAD instead of overwriting
–upload-pack <path> path to upload pack on remote end
-f, –force force overwrite of local branch
-m, –multiple fetch from multiple remotes
-t, –tags fetch all tags and associated objects
-n do not fetch all tags (–no-tags)
-p, –prune prune remote-tracking branches no longer on remote
–recurse-submodules[=<on-demand>]
control recursive fetching of submodules
–dry-run dry run
-k, –keep keep downloaded pack
-u, –update-head-ok allow updating of HEAD ref
–progress force progress reporting
–depth <depth> deepen history of shallow clone
–unshallow convert to a complete repository

然后 checkout 远程的 Repo 到本地:

$ git checkout -b zhanhui2.1 mzhanhui/zhanhui2.1