Git 速查手册 
Git 基本流程 

Git管理的文件有 5 种状态:
- 未跟踪(untracked):新添加的文件,或被移除跟踪的文件,未建立跟踪,通过 git add 添加暂存并建立跟踪。
- 未修改:从仓库签出的文件默认状态,修改后就是“已修改”状态了。
- 已修改(modified):文件被修改后的状态。
- 已暂存(staged):修改、新增的文件添加到暂存区后的状态。
- 已提交(committed):从暂存区提交到版本库。
分支操作 
创建并切换分支 
git checkout -b <new-branch-name>切换分支 
git checkout <branch-name>重命名分支 
先切换到要重命名的分支,然后执行以下命令:
git checkout <old-branch-name>
git branch -m <new-branch-name>或者不需要切换分支,直接使用以下命令:
git branch -m <old-branch-name> <new-branch-name>删除分支 
# 在删除某个分支之前,确保你不在该分支上
git branch -d <branch-name>Git Rebase 
git rebase 是 Git 中一个用于合并变更的命令,可以将一个分支的提交“重新应用”到另一个分支上,同时保持提交历史的清晰。通常在下面的场景中使用:
- 我们从 main 分支拉取了一条 feature 分支在本地进行功能开发。
- 远程的 main 分支在之后又合并了一些新的提交。
- 我们想在 feature 分支集成 main 的最新更改。(比如与 main 分支有冲突,需要在 feature 分支解决冲突)
基本操作 
- 切换到要 rebase 的分支:
git checkout <branch>- 执行 rebase:将 feature-branch的提交应用到main分支上。
git rebase main- 处理冲突:如果 rebase 过程中遇到冲突,Git 会提示手动解决。解决冲突后执行:
git add <file>
git rebase --continue- 完成 rebase 后推送:由于 rebase 会重写提交历史,推送时需要使用 --force。
git push --force在推送到自己的 feature 分支之后,可以提交 pull request 将修改合并到 main 分支。
交互式 Rebase 
git rebase -i(interactive rebase)是 Git 提供的一个交互式 rebase 功能,允许你在 rebase 过程中精细控制提交历史。它特别适合整理和优化提交历史,修改多个提交的顺序、内容,甚至合并、删除提交。
- 执行交互式 rebase: 在分支上使用 git rebase -i,并指定基准提交(基准是当前分支的父分支或任意提交),例如:
git rebase -i HEAD~3这会打开一个文本编辑器,显示过去 3 次提交的列表:
a1b2c3d Fix a bug
b2c3d4e Add new feature
c3d4e5f Improve documentationgit rebase -i 不仅可以使用 HEAD~N 指定一个范围,还可以直接指定一个具体的提交哈希(commit hash)作为基准,这样可以更灵活地选择需要操作的提交。
git rebase -i <commit-hash>在这条命令中,<commit-hash> 是你想要作为基准的提交。所有位于该提交之后的提交都会进入交互式 rebase 编辑模式。值得注意的是,指定的 <commit-hash> 本身不会被修改,它只会作为 rebase 的起点。
假设你的提交历史如下:
a1b2c3d Fix a bug
b2c3d4e Add new feature
c3d4e5f Improve documentation
d4e5f6g Initial commit你想对最近的 3 个提交进行交互式 rebase,但基准设为 d4e5f6g(即最早的 Initial commit)。可以执行以下命令:
git rebase -i d4e5f6g这将会打开编辑器,显示从 c3d4e5f 到 a1b2c3d 的提交列表供你编辑:
a1b2c3d Fix a bug
b2c3d4e Add new feature
c3d4e5f Improve documentation- 编辑提交操作: 每个提交前的 pick表示 Git 将按顺序应用这些提交。可以将pick替换为以下命令:
- pick:保持提交不变。
- reword:修改提交信息。
- edit:修改提交的内容或信息。
- squash:将当前提交与前一个提交合并。
- fixup:类似- squash,但不保留当前提交的信息。
- drop:删除提交。
- 保存并退出: 编辑完提交列表后,保存文件并退出编辑器,Git 会根据你指定的命令逐步执行操作。
假设你有以下提交历史:
pick a1b2c3d Fix a bug
pick b2c3d4e Add new feature
pick c3d4e5f Improve documentation你可以将这些操作修改为:
pick a1b2c3d Fix a bug
squash b2c3d4e Add new feature
fixup c3d4e5f Improve documentation这会将后两个提交合并到第一个提交中,保持一个干净的历史记录。
处理冲突 
如果在 rebase 过程中遇到冲突,Git 会暂停,并要求你解决冲突。解决冲突后,运行:
git add <conflict-file>
git rebase --continue如果你想中止 rebase,可以运行以下命令:
git rebase --abort参考资料
Git Merge 
git merge 和 git rebase 命令类似,也是用于将一个分支的变更合并到当前分支。与 git rebase 保持历史记录清晰线性不同,git merge 会保留分支的历史记录并生成一个新的合并提交(merge commit)。
要将 main 分支合并到 feature 分支,以下是详细步骤和例子:
- 切换到 feature 分支:
git checkout feature- 执行 git merge 命令将 main合并到feature:
git merge main如果两者的代码没有冲突,Git 会直接进行快速合并。 如果合并过程中有冲突,Git 会标记冲突的文件,并要求你手动解决冲突:
使用编辑器打开冲突文件,解决冲突后,将其标记为已解决:
git add <conflict-file>继续合并过程:
git commitGit Rebase 和 Git Merge 的区别 

