git

利用 Git-hook 自动配置不同仓库的用户信息

用正确的工具,做正确的事情。

Posted by Jingh on May 21, 2018
本文阅读量:

问题的起因来自于某天一位同学的问题:“我给一个知名开源项目提交了代码,也被合并了,为什么 contributors 里面没有我?”其实,这多是因为提交代码时本地仓库的user.nameuser.email与GitHub账号不匹配导致,只有提交代码时的用户设置与自己的 GitHub 账号相匹配时,各项数据才会被 GitHub 计入统计。如下图所示,这样的 commit 记录便来自于一个用户设置和我 GitHub 账号不匹配的本地仓库。

如果你不仅使用 GitHub ,还会向公司自建的 GitLab ,以及 oschinacoding.net 等基于 Git 的托管服务商提交代码,那么便会面临这个问题:你需要为不同来源的 Git 仓库一一配置用户名与邮箱信息,来避免上述的不同步情况。然而,手动在每个本地仓库路径下都使用 git config user.namegit config user.email 命令,难免会有忘记的情况,也过于繁琐。所以,我们可以使用Git初始模板、钩子函数的特性,达到在每次clone一个新的仓库时,根据仓库来源域名的不同,自动配置不同的用户信息

  • 首先,在命令行使用该命令建立一个新的文件夹:mkdir -p ~/.git-templates/hooks

  • 然后配置git,让git知道这个文件夹是你的模板文件夹:git config --global init.templatedir ~/.git-templates

  • 接下来,在这个文件夹中新建钩子文件:vi ~/.git-templates/hooks/post-checkout

    钩子文件的内容较长,可在文末复制即可,完成之后赋予这个文件可执行权限:chmod +x ~/.git-templates/hooks/post-checkout

  • 最后,新建一个文件:vi ~/.git-clone-init

    最后一个文件是唯一一个内容需要自己配置的文件,也是整个过程的关键,意为对应不同域名下的仓库,自动配置不同的user.nameuser.email

    #!/bin/bash
    
    case "$url" in
      *@github.com:*    ) email=""; name="";;
      *//github.com/*   ) email=""; name="";;
    esac
    

​整个过程的原理就是我们在执行克隆操作时,git会执行初始模板里的钩子文件,钩子文件根据git-clone-init文件定义的规则,自动配置用户名与邮箱信息

post-checkout

#!/bin/bash

#checkout hook to locally set user name and email based on user defined patterns
#The patterns are matched against the clone url.
#
#Based on http://www.dvratil.cz/2015/12/git-trick-628-automatically-set-commit-author-based-on-repo-url/

function warn {
  echo -e "\n$1 Email and author not initialized in local config!"
}

email="$(git config --local user.email)"
name="$(git config --local user.name)"

if [[ $1 != "0000000000000000000000000000000000000000" || -n $email || -n $name ]]; then
  exit 0
fi

#get remote name:
#  only one: take it
#  more: take "origin", or fail
remote="$([[ $(git remote | wc -l) -eq 1 ]] && git remote || git remote | grep "^origin$")"

if [[ -z $remote ]]; then
  warn "Failed to detect remote."
  exit 0
fi

url="$(git config --local remote.${remote}.url)"

if [[ ! -f ~/.git-clone-init ]]; then
cat << INPUT > ~/.git-clone-init
#!/bin/bash

case "\$url" in
  *@github.com:*    ) email=""; name="";;
  *//github.com/*   ) email=""; name="";;
esac
INPUT
  warn "\nMissing file ~/.git-clone-init. Template created..."
  exit 0
fi
. ~/.git-clone-init

if [[ -z $name || -z $email ]]; then
  warn "Failed to detect identity using ~/.git-clone-init."
  exit 0
fi

git config --local user.email "$email"
git config --local user.name "$name"

echo -e "\nIdentity set to $name <$email>"