当前位置:   article > 正文

使用 git add -p 整理 patch

git add -p

背景

不格 https://m.vbuge.com

当我们修改了代码准备提交时,本地的改动可能包含了不能提交的调试语句,还可能需要拆分成多个细粒度的 pactch

本文将介绍如何使用 git add -p 来交互式选择代码片段,辅助整理出所需的 patch

官方介绍

先贴个帮助信息供参考

英文版本:

  1. -p, --patch
  2. Interactively choose hunks of patch between the index and the work tree and add them to
  3. the index. This gives the user a chance to review the difference before adding modified
  4. contents to the index.
  5. This effectively runs add --interactive, but bypasses the initial command menu and
  6. directly jumps to the patch subcommand. See “Interactive modefor details.

中文版本:

  1. -p, --patch
  2. 交互地在索引和工作树之间选择补丁块并将它们添加到索引中。这让用户有机会在将修改后的内容添加到索引之前查看差异。
  3. 这可以有效地运行 add --interactive,但是会绕过初始命令菜单,而直接跳转到 patch 子命令。有关详细信息,请参见`‘交互模式’'。

demo 视频版

以下文字版例子对应的视频演示:

demo 文字版

我们造个例子来说明,假设我们本次完成了两个功能,fun1 和 fun2,希望分开提交。另外在修改过程中还引入了一些调试的打印,是不需要提交的。

代码的 diff 如下

  1. --git a/demo.c b/demo.c
  2. index 0473c1a..76cfb22 100644
  3. --- a/demo.c
  4. +++ b/demo.c
  5. @@ -1,16 +1,31 @@
  6. #include <stdio.h>
  7. +void fun1()
  8. +{
  9. + printf("before hello world
  10. ");
  11. +}
  12. +
  13. void demo()
  14. {
  15. ;
  16. }
  17. +void fun2()
  18. +{
  19. + printf("after hello world
  20. ");
  21. +}
  22. +
  23. int main()
  24. {
  25. + fun1();
  26. printf("hello world
  27. ");
  28. + printf("debug %s %d
  29. ", __func__, __LINE__);
  30. printf("hello world
  31. ");
  32. printf("hello world
  33. ");
  34. printf("hello world
  35. ");
  36. + printf("debug %s %d
  37. ", __func__, __LINE__);
  38. printf("hello world
  39. ");
  40. + fun2();
  41. demo();
  42. + printf("debug %s %d
  43. ", __func__, __LINE__);
  44. }

此时直接 git add 会把整个文件的改动都加进来,不符合需求。

这正是 patch mode 发挥作用的地方,我们可以挑选一部分改动进行提交。

输入 git add -p 进入 patch mode , 此时 git 会自动将改动切分成多个片段,并展示第一个片段,提示你进行选择。

提示语句是 Stage this hunk [y,n,q,a,d,/,s,e,?]?

这些字母都是什么意思呢? 输入?回车,可以查看详细的帮助信息。

英文版本:

  1. y - stage this hunk
  2. n - do not stage this hunk
  3. q - quit; do not stage this hunk or any of the remaining ones
  4. a - stage this hunk and all later hunks in the file
  5. d - do not stage this hunk or any of the later hunks in the file
  6. g - select a hunk to go to
  7. / - search for a hunk matching the given regex
  8. j - leave this hunk undecided, see next undecided hunk
  9. J - leave this hunk undecided, see next hunk
  10. k - leave this hunk undecided, see previous undecided hunk
  11. K - leave this hunk undecided, see previous hunk
  12. s - split the current hunk into smaller hunks
  13. e - manually edit the current hunk
  14. ? - print help

中文版本:

  1. y - 暂存此区块
  2. n - 不暂存此区块
  3. q - 退出;不暂存包括此块在内的剩余的区块
  4. a - 暂存此块与此文件后面所有的区块
  5. d - 不暂存此块与此文件后面所有的 区块
  6. g - 选择并跳转至一个区块
  7. / - 搜索与给定正则表达示匹配的区块
  8. j - 暂不决定,转至下一个未决定的区块
  9. J - 暂不决定,转至一个区块
  10. k - 暂不决定,转至上一个未决定的区块
  11. K - 暂不决定,转至上一个区块
  12. s - 将当前的区块分割成多个较小的区块
  13. e - 手动编辑当前的区块
  14. ? - 输出帮助

对于我们的例子,git第一次自动给出的hunk很大,可以先执行 s 分割下。分割后第一个区块就只包含增加的 fun1 函数了。

  1. /* 太占篇幅,此处省略原始 hunk */
  2. Stage this hunk [y,n,q,a,d,/,s,e,?]? s /* 询问我们对第一个片段的处理,我们觉得太大,按 s 要求分割 */
  3. Split into 7 hunks. /* 可以看到,s 让 git 将原始片段进一步切分成了 7 个片段,接下来就是自动展示第一个片段 */
  4. @@ -1,7 +1,12 @@
  5. #include <stdio.h>
  6. +void fun1()
  7. +{
  8. + printf("before hello world
  9. ");
  10. +}
  11. +
  12. void demo()
  13. {
  14. ;
  15. }
  16. Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? /* 询问我们对第一个片段的处理 */

输入 y 回车选中这个 fun1 的改动,git 就会自动展示下一个片段,继续询问我们。

这样对片段使用 yn,我们就可以只挑选出涉及 fun1 的改动,当我们确认后续没有 fun1 相关的改动时,就可以按 q 退出挑选了。

此时 git status 可以看到部分改动在暂存区中。

  1. $ git status
  2. On branch master
  3. Changes to be committed:
  4. (use "git reset HEAD <file>..." to unstage)
  5. modified: demo.c
  6. Changes not staged for commit:
  7. (use "git add <file>..." to update what will be committed)
  8. (use "git checkout -- <file>..." to discard changes in working directory)
  9. modified: demo.c

使用 git diff --cached 可以具体确认要提交的内容,是否符合我们的预期,只包含 fun1 的改动,不包含 fun2 和调试语句。

  1. $ git diff --cached
  2. diff --git a/demo.c b/demo.c
  3. index 0473c1a..b9fd4d4 100644
  4. --- a/demo.c
  5. +++ b/demo.c
  6. @@ -1,5 +1,10 @@
  7. #include <stdio.h>
  8. +void fun1()
  9. +{
  10. + printf("before hello world
  11. ");
  12. +}
  13. +
  14. void demo()
  15. {
  16. ;
  17. @@ -7,6 +12,7 @@ void demo()
  18. int main()
  19. {
  20. + fun1();
  21. printf("hello world
  22. ");
  23. printf("hello world
  24. ");
  25. printf("hello world
  26. ");

确认无误就可以提交第一个patch, 即 fun1 的改动了。

git commit -m "fun1"

接下来继续使用 git add -p,配合s,y,'n'就可以进一步挑选出fun2的改动了。

如果要挑选的改动比较明确,可以直接使用 /来搜索到目标hunk,省去逐个片段判断的麻烦。例如执行 /fun2 来搜索包含 fun2 的代码片段。

git add -p 挑选完之后,建议使用 git diff --cached 确认下,或者在提交之后 git show 确认下改动,如有错漏,及时修正,多退少补。

大部分情况使用s y n就足够了。但如果有些改动是混合在一起的,无法使用s来分割,那就得用 e 来手工编辑了,下回分解吧。

blog: https://www.cnblogs.com/zqb-all/p/13020293.html
公众号:https://sourl.cn/MDcrJA

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/822821
推荐阅读
相关标签
  

闽ICP备14008679号