Странное поведение патча при изменении имени файла - PullRequest
0 голосов
/ 20 декабря 2018

В последнее время я учусь diff и patch.Я создал два файла: файл a с содержанием abc и файл b с содержанием def.Затем я использовал diff -u a b > p и patch < p, он вел себя правильно, как показано ниже:

[joe@joe-pc c]$ ls
a  b
[joe@joe-pc c]$ more a
abc
[joe@joe-pc c]$ more b
def
[joe@joe-pc c]$ diff -u a b > p
[joe@joe-pc c]$ more p
--- a   2018-12-20 22:56:33.865661540 +0800
+++ b   2018-12-20 22:54:15.241516269 +0800
@@ -1 +1 @@
-abc
+def
[joe@joe-pc c]$ patch < p
patching file a
[joe@joe-pc c]$ more a
def
[joe@joe-pc c]$ more b
def
[joe@joe-pc c]$ ls
a  b  p
[joe@joe-pc c]$

Но если я изменил имя файла с a на ab, произошло нечто странное.Команда patch < p сказала мне, что
patching file b Reversed (or previously applied) patch detected! Assume -R? [n]

[joe@joe-pc c]$ ls
ab  b
[joe@joe-pc c]$ more ab
abc
[joe@joe-pc c]$ more b
def
[joe@joe-pc c]$ diff -u ab b > p
[joe@joe-pc c]$ more p
--- ab  2018-12-20 22:57:29.767980973 +0800
+++ b   2018-12-20 22:54:15.241516269 +0800
@@ -1 +1 @@
-abc
+def
[joe@joe-pc c]$ patch < p
patching file b
Reversed (or previously applied) patch detected!  Assume -R? [n] ^C
[joe@joe-pc c]$

Содержимое файла такое же, но почему во второй ситуации patch не может найти нужный файл ab дляисправлен?

Вышеуказанные операции выполнялись на машине Linux с оболочкой bash.

Заранее спасибо.

1 Ответ

0 голосов
/ 21 декабря 2018

Это особенность патча GNU .Поскольку вы не указали конкретный файл для исправления, он должен быть как-то выведен из входных данных.По сути, если вы не указываете пути (только базовые имена), предполагается, что он должен пропатчить файл с более коротким именем, если только не передан --posix аргумент командной строки или не установлена ​​POSIXLY_CORRECT переменная окружения:

patch --posix <p
# or
POSIXLY_CORRECT=1 patch <p

В вашем случае, между a и b первый выбран правильно, но для ab и b второй выбран в качестве цели патча (как указывает строка patching file b), но исправление не выполняется, поэтому возникает ошибка.

Вы также можете исправить это поведение, указав цель исправления явно:

patch ab <p

Копание в документах

В патче GNU используетсяследующая логика (см. руководство по исправлению, раздел «10.6 Несколько исправлений в файле» ):

Сначала исправление принимает упорядоченный список имен файлов-кандидатов следующим образом:

  • Если заголовок совпадает с контентом diff, patch берет старые и новые имена файлов в заголовке....

...

Затем исправление выбирает имя файла из списка кандидатов следующим образом:

  • Если существуют некоторые из названных файловpatch выбирает первое имя, если оно соответствует POSIX, и лучшее имя в противном случае.

Для " единый контекстный формат " "старый" файл упоминается после --- (a или ab в вашем случае), а также«новый» файл упоминается после +++ (b в вашем случае).

Если оба файла существуют и patch не настроен на «подтверждение POSIX» (например, установкой POSIXLY_CORRECTпеременная окружения или --posix аргумент командной строки, см. «10.12 patch и раздел POSIX Standard» руководства ), тогда patch выберет «лучшее» имя из двух.«Имя» здесь включает полный путь, полученный из файла патча (в вашем случае это не имеет значения).Подробности уточняются позже:

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

«Компонент имени» - это, в основном, имя папки / файла (например, /foo/bar/baz имеет три из них), «базовое имя» - это просто имяфайл (baz).Итак, если имена a (старые) и b (новые) и оба файла существуют, «лучшего имени» не существует, поэтому первый из них исправляется.Но если имена ab (старые) и b (новые) и оба файла существуют, то b «лучше», поэтому инструмент пытается его исправить и не удается.

У меня нетИдея, почему это поведение было сделано по умолчанию.

...