介绍

Git 在实际使用时,经常会遇到一些反直觉的特性,这里简单总结一下。

撤消已推送的提交

如果提交已经推送到远程分支,则分为两种情况:

如果是多人协作的分支,例如 main 分支。在这种情况下,如果修改已经推送的提交,再使用强制推送方式更新远程分支,对于拉取到之前错误提交的人来说,再次拉取时会产生合并冲突。因此对于这种情况,推荐使用 revert 命令生成一个相反的提交来进行撤消操作。

如果是少数人使用的特性分支,在可以通知其他人使用 pull --rebase 方式更新的话,可以修改已推送的提交并强制推送。

轻量的分支

很多人以为 Git 的分支与其他版本控制系统一样会非常占用空间,实际上并不是这样。Git 的分支只是提交的指针而已,切换分支只是将工作目录中的文件更新为指针指向的快照而已。因此 Git 创建分支的速度非常快,正常不到 100ms 就可以创建成功。

由于切换分支时工作目录中的文件会发生变化,会导致 Unity 重新导入文件之类的操作。因此对于比较大型复杂的项目,建议使用复制多个项目目录的方式进行并行工作,这样同时也减少了不必要的处理未提交文件的问题。

隐藏的提交

reflog 与 stash 默认情况下都看不到,需要使用单独的命令管理,不过 Fork 客户端可以将其在 UI 中显示出来。

reflog

Git 使用 reflog 管理分支头部与本地其他引用的变化。也就是说只要提交过的东西,都可以使用 reflog 查询到。

Fork 可以通过 View | Show Lost Commits (Reflog) 在 UI 中显示 reflog。

注意:gc 之类的清理命令有可能会将没有直接引用的提交删除,这意味着 reflog 中的提交可能会被清理。

stash

stash 操作会将暂存区与工作目录的文件提交,并移除本地的修改。

Fork 可以通过 View | 取消勾选 Hide Stashes in Commit List 在 UI 中显示 stash。

注意:默认情况下 stash 并不会处理未追踪文件,需要手动指定 --include-untracked 选项才能处理未追踪文件。

提交历史图

Git 的提交可以有 0 个、1 个或多个父提交,所有提交组合在一起就是提交历史,因此严格意义上来说,Git 的提交历史是一个有向无环图。

由于 pull 默认的操作是 merge,因此如果本地与远程同时提交后,本地 pull 操作后会生成一个合并提交才能推送,如果所有协作者都使用这种方法,很快提交历史图就会变成一团乱麻。具体的处理方法见: