Git:如何按行号将(更改的)文件的部分内容添加到索引中

7
有没有一个git命令可以将行号范围内的差异添加到索引中?
我想能够在编辑器中选择行并运行宏,将选择中的任何更改添加到索引中。

你对在编辑器内完成这个想法比通过 git add -i 完成更有兴趣吗?如果你真的想要,你可以编写一些调用 git diff 的代码,提取与你选择的行相关的 hunks,并将该补丁应用到索引中... - Cascabel
4个回答

18
如果你能说服编辑器编写一个你希望被存储的文件版本,那么你可以使用Git的底层命令将其添加到正确的名称下的索引中。你需要绕过"git add",因为它会始终将工作树中的路径X与索引中的路径X关联起来(据我所知)。
一旦你有了想要暂存的内容写入到某个临时文件$tempfile中,运行git hash-object -w $tempfile。这将把对象写入.git/objects并输出blob id。然后使用git update-index --cacheinfo 100644 $blobid $path将这个blob id传给索引,以将路径$path与该对象关联起来。
这里是一个例子,演示了如何在不覆盖文件本身的情况下暂存我的repo中名为"post_load"的脚本的更改(还展示了您可以不使用临时文件)。
git update-index --cacheinfo 100755 $(perl -lne 'print unless (/^#/)' post_load \
                                      | git hash-object -w --stdin) post_load

由于您没有提及使用哪个编辑器,因此很难为您提供建议。正如我之前提到的,您需要以某种方式将文件呈现给git,使其作为您要暂存的文件(记住,git不会处理存储的更改)。如果您可以编写一个宏,只需将文件保存为“$file.tmp”,然后使用如上所述的内容进行git update-index --cacheinfo $the_mode $(git hash-object -w $file.tmp) $file(获取$the_mode留作练习 :p),删除$file.tmp并将编辑器缓冲区恢复为$file,那基本上就达到了您所要求的效果。

例如,以下脚本接受三个参数:M N path。它将更新路径下的文件的索引内容,以便将第M行至第N行(包括这两行)替换为stdin中的内容:

#!/bin/sh

start_line=$1
end_line=$2
path=$3

mode=$(git ls-files -s $path | awk '{print $1}')
blob_id=$(
    (
        head -n $(expr $start_line - 1) $path
        cat
        tail -n +$(expr $end_line + 1) $path
        ) | git hash-object -w --stdin
    )
exec git update-index --cacheinfo $mode $blob_id $path

例如,echo "HELLO WORLD" | ./stage-part 8 10 post_load 将用 "HELLO WORLD" 替换第 8-10 行的三行。


3
目前最简单的方法是使用交互模式下的git add命令:
git add -i path/to/file

它将启动简单的用户界面,您可以在其中选择要暂存的块,并允许您编辑任何块以删除不想提交的行。


这是我的当前做法,但当 diff 中有太多“噪音”需要测试/提交时,我会感到困惑(由于缺乏上下文行等)。在这种情况下,我真的希望能够从我的编辑器中进行操作。 - RobM

2
在我自己的经验中,git-cola在这方面表现非常出色。但我希望它支持Atom集成...

虽然这原理上可以回答问题,但最好在此处包含答案的必要部分,并提供链接供参考。 - Enamul Hassan
在 git-cola 中,选择行并从下拉菜单中选择“Stage Selected Lines”,或按 H 键。这确实需要从常规编辑器切换到 git-cola 进行暂存,但两者可以同时运行,我并没有觉得不方便。 - Roger Dahl

0

最接近此功能的预构建工具是git gui citool。它不能直接在您的编辑器中使用(并非所有编辑器都有有用的差异视图,我认为大多数人可能不关心记住自上次提交以来确切更改了哪些行,因此差异视图非常有用),但似乎接近您想要的。

git gui citool允许您在与git diff --cachedgit diff等效的视图中查看已暂存和未暂存的更改。

在查看未暂存的更改时,上下文菜单(右键单击)提供选项以将所选行(或如果没有选择,则单击行)暂存,并提供一个选项以暂存整个块。 同样,在查看已暂存的更改时,上下文菜单提供选项以取消暂存行或块。

要获取更多上下文信息,可以使用“显示更多上下文”菜单项(如果要缩小块,则使用“显示更少上下文”)。

一旦您的新内容已暂存,您还可以从GUI内部组合提交消息并进行提交。

我想有些人会像这样使用git gui的工作流程:

  1. 使用CLI添加新的跟踪文件并删除旧文件(git add的各种选项)。
  2. 在您喜欢的编辑器/环境中编辑已跟踪的文件。
  3. git gui中,选择“重新扫描”,查看更改,对一些进行暂存/取消暂存,最终提交它们。
  4. [重复]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接