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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6276752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 11:08:07  来源:igfitidea点击:

Can I split an already split hunk with git?

gitsplitaddpatch

提问by greg0ire

I've recently discovered git's patchoption to the addcommand, and I must say it really is a fantastic feature. I also discovered that a large hunk could be split into smaller hunks by hitting the skey, which adds to the precision of the commit. But what if I want even more precision, if the split hunk is not small enough?

我最近发现了 git 的命令patch选项add,我必须说这确实是一个很棒的功能。我还发现通过敲击s键可以将大块块拆分为较小块块,这增加了提交的精度。但是如果我想要更高的精度,如果拆分的大块不够小怎么办?

For example, consider this already split hunk:

例如,考虑这个已经分裂的大块:

@@ -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;
 }

How can I add the CSS comment removal only to the next commit ? The soption is not available anymore!

如何仅将 CSS 注释删除添加到下一次提交?该s选项不再可用!

回答by Mark Longair

If you're using git add -pand even after splitting with s, you don't have a small enough change, you can use eto edit the patch directly.

如果您正在使用git add -p并且即使在使用拆分后s,您也没有足够小的更改,您可以使用e直接编辑补丁。

This can be a little confusing, but if you carefullyfollow the instructions in the editor window that will be opened up after pressing ethen you'll be fine. In the case you've quoted, you would want to replace the -with a space at the beginning of these lines:

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

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

... and delete the the following line, i.e. the one that begins with +. If you then save and exit your editor, just the removal of the CSS comment will be staged.

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

回答by Jeff Puckett

Let's say your example.csslooks like this:

假设你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;
}

Now let's change the style selectors in the middle block, and while we're at it, delete some old commented-out style we don't need anymore.

现在让我们更改中间块中的样式选择器,同时删除一些我们不再需要的已注释掉的旧样式。

.classname {
  width: 440px;
}

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

.another {
  width: 420px;
}

That was easy, now let's commit. But wait, I want to maintain logical separation of changes in version control for simple step-wise code review, and so that my team and I can easily search commit history for specifics.

这很容易,现在让我们提交。但是等等,我想保持版本控制中更改的逻辑分离,以便进行简单的逐步代码,这样我和我的团队就可以轻松搜索提交历史以了解细节。

Deleting old code is logically separate from the other style selector change. We're going to need two distinct commits, so let's add hunks for a patch.

删除旧代码与其他样式选择器更改在逻辑上是分开的。我们将需要两个不同的提交,所以让我们为补丁添加大量代码。

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,?]?
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,?]?

Whoops, looks like the changes are too close, so git has hunked them together.

哎呀,看起来变化太接近了,所以 git 将它们组合在一起。

Even trying to splitit by pressing shas the same result because the split isn't granular enough for our precision changes. Unchanged lines are required between changed linesfor git to be able to automatically split the patch.

即使尝试通过按下来拆分它也会s得到相同的结果,因为拆分的粒度不足以满足我们的精度变化。更改的行之间需要未更改的行,以便 git 能够自动拆分补丁。

So, let's manually editit by pressing e

所以,让我们通过按手动编辑e

Stage this hunk [y,n,q,a,d,/,e,?]? e

git will open the patch in our editor of choice.

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.
# 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.

Let's review the goal:

让我们回顾一下目标:

How can I add the CSS comment removal only to the next commit ?

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

We want to split this into two commits:

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

  1. The first commit involves deleting some lines (comment removal).

    To remove the commented lines, just leave them alone, they are already marked to track the deletions in version control just like we want.

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

  2. The second commit is a change, which is tracked by recording both deletions and additions:

    • Deletions (old selector lines removed)

      To keep the old selector lines (do not delete them during this commit), we want...

      To remove '-' lines, make them ' '

      ...which literally means replacing the minus -signs with a space character.

      So these three lines...

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

      ...will become (noticethe single space at the first of all 3 lines):


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

    • Additions (new selector line added)

      To not pay attention to the new selector line added during this commit, we want...

      To remove '+' lines, delete them.

      ...which literally means to delete the whole line:

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

      (Bonus: If you happen to be using vimas your editor, press ddto delete a line. Nanousers press Ctrl+K)

  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

Your editor should look like this when you save:

保存时,您的编辑器应如下所示:

# 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.
# 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.

Now let's commit.

现在让我们承诺。

git commit -m "remove old code"

And just to make sure, let's see the changes from the last commit.

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

git show
commit 572ecbc7beecca495c8965ce54fbccabdd085112
Author: Jeff Puckett <[email protected]>
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 {
commit 572ecbc7beecca495c8965ce54fbccabdd085112
Author: Jeff Puckett <[email protected]>
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 {

Perfect - you can see that only the deletions were included in that atomic commit. Now let's finish the job and commit the rest.

完美 - 您可以看到该原子提交中仅包含删除。现在让我们完成工作并提交其余的。

git add .
git commit -m "change selectors"
git show
commit 83ec3c16b73bca799e4ed525148cf303e0bd39f9
Author: Jeff Puckett <[email protected]>
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;
 }
commit 83ec3c16b73bca799e4ed525148cf303e0bd39f9
Author: Jeff Puckett <[email protected]>
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;
 }

Finally you can see the last commit only includes the selector changes.

最后,您可以看到最后一次提交仅包括选择器更改。

回答by vhallac

If you can use git gui, it allows you to stage changes line by line. Unfortunately, I don't know how to do it from the command line - or even if it is possible.

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

One other option I've used in the past is rolling back part of the change (keep the editor open), commit the bits I want, undo and re-save from the editor. Not very elegant, but gets the job done. :)

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



EDIT (git-gui usage):

编辑(git-gui 用法):

I am not sure if the git-gui is the same in msysgit and linux versions, I've only used the msysgit one. But assuming it is the same, when you run it, there are four panes: top-left pane is your working directory changes, bottom-left is your stages changes, top-right is the diff for the selected file (be it working dir or staged), and bottom right is for description of the commit (I suspect you won't need it). When you click a file in the top-right one, you will see the diff. If you right-click on a diff line, you'll see a context menu. The two options to note are "stage hunk for commit" and "stage line for commit". You keep selecting "stage line for commit" on the lines you want to commit, and you are done. You can even select several lines and stage them if you want. You can always click the file in the staging box to see what you are bout to commit.

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

As for committing, you can use either the gui tool or the command line.

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

回答by Abizern

One way to do it is to skip the chunk, git addwhatever else you need, and then run git addagain. If this is the only chunk, you'll be able to split it.

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

If you're worried about the order of commits, just use git rebase -i.

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