Git笔记

本文记录一些常用的git操作和设置技巧。

信任自签名证书

Windows上的git比泛unix系统下要难处理一些,问题包括

  • 不使用系统的HTTP代理,git clone速度可能会慢甚至失败
  • 不使用系统的证书存储

在windows terminal里打印git的配置变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PS C:\Users\martin> git config --list --show-scope
system diff.astextplain.textconv=astextplain
system filter.lfs.clean=git-lfs clean -- %f
system filter.lfs.smudge=git-lfs smudge -- %f
system filter.lfs.process=git-lfs filter-process
system filter.lfs.required=true
system http.sslbackend=openssl
system http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
system core.autocrlf=true
system core.fscache=true
system core.symlinks=false
system pull.rebase=false
system credential.helper=manager-core
system credential.https://dev.azure.com.usehttppath=true
system init.defaultbranch=master
global http.proxy=http://localhost:7890

第8行http.sslcainfo是git信任的证书,第16行设置git使用代理端口。

我司有一个私有Gitlab实例作代码版本管理,gitlab通过nginx反向代理提供服务。因为只在内网里开发,所以无法获得公共签发的TLS证书。

其实我讨了一个巧把Gitlab配置在域名gitlab.xuanlingasset.com,而我司其实注册了xuanlingasset.com根域名,所以原则上其实Gitlab是可以假设在公网上的。但一方面是为了安全,另一方面公网访问的需求不大,我司用蒲公英的内网穿透实现远程开发的需求。我司在这个域名上只有一个邮件服务,购置云服务器也不是用来做web服务而是做交易的。

无奈只能自签发一张证书,配置nginx上代理的所有web服务都用这种自签名证书,然后配置公司内的机器信任。

这里有个容易踩坑的地方,如果

1
git config --global http.sslcainfo /path/to/cert

http.sslcainfo指向自签名证书,这时global层和system层都存在这个变量,你可能会遇到一个问题:克隆自己的服务器上的仓库没问题,但是克隆Github上的仓库会报类似“无法找到ssl证书”的错误。

最好的解决方案是,打开git默认的系统证书bundle(C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt),其实里面就是一串证书写在一个文件里

1
2
3
4
5
6
7
8
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
...

把自签名证书(.crt)文件用任意文本编辑器打开,把证书内容复制然后粘贴在ca-bundle.crt,移除刚添加的global变量

1
git config --global --unset http.sslcainfo

可以正常克隆公共和私有仓库了。

处理异常”warning: redirecting to

出现这个错误,是因为配置Remote的时候,忘记在网址的最后加上”.git”了,比如https://git.example.com/abc/xyz而不是https://git.example.com/abc/xyz.git。那么解决也很简单

1
git remote set-url origin https://git.example.com/abc/xyz.git

Fork Repository的维护流程

当你在Github上发现了感兴趣的项目,可以fork下来到自己的仓库

1
git remote add fork <your repo url>

然后在本地做出了一些代码修改,commit之后

1
git push fork main

在Github上打开fork仓库,在顶部会自动出现一个contribute按钮,点击就会自动创建一个PR给原项目。

另一种情形是,假设你花了一阵子在自己的fork上实现了新feature,这时候距离你的fork已经过去了一段时间,原项目增加了一些 commits,这些commits不在你的fork上存在,你要把原项目的新的commits同步到自己的fork上面,以便你创建PR的时候没有冲突。

1
2
3
4
5
6
7
8
9
10
11
12
# assume your work is on branch private
git checkout private
git fetch origin main
# rebase onto main
git rebase origin/main
# now your private branch is synced
git checkout main
# show commits that private has but main does not have
git log main..private
# pick commits from private that you would like to contribute
git cherry-pick commit1 commit2 ...
git push fork main

Advance search in git history

  1. Search for commits that changed a line, by matching line pattern
    1
    git log -S"<pattern>" -- <path>
  2. Search for commits that changed some lines, by specifing the region of lines
    1
    git log -L start_line,end_line:<file_path>
  3. Search for commits that add or remove a file
    1
    git log --diff-filter=D -- <directory-path>

Peeking the Git Data Model

Unexpectedly, how git data model to represent history is trivial, just object and reference:

  • Objects store files and directory structure of a repository;
  • References keep track of branches, tags and remotes.

You can peek at the information in an object or reference using git cat-file:

git cat-file -p <commit/ref>

The -p flag is to make git output in human friendly format.