我可以用 git 拆分已经拆分的块吗?

Posted

技术标签:

【中文标题】我可以用 git 拆分已经拆分的块吗?【英文标题】:Can I split an already split hunk with git? 【发布时间】:2011-09-10 17:30:43 【问题描述】:

我最近发现了add 命令的git 的patch 选项,我必须说它确实是一个很棒的功能。 我还发现可以通过点击 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 选项不再可用!

【问题讨论】:

【参考方案1】:

假设您的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 注释删除仅添加到下一次提交?

我们想把它分成两个提交:

    第一次提交涉及删除一些行(注释删除)。

    要删除注释行,请不要理会它们,它们已经被标记为跟踪版本控制中的删除,就像我们想要的那样。

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

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

    删除(删除了旧的选择器行)

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

    要删除 '-' 行,请将它们设为 ' '

    ...字面意思是用空格 字符替换减号- 符号

    所以这三行...

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

    ...将变为(notice所有 3 行中第一行的单个空格):

    <br>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;
 

最后你可以看到最后一次提交只包括选择器的变化。

【讨论】:

Bonus #2: 如果你碰巧使用 VIM 作为你的编辑器,你必须在键盘上按两次“d”来删除一行:D 另外,您可以将+ 替换为#,而不是删除您不想添加的行。结果是一样的,但也许您对删除(并且无法恢复)感到不舒服,或者您想在保存之前进行试验。 而且,对于 vim 来说,r # 超过了 xD 目标是“我如何才能将 CSS 注释删除仅添加到下一次提交?”,但这些步骤对于它所完成的工作确实令人困惑。 (我们只想在下一次提交中“添加”几行的“删除”。)所以简单地说删除或添加是非常令人困惑的。说明每个步骤完成了什么有助于澄清。【参考方案2】:

如果你使用git add -p,即使在使用s分割后,你也没有足够小的变化,你可以使用e来编辑补丁直接。

这可能有点令人困惑,但如果您仔细按照按 e 后将打开的编辑器窗口中的说明进行操作那么你会没事的。在您引用的情况下,您可能希望在这些行的开头用空格替换 -

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

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

【讨论】:

很酷的解决方案!我看到了,但误解了......我虽然这些更改也会从工作树中删除。 确实,从帮助文本中看不是很明显。实际上,我发现自己经常使用它,因为我认为 git 确实鼓励您使每个提交尽可能精确和美观:) 请注意,您确实必须将其替换为 空格。我尝试了一下,认为我可以删除 - 字符,但 Git 抱怨我的补丁不适用。 我猜你删除带有'-'的行并用空格替换'+'的原因是你正在形成一个补丁,其中那些带有'-'的行已经已删除,并且已经添加了带有“+”的行(在补丁的眼睛中)。或者另一种看待它的方式,您实际上是在执行这些字符 (-,+) 所代表的操作(添加或删除一行)。只有带有 '-'s 和 '+'s 的其余行被记录为更改,其余的就是“文件的原样”。 @Filype:我不知道为什么会发生这种情况,恐怕 - 如果你正在运行 git add -p 并用 e 编辑了一个大块,那只会影响上演的内容,而不是你的工作树。【参考方案3】:

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

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

【讨论】:

这是我尝试过的,当我再次运行git add -p 时,我的问题中的大块是唯一的,但我无法拆分它。我明白了:Stage this hunk [y,n,q,a,d,/,e,?]? 然后点击 's' 打印帮助。顺便说一句,你的意思是add patch,而不是patch add?或者有没有我应该安装的git patch 插件? 你在再次运行之前提交了分阶段的帅哥吗?不,Mercurial 有插件,Git 没有。 不,我没有,我希望它们在同一个提交中(但我想如果你的解决方案有效,我可以使用 --amend 来实现这一点)。我试试看。 正如我的回答所说 → git rebase -i。哪个比commit --amend更灵活【参考方案4】:

如果您可以使用 git gui,它允许您逐行进行更改。不幸的是,我不知道如何从命令行执行此操作 - 或者即使有可能。

我过去使用的另一个选项是回滚部分更改(保持编辑器打开),提交我想要的位,撤消并从编辑器重新保存。不是很优雅,但可以完成工作。 :)


编辑(git-gui 用法):

我不确定 git-gui 在 msysgit 和 linux 版本中是否相同,我只使用了 msysgit 之一。但是假设它是相同的,当你运行它时,有四个窗格:左上窗格是您的工作目录更改,左下是您的阶段更改,右上角是所选文件的差异(无论是工作目录或暂存),右下角用于描述提交(我怀疑你不需要它)。当您单击右上角的文件时,您将看到差异。如果您右键单击差异线,您将看到一个上下文菜单。需要注意的两个选项是“stage hunk for commit”和“stage line for commit”。您继续在要提交的行上选择“stage line for commit”,然后就完成了。如果需要,您甚至可以选择多条线并将它们分阶段。您可以随时单击暂存框中的文件以查看您要提交的内容。

至于提交,你可以使用 gui 工具或命令行。

【讨论】:

你的第二个命题很明显,但第一个很有趣,你能再详细一点吗?我安装了git-gui,但我不知道如何实现你所描述的。 坦克很多!这行得通!我什至可以一键选择我想要暂存的行并为其编制索引。

以上是关于我可以用 git 拆分已经拆分的块吗?的主要内容,如果未能解决你的问题,请参考以下文章

将数组拆分为具有最小块大小的给定大小的块

javascript 将数组拆分为相同大小的块

python 将列表拆分为大小均匀的块

csharp 将列表拆分为集合的块

将数组拆分为给定大小的块[重复]

将数组拆分为不同大小的块(4、3、3、3、4、3、3、3 等)