Почему `git stash -p` иногда терпит неудачу? - PullRequest
71 голосов
/ 19 февраля 2011

I ♥ git stash -p.Но иногда, после удовлетворительного сеанса y, n и s, я получаю это:

Saved working directory and index state WIP on foo: 9794c1a lorum ipsum
error: patch failed: spec/models/thing_spec.rb:65
error: spec/models/thing_spec.rb: patch does not apply
Cannot remove worktree changes

Почему?

Ответы [ 5 ]

27 голосов
/ 07 октября 2012

Это происходит для меня всякий раз, когда я пытаюсь разделить кусок на более мелкие фрагменты, которые расположены слишком близко друг к другу (менее 3 строк между изменениями). Краткое объяснение состоит в том, что в патче есть контекстные строки, которые конфликтуют с вашими локальными изменениями. Более полное объяснение ниже.


Предположим, у меня есть git-репо со следующими незафиксированными изменениями:

--- a/pangram
+++ b/pangram
@@ -1,8 +1,8 @@
 The
-quick
+relatively quick
 brown
 fox
-jumps
+walks
 over
 the
 lazy

Если я прячу первое изменение, я получаю:

--- a/pangram
+++ b/pangram
@@ -1,5 +1,5 @@
 The
-quick
+relatively quick
 brown
 fox
 jumps

Команда git stash действительно успешно сохраняет патч (отметьте git stash list), но затем git использует этот патч в обратном порядке, чтобы удалить сохраненные изменения из моего рабочего каталога. Контекст после фрагмента содержит «скачки», которые не соответствуют «прогулкам» в моем рабочем каталоге. Так что Git выручает с

error: patch failed: pangram:1
error: pangram: patch does not apply
Cannot remove worktree changes

и оставляет все изменения в моем рабочем каталоге, а тайник становится практически бесполезным.


Я бы назвал это ошибкой в ​​поддержке разбиения фрагментов в git. Если он знает, что разделяет изменения слишком близко, он может сбрить несколько строк контекста из патча или изменить его, чтобы иметь измененные строки контекста вместо первоначальных. В качестве альтернативы, если разделение фрагментов в этом закрытии официально не поддерживается, оно фактически должно отказаться от разделения фрагментов в этом закрытии.

6 голосов
/ 17 марта 2018

git stash -p должен потерпеть неудачу меньше с Git 2.17 (Q2 2018).
До этого "git add -p" (который разделяет логику с git stash) ленился в объединении разделенных патчей перед передачей результата в базовый "git apply", что приводило к ошибкам в регистре; логика для подготовки патча для применения после выбора фрагментов.

См. коммит 3a8522f , коммит b3e0fcf , коммит 2b8ea7f (05 марта 2018), коммит fecc6f3 , коммит 23fea4c , коммит 902f414 (01 марта 2018 г.) и коммит 11489a6 , коммит e4d671c , коммит 492e60c (19 фев 2018 г.) Филлип Вуд (phillipwood) .
(Объединено с Junio ​​C Hamano - gitster - в коммит 436d18f , 14 марта 2018 г.)

add -p: отрегулировать смещения последующих блоков, если один из них пропущен

(добавить, но опять же, можно применить к тайнику)

С коммит 8cbd431 ("git-add--interactive: заменить ханк пересчет с apply --recount ", 2008-7-2, Git v1.6.0-rc0), если кусок пропущен, то мы полагаемся на строки контекста, чтобы применить последующие фрагменты справа место.

В то время как это работает большую часть времени, это возможно в конечном итоге применяется в неправильном месте.

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

Здесь вы можете увидеть некоторые тесты .


Git 2.19 улучшается git add -p: когда пользователь редактирует патч в "git add -p", а редактор пользователя настроен на произвольную очистку конечных пробелов, пустая строка, которая остается неизменной в патче, становится полностью пустой (вместо линия с единственным ИП на нем).
Код, введенный в таймфрейме Git 2.17, не смог разобрать такой патч, но теперь он научился замечать ситуацию и справляться с ней.

См. коммит f4d35a6 (11 июня 2018 г.) от Филиппа Вуда (phillipwood) .
(Объединено с Junio ​​C Hamano - gitster - в коммит 5eb8da8 , 28 июня 2018 г.)

add -p: исправлен подсчет пустых строк контекста в отредактированных патчах

recount_edited_hunk() введено в commit 2b8ea7f ("add -p: вычислить дельту смещения для отредактированных патчей ", 2018-03-05, Git v2.17.0) требуется, чтобы все строки контекста начинались с пробела, пустые строки не учитываются.
Это было сделано для того, чтобы избежать каких-либо проблем с пересчетом, если пользователь вводил пустые строки в конце при редактировании патча.

Однако это ввело регрессию в 'git add -p', так как редакторы, как правило, удаляют конечный пробел из пустых контекстных строк при редактировании патчей, тем самым вводя пустые строки, которые должны быть подсчитывали.
«git apply» знает, как обращаться с такими пустыми строками, и POSIX сообщает, что наличие или отсутствие пробела в пустой контекстной строке определяется реализацией (см. команда diff ).

Исправить регрессию, считая строки, состоящие исключительно из новой строки а также строки, начинающиеся с пробела, как строки контекста и добавить тест предотвратить будущие регрессии.


Git 2.23 (Q3 2019) улучшает git add -p, используемый "git checkout -p", который должен выборочно применять патч в обратном порядке: раньше он не работал должным образом.

См. коммит 2bd69b9 (12 июня 2019 г.) от Филиппа Вуда (phillipwood) .
(Объединено Junio ​​C Hamano - gitster - в коммит 1b074e1 , 09 июля 2019 г.)

add -p: исправить checkout -p с патологическим контекстом

Commit fecc6f3 ("add -p: корректировать смещения последующих фрагментов, когда одинskipped ", 2018-03-01, Git v2.17.0-rc0) исправлено добавление блоков в правильном месте, когда предыдущий блок был пропущен.

Однако это не относится к патчам, которые применяются в обратном порядке.

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

6 голосов
/ 17 октября 2014

После такого же сбоя git stash -p мне повезло с этим обходным решением (git 2.0.2):

  • git add -p, разделяя те же самые фрагменты, но с обратными ответами (от "y" до add "сохраняет" изменения, от "n" до stash сохраняет изменения.)
  • git stash -k чтобы сохранить индекс и спрятать все остальное
  • git reset чтобы продолжить работу над моими файлами

Я не уверен, почему git add -p не провалился так же, как git stash -p. Я думаю, потому что добавление работает с индексом, а не создает файл патча?

4 голосов
/ 07 апреля 2018

Принятый на данный момент ответ может, к сожалению, потерпеть неудачу, даже в Git 2.17.

Если, как и я, вы потратили много усилий на создание идеального тайника и не хотите отбрасывать это усилие, по-прежнему возможно получить в основном то, что вы хотите:

git stash show -p | patch -p1 -R

Это не удастся с отклонениями, но шансы хорошие, большинство блоков будут применены правильно и, по крайней мере, спасут васвремя повторного просмотра всех файлов.

0 голосов
/ 22 июля 2011

Применение состояния может завершиться с конфликтом; в этом случае он не удаляется из списка. Вам нужно разрешить конфликты вручную и вручную вызвать git stash drop

...