git merge:
- 方式:将两个分支的变更合并,并创建一个新的合并提交(merge commit)。它保留了每个分支的原始提交历史。
- 结果:合并历史会显示出分叉点,并在合并时产生额外的 merge commit。
git rebase:
- 方式:将一个分支的提交重新应用到目标分支的最新状态。它会将你当前分支的提交“移到”目标分支之上,使提交历史变得线性。
- 结果:不产生新的 merge commit,提交历史更简洁、连续。
Cherry-pick 操作 
git cherry-pick 是一个 Git 命令,用于从一个分支中选择特定的提交,并将该提交应用到当前所在的分支。它的作用是将某个提交(或者多个提交)从一个分支复制到另一个分支,而无需合并整个分支。这样可以方便地在不同分支之间应用特定的修改,而不需要进行完整的合并。
主要用途:
- 修复或功能迁移:当你只想从某个分支(如 master)提取特定的修改,应用到当前分支(如hotfix),而不需要整个分支的改动时。
 
- 修复或功能迁移:当你只想从某个分支(如 
- 避免全量合并:有时你不希望将整个分支合并到当前分支,只想引入一个或多个具体的提交,cherry-pick就能帮你做到这一点。
 
- 避免全量合并:有时你不希望将整个分支合并到当前分支,只想引入一个或多个具体的提交,
- 快速修复:如果你在 master分支上做了一些修复,想要将这些修复快速应用到hotfix分支中,可以使用cherry-pick。
 
- 快速修复:如果你在 
假设你在 master 分支上有一个提交(commit A),而你想把这个提交应用到 hotfix 分支上:
git checkout hotfix
git cherry-pick <commit-hash-of-A>这样,commit A 就会被应用到 hotfix 分支,而不会影响 master 分支上的其他提交。
撤销修改 
撤销工作区中的修改 
如果你在工作目录中修改了文件,但尚未将其添加到暂存区,可以使用以下命令恢复到最近的提交状态:
# 建议使用 -- 参数用于明确区分文件名和其他选项
git checkout -- <file-name>
# 撤销工作区中所有文件的修改
git checkout .修改上一次提交(未推送到远程) 
如果你只是想修改上一次提交的内容或提交信息,可以使用 --amend 选项。这不会真正撤销提交,而是允许你修改它。
git commit --amend这会打开编辑器,你可以修改提交信息,也可以通过 git add 添加新的更改到该提交中。
撤销最后一次提交,但保留文件的更改和暂存 

如果你已经提交了更改,但希望撤销提交并保留文件的更改在工作目录中(即不丢失工作内容),你可以使用 git reset --soft。
git reset --soft HEAD^- --soft:将提交撤销,但保留所有修改在暂存区中,你可以重新提交。
- HEAD^:表示上一个提交(最后一次提交)。
这样提交会被撤销,但文件仍然保持已暂存状态,你可以根据需要修改或者重新提交。
撤销最后一次提交并保留修改但不暂存 
如果你希望撤销提交,并且将所有文件的更改从暂存区移到工作目录中(即取消暂存),可以使用 git reset --mixed。 --mixed 是默认选项,可以省略。
git reset --mixed HEAD^
# 或者
git restore --staged撤销最后一次提交并取消所有更改 
如果你不仅想撤销提交,还想丢弃所有已提交的更改(即回到提交之前的状态),你可以使用 git reset --hard。注意,这种方式会丢失更改。
git reset --hard HEAD^撤销已经推送到远程仓库的提交 
如果你已经将提交推送到远程仓库,那么你撤销的操作会更加复杂,特别是在团队协作中,你需要谨慎操作。以下是几种方法:
方法 1:使用 git revert 
git revert 用来生成一个新的提交,它会反转某个提交的内容,不修改提交历史。适用于已经推送到远程的情况。
git revert <commit-hash>- 这会生成一个新的提交,撤销指定的提交。
方法 2:使用 git reset + 强制推送 
你也可以使用 git reset --hard 撤销本地提交,然后强制推送到远程仓库。注意:这会重写远程历史记录,可能会影响其他团队成员的工作,慎用。
git reset --hard HEAD^
git push origin <branch-name> --force参考资料
保持本地 Fork 仓库与上游仓库同步 
设置上游仓库(只需要首次设置) 
首先在 Github 上 fork 上游仓库。

然后 clone fork 的仓库到本地。
# 本例中是 git clone https://github.com/cr7258/higress.git
git clone https://github.com/<your-github-user>/<repo>.git
cd <repo>添加上游仓库作为远程仓库。
# 本例中是 git remote add upstream https://github.com/alibaba/higress.git
git remote add upstream https://github.com/<upstream>/<repo>.git验证上游仓库是否添加成功。
git remote -v
# 示例输出
origin	https://github.com/cr7258/higress.git (fetch)
origin	https://github.com/cr7258/higress.git (push)
upstream	https://github.com/alibaba/higress.git (fetch)
upstream	https://github.com/alibaba/higress.git (push)同步上游仓库的更新 
获取上游仓库的更新。
git fetch upstream将上游的更新 rebase 到本地分支。
git checkout main  # 切换到你要更新的分支,通常是 main 或 master
git rebase upstream/main  # 将上游的 main 分支 rebase 到本地的 main 分支解决可能的冲突,如果有冲突,Git 会提示你处理冲突,处理完冲突后继续 rebase。
git rebase --continue推送更新到你的 fork 仓库,如果使用了 rebase,需要强制推送。
git push -f origin main完全同步上游(丢弃本地改动) 
git fetch origin
git reset --hard origin/<branch-name>使用 Git Worktree 管理多分支 
git worktree 允许你在同一仓库中同时检出多个分支,从而方便并行开发和减少频繁的分支切换,提高开发效率。
创建一个新的 Worktree 
# 方式一:基于当前分支,新建一个 worktree 目录,新的分支名就是新建目录的名称
git worktree add <path>
# 示例:假设当前在 feature-1 分支,那么执行以下命令会在项目目录平级(假设在项目根目录执行命令)的 feature-2 目录下基于 feature-1 分支创建一个 feature-2 分支
git worktree add ../feature-2
# 方式二:基于当前分支,新建一个 worktree 目录,新的分支名是指定的名称
git worktree add <path> -b <branch>
# 方式三:基于指定分支,新建一个 worktree 目录,新的分支名是指定的名称
git worktree add <path> -b <branch> <commit|branch>
# 示例:假设当前在 feature-1 分支,那么执行以下命令会在项目目录平级(假设在项目根目录执行命令)的 feature-2 目录下基于 main 分支创建一个 feature-2 分支
git worktree add ../feature-2 -b feature-2 main
# 或者
git worktree add ../feature-2 main列出 Worktree 
git worktree list
# 输出示例
/Users/I576375/tmp/git-demo/higress        6f5c0f4 [new-feature-1]
/Users/I576375/tmp/git-demo/hotfix-1       210b97b [hotfix-1]删除 Worktree 
git worktree remove <worktree>
# 示例
git worktree remove hotfix-1参考资料
Git Clone 
使用 Git SSH 协议 Clone 仓库 
当 Git 仓库太大时,或者网络环境不好时,使用 SSH 协议 clone 仓库可能会更稳定。请确保你已设置 SSH 密钥对并将公钥添加到你的 GitHub 帐户。

如果默认的 Github 的 22 端口不可用,可以使用 443 端口。配置 ~/.ssh/config 文件:
Host github.com
  Hostname ssh.github.com
  Port 443然后就可以使用 SSH 协议 clone 仓库了:
git clone git@github.com:<username>/<repo>.git
# 例如
git clone git@github.com:cr7258/pytorch-deep-learning.gitGit 配置 
设置缓冲区 
遇到 fatal: the remote end hung up unexpectedly 错误时,可以尝试增加缓冲区大小。
git config http.postBuffer 524288000Git LFS 
Git LFS(Large File Storage)是一个 Git 扩展,专门用于管理大文件或二进制文件。它允许你将大文件托管在远程服务器,而不占用 Git 仓库的空间。使用 Git LFS 可以有效避免 Git 仓库膨胀问题。
以下是 Git LFS 的使用步骤:
1. 安装 Git LFS
在使用 Git LFS 之前,你需要先安装它。
macOS:
brew install git-lfsUbuntu/Debian:
sudo apt-get install git-lfsWindows: 通过 Git for Windows 安装程序安装 Git LFS,或从官网 Git LFS Releases 下载并安装。
2. 初始化 Git LFS
安装完成后,在你的项目中运行以下命令来初始化 Git LFS:
git lfs install这会将 Git LFS 设置为你的 Git 仓库的一部分。
3. 跟踪大文件
Git LFS 可以通过文件扩展名或者特定的文件路径来跟踪大文件。比如要跟踪所有的 .psd 文件,可以使用以下命令:
git lfs track "*.psd"这会在仓库中创建一个 .gitattributes 文件,记录了哪些文件是用 Git LFS 跟踪的。
4. 提交大文件
当你添加和提交文件时,Git LFS 会自动处理大文件。可以像平常一样使用 Git 命令提交大文件:
git add path/to/largefile.psd
git commit -m "Add large PSD file"
git push origin mainGit LFS 会将大文件推送到远程 Git LFS 服务器,而 Git 仓库只存储指向这些文件的指针文件。
5. 获取大文件
如果克隆了一个使用 Git LFS 的仓库,你需要运行以下命令来下载 LFS 文件:
git lfs pull可以通过 git config lfs.fetchinclude 或者 git config lfs.fetchexclude 设置在 git lfs pull 时处理的文件,例如:
# 配置 LFS 下载对象时仅包含 images 文件夹
git config lfs.fetchinclude 'images/**'
# 也可以选择仅排除指定的文件夹
git config lfs.fetchexclude 'videos/**'如果你想在克隆时自动获取大文件,可以在克隆时加上 --recursive 选项:
git clone --recursive <repository-url>6. 检查 LFS 状态
要检查哪些文件被 LFS 跟踪,可以使用以下命令:
git lfs ls-files7. 移除文件跟踪
如果想要停止 LFS 跟踪某个文件类型或文件路径,你可以手动编辑 .gitattributes 文件,移除相关条目,然后执行以下命令:
git lfs untrack "*.psd"参考资料
用户管理 
保存用户凭证 
执行以下命令,然后执行 Git 操作(比如 pull 或者 push 仓库),密码就会被自动保存在 ~/.git-credentials 文件中。
git config --global credential.helper store为不同 Repo 设置不同的用户信息 
假设要为个人 Repo 和工作 Repo 设置不同的用户信息,个人 Repo 是默认的 github.com,工作 Repo 是 <your-git-url>。首先创建一个配置文件 ~/.gitconfig-work 存放工作 Repo 的用户信息:
# ~/.gitconfig-work
[user]
  name = sevenc
  email = sevenc@your-domain.com然后在 ~/.gitconfig 中包含工作 Repo 的配置文件。
# 默认的用户信息
[user]
  name = cr7258
  email = chengzw258@163.com
# 包含工作 Repo 的配置文件
[includeIf "hasconfig:remote.*.url:https://<other-git-url>/**"]
  path = /<your-path>/.gitconfig-nvidia问题 
Git 仓库太大或者网络问题 Clone 失败 
有时候由于网络问题或者 Git 仓库太大,可能导致 clone 失败。
git clone https://github.com/cr7258/pytorch-deep-learning.git
Cloning into 'pytorch-deep-learning'...
remote: Enumerating objects: 4252, done.
remote: Counting objects: 100% (274/274), done.
remote: Compressing objects: 100% (107/107), done.
error: RPC failed; curl 18 Transferred a partial file46 MiB/s
error: 8172 bytes of body are still expected
fetch-pack: unexpected disconnect while reading sideband packet
fatal: early EOF
fatal: fetch-pack: invalid index-pack output可以尝试以下方法:
- 增加缓冲区大小:可以尝试增加 Git 的缓冲区大小以允许更大的传输。
git config --global http.postBuffer 524288000  # Set a larger buffer size
git config --global core.compression 0         # Disable compression- 使用 SSH clone。
- 尝试 shallow clone,只克隆最近的提交,例如:
git clone --depth=1 https://github.com/cr7258/pytorch-deep-learning.git参考资料
 Se7en的架构笔记
Se7en的架构笔记