背景
在学习过 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
,rebase
1.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
大法🤓~