Можно ли разделить уже разделенный кусок с git?

Недавно я обнаружил параметр 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 больше не доступна!

Ответ 1

Если вы используете git add -p и даже после разбиения с помощью s, у вас нет достаточно небольших изменений, вы можете использовать e для непосредственного редактирования патча.

Это может немного сбивать с толку, но если вы будете тщательно следовать инструкциям в окне редактора, которое откроется после нажатия e, то все будет в порядке. В случае, когда вы цитировали, вы бы хотели заменить - пробелом в начале этих строк:

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

... и удалите следующую строку, то есть ту, которая начинается с +. Если вы затем сохраните и выйдите из редактора, будет просто удалено CSS-комментарий.

Ответ 2

Допустим, ваш 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 {

      ... станет (обратите внимание на один пробел в первой из всех трех строк):


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

    • Дополнения (добавлена новая строка выбора)

      Чтобы не обращать внимания на новую строку селектора, добавленную во время этого коммита, мы хотим...

      Чтобы удалить строки "+", удалите их.

      ... что буквально означает удалить всю строку:

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

      (Бонус: если вы используете vim в качестве редактора, нажмите d d, чтобы удалить строку. Нано пользователи нажимают 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 <[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 {

Отлично - вы можете видеть, что в этот атомарный коммит были включены только удаления. Теперь давайте закончим работу и передадим все остальное.

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

Наконец, вы можете видеть, что последний коммит включает только изменения селектора.

Ответ 3

Если вы можете использовать git gui, он позволяет создавать изменения по строкам. К сожалению, я не знаю, как это сделать из командной строки - или даже если это возможно.

Еще один вариант, который я использовал в прошлом, - это откат части изменения (сохранить редактор открытым), зафиксировать бит, которые я хочу, отменить и повторно сохранить из редактора. Не очень элегантный, но выполняет свою работу.:)


EDIT (git -gui use):

Я не уверен, что git -gui тот же, что и в версиях msysgit и linux, я использовал только msysgit. Но предполагая, что это то же самое, когда вы запускаете его, есть четыре панели: верхняя левая панель - это изменения вашего рабочего каталога, внизу слева - ваши этапы изменений, верхний правый - это diff для выбранного файла (будь то рабочий каталог или поэтапно), а внизу справа - описание фиксации (я подозреваю, что вам это не понадобится). Когда вы нажимаете файл в правом верхнем углу, вы увидите diff. Если вы щелкните правой кнопкой мыши на строке diff, вы увидите контекстное меню. Два варианта, которые следует отметить, - это "хост этапа для фиксации" и "линия этапа для фиксации". Вы продолжаете выбирать "линию сцены для фиксации" в строках, которые хотите зафиксировать, и все готово. Вы даже можете выбрать несколько строк и выполнить их, если хотите. Вы всегда можете щелкнуть файл в промежуточном блоке, чтобы узнать, что вам нужно сделать.

Что касается фиксации, вы можете использовать либо инструмент gui, либо командную строку.

Ответ 4

Один из способов сделать это - пропустить блок, git add все, что вам нужно, и снова запустить git add. Если это единственный кусок, вы сможете разбить его.

Если вас беспокоит порядок коммитов, просто используйте git rebase -i.