• 【git | 08】使用 git add -p 整理 patch


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

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

    官方介绍

    先贴个帮助信息供参考

    英文版本:

    -p, --patch

    Interactively choose hunks of patch between the index and the work tree and add them to
    the index. This gives the user a chance to review the difference before adding modified
    contents to the index.

    This effectively runs add --interactive, but bypasses the initial command menu and
    directly jumps to the patch subcommand. See “Interactive mode” for details.

    中文版本:

    -p, --patch

    交互地在索引和工作树之间选择补丁块并将它们添加到索引中。
    这让用户有机会在将修改后的内容添加到索引之前查看差异。

    这可以有效地运行 add --interactive,但是会绕过初始命令菜单,
    而直接跳转到 patch 子命令。有关详细信息,请参见`‘交互模式’'。

    demo 动图

    后文例子对应的gif (上传的时候才知道公众号的 gif 限制为300帧,于是临时删除了一多半的帧,将就看吧) :

    图片

    试试转成视频:

    demo 文字版

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

    代码的 diff 如下

     --git a/demo.c b/demo.c
    index 0473c1a..76cfb22 100644
    --- a/demo.c
    +++ b/demo.c
    @@ -1,16 +1,31 @@
     #include <stdio.h>

    +void fun1()
    +{
    +       printf("before hello world ");
    +}
    +
     void demo()
     {
            ;
     }

    +void fun2()
    +{
    +       printf("after hello world ");
    +}
    +
     int main()
     {
    +       fun1();
            printf("hello world ");
    +       printf("debug %s %d ", __func__, __LINE__);
            printf("hello world ");
            printf("hello world ");
            printf("hello world ");
    +       printf("debug %s %d ", __func__, __LINE__);
            printf("hello world ");
    +       fun2();
            demo();
    +       printf("debug %s %d ", __func__, __LINE__);
     }

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

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

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

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

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

    英文版本:

    y - stage this hunk
    n - do not stage this hunk
    q - quit; do not stage this hunk or any of the remaining ones
    a - stage this hunk and all later hunks in the file
    d - do not stage this hunk or any of the later hunks in the file
    g - select a hunk to go to
    / - search for a hunk matching the given regex
    j - leave this hunk undecided, see next undecided hunk
    J - leave this hunk undecided, see next hunk
    k - leave this hunk undecided, see previous undecided hunk
    K - leave this hunk undecided, see previous hunk
    s - split the current hunk into smaller hunks
    e - manually edit the current hunk
    ? - print help

    中文版本:

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

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

    /* 太占篇幅,此处省略原始 hunk */
    Stage this hunk [y,n,q,a,d,/,s,e,?]? s /* 询问我们对第一个片段的处理,我们觉得太大,按 s 要求分割 */
    Split into 7 hunks. /* 可以看到,s 让 git 将原始片段进一步切分成了 7 个片段,接下来就是自动展示第一个片段 */
    @@ -1,7 +1,12 @@
     #include <stdio.h>

    +void fun1()
    +{
    +       printf("before hello world ");
    +}
    +
     void demo()
     {
            ;
     }

    Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?  /* 询问我们对第一个片段的处理 */

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

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

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

    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)

            modified:   demo.c

    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)

            modified:   demo.c

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

    $ git diff --cached
    diff --git a/demo.c b/demo.c
    index 0473c1a..b9fd4d4 100644
    --- a/demo.c
    +++ b/demo.c
    @@ -1,5 +1,10 @@
     #include <stdio.h>

    +void fun1()
    +{
    +       printf("before hello world ");
    +}
    +
     void demo()
     {
            ;
    @@ -7,6 +12,7 @@ void demo()

     int main()
     {
    +       fun1();
            printf("hello world ");
            printf("hello world ");
            printf("hello world ");

    确认无误就可以提交第一个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 来手工编辑了,下回分解吧。

     

    参考资料

    1. 使用 git add -p 整理 patch

  • 相关阅读:
    剑指offer 31.时间效率 整数中1出现的次数(从1到n整数中1出现的次数)
    剑指offer 30.时间效率 连续子数组的最大和
    ElasticSearch 数据路由原理+增删改查内部原理+写一致性原理以及quorum机制
    剑指offer 29.时间效率 最小的K个数
    剑指offer 28.时间效率 数组中出现次数超过一半的数字
    剑指offer 27.分解让复杂问题简单 字符串的排列
    ElasticSearch 并发冲突+悲观锁与乐观锁+基于_version和external version进行乐观锁并发控制
    剑指offer 26.分解让复杂问题简单 二叉搜索树与双向链表
    Spfa+DP【p2149】[SDOI2009]Elaxia的路线
    Dfs【bzoj3252】攻略
  • 原文地址:https://www.cnblogs.com/sunbines/p/14907713.html
Copyright © 2020-2023  润新知