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

205

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

greg0ire
источник

Ответы:

254

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

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

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

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

Марк Лонгэйр
источник
9
Классное решение! Я видел это, но неправильно понял ... Я, хотя изменения также будут удалены из рабочего дерева.
greg0ire
7
На самом деле, это не очень очевидно из текста справки. На самом деле, я
часто
27
Обратите внимание, что вы действительно должны заменить его пробелом . Я попробовал это, полагая, что могу просто удалить -символы, и Git пожаловался, что мой патч не применяется.
Райан Ланди
3
Я предполагаю, что причина, по которой вы удаляете строки с '-' и заменяете '+' пробелом, заключается в том, что тогда вы формируете патч, в котором эти строки с '-' уже удалены, а строки с ' + уже были добавлены (в глазу патча). Или другой способ взглянуть на это: вы действительно делаете действие, которое представляют эти символы (-, +) (добавление строки или удаление ее). Только оставшиеся строки с '-s' и '+' записываются как изменения, а остальные - "просто как файл".
atomictom
3
@Filype: я не знаю, почему это случилось бы, я боюсь - если бы вы работали git add -pи редактировали кусок с eэтим, это должно влиять только на то, что поставлено, а не на ваше рабочее дерево.
Марк Лонгэйр
60

Допустим, ваша 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 в качестве редактора, нажмите, 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
Кроме того, вместо удаления добавленных строк, которые вы не хотите добавлять, вы можете заменить +на #. Результат тот же, но, возможно, вам неудобно удалять (и вы не можете вернуться), или вы хотите поэкспериментировать перед сохранением.
об-иван
И это, потому что VIM r #больше, чем плюс xD
aksh1618
Цель - «Как я могу добавить удаление комментариев CSS только к следующему коммиту?», Но шаги действительно сбивают с толку относительно того, что он выполняет. (мы хотим «добавить» только «удаление» нескольких строк к следующему коммиту.) Поэтому просто сказать, что удалить или добавить, очень сложно. Заявление о том, что было достигнуто на каждом этапе, поможет уточнить.
Анбизкад
9

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

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


РЕДАКТИРОВАТЬ (использование git-gui):

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

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

vhallac
источник
Ваше второе предложение вполне очевидно, но первое интересно, не могли бы вы рассказать подробнее? Я установил, git-guiно понятия не имею, как добиться того, что вы описываете.
greg0ire
большое спасибо! Это работает! Я даже смог выбрать строки, которые я хотел поставить и проиндексировать их одним щелчком мыши.
greg0ire
0

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

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

Abizern
источник
Это то, что я пытался, и кусок в моем вопросе - единственный, когда я бегу 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 -i. Который является более гибким, чемcommit --amend
Abizern