Skip to content

Git

安装

核心概念

author vs committer: author 代码是谁编写, committer 是谁合并/提交代码到仓库

head: TBD.

origin: TBD.

upstream: TBD.

stash: TBD.

常用配置

如无特别说明,以下以使用 Github 托管代码为例。

全局配置文件路径

macOS 和 Linux $HOME/.gitconfig Windows %USERPROFILE%\.gitconfig

直接添加或修改文件 .gitconfig 修改全局通用配置

# 设置 author 用户名和邮件地址
[user]
  name = Zhang San
  email = 12345678+san123456@users.noreply.github.com

[init]
  # 默认分支名为 master,不用 main
  defaultBranch = master

[core]
  # 禁止自动转换文件换行符(CRLF/LF),编辑器保存文件是什么就是什么,要修改用户自己手动修改
  autocrlf = false

  # 忽略文件权限变更
  fileMode = false

# 通过代理访问 Github
[https "https://github.com"]
  proxy = socks5h://192.168.1.100:7890

注意:Github 上可在 profile 设置 Name ,这个值如果和 gitconfig user.name 不一致,那么通过 Github 网页操作 pr / commit 时会替代 author 值。

在仓库执行 git shortlog -nse 统计时,可能会出现相同邮件地址的 committer 显示为不同的两个 committer(因为 user name 不一样)

266 Zhang San <12345678+san123456@users.noreply.github.com>
4 San <12345678+san123456@users.noreply.github.com>

修改 Name 和 gitconfig 一致可以避免这个问题。如果想篡改历史中记录修复,见后面「常见用法」中「篡改历史」说明。

通过命令行设置或修改用户名和邮件地址

git config --global user.name "Zhang San"
git config --global user.email 12345678+san123456@users.noreply.github.com

Github 认证方式 SSH vs HTTPS

    优势                       劣势
SSH 配置公私钥后,提交或拉取代码时不需要手动输入密码  无法使用 HTTPS 代理
HTTPS  可使用 HTTPS 代理提交或拉取代码           需提前预先配置 HTTP 认证信息

配置 Github HTTPS 认证信息步骤

Github settings 生成 token

修改全局配置文件 .gitconfig,补充以下

[url "https://<github用户名>:<github token值>@github.com"]
  insteadOf = https://github.com

.gitattributes

放在仓库根目录(也可放在子目录,只对该目录及其子目录生效),按路径给文件指定属性,作用于换行符、diff、合并、打包、LFS 等。语法为 <pattern> <attr1> <attr2> ...,pattern 规则同 .gitignore。

属性有四种取值形式:attr(设为 true)、-attr(设为 false)、!attr(取消设置)、attr=value(赋值)。

注:.gitattributes 需提交到仓库,对所有 clone 生效,优先级高于 .gitconfig 中 core.autocrlf 等个人配置。

换行符规范化

# 默认由 Git 自动判断是否为文本文件,入库统一存为 LF
* text=auto

# 显式声明文本文件,检出时按平台转换
*.go      text
*.md      text

# 强制检出为 LF(shell 脚本、Dockerfile 等在 Windows 上也不能是 CRLF)
*.sh      text eol=lf
Dockerfile text eol=lf

# 强制检出为 CRLF
*.bat     text eol=crlf
*.ps1     text eol=crlf

# 声明为二进制,等价于 -text -diff
*.png     binary
*.pdf     binary

注:* text=auto 只影响新增或再次入库的文件,已在历史中以 CRLF 存储的文件不会自动改写。要一次性规范化整个仓库:

shell
git add --renormalize .
git commit -m "chore: normalize line endings"

diff 与 merge 行为

# 指定语言的 hunk header,diff 时显示所在函数名
*.go      diff=golang
*.ts      diff=typescript
*.css     diff=css

# 合并冲突时直接取本地版本,不做逐行合并(适合锁文件、生成产物)
package-lock.json  merge=ours
*.pbf              -merge

# 生成的文件不参与合并,冲突时保留本地再重新生成
dist/**   -diff -merge

merge=ours 需先在 .gitconfig 中注册驱动:

[merge "ours"]
  name = keep local version
  driver = true

从归档中排除文件

git archive 打包(GitHub 的 source tarball 同理)时排除开发用文件:

/.github        export-ignore
/.issues        export-ignore
/docs           export-ignore
.gitattributes  export-ignore
.gitignore      export-ignore
*_test.go       export-ignore

关键字展开

# 检出时把 $Id$ 展开为 blob 的 SHA-1
*.txt     ident

注:Git 不支持 SVN 那样的 $Revision$$Date$ 展开,只有 ident 一种,一般用 build 时注入版本号代替。

Git LFS

git lfs track "*.psd" 实际就是往 .gitattributes 写一行:

*.psd filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text

GitHub linguist

影响仓库语言统计和 diff 折叠:

# 不计入语言统计,并在 PR diff 中默认折叠
pkg/api/*.pb.go   linguist-generated=true
vendor/**         linguist-vendored=true
docs/**           linguist-documentation=true

# 纠正语言识别
*.h               linguist-language=C

查看某个文件实际生效的属性

shell
git check-attr -a path/to/file
git check-attr text eol -- path/to/file

参考

常见用法

克隆仓库指定版本快照 git clone --depth 1 --branch v1.2.3 https://github.com/foo/bar.git $GOPATH/src/github.com/foo/bar

统计提交者信息 git shortlog -nse

push 到 fork 的 pr git push git@github.com:user/repo local_branch_name:remote_branch_name

从所有历史中删除指定敏感数据

shell
brew install git-filter-repo

git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY
cd YOUR-REPOSITORY
git filter-repo --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
git add .gitignore
git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"

git remote add origin https://github.com/YOUR-USERNAME/YOUR-REPOSITORY

git push origin --force --all
git push origin --force --tags

参考

合并两个仓库

合并 project-a 入 project-b

shell
cd path/to/project-b
git remote add project-a /path/to/project-a
git fetch project-a --tags
git merge --allow-unrelated-histories project-a/master # or whichever branch you want to merge
git remote remove project-a

注:可能会触发大量冲突需要手动合并。

发布版本和打标签

列出标签 git tag -l

看标签详情 git show v0.0.1

打标签 git tag -a <tag name, such as v0.0.1> -m "description ..."

删除标签 git tag -d <tag name>

推送标签到上游 git push --tags

修改已有标签 git tag v0.0.35 -f -a

修改已有标签后推送到上游覆盖已有的 git push --tags -f

Push code to gitlab with access token

https://stackoverflow.com/questions/42074414/gitlab-push-to-a-repository-using-access-token

篡改历史

TBD.

fatal: refusing to merge unrelated histories

解决 git pull origin master --allow-unrelated-histories

注:会覆盖本地未同步到远程仓库的变更。

Git 2.46.2 Setup

  • Configuring extra options
    • Enable symbolic links

gpedit.msc 本地组策略编辑器

  • Computer Configuration / 计算机设置
    • Windows Settings / Windows 设置
      • Security Settings / 安全设置
        • Local Policies / 本地策略
        • User Rights Assignment / 用户权限分配
          • Create symbolic links / 创建符号链接
          • 添加用户或组

此法在 Windows 7 不生效。

Change default branch name to master

shell
git branch -m main master

git config --global init.defaultBranch master

Change last commit message and committer

git commit --amend --author="some-one <123456+some-one@users.noreply.github.com>"

Released under the CC-BY-NC-4.0