我能否使用git拆分已经被拆分的块?

254

我最近发现了git的patch选项,可以用于add命令,我必须说这真是一个很棒的功能。 我还发现,通过按下s键,可以将大块分成更小的块,这样可以增加提交的精度。 但是如果我想要更高的精度,如果分割的块还不够小怎么办?

例如,考虑这个已经分割好的块:

@@ -34,12 +34,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

我该如何仅将CSS注释删除并应用于下一次提交?选项s已不再可用!

4个回答

315
如果你使用git add -p,即使使用s拆分后,更改量仍然不够小,你可以使用e直接编辑补丁。这可能有点令人困惑,但是如果你在按下e后打开的编辑器窗口中仔细地按照说明操作,那么你就没问题了。在你引用的情况下,你需要将这些行开头的-替换为一个空格。
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {

...并删除以下行,即以+开头的行。如果您保存并退出编辑器,则只会暂存CSS注释的删除。


12
很棒的解决方案!我看到了,但是误解了……我以为更改也会从工作树中删除。 - greg0ire
7
的确,从帮助文本中并不十分明显。实际上,我经常使用这个功能,因为我认为git真的鼓励你尽可能地使每个提交精确而美观 :) - Mark Longair
37
请注意,您确实需要将其替换为一个空格。我试过删除“-”字符,想着这样就可以了,但Git会抱怨我的补丁无法应用。 - Ryan Lundy
3
我猜测你删除带有"-"的行并将"+"替换为空格的原因是:这样你就可以形成一个补丁(patch),其中那些带有"-"的行已经被删除,而带有"+"的行已经被添加(在补丁的视角下)。或者另一种看待方式是,你实际上执行了那些符号(-,+)所代表的操作(添加或删除一行)。只有留下的带有"-"和"+"的行被记录为更改,其余部分则是"文件的本来面目"。 - atomictom
3
@Filype:我不知道为什么会发生这种情况,如果你运行了git add -p并使用e编辑了一个块,那应该只影响已暂存的内容,而不是你的工作目录。 - Mark Longair
显示剩余6条评论

81

假设你的example.css长这个样子:

.classname {
  width: 440px;
}

/*#field_teacher_id {
  display: block;
} */

form.table-form #field_teacher + label,
form.table-form #field_producer_distributor + label {
  width: 300px;
}

.another {
  width: 420px;
}

现在让我们更改中间块中的样式选择器,顺便删除一些不再需要的旧注释样式。
.classname {
  width: 440px;
}

#user-register form.table-form .field-type-checkbox label {
  width: 300px;
}

.another {
  width: 420px;
}

这很简单,现在让我们提交。但是等等,我想保持逻辑分离以便进行简单的逐步代码审查,并且我和我的团队可以轻松搜索提交历史记录以获取具体信息。 删除旧代码与其他样式选择器更改在逻辑上是分开的。我们需要两个不同的提交,因此让我们为补丁添加块。
git add --patch
diff --git a/example.css b/example.css
index 426449d..50ecff9 100644
--- a/example.css
+++ b/example.css
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

Stage this hunk [y,n,q,a,d,/,e,?]?
抱歉,看起来更改太接近了,所以git已将它们合并在一起。即使尝试通过按下s键进行拆分,结果也是相同的,因为拆分不足以满足我们精确更改的需求。对于git能够自动拆分补丁,更改行之间需要保留未更改的行。因此,让我们通过按下e键手动进行编辑。
Stage this hunk [y,n,q,a,d,/,e,?]? e

Git会在我们选择的编辑器中打开补丁。

# Manual hunk edit mode -- see bottom for a quick guide
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging. If it does not apply cleanly, you will be given
# an opportunity to edit again. If all lines of the hunk are removed,
# then the edit is aborted and the hunk is left unchanged.

让我们回顾一下目标:

我如何仅将CSS注释删除添加到下一个提交中?

我们想将其拆分为两个提交:

  1. 第一个提交涉及删除一些行(注释删除)。

    要删除注释行,请不要做任何修改,它们已经被标记以跟踪版本控制中的删除操作,就像我们想要的那样。

    -/*#field_teacher_id {
    - display: block;
    -} */

  2. 第二个提交是更改,通过记录删除和添加来跟踪:

    • 删除(旧选择器行被删除)

      为了保留旧选择器行(在此提交期间不要删除它们),我们希望...

      删除 '-' 行,将其替换为 ' '

      ...这意味着将减号 - 替换为一个空格字符

      因此,这三行...

      -
      -form.table-form #field_teacher + label,
      -form.table-form #field_producer_distributor + label {

      ...将变成(注意 所有3行开头都有一个单独的空格):


      form.table-form #field_teacher + label,
      form.table-form #field_producer_distributor + label {

    • 添加(新选择器行被添加)

      为了不关注此提交期间添加的新选择器行,我们希望...

      删除 '+' 行,将其删除。

      ...这意味着删除整行:

      +#user-register form.table-form .field-type-checkbox label {

      (奖励:如果您使用的是vim编辑器,请按下 dd 删除一行。Nano 用户按下 Ctrl+K

当您保存时,您的编辑器应该看起来像这样:

# Manual hunk edit mode -- see bottom for a quick guide
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */

 form.table-form #field_teacher + label,
 form.table-form #field_producer_distributor + label {
   width: 300px;
 }

# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging. If it does not apply cleanly, you will be given
# an opportunity to edit again. If all lines of the hunk are removed,
# then the edit is aborted and the hunk is left unchanged.

现在让我们提交。

git commit -m "remove old code"

为了确保,让我们来看看上次提交的更改。

git show
commit 572ecbc7beecca495c8965ce54fbccabdd085112
Author: Jeff Puckett <jeff@jeffpuckett.com>
Date:   Sat Jun 11 17:06:48 2016 -0500

    remove old code

diff --git a/example.css b/example.css
index 426449d..d04c832 100644
--- a/example.css
+++ b/example.css
@@ -2,9 +2,6 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */

 form.table-form #field_teacher + label,
 form.table-form #field_producer_distributor + label {

很好 - 你可以看到只有删除操作被包含在这个原子提交中。现在让我们完成工作并提交剩下的部分。

git add .
git commit -m "change selectors"
git show
commit 83ec3c16b73bca799e4ed525148cf303e0bd39f9
Author: Jeff Puckett <jeff@jeffpuckett.com>
Date:   Sat Jun 11 17:09:12 2016 -0500

    change selectors

diff --git a/example.css b/example.css
index d04c832..50ecff9 100644
--- a/example.css
+++ b/example.css
@@ -2,9 +2,7 @@
   width: 440px;
 }

-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }
最后,您可以看到最后一次提交仅包括选择器更改。

1
奖励2:如果您正在使用VIM作为编辑器,则必须在键盘上按两次“d”才能删除一行:D - Alexxus
3
另外,如果你不想添加已添加的行,你可以将+替换为#。结果相同,但也许你不想删除(并且无法恢复)或者想在保存之前做实验。 - ob-ivan
而对于vim来说,这是r #在加上xD。 - aksh1618
目标是“我如何仅将CSS注释移除添加到下一次提交中?”,但步骤对于其所要完成的目标非常困惑。(我们只想在下一次提交中“添加”几行代码的“移除”)。因此,仅说“删除”或“添加”非常令人困惑。在每个步骤中说明已完成的内容将有助于澄清。 - ahnbizcad
我相信这个答案应该是最佳答案。它更好地解释了如何进行这个过程! - undefined

10
如果你会使用git gui,它允许你逐行地暂存更改。不幸的是,我不知道如何从命令行中做到这一点——甚至不确定是否可能。

过去我使用过的另一个选择是回滚部分更改(保持编辑器打开),提交我想要的部分,然后撤消并重新保存。并不十分优雅,但能完成工作。


编辑(git gui使用):

我不确定msysgit和linux版本中的git-gui是否相同,我只用过msysgit的版本。但是假设它们是相同的,当你运行它时,有四个面板:左上方面板是你的工作目录更改,左下方是你暂存的更改,右上方是选定文件的差异(无论是工作目录还是已暂存的),右下方是提交的描述(我认为你不需要它)。当你在右上方的文件上单击时,你会看到差异。如果你在差异行上右键单击,你会看到一个上下文菜单。需要注意的两个选项是“为提交暂存块”和“为提交暂存行”。你可以在你想要提交的行上持续选择"为提交暂存行",然后就完成了。如果需要,你甚至可以选择多行并将它们暂存。你总是可以在暂存框中点击文件来查看你将要提交的内容。

至于提交,你可以使用图形界面工具或命令行。


你的第二个建议很明显,但第一个很有趣,能否详细说明一下?我安装了 git-gui 但是不知道如何实现你所描述的操作。 - greg0ire
非常感谢!这个有效!我甚至能够选择我想要暂存的行并用一次点击对它们进行索引。 - greg0ire

0

一种方法是跳过这个块,git add其他需要的内容,然后再次运行git add。如果这是唯一的块,您将能够拆分它。

如果您担心提交的顺序,只需使用git rebase -i


这是我尝试的方法,我问题中的 hunk 在我再次运行 git add -p 时是唯一的,但我无法将其拆分。我得到了这个:Stage this hunk [y,n,q,a,d,/,e,?]?,然后按下's'会打印帮助信息。顺便问一句,你是指 add patch 而不是 patch add 吗?或者我需要安装一个 git patch 插件? - greg0ire
你在再次运行之前提交了暂存区的块吗?不,Mercurial 有插件,Git 没有。 - Abizern
不,我没有这样做,我希望它们在同一个提交中(但是如果你的解决方案有效,我可以使用 --amend 来实现这一点)。我会尝试一下。 - greg0ire
如我之前回答所述,git rebase -icommit --amend 更灵活。 - Abizern

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