由于最近刚刚快速过完了一遍《Pro Git》,因此想要将个人比较常用的 git 命令整理出来,以便需要时翻看。因此本文是一个个人向的笔记,不会涉及对 git 原理的介绍,这部分的具体内容可以参考《Pro Git》。

准备阶段

初始化配置

# 全局配置文件位置
~/.gitconfig

# 全局配置用户名
git config --global user.name <your_name>

# 全局配置邮箱
git config --globale user.email <your_email>

新建仓库

# 本地初始化仓库
git init <repo_name>

# 远程克隆仓库
git clone <repo_url>

工作阶段

查看日志

# 查看当前分支提交日志
git log

# 查看 HEAD 指针的变动日志
git reflog

# 查看当前仓库状态
# 包括未跟踪文件、工作区变更、暂存区内容
git status

提交文件

# 将工作区更新文件存入暂存区
git add <file_path>
# 分块交互式提交
git add -p <file_path>

# 将暂存区更新提交至本地仓库
git commit
# 将当前暂存区内容追加到 HEAD 指向的提交中
git commit --amend

变更文件

# 删除文件
# 相当于 rm + git add
git rm <file_path>

# 将一个已被跟踪的文件从仓库中移除,变成未跟踪状态
git rm --cached <file_path>

# 移动/重命名文件
git mv <file_path> <new_file_path>

版本回退

# soft: 回退到 git add 后 git commit 前的状态
# mixed: 回退到修改后 git add 前的状态
# hard: 回退到修改前的状态(危险,清空的工作区不可逆)
git reset --<reset_flag> <commit>

# 反向应用 commit 的新增内容来实现回退,并创建一条新提交
git revert <commit>

差异比较

# 比较当前工作区和 Index 的差异
git diff

# 已暂存的更改
git diff --cached

分支

# 查看分支列表
git branch

# 创建新分支
git branch <branch_name>
# 创建并切换到新分支
git checkout -b <branch_name>

# 切换分支
git switch <branch_name>

# 合并提交
# 在被合并分支和当前分支在一条线上时,指针只会进行移动(fast-forward),无合并提交
# 当被合并分支和当前分支存在分叉时,将会产生一次合并提交
git merge <branch_name>

# 变基(线性合并)提交
git rebase <branch_name>

# 删除已合并的分支
git branch -d <branch_name>
# 删除未合并的分支
git branch -D <branch_name>

# 修改当前分支名
git branch -m <new_name>

远程仓库

# 添加远程仓库
git remote add <remote_name> <remote_url>

# 查看远程仓库信息
git remote -v

# 将当前仓库推送至远程仓库
# 若不指定 remote_branch,则默认 remote_branch = local_branch
# (如果 fetch = +refs/heads/*:refs/remotes/origin/* 匹配关系不做修改)
git push <remote_name> <local_branch>:<remote_branch>

# 将本地仓库的远程分支更新为远程仓库相应分支最新的状态
# 不会自动修改本地仓库的状态
git fetch <remote_name>

# 相当于 git fetch + git merge
git pull <remote_name> <remote_branch>:<local_branch>
# 相当于 git fetch + git rebase
git pull --rebase <remote_name> <remote_branch>:<local_branch>

标签

# 为 HEAD 指向的提交创建一个附注标签(允许包含说明)
git tag -a <tag_name>
# 展示标签信息
git show <tag_name>

# 为 HEAD 指向的提交创建一个轻量级标签(只是提交的一个别名标记)
git tag <tag_name>

# 为某个特定 commit 打上标签
git tag <tag_name> <commit>

# 标签需要显式推送至远程仓库
git push origin <tag_name>

补丁

# 打印某个提交并将其重定向为一个 diff 补丁文件
git show <commit> > 1.patch 
# 将补丁应用到工作区中
git apply 1.patch

# 根据最近 3 次提交创建 git 专用补丁文件
# 邮件形式,部分开源项目贡献的方式
git format-patch -3
# 应用补丁并创建提交
git am <file_path>

常用引用与限定符

# 指向下次提交的位置
HEAD
# 指向 HEAD 前一次提交
HEAD^
# 指向 HEAD 前 n 次提交
HEAD~n

# 限定操作对象为指定的文件
# 对于 diff, checkout 等均适用
-- <file_path>

实用工作场景

提取仓库中的特定提交到当前分支

# 将某个提交应用到当前分支
git cherry-pick <commit>
# 若遇到冲突,编辑冲突的文件,解决冲突后标记/添加进暂存区
git add <file_path>
# 继续应用过程
git cherry-pick --continue

暂存工作区更改

# 将工作区修改(除了未跟踪文件)暂存,并添加文字说明
git stash push -m <message>

# 恢复最近一次暂存(类似进栈出栈)到工作区
git stash pop

# 查看暂存列表
git stash list

# 恢复编号为 n 的暂存内容
git stash apply stash@{n}

# 删除编号为 n 的暂存内容
git stash drop stash@{n}

提交大文件

# 安装 LFS
sudo apt install git-lfs
git lfs install

# 跟踪大文件类型
git lfs track '*.bin'

# 正常 add 和 commit
git add largefile.bin
git commit

创建无历史记录的全新分支

# 切换到一个无任何历史的新分支
git checkout --orphan <branch_name>

# 将所有暂存区中的文件取消跟踪
git rm -rf --cached .

# 此时所有文件都处于未跟踪状态
# 可以选择性地删除本分支不需要的文件
# 并 git add + git commit 创建第一次提交

调试手段

# 打印代码中的每一次最近一次是由哪个提交修改的
git blame <file_path>

# 当想要找到某个 bug 最早是哪次提交引入的时,可以采用二分搜索
# 首先确定一个大致范围,一个有 bug 的提交,一个无 bug 的提交
# 确保 HEAD 移动到包含这两次提交的位置(如 master 分支)
git checkout master

# 重置 bisect 状态
git bisect reset
# 开始 bisect
git bisect start

# 标记两次关键提交
git bisect good <good_commit>
git bisect bad <bad_commit>

# 编译测试,判断是否存在 bug
# 有则标记为 bad,无则标记为 good
git bisect bad/good
# 标记后自动跳转到中间提交位置
# 重复以上操作,直到收敛到最终的一次关键提交

参考资料

【GeekHour】一小时Git教程_哔哩哔哩_bilibili

前言 · Pro Git 第二版 简体中文