【问题标题】:Git add specific lines not interactivelyGit 不以交互方式添加特定行
【发布时间】:2018-11-10 15:03:50
【问题描述】:

我想git add 仅使用单个 shell 命令从文件中获取特定范围的行。我正在成像:

git add -c myfile.go@123..204

不想使用 git add -igit add -pgit -e(交互式 git 工具),因为我的文件很大并且有很多更改,而且我已经确切知道哪个我想要的线条。为了争论(明白吗?),假设我想在 2000 行文件myfile.go 中包含包含123-204 的行。

也不想使用图形用户界面。我的电脑对于新程序来说太旧了,运行速度太慢了,屏幕太小了……随便。以上都是。 Github GUI、Sourcetree(Atom|IntelliJ|VSC|.* 插件、KDiff、Kaleidescope……他们都出来了。

可以吗?

奖励积分:可以同时处理多个文件吗?

供参考:

两个相关的、但不重复的问题。都不符合我的需要:

Git 文档很接近,但没有雪茄:

【问题讨论】:

  • 我认为你必须接受 --patch 是你得到的最接近的 lol
  • 所以像 Sourcetree 这样的工具实际上必须像至少 4 个不同的 git 和/或文件操作步骤一样逐步完成,才能只上演一个微不足道的大块头?
  • 但是我值得信赖的 TI-86 已经让我走到了这一步……我现在不能放弃它。
  • 最有可能您需要寻找的是“管道”(低级数据结构操作)命令,而不是“瓷器”(高级版本控制)命令。
  • 如果您可以使用所需的行构建补丁文件,git apply --cached 将在不触及工作树的情况下暂存这些更改。 implementation of git add --interactive 似乎是用 Perl 编写的,并且在后台以这种方式工作。据我所知,它采用的方法是从补丁中提取部分(基本上是git diff 输出),然后通过操作标题/上下文行将所需的部分重构为新的补丁文件。

标签: git


【解决方案1】:

从 cmets 来看,不清楚您是否关心执行添加操作的效率、需要完成的键入以指示工具做什么,或两者兼而有之。

我不会担心前者;如果您担心,那么无论如何您也无能为力。有比您认为合理的更多步骤,它们涉及处理整个文件;但实际上,这并不重要,因为我从未见过单文件暂存操作需要足够的时间来担心它。

至于涉及的输入量,您列出的add 选项是最接近的内置支持git 提供的。因此,您可以编写一些脚本来增强它们。但要确保它总是“做对”并不容易。

特别是,定义“对这一行范围的更改”比您可能意识到的要棘手。看似显而易见的问题是行的添加和删除会改变它们之后出现的行的行号;但是您可能可以通过根据文件的当前工作版本定义行号范围来解决这个问题(因为这是确定行号范围时最近可能会查看的内容).. .

但更大的问题是检测一个范围内的所有行都被编辑的情况,并且该范围与您正在暂存更改的行范围的末端重叠。例如,假设您有文件

1
2
3
4
5

在索引中,你的工作副本说

1
2
3 THREE
4 FOUR
5 FIVE

现在您指定要暂存第 2-4 行的更改。

补丁看起来像

@@ -1,5 +1,5 @@
 1
 2
-3
-4
-5
+3 THREE
+4 FOUR
+5 FIVE

很明显,在这种情况下直观的结果是

1
2
3 THREE
4 FOUR
5

但是编写代码来“正确”而不让其他情况“错误”(相对于同样直观的解释)并不是那么容易。有时它真的可以解释。 “这是一个更改三行的操作吗?还是一个删除三行的操作,然后是三个各添加一行的操作?还是……”

git 中的自动化工具避免了做出这些解释性决定,首先通过查看大量变化的代码(而不是任意行范围),如果你想要不同的东西(即使用补丁编辑模式),让你手动干预;然后在似乎仍然需要解释时插入冲突标记(并且再次需要人工干预)。

因此,您基本上必须做出简化假设来构建工具,并确保这些假设在使用该工具时是有效的。

因此,我们的想法是创建一个脚本,该脚本从由其第一个参数命名的文件中读取补丁并就地编辑补丁;并在运行git add -e 时将该脚本设置为编辑器(即通过设置GIT_EDITOR 环境变量)。您将使用 @@ -#,# +#,# @@ 形式的行来确定更改受影响的行号,使用该信息(和您的假设)来决定是否要保留或丢弃给定的更改行,以及是否要丢弃它

  • 如果该行以- 开头,请将- 更改为
  • 如果该行以+ 开头,则删除该行

【讨论】:

  • 除非我误解了某些内容,否则您示例中的补丁将是 diff 而不是阶段 2-4 的补丁。
【解决方案2】:

我已经对此进行了研究,但没有深入研究。我的理解是git add -p 的工作方式是生成补丁,提供一个直观的界面来编辑它们,然后应用它们。

你可以自己做这个过程。

工作树中的更改由git diff 提供。这些更改可以使用git apply作为补丁应用到您的索引

所以你可以运行而不是git add .

git diff . | git apply - --cached

即。在当前目录中获取工作树中的所有差异并将它们全部应用于索引。

所以你可以做的是自己修改 diff 的输出,并在应用它之前生成一个不同的补丁,使用脚本或任何方法。

使用脚本修改此问题的过程可能比选择 git add -egit add -p 解决方案更棘手,但据我所知,如果您想以不同的方式解决问题,这是解决问题的方法.

附录:

这基本上正是交互式 git 命令所做的,使用 perl 脚本。它创建分块的差异文件,然后在$EDITOR 中打开它们。重要的是,它会在您完成修改后自动修复差异格式(自己做很烦人),因为差异顶部的行摘要内容 ++ XYZ / -- zyx 需要正确才能应用补丁。

我不记得 perl 脚本运行什么命令来分块差异,但它在某处的源代码中。

如果我今天必须解决这个问题,我可能会生成分块差异。删除线外的。然后git appy foo.diff --cached && git restore --staged foo.diff && git add -p

【讨论】:

    猜你喜欢
    • 2012-09-05
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 2017-10-31
    • 1970-01-01
    相关资源
    最近更新 更多