背景
在学习过 Git 的常用、进阶操作之后,我们再来结合工作中的实际场景以进一步提高实战能力。 如果对 Git 的基础还不够扎实,可以看看前一篇文章。 上集回顾:☝️🤓重学 Git(一)------ 掌握从常用到进阶的指令操作
首先说一下通过这篇文章大家能收获什么:
- 继上一章,对于一些
Git指令的补充。- 使用一系列
Git指令熟练处理工作中的问题。
Git 指令补充
在模拟实际场景前,我们先对一些指令的作用、比对,以及一些操作进行深入探讨。
强推的细节
强制推送是指将本地分支的提交强制推送到远程仓库,覆盖远程仓库中的相应分支。切记!强制推送也可能导致数据丢失或冲突,因此需要谨慎使用。
这边仅介绍工作中常见的两种强推方式: --force、--force-with-lease
--force
shell
git push -f/--force origin <branch-name>
这种强推是没有任何协商的,建议仅在单人开发分支使用,使用这个选项时,Git 不会检查是否有其他人同时在远程仓库上进行了提交,可能会导致数据丢失或冲突。
--force-with-lease
shell
git push --force-with-lease origin <branch-name>
相对更安全的强制推送选项,在执行之前会先检查远程仓库上的提交历史,与本地提交历史比较。只有在本地仓库的提交历史是基于远程仓库的最新提交时,才会执行推送操作。个人建议仅使用这种强推。
blob通配符筛选文件,进行批量操作
通配符在需要批处理文件记录时有很大的用处。
案例:ts 项目,工作区有修改过的 ts 文件,此时执行了 npx tsc --build,产生了大量的 .d.ts、.js、.js.map 等文件(但并不需要这些文件),此时手动筛选出修改过的文件就比较考验眼力了,因此可以通过通配符,将这些格式的文件清除。
相关的操作方式还请阅读相关文档:Git 使用通配符扩展的Git命令
revert和reset对比
两者的核心功能都是撤销 Git 提交,相关的区别如下:
-
作用对象:
revert:用于撤销一个或多个已提交的提交记录。它会创建对应数量的新提交来撤销指定的提交内容。reset:用于修改当前分支的位置,并丢弃一些提交记录。
-
修改历史记录:
revert:会保留之前的提交记录。reset:可以通过不同的模式来修改历史记录。使用--soft模式会移动当前分支的指向,但不会更改工作目录和暂存区。使用--mixed模式(默认)会移动当前分支的指向,并重置暂存区,但不会更改工作目录。使用--hard模式会完全重置当前分支的指向,并将工作目录和暂存区恢复为指定提交的状态。
-
影响协作:
revert:适用于公共分支上的协作,因为它创建一个新的提交来撤销指定提交,不会影响其他人的工作。reset:慎用在公共分支上,因为它会修改历史记录,可能导致其他人在分支上的工作丢失或冲突。
-
安全性:
revert:较为安全,因为它创建一个新的提交来撤销指定提交,不会修改已有的提交记录。reset:潜在风险较高,因为它会修改历史记录,可能导致数据丢失。使用前需谨慎考虑。 git revert 会依据选择的提交记录进行抵消
各类分支场景的解决方案
这一部分会结合各个可能在工作中遇到的场景,给出有效的解决方案,这边建议在看到场景和需求之后先自己实现一下(脑补也行)!千万不要怕麻烦,不然麻烦的就是工作中的自己😭!
场景一:分支合并
基准分支:release1.0
开发分支: featA、featB
分支情况:分支开发完毕,featB 有4个提交,featB 有2个提交
需求:release1.0 经过一次 bug 修复,现在需要将两分支合入release1.0
最简单的思路:逐个 merge,然后解冲突。这种逐个合并的方法相对简单直接,但可能比较耗时、复杂,尤其是在合并多个提交时。
因此我们可以使用 rebase、cherry-pick 的方式来合并分分支:
(featA) git rebse release1.0将 featA 变基到 release1.0 上(featA) git cherry-pick featB-commit-1 featB-commit-2将 featB 的两个提交- 提 mr ------ featA 合入 release1.0
这边在第二点使用 cherry-pick 是考虑到 featB 的提交只有2个,比 rebase 4个提交要方便得多。


场景二:回滚提交
基准分支:release1.0
开发分支: featA 分支情况:分支开发完毕,featA 有2个提交,commit1 新增了功能1,commit2 新增了功能2
需求:将这一版本的功能1延期到 release1.1
此时我们就需要将 featA 的 commit1 进行回滚。 此处可能会想到使用 reset,但其实有个更好的方案: revert。
git revert 通过创建一个新的提交来撤销指定的提交(相互抵消)

因此我们可以直接通过 git revert commit1 来抵消第一次的提交。 ps:revert 与 reset 的比对会在下一部分详细说明。
场景三:最新提交的错误修复
基准分支:release1.0
开发分支: featA 分支情况:分支开发完毕,featA 有2个提交,commit1 新增了功能1,commit2 新增了功能2 需求:发现功能2还有缺陷,但不希望有新提交
此时的方案就是修改后,通过 git commit --amend 来合并分支,具体的步骤如下:
- 修改缺陷,
git add -A、git commit --amend - 根据情况改写 commit 的说明,保存提交
git push --force-with-lease origin featA强推提交
场景四:git stash 暂存记录
基准分支:release1.0
开发分支: featA 分支情况:分支开中 需求:开发到一半,工作区未提交,此时因为一些紧急需求需要切换分支
通过 git stash 可以轻松实现这个问题:
git stash将工作区内容储藏- 切换分支,处理好问题后,切回分支
git stash pop将储藏的内容取回
当然还有一个解决思路:一个仓库拉两个项目,这个行为是十分推荐的,比如对构建工具进行升级,一些配置需要进行对比,拉两个对比新旧无疑是非常方便的选择~
场景五:重要分支被污染
这是本人在工作中遇到的一个场景,因为一时的疏忽,rebase 的分支选错了。背景有点长,先仔细看看:
基准分支:release1.0
开发分支: featA、release1.1
分支情况:分支需要集中于
release1.1提测,featA涉及到基建改动,提 mr (merge request) 时不希望被其他改动污染,因此切出featA-backup,rebase1.1 后提交了 mr,此时featA需要再提一个 mr 基于 1.0 方便进行code review污染原因:提测一半发现有源自
featA的 bug,在featA上修改后rebase了 1.1,切出新分支合入 1.1
仔细想想真的很粗心,本来应该从 featA 再切出一个新分支再 rebase 1.1 的,先后顺序的不一致导致了 featA mr 1.0 的 code review 受到了影响。
这边是操作前后的分支情况图:

还好有 Git 大法!!!这边祭出我的解决方案:
- 可以看到 C3、C4 混进了
featA的提交记录中,可以先通过git reset C2清除后面的记录 - 切换到
featA-backup分支,拿到 C5 的 commit 值,返回featA - 通过
git cherry-pick C5将 C5 接入 C2 后,至此完成回退
其实还有另一种办法:
git revert C3 C4,通过新的提交抵消 C3、C4git rebase -i HEAD~5合并 C3、C4、C5、C3'、C4',等同于 C5
还有更多的场景会在后续逐步更新~
最后的最后
Git 的实际远远不止于此,在后续也会随着能力积累更新更多相关的文章出来。
面对工作中的 Git 问题,还是要熟能生巧,多查多练,期望能早早玩透 Git 大法🤓~