Kyle's Notebook

Git Cheat Sheet

Word count: 3.9kReading time: 16 min
2020/02/15

Git Cheat Sheet

之前给部门培训写了份 Git 教程,现在拿出来分享给大家。

懒得每节都看的话可以直接参考下图:
Git 图解

仓库管理

代码提交过程

1
2
# 工作区         ->      暂存区      ->       HEAD     ->       远端仓库
# WorkingDir -(add)-> Index -(commit)-> HEAD -(push)-> RemoteRepository

创建本地仓库

1
2
mkdir d && cd !$
git init

保存工作

1
2
3
4
git stash
[-u] # 包括 untracked 文件(新建的)
git stash pop # 回到最后一个保存的状态,并删除该 stash
git stash clear # 删除所有 stash

可保存多次、读取

1
2
3
git stash list					# 查看所有 stash
git stash apply <stashId> # 读取某次 stash,不删除
git checkout <stashId> -- <filename> # 读取某次 stash 中某个文件的更改

提交代码

添加/ 放弃更改(到本地仓库暂存区):

1
2
3
4
5
6
7
8
# 添加
git add filename
git add *
[-i] # 交互式添加文件到暂存区

# 放弃
git checkout <filename>
git checkout .

提交更改(到本地仓库 HEAD,指向最后一次提交的结果):

1
2
3
4
git commit -m ":memo: first commit"

# 修改上一个 commit 的描述,也可以补充提交在 commit 后又 add 的部分。
git commit --amend

合并多次提交(为一次):

1
git rebase -i HEAD~4		# 最近四次提交合并为一次

查看所有新建的/有提交记录的文件(untracked/ tracked)

1
2
git ls-files -t				# tracked
git ls-files --others # untracked

查看所有忽略的文件:

1
git ls-files --others -i --exclude-standard

远端仓库

远端仓库默认名为 origin,查看远程库信息:

1
git remote -v			

克隆仓库(到本地),如克隆远端仓库,则会其别名为”origin“:

1
2
git clone /path/to/repository					# 本地
git clone username@host:/path/to/repository # 服务器

关联仓库(本地已存在的仓库与远端仓库关联):

1
git remote add origin git@github.com:ywh/learngit.git

更新本地仓库:

1
git pull

连接远端仓库:

1
git remote add origin <server>

推送到远端仓库(到指定分支):

1
2
git push origin dev				# 把本地推送到远端 dev 分支
git push origin/mybranch -u # 推送到指定分支

删除操作

删除文件:

1
2
3
4
rm <filename>					# 删除本地文件
git rm <filename> # 删除版本库文件
git commit
git checkout -- <filename> # 从版本库恢复删除的文件

强制删除新建的文件(未提交过的):

1
2
git clean <filename> -f		# 不指定文件名则删除全部;删除的文件无法找回
[-df] # 删除目录

删除远程仓库的文件:

1
2
3
git rm -r --cached best_practice/.api-service
git commit
git push

标签管理

标签用于标记一个版本,表示版本库的一个快照(类似分支上的一个提交,但不能移动)。

查看标签:

1
2
git tag
git show <tagname>

切换分支,在分支上打上标签(最新的提交上):

1
2
3
git branch
git checkout master
git tag v1.0

在指定的提交上打上标签:

1
2
git log --pretty=oneline --abbrev-commit		# 获取提交 id
git tag 1.0.0 <commitId> -m "xxx" # 根据提交 id 的前 10 位选定,打上标签

推送标签(的提交)到远端:

1
2
git push origin v1.0			
git push origin --tags # 所有未提交的标签

删除标签:

1
2
3
4
git tag -d v0.1

# 如要删除的标签已经推送到远端,还需要执行:
git push origin :refs/tags/v0.1

分支管理

在本地仓库上拉取指定分支:

1
2
3
git brancn -a
git fetch origin xxx
git checkout xxx

创建并推送远程仓库分支:

1
2
3
git branch -r
git checkout -b dev
git push --set-upstream origin dev [--force]

管理策略

分支管理建议遵顼以下原则:

  • master 分支应该是非常稳定的,仅用来发布新版本,平时不能在上面工作;

  • 创建 dev 分支用于工作,dev 分支是不稳定的,比如 1.0版本发布时,再把 dev 分支合并到 master 上,在 master 分支发布 1.0 版本;

  • 开发组成员在 dev 的分支上工作,时不时地往 dev 分支上合并即可。

git-br-policy

多人协作模式:

  • 拉取远端主分支上的代码:git clone git@github.ywh/learngit.git

  • 创建本地分支:git checkout -b dev origin/dev

  • 修改后尝试 git push origin dev 推送自己的修改;

  • 推送失败表示远端分支比本地的更新,使用 git pull 试图合并;

  • git pull 失败,要求先把本地和远端分支关联 git branch --set-upstream-to=origin/dev dev

  • 合并发生冲突则解决,在本地提交;没有冲突或解决以后,再重新推送。

关于是否需要推送分支:

  • master 分支是主分支,因此要时刻与远程同步;

  • dev 分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;

  • bug 分支只用于在本地修复 bug,没必要推到远程;

  • feature 分支是否推到远程,取决于是否团队成员合作在上面开发。

Feature 分支

当添加实验性的新功能、又不希望把主分支搞乱可以新建一个 Feature 分支。

假设原在 dev 分支上开发,需要临时添加实验性的新功能 feature-vulcan,创建分支:

1
git checkout -b feature-vulcan

开发完成后提交:

1
2
git add <filename>
git commit -m "xxx"

切换回 dev 分支,准备合并:

1
git checkout dev

但该新功能收到指示需要取消,需要删除分支:

1
git branch -D feature-vulcan

Bug 分支

当出现紧急情况需要修复 bug,当前工作又还未完成,可以使用 stash 先把当前工作保存、再创建临时分支修复 bug,恢复现场后再继续工作。

假设在 dev 分支上工作,此时 master 分支上出现紧急 bug,先保存当前工作:

1
git stash

在 master 分支上创建临时分支:

1
2
git checkout master
git checkout -b issue-101

修复后提交代码:

1
2
git add <filename>
git commit -m "fix bug 101"

切换回出现 bug 的分支,合并,删除临时分支:

1
2
git checkout master
git merge --no-ff -m "merged bug fix 101" issue-101

切换回 dev 分支上继续工作:

1
2
3
git checkout dev
git stash list
git stash pop

标准版本号

标准版本号格式:X.Y.Z,其中:

  • X:主版本号,当添加了不兼容或颠覆性的更新时修改;

  • Y:次版本号,当添加了向下兼容的功能性修改时修改;

  • Z:修订号,当做了向下兼容的问题修正时修改。

其中 X、Y、Z 为非负整数,禁止数字前补 0,每个数值递增。

查看分支:

1
2
3
4
git branch 
[-vv] # 本地分支关联远端的情况
[-r] # 远端
[-a] # 本地 + 远端

查看远程分支和本地分支对应关系:

1
git remote show origin

关联远端分支:

1
git branch -u origin/mybranch

使用分支

指定远程分支链接:

1
git branch --set-upstream-to=origin/dev dev

创建(并切换)分支、重命名:

1
2
3
git checkout -b branch_x		# 分支在推送到远端之前只在本地可见
git checkout -b dev origin/dev # 创建本地 dev 分支,并于远端 origin/dev 分支关联
git branch -m branch_y # 重命名

切换分支:

1
git checkout - 					# 上一个分支

合并分支:

1
2
3
4
git checkout master				# 切换到 master
git merge <branch> # 合并 branch 到 master
# 合并分支默认采用 Fast forward 模式,删除分支后会丢弃分支信息
git merge --no-ff -m "merge with no-ff" <branch> # 合并分支时生产一个新的 commit,分支历史上可以看出分支信息

把 A 分支的某个 commit 放到 B 分支上:

1
git checkout B && git cherry-pick <commitId>

删除操作

删除分支:

1
2
3
git branch -d branch_x							# 本地
git push origin --delete <remote-branchname> # 远端
git push origin :<remote-branchname> # 远端

删除已经合并到 master 的分支:

1
git branch --merged master | grep -v '^\*\|  master' | xargs -n 1 git branch -d

删除远端已删除、本地剩余的分支:

1
git remote prune origin

保存备份

把某个分支导出成一个文件:

1
git bundle create <file> <branch>

新建一个分支,内容为上面导出的文件:

1
git clone repo.bundle <targetDir> -b <branchName>

合并多个 commit

(建议只在自己的分支上使用)使用 rebase 可以合并多个 commit 为一个完整的 commit。

比如在一个分支上的修改:

1
A -> B -> C -D

后面的 B、C、D 合并为一个完整提交,再推送到远端仓库:

1
A -> B'

可执行命令:

1
2
3
git rebase -i [start] [end]		# 区间是前开后闭的,如果不指定区间中间,则直接合并到 HEAD 指向的 commit
git rebase -i 32bs22 # -i 表示交互式编辑合并操作
git rebase -i HEAD~3

其中交互式的编辑指令:

  • pick/ p:保留该 commit

  • reword/ r:保留该 commit,但我需要修改该 commit 的注释

  • edit/ e:保留该 commit,但我要停下来修改该提交(不仅仅修改注释)

  • squash/ s:将该 commit 和前一个 commit 合并

  • fixup/ f:将该 commit 和前一个 commit 合并,但不要保留该提交的注释信息

  • exec/ x:执行 shell 命令

  • drop/ d:丢弃该 commit

将某段 commit 粘贴到另一分支

比如在某个分支上开发,有时需要将整段提交都应用到另一分支上,比如把下面 dev 分支上的 C、D、E 都合并到 master 分支的 G 后面:

1
2
3
A -> B -> C -> D -> E -> F		(dev)
\
-> G (master)

可执行命令:

1
2
git rebase [start] [end] --onto [branchName]		# 区间是前开后闭的,此处要指定 B 到 E 的 id
git rebase 90bc0045b^ 5de0da9f2 --onto master

注意粘贴后 HEAD 处于游离状态,git 只是将 C ~ E 部分的内容复制一份粘贴到了 master 所指向的提交后面,还需要将 master 所指向的提交 id 设置为当前 HEAD 所指向的提交 id:

1
2
git checkout master				# 切换到主分支,输出:this may be a good time to do so with: git branch <new-branch-name> 0c72e64
git reset --hard 0c72e64

fork 分支与主分支同步

本地添加远程主分支:

1
2
git remote -v
git remote add upstream git@github.com:coreos/etcd.git

拉取主分支最新修改:

1
git fetch upstream

将 upstream 分支修改内容 merge 到本地个人分支:

1
2
3
4
5
6
git merge upstream/master
# 等价于:git checkout master && git merge upstream
# git merge --abort
# git reset --merge

# git merge origin/master

将本地修改提交:

1
git push

错误提交到某分支

撤销最后一次提交,并保留变更代码:

1
2
git reset HEAD~ --soft
git stash

切换到正确到正确的分支,提交代码:

1
2
3
4
git checkout name-of-the-correct-branch
git stash pop
git add .
git commit -m "xxx"

也可以使用 cherry pick:

1
2
3
4
5
6
git checkout name-of-the-correct-branch
git cherry-pick master

# 最后记得把错误提交的分支上提交删除
git checkout master
git reset HEAD~ —-hard

问题排查

查看日志

查看当前状态(修改的、提交的、冲突的):

1
git status

查看本地仓库日志:

1
2
3
4
git log
[--author=ywh] # 筛选作者为 ywh 的
[--pretty=oneline] # 一个压缩后的每一条提交记录只占一行的输出\
[--name-status] # 查看变更文件

查找相关记录:

1
git log --all --grep='<content>'

简化查看提交历史:

1
2
git log --pretty=oneline --graph --decorate --all
git log --pretty=oneline --graph --abbrev-commit # 上新下旧

以树形结构查看所有分支日志:

1
git log --graph --oneline --decorate --all		

查看两周内的改动:

1
git whatchanged --since='2 weeks ago'

查看本地更新过 HEAD 的 git 命令记录,如 commit、amend、cherry-pick、reset、revert 等,可以找到 commitId 并 reset 到任意一次:

1
git reflog

错误恢复

回退版本:

1
2
git reset --hard HEAD^			# 到上一版本
git reset --hard commitId # 到指定版本

本次操作失误后撤销修改:

1
2
3
git checkout -- <filename>		# 放弃工作区的修改,有两种情况
# 文件自修改后还没有被放到暂存区,撤销修改就回到和版本库一样的状态(最近一次 git gommit)
# 文件已经添加到暂存区后又作了修改,撤销修改就回到添加到暂存区后的状态(最近一次 git add)

本地操作失误后(已添加到暂存区)撤销修改:

1
git reset HEAD <filename>		# 把已经 git add 的重新放回工作区

本地操作失误后(已提交到版本库)撤销修改:

1
git reset --hard HEAD^			# 回退到上一版本

丢弃本地所有改动和提交,获取远端的最新版本,并把本地主分支指向它:

1
git fetch --all && git reset --hard origin/master

回到某个 commit 的状态,删除后面所有 commit:

1
2
3
4
5
6
7
git reset <commit-id>			# 默认就是 -mixed 参数。

git reset –mixed HEAD^ # 回退至上个版本,它将重置HEAD到另外一个commit,并且重置暂存区以便和HEAD相匹配,但是也到此为止,工作区不会被更改。

git reset –soft HEAD~3 # 回退至三个版本之前,只回退了commit的信息,暂存区和工作区与回退之前保持一致。如果还要提交直接commit即可

git reset –hard <commitId> # 彻底回退到指定 commitId 的状态,暂存区和工作区也会变为指定commit-id版本的内容

把所有的改动重新放回工作区,删除所有 commit(目的是重新提交第一个 commit)

1
git update-ref -d HEAD

解决冲突

当 merge 出现冲突时,可查看冲突的文件:

1
2
git status
# 此时直接打开文件 查看 <<<<<<<,=======,>>>>>>> 标记的内容,修改后保存重新提交即可(add、commit)

预览差异:

1
2
3
4
git diff <sourceBarnch> <targetBranch>		# 对比两个分支
git diff <sourceCommitId> <targetCommitId> # 对比两个提交
git diff --cached # 对比暂存区和最近版本的不同
git diff HEAD # 对比暂存区、工作区和最近版本的不同

查看某个文件、任意分支的内容:

1
git show <branch>:<filename>

查看某段代码的作者:

1
git blame <filename>

配置及其他操作

忽略文件

编写 .gitignore 文件可以避免目录中的指定文件被提交,比如(可通过 git status 检验):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini

# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build

# My configurations:
db.ini
deploy_key_rsa

如果某些文件被 .gitignore 匹配,但又希望提交,可以强制添加:

1
git add -f a.egg

检查 .gitignore,会提示在哪行的规则匹配了指定的文件:

1
git check-ignore -v a.class

基本配置

设置姓名和邮箱地址:

1
2
git config --global user.name "Firstname Lastname"
git config --global user.email "Email"

命令别名:

1
git config --global alias.st "status"

修改作者名:

1
git commit --amend --author='Author Name <email@address.com>'

设置 SSH Key:

1
2
ssh-keygen -ty rsa -C "EMail"
cat ~/.ssh/id_rsa.pub # 保存到 GitHub

优化显式效果

内建图形化工具:

1
gitk

彩色的 git 输出:

1
2
3
4
# git config --global color.ui [true| auto]
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --" # git log 输出颜色

git config --global --replace-all alias.lg "log --pretty=format:'%C(auto) %h | %ai | %Cred %an %Cgreen %s'"

显示历史记录时,每个提交的信息只显示一行:

1
git config format.pretty oneline

其他

  • 如果当前修改的文档在本地的 master 上,然后想把这个修改迁移到一个 branch 上,方便做 PR,如果这些修改还没有被 add,可使用 git checkout -b new_branch_name 来完成。

  • 如果 commit 后,还没有 push,想修改一下这前的 commit,可以使用 git commit --amend

  • 使用 git pull --rebase 可以避免出现一个 merge buble。

  • 如果要删除远程分支,可以使用 git push origin --delete <remote-branchname>

  • 使用 git add -p 可以让挑选修改,可以把的一次大改动变成多个提交。

  • git checkout -pgit add -p 类似,可挑选想 checkout 的修改。

  • 可以让使用时间显示在 git 命令行上,比如:git diff HEAD@{'2 months ago'}git diff HEAD@{yesterday}git diff HEAD@{'2010-01-01 12:00:00'}

参考

CATALOG
  1. 1. Git Cheat Sheet
    1. 1.1. 仓库管理
      1. 1.1.1. 保存工作
      2. 1.1.2. 提交代码
      3. 1.1.3. 远端仓库
      4. 1.1.4. 删除操作
    2. 1.2. 标签管理
    3. 1.3. 分支管理
      1. 1.3.1. 管理策略
        1. 1.3.1.1. Feature 分支
        2. 1.3.1.2. Bug 分支
      2. 1.3.2. 标准版本号
      3. 1.3.3. 使用分支
      4. 1.3.4. 删除操作
      5. 1.3.5. 保存备份
      6. 1.3.6. 合并多个 commit
      7. 1.3.7. 将某段 commit 粘贴到另一分支
      8. 1.3.8. fork 分支与主分支同步
      9. 1.3.9. 错误提交到某分支
    4. 1.4. 问题排查
      1. 1.4.1. 查看日志
      2. 1.4.2. 错误恢复
      3. 1.4.3. 解决冲突
    5. 1.5. 配置及其他操作
      1. 1.5.1. 忽略文件
      2. 1.5.2. 基本配置
      3. 1.5.3. 优化显式效果
      4. 1.5.4. 其他
    6. 1.6. 参考