reference/docs/git.md
2022-11-26 18:49:41 +08:00

1019 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Git 备忘清单
===
本备忘单总结了常用的 [Git](https://git-scm.com/) 命令行指令,以供快速参考。
入门
----
### 创建存储库
创建一个新的本地存储库
```shell
$ git init [项目名称]
```
克隆存储库(代码仓库)
```shell
$ git clone <git_url>
```
将存储库克隆到指定目录
```shell
$ git clone <git_url> 指定目录
```
将存储库克隆到指定目录,并指定分支
```shell
$ git clone <git_url> -b <分支名称> 指定目录
```
### 做出改变
<!--rehype:wrap-class=row-span-3-->
在工作目录中**显示**修改后的文件,为您的下一次提交暂存
```shell
$ git status
```
暂存文件,准备提交
```shell
$ git add [file]
```
暂存**所有**更改的文件,准备提交
```shell
$ git add .
```
将所有暂存文件提交到版本化历史记录
```shell
$ git commit -m "commit message"
```
将所有跟踪的文件提交到版本化历史记录
```shell
$ git commit -am "commit message"
```
取消暂存文件,保留文件更改
```shell
$ git reset [file]
```
将所有内容恢复到最后一次提交
```shell
$ git reset --hard
```
已更改但未暂存内容的差异
```shell
$ git diff
```
已 commited 但尚未提交的内容的差异
```shell
$ git diff --staged
```
在指定分支之前应用当前分支的任何提交
```shell
$ git rebase [branch]
```
### 配置
<!--rehype:wrap-class=row-span-2-->
设置将附加到您的提交和标签的名称
```shell
$ git config --global user.name "name"
```
设置将附加到您的提交和标签 tags 的**电子邮件地址**
```shell
$ git config --global user.email "email"
```
启用 Git 输出的一些着色
```shell
$ git config --global color.ui auto
```
在文本编辑器中编辑全局配置文件
```shell
$ git config --global --edit
```
显示本地 `repo` 配置设置
```shell
$ git config --list
```
删除全局设置
```bash
$ git config --global --unset <entry-name>
```
### 使用分支
<!--rehype:wrap-class=row-span-3-->
列出所有本地分支
```shell
$ git branch
```
列出所有分支,本地和远程
```shell
$ git branch -av
```
切换到 `my_branch`,并更新工作目录
```shell
$ git checkout my_branch
```
创建一个名为 `new_branch` 的新分支
```shell
$ git checkout -b new_branch
```
删除名为 `my_branch` 的分支
```shell
$ git branch -d my_branch
```
将分支 `A` 合并到分支 `B`
```shell
$ git checkout branchB
$ git merge branchA
```
标记当前提交
```shell
$ git tag my_tag
```
从远程分支中创建并切换到本地分支
```shell
$ git checkout -b <branch-name> origin/<branch-name>
```
<!--rehype:className=wrap-text-->
### 临时提交
```shell
# 保存已修改和分阶段的更改
$ git stash
# 列出隐藏文件更改的堆栈顺序
$ git stash list
# 从存储堆栈顶部编写工作
$ git stash pop
# 丢弃存储堆栈顶部的更改
$ git stash drop
# 回到某个 stash 的状态
$ git stash apply <stash@{n}>
# 删除所有的 stash
$ git stash clear
```
### 观察你的存储库
<!--rehype:wrap-class=row-span-2-->
显示当前活动分支的提交历史
```shell
$ git log
```
显示 branchA 上不在 branchB 上的提交
```shell
$ git log branchB..branchA
```
显示更改文件的提交,即使跨重命名
```shell
$ git log --follow [file]
```
显示 branchA 中的内容与 branchB 中的内容的差异
```shell
$ git diff branchB...branchA
```
以人类可读的格式显示 Git 中的任何对象
```shell
$ git show [SHA]
```
### 忽略文件 .gitignore
<!--rehype:wrap-class=row-span-4-->
文件 `.gitignore` 指定了 `Git` 应该忽略的 **未跟踪的** 文件
:- | :-
:- | :-
行首 `#` | 全行注释,不支持行尾类注释 _(转义 `\#`)_
行首 **`!`** | 否定模式 _(转义 `\!`)_
`**` | 匹配任意路径
`*` | 匹配任意多个字符
`?` | 匹配任意一个字符
`doc/**` | 匹配 `doc` 文件夹下的全部内容
`doc/**/a` | 匹配任意深度路径下的 `a` 文件或文件夹
`/` | 表示路径分隔符,不区分操作系统
`/` 结尾 | 仅会匹配文件夹,否则会匹配文件和文件夹
空行 | 不匹配任何文件
行尾空格 | 默认被忽略,可使用`\`进行转义
行首空格 | 被正常处理,不会被忽略
当前 `.gitignore` 文件定义规则的优先级高于上级路径 `.gitignore` 定义规则的优先级;后定义的规则优先级高于前面定义规则的优先级
```gitignore showLineNumbers
# 忽略当前目录logs文件夹下的全部内容
/logs/
/logs/*
/logs/**
# 上述几条规则等效
# 忽略 Mac 系统文件,包括任意子路径下的同名文件(夹)
.DS_store
# 忽略 node_modules 文件夹,包括任意子路径下的同名文件夹
node_modules/
# 忽略任意子路径下build、target文件夹
# 但不忽略src/main、src/test下的build、target文件夹
build/
!**/src/main/**/build/
!**/src/test/**/build/
target/
!**/src/main/**/target/
!**/src/test/**/target/
# 使用 ! 重新包含指定文件(夹)
!logs/.gitkeep
```
<!--rehype:className=wrap-text-->
### 重构文件名
```bash
# 从工作目录中删除文件并暂存删除
git rm <filename>
# 从版本控制中删除文件但在本地保留文件
git rm --cached <filename>
# 更改文件名并准备提交
git mv <filename-orig> <filename-renamed>
```
### 同步
<!--rehype:wrap-class=row-span-2-->
从该 Git 远程获取所有分支
```shell
$ git fetch [alias]
```
将远程分支合并到当前分支以使其保持最新状态
```shell
$ git merge [alias]/[branch]
# 没有快进
$ git merge --no-ff [alias]/[branch]
# 仅快进
$ git merge --ff-only [alias]/[branch]
```
将本地分支提交传输到远程存储库分支
```shell
$ git push [alias] [branch]
```
从跟踪远程分支获取并合并任何提交
```shell
$ git pull
```
将另一个分支的一个特定提交合并到当前分支
```shell
$ git cherry-pick [commit_id]
```
### 远程
<!--rehype:wrap-class=row-span-2-->
添加一个 git URL 作为别名
```shell
$ git remote add [alias] [url]
```
显示您设置的远程存储库的名称
```shell
$ git remote
```
显示远程存储库的名称和 URL
```shell
$ git remote -v
```
删除远程存储库
```shell
$ git remote rm [remote repo name]
```
更改 git repo 的 URL
```shell
$ git remote set-url origin [git_url]
```
### 跟踪路径更改
从项目中删除文件并暂存删除以进行提交
```shell
$ git rm [file]
```
更改现有文件路径并暂存移动
```shell
$ git mv [existing-path] [new-path]
```
显示所有提交日志,并指示任何移动的路径
```shell
$ git log --stat -M
```
### git 配置 ssh 代理
<!--rehype:wrap-class=col-span-2-->
```bash
$ cat ~/.ssh/config
Host gitlab.com
# 直接使用 shadowsocks 提供的 socks5 代理端口
ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p
Host github.com
ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p
```
<!--rehype:className=wrap-text-->
### .gitattributes
```ini
# 设置默认行为,以防人们没有设置 core.autocrlf
* text=auto
# 明确声明您希望始终规范化并在结帐时
# 转换为本机行结尾的文本文件
*.c text
*.h text
# 声明在结帐时始终以 CRLF 行结尾的文件
*.sln text eol=crlf
# 表示所有真正二进制且不应修改的文件
*.png binary
*.jpg binary
```
[计入存储库语言](https://github.com/github/linguist/blob/master/docs/overrides.md#using-gitattributes)
```ini
# 标记或取消标记要根据存储库的语言统计数据而
# 忽略或默认隐藏差异的路径
search/index.json linguist-generated=true
# 以下属性统计 SQL 文件
*.sql linguist-detectable=true
# 从统计信息中排除
docs/formatter.rb linguist-documentation=false
# 将它们从统计信息中排除
special-vendored-path/* linguist-vendored
# 将所有 .rb 文件检测为 Java 文件
*.rb linguist-language=Java
```
Git 技巧
------
### 重命名分支
- **重命名**为`new`
```shell
$ git branch -m <new>
$ git branch -m <old> <new> #重命名分支
```
- **推送**并重置
```shell
$ git push origin -u <new>
```
- **删除**远程分支
```shell
$ git push origin --delete <old> #方法1
$ git push origin :oldBranchName #方法2
```
<!--rehype:className=style-timeline-->
### Log
按内容搜索更改
```shell
$ git log -S'<a term in the source>'
```
显示特定文件随时间的变化
```shell
$ git log -p <file_name>
```
打印出很酷的日志可视化
```shell
$ git log --pretty=oneline --graph --decorate --all
```
<!--rehype:className=wrap-text-->
### 分支
<!--rehype:wrap-class=row-span-2-->
列出所有分支及其上游
```shell
$ git branch -vv
```
快速切换到上一个分支
```shell
$ git checkout -
```
只获取所有远程分支
```shell
$ git branch -r
```
从另一个分支签出单个文件
```shell
$ git checkout <branch> -- <file>
```
删除本地存在远程不存在的分支
```shell
git remote prune origin
```
### Commit
```shell
$ git commit -v --amend
```
重写最后的提交信息
### 忽略文件的权限变化
```shell
git config core.fileMode false
```
不再将文件的权限变化视作改动
### Git 别名
```shell
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
```
也可以看看:[更多别名](https://gist.github.com/johnpolacek/69604a1f6861129ef088)
### 设置大小写敏感
```shell
# 查看git 的设置
$ git config --get core.ignorecase
# 设置大小写敏感
$ git config core.ignorecase false
# 远程有俩相同目录,通过这种方式清除掉,然后提交记录
$ git rm -r --cached <目录/文件>
```
### 修改远程 Commit 记录
<!--rehype:wrap-class=row-span-4-->
```shell
$ git rebase -i HEAD~3
# 表示要修改当前版本的倒数第三次状态
# 将要更改的记录行首单词 pick 改为 edit
pick 96dc3f9 提交 commit 描述内容 1
pick f1cce8a 提交 commit 描述内容 2
pick 6293516 提交 commit 描述内容 3
# Rebase eeb03a4..6293516 onto eeb03a4
# (3 commands)
#
# Commands:
# p, pick = 使用提交
# r, reword = 使用提交,但编辑提交消息
# e, edit = 使用提交,但停止修改
# s, squash = 使用提交,但融合到先前的提交中
# f, fixup = 像 squash但丢弃此提交的日志消息
# x, exec = 使用 shell 运行命令(该行的其余部分)
# d, drop = 删除提交
```
保存并退出,会弹出下面提示
```shell
# 您现在可以修改提交,使用
#
# git commit --amend
#
# 对更改感到满意后,运行
#
# git rebase --continue
#
# 1. 通过这条命令进入编辑更改 commit保存退出
$ git commit --amend
# 2. 保存退出确认修改,继续执行下面命令,
$ git rebase --continue
# 如果修改多条记录反复执行上面两条命令直到完成所有修改
# 最后,确保没有人提交进行推送,最好不要加 -f 强制推送
$ git push -f origin master
```
### 撤销远程记录
```shell
# 撤销一条记录
$ git reset --hard HEAD~1
# 强制同步到远程仓库
$ git push -f origin HEAD:master
```
### 放弃本地修改内容
```shell
# 如果有的修改以及加入暂存区的话
$ git reset --hard
# 还原所有修改,不会删除新增的文件
$ git checkout .
# 下面命令会删除新增的文件
$ git clean -xdf
```
### 获取最近一次提交的 Hash
```shell
$ git rev-parse HEAD # e10721cb8859b2c
# 获取短 hash
$ git rev-parse --short HEAD # e10721c
```
### 删除已经合并到 master 的分支
```shell
$ git branch --merged master | grep -v '^\*\| master' | xargs -n 1 git branch -d
```
<!--rehype:className=wrap-text-->
### 把 A 分支的某一个 commit放到 B 分支上
```shell
# 切换到 B 分支
$ git checkout <B>
# 将 A 分支 <hash-id> 的内容 pick 到 B 分支
$ git cherry-pick <hash-id>
```
### 回到远程仓库的状态
```bash
$ git fetch --all && git reset --hard origin/master
```
<!--rehype:className=wrap-text-->
抛弃本地所有的修改,回到远程仓库的状态
### 重设第一个 commit
```bash
$ git update-ref -d HEAD
```
把所有的改动都重新放回工作区,并**清空所有的 commit**,这样就可以重新提交第一个 `commit` 了
### 查看冲突文件列表
```bash
$ git diff --name-only --diff-filter=U
```
### 展示工作区的冲突文件列表
<!--rehype:wrap-class=row-span-2-->
输出工作区和暂存区的 different (不同)。
```bash
$ git diff
```
还可以展示本地仓库中任意两个 commit 之间的文件变动:
```bash
$ git diff <commit-id> <commit-id>
```
### 展示暂存区和最近版本的不同
```bash
git diff --cached
```
### 中文乱码的解决方案
```shell
$ git config --global core.quotepath false
```
### 展示暂存区、工作区和最近版本的不同
```bash
$ git diff HEAD
```
输出工作区、暂存区 和本地最近的版本(commit)的different(不同)。
### 删除已经合并到 master 的分支
```bash
$ git branch --merged master | grep -v '^\*\| master' | xargs -n 1 git branch -d
```
<!--rehype:className=wrap-text-->
### 关联远程分支
<!--rehype:wrap-class=row-span-2-->
```bash
$ git branch -u origin/mybranch
```
或者在 `push` 时加上 `-u` 参数
```bash
git push origin/mybranch -u
```
关联之后,`git branch -vv` 就可以展示关联的远程分支名了, 同时推送到远程仓库直接:`git push`,不需要指定远程仓库
### 查看远程分支和本地分支的对应关系
```bash
$ git remote show origin
```
### 展示当前分支的最近的 tag
```bash
$ git describe --tags --abbrev=0
```
### 查看某段代码是谁写的
```bash
$ git blame <file-name>
```
`blame` 的意思为`责怪`,你懂的。
### 修改作者名
```bash
$ git commit --amend --author='Author Name <email@address.com>'
```
<!--rehype:className=wrap-text-->
### 修改远程仓库的 url
```bash
$ git remote set-url origin <URL>
```
### 增加远程仓库
```bash
$ git remote add origin <remote-url>
```
<!--rehype:className=wrap-text-->
### 列出所有远程仓库
```bash
$ git remote -v
```
### 查看两个星期内的改动
```bash
$ git whatchanged --since='2 weeks ago'
```
### 从 stash 中拿出某个文件的修改
```bash
$ git checkout <stash@{n}> -- <file-path>
```
<!--rehype:className=wrap-text-->
### 展示所有 tracked 的文件
```bash
$ git ls-files -t
```
### 展示所有 untracked 的文件
```bash
$ git ls-files --others
```
### 展示所有忽略的文件
```bash
$ git ls-files --others -i --exclude-standard
```
<!--rehype:className=wrap-text-->
### 把某一个分支导出成一个文件
```bash
$ git bundle create <file> <branch-name>
```
### 从包中导入分支
<!--rehype:wrap-class=row-span-2-->
```bash
$ git clone repo.bundle <repo-dir> -b <branch-name>
```
<!--rehype:className=wrap-text-->
新建一个分支,分支内容就是上面 `git bundle create` 命令导出的内容
### 执行 rebase 之前自动 stash
```bash
$ git rebase --autostash
```
### 从远程仓库根据 ID拉下某一状态到本地分支
```bash
$ git fetch origin pull/<id>/head:<branch-name>
```
<!--rehype:className=wrap-text-->
### 详细展示一行中的修改
```bash
$ git diff --word-diff
```
### 清除 gitignore 文件中记录的文件
```bash
$ git clean -X -f
```
### 展示忽略的文件
```bash
$ git status --ignored
```
### commit 历史中显示 Branch1 有的但是 Branch2 没有 commit
```bash
$ git log Branch1 ^Branch2
```
### 在 commit log 中显示 GPG 签名
```bash
$ git log --show-signature
```
### 新建并切换到新分支上,同时这个分支没有任何 commit
```bash
$ git checkout --orphan <branch-name>
```
相当于保存修改,但是重写 commit 历史
### 展示任意分支某一文件的内容
```bash
$ git show <branch-name>:<file-name>
```
### 配置 http 和 socks 代理
<!--rehype:wrap-class=row-span-4-->
```bash
# 查看代理
$ git config --global http.proxy
$ git config --global https.proxy
$ git config --global socks.proxy
# 设置代理
# 适用于 privoxy 将 socks 协议转为 http 协议的 http 端口
$ git config --global http.proxy http://127.0.0.1:1080
$ git config --global https.proxy http://127.0.0.1:1080
$ git config --global socks.proxy 127.0.0.1:1080
# 取消代理
$ git config --global --unset http.proxy
$ git config --global --unset https.proxy
$ git config --global --unset socks.proxy
# 只对 github.com 设置代理
$ git config --global http.https://github.com.proxy socks5://127.0.0.1:1080
$ git config --global https.https://github.com.proxy socks5://127.0.0.1:1080
# 取消 github.com 代理
$ git config --global --unset http.https://github.com.proxy
$ git config --global --unset https.https://github.com.proxy
```
### clone 最新一次提交
```bash
$ git clone --depth=1 https://github.com/user/repo.git
```
只会 `clone` 最近一次提交,将减少 `clone` 时间
### 忽略某个文件的改动
<!--rehype:wrap-class=row-span-2-->
关闭 track 指定文件的改动,也就是 Git 将不会在记录这个文件的改动
```bash
git update-index --assume-unchanged path/to/file
```
<!--rehype:className=wrap-text-->
恢复 track 指定文件的改动
```bash
git update-index --no-assume-unchanged path/to/file
```
<!--rehype:className=wrap-text-->
### 以最后提交的顺序列出所有 Git 分支
```bash
git for-each-ref --sort=-committerdate --format='%(refname:short)' refs/heads
```
最新的放在最上面
### 在 commit log 中查找相关内容
```bash
git log --all --grep='<given-text>'
```
通过 grep 查找given-text: 所需要查找的字段
### 把暂存区的指定 file 放到工作区中
```bash
git reset <file-name>
```
不添加参数,默认是 `-mixed`
### 配置 SSH 协议代理
```shell
# 对于使用 git@ 协议的,可以配置 socks5 代理
# macOS 系统编辑 ~/.ssh/config 文件,添加这几行,设置 github 代理
Host github.com
ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p
```
<!--rehype:className=wrap-text-->
Conventional Commmits
----
### 格式
<!--rehype:wrap-class=col-span-3-->
```text
<type>(<scope>): <short summary>
│ │ │
│ │ └─⫸ 紧凑简短的描述,无需大写,也不需要用句号结尾
│ │
│ └─⫸ Commit 范围: animations|bazel|benchpress|common|compiler|compiler-cli|core|
│ elements|forms|http|language-service|localize|platform-browser|
│ platform-browser-dynamic|platform-server|router|service-worker|
│ upgrade|zone.js|packaging|changelog|docs-infra|migrations|ngcc|ve|
│ devtools....
└─⫸ Commit 类型: build|ci|doc|docs|feat|fix|perf|refactor|test
website|chore|style|type|revert
```
### 常用
<!--rehype:wrap-class=row-span-1-->
| 类型 | 描述 |
| ----------|------------ |
| `feat:` | 新特性 |
| `fix(scope):` | 修复 scope 中的 Bug |
| `feat!:` / `feat(scope)!:` | breaking change / 重构 API |
| `chore(deps):` | 更新依赖 |
<!--rehype:className=left-align-->
### Commit 类型
<!--rehype:wrap-class=col-span-2-->
| 类型 | 描述 |
| ----------|------------ |
| `build:` | 变更影响的是**构建系统**或者**外部依赖** (如: gulp, npm) |
| `ci:` | 修改了 CI 配置文件或脚本 (如: Github Action, Travis) |
| `chore:` | **【重要】** 变更不影响源代码或测试(如更新了辅助工具、库等) |
| `docs:` | 只修改了文档 |
| `feat:` | **【重要】** 一个新特性 |
| `fix:` | **【重要】** 修复了一个 Bug |
| `perf:` | 增强性能的代码变更 |
| `refactor:` | 并非修复 Bug 或添加新特性的代码变更 |
| `revert:` | 回退代码 |
| `style:` | 变更不影响一些有意义的代码 (如: 删除空格、格式化代码、添加分号等) |
| `test:` | 添加测试代码或修正已有的测试 |
<!--rehype:className=left-align-->
另见
---
- [最常用的 git 提示和技巧](https://github.com/git-tips/tips)
- [Conventional Commits 官方网站](https://www.conventionalcommits.org/zh-hans/v1.0.0/) _(conventionalcommits.org)_
- [Conventional Commits Cheatsheet](https://gist.github.com/Zekfad/f51cb06ac76e2457f11c80ed705c95a3) _(gist.github.com)_