![К каким файлам `patch -p1` применяет патч в этом примере?](https://rvso.com/image/109227/%D0%9A%20%D0%BA%D0%B0%D0%BA%D0%B8%D0%BC%20%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%D0%BC%20%60patch%20-p1%60%20%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D1%8F%D0%B5%D1%82%20%D0%BF%D0%B0%D1%82%D1%87%20%D0%B2%20%D1%8D%D1%82%D0%BE%D0%BC%20%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B5%3F.png)
Для отмены изменений в файле в коммите, изhttps://stackoverflow.com/a/2620822/156458
#!/bin/bash
function output_help {
echo "usage: git-revert-single-file <sha1> <file>"
}
sha1=$1
file=$2
if [[ $sha1 ]]; then
git diff $sha1..$sha1^ -- $file | patch -p1
else
output_help
fi
К каким файлам patch -p1
применяется файл исправления (т.е. вывод git diff $sha1..$sha1^ -- $file
)?
Применимо ли это ко всем файлам в рабочем каталоге?
Но рабочий каталог может не совпадать с коммитом $sha1
. Так имеет ли смысл применять разницу между $sha1^
и $sha1
к рабочему каталогу, который может совпадать или не совпадать с $sha1
?
Спасибо.
решение1
git diff $sha1..$sha1^
создает патч, который отменяет $sha1
коммит (он перечисляет различия между этим коммитом и его родителем). Если $file
указано, он ограничивает этот патч изменениями, внесенными $file
в указанный коммит.
Затем этот патч передается в patch -p1
, который удаляет поддельные имена каталогов, используемые git
( a/
и b/
), и пытается применить патч к любым файлам, перечисленным в патче (то есть, $file
если он был назван и изменен в данном коммите, или все файлы, измененные в данном коммите, включая файлы в подкаталогах). Если файлы, присутствующие в текущем каталоге и его подкаталогах, существенно отличаются (или, соответственно, отсутствуют), то patch
применить патч не удастся.
Это стало возможным благодаря тому, что патчи в унифицированном формате, как это сделано git diff
(и diff -u
), включают имена файлов, которые подвергаются исправлению, и контекст для исправления. Вот пример (не из git
, но он показывает идею):
diff -ur cli-common-0.9+nmu1.orig/policy-remove cli-common-0.9+nmu1/policy-remove
--- cli-common-0.9+nmu1.orig/policy-remove 2015-02-25 21:34:08.000000000 +0100
+++ cli-common-0.9+nmu1/policy-remove 2017-04-08 20:47:09.029065259 +0200
@@ -11,4 +11,4 @@
#echo "Removing GAC policy file ($POLICY) from available GACs"
/usr/share/cli-common/gac-package-remove $POLICY > /dev/null
-rm /usr/share/cli-common/packages.d/$POLICY.installcligac
+rm -f /usr/share/cli-common/packages.d/$POLICY.installcligac
Этот патч говорит, что он изменяет файл с именем cli-common-0.9+nmu1.orig/policy-remove
для создания файла с именем cli-common-0.9+nmu1/policy-remove
. Само изменение начинается со строки 11 и охватывает 4 строки, включая контекст (это @@ -11,4
); в цели измененные строки находятся в том же положении ( +11,4 @@
). Над изменением идут три строки контекста, затем само изменение, удаление строки, начинающейся с , rm
и добавление строки, начинающейся с rm -f
. При patch
применении этого он будет искать файл с соответствующим именем (после удаления компонентов пути, если указано с помощью -p
параметра), и сравнивать контекст в файле с патчем; только если контекст совпадает (в пределах нескольких строк, в зависимости от параметров fuzz), изменение будет применено.
Весь смысл этого скрипта в том, чтобы попытаться отменить изменения, внесенные в один файл в данном коммите (отсюда и его название). Возможно это или нет, зависит от изменений, внесенных в файл после этого коммита; но на практике это часто бывает весьма полезно. (Чтобы отменить полный коммит, вы бы использовали git revert
вместо этого.)