【问题标题】:How to prepare clear diffs, when `git add --patch` edits are awkward?当`git add --patch`编辑很尴尬时,如何准备清晰的差异?
【发布时间】:2013-06-24 09:03:06
【问题描述】:

情况:在提出拉取请求时,我希望接收者能够了解它所做的更改。我发现将它们压缩到一个提交中可能会令人困惑,尤其是在以下情况下:

  1. 对代码的编辑也被移动了 - diff 将其呈现为批量删除和添加,而不是突出显示编辑。

  2. 代码被添加到一系列类似的部分,例如case 语句、级联 ifs、yacc 产生式 - diff 通常将更改重建为重叠部分(例如,它不添加一个部分,而是使用前一部分的开头,添加一个新的结尾和另一个开头,然后使用前一部分的结尾);添加新的代码结尾,在某些情况下,挑选出一些小的相似之处,然后删除并插入大量相同的代码。 (我意识到 diff 使用 LCS 并且速度非常快 - 但有时它的结果很难理解,即使考虑到 diff 不具备语法感知能力并且无法识别您看到的代码“部分”)。

    李>

顺便说一句:我使用git diff --color-words --ignore-space-change,这很好,但也错误重构,可以隐藏细节 - 我担心收件人可能会使用普通的git diff 并看到完全不同的东西(他们可以不同地重构) .

TASK:好的,因此显而易见的解决方案是将拉取请求分成单独的提交。有时,这些可能是我开始时的实际提交,所以我需要做的就是首先不要 rebase/squash。但我发现即使那样,差异也可能不清楚(尤其是出于上述原因(2)),我需要进一步将它们分开。

  1. 执行此操作的明显方法是使用git add --patch/-p。但是,补丁很难用于重叠更改 - 您可以divide and even edit the hunks,但是当您想要的更改结合了添加、删除和公共代码时,考虑反转差异有点令人费解。

  2. 我实际上所做的是直接编辑文件:删除我不想要的部分并提交;然后撤消删除(使用我的编辑器)并提交。根据实际来源工作比根据差异工作更清晰和直观 - 但感觉就像我在与 git 作斗争并且做错了(而且,依赖编辑器撤消似乎很容易发生意外)。

  3. 我想到先git stash 文件,然后通过删除我不想要的部分来准备第一次提交;然后git stash apply“撤消”该删除以准备第二次提交。但我不确定你是否可以在 rebase 中间这样做(还没有尝试过)。

问题:我需要 几个小时 才能做到这一点...我想我会通过练习有所提高,但是... 我在正确的轨道上吗?有没有更好的办法?你能从一开始就防止错误重构的差异吗?我是否为了清晰而努力工作?

(说句公道话,这是不久前对微妙而复杂的代码进行的许多编辑 - 花费这些时间揭示了更深入的见解。)

【问题讨论】:

    标签: git github diff


    【解决方案1】:

    基于these answers,在启动交互式rebase (get rebase -i ...) 和editing 一次提交后:

    git reset HEAD^     # reverts index to previous commit (not change files)
                        # so it's as if you are just about to add and commit
    git stash           # save
    git stash apply     # get it back
    ...edit the file, deleting the changes you don't want in the first commit
    git add .
    git commit -m "...first changes..."
    
    git stash apply     # get it back again (ie undo the above delete)
    ...(I needed to resolve a merge conflict)
    git add .
    git commit -m "...second changes..."
    
    git rebase --continue
    

    遗憾的是,没有 git stash copy 可以保存您的更改而不进行还原。可能有更顺畅的方式来做到这一点。

    令我惊讶的是,您可以在交互式 rebase 中间使用 git 的全部功能。您可以忽略您“应该”正在编辑的旧提交,而是添加两个提交;您可以存储并申请。我可能需要研究rebase 的实际实现方式,并停止将其视为抽象。实际上,rebase 手册页的标题为 splitting commits

    【讨论】:

      【解决方案2】:

      既然我们已经有了它们,为什么不使用提交来撤消更改(而不是存储)?有两个问题:引用提交,以及获取正确状态的文件(工作树)和索引。

      1. 引用提交 我们可以剪切并粘贴提交的哈希。或者,使用git tag tmp 创建一个临时标签(使用git tag -d tmp 删除)。或者,计算分支中的提交n 并使用branch~n。或者,对于 rebase 正在修改的提交,使用它存储的散列和 cat .git/rebase-merge/amend(但尴尬和未记录的实现细节 - 我得到了信息 here)。

      2. 文件和索引 我目前的理解:resetcheckout 不会在您指定文件(路径)时更改HEAD。像这样使用时,reset 只改变索引; checkout 更改索引和文件。要仅更改一个文件,您可以使用 git show <commit>:file > file 破坏它(注意文件的奇怪 : 语法而不是 --)。

      把它放在一起:

      git checkout -b newbranch  # I'm on a dev branch already; make a new one
      git rebase -i master       # only the commits not part of master
      ...mark one with `edit` or `e`...
      
      git tag tmp    
      git reset HEAD^            # changes index only, as if we had just edited
      ...edit myfile, deleting what is to be split into another commit...
      git add .
      git commit -m "first commit"
      
      git tag tmp2
      git checkout tmp -- myfile # get file and index before above edit
      git reset tmp2             # ...so need to reset *index* to first commit
                                 # 1. index is same as "first commit"
                                 # 2. file is same as commit we wanted to split
                                 # (the diff is what we deleted above)
      git add .
      git commit -m "second commit"
      
      git rebase --continue
      git tag -d tmp tmp2        # clean up
      

      如果我们使用'git show',第二次提交会稍微简单一些,因为我们不需要git reset tmp2

      git show tmp:myfile > myfile   # clobber file, but not index
      git add .
      git commit -m "second commit"
      

      很难说这一切发生了什么!检查当前状态的一些方法:

      git log -1                 # see HEAD
      git diff                   # between files and index
      git diff --cached HEAD     # between index and HEAD
      git show-ref tmp           # see tag
      

      无论如何,这一切似乎远比在我的编辑器中 *undo*ing 复杂得多,我一开始就这样做了。 但我敢打赌,对resetcheckout 的更好理解会派上用场……

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-23
        • 1970-01-01
        • 2018-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多