Git diff - только для имени и скопировать этот список

151

Я просто хочу получить список измененных файлов между двумя ревизиями, который прост:

git diff -–name-only commit1 commit2 > /path/to/my/file

Но что мне написать, если я хочу скопировать все перечисленные файлы в другое место? И мне нужна полностью идентичная структура каталогов для скопированных файлов.

Например, я изменил и добавил файлы:

/protected/texts/file1.txt
/protected/scripts/index.php
/public/pics/pic1.png

Я хочу иметь во /home/changes/всех этих измененных и добавленных файлах:

/home/changes/protected/texts/file1.txt
/home/changes/protected/scripts/index.php
/home/changes/public/pics/pic1.png
Bazzy
источник
1
я не совсем понимаю, чего вы пытаетесь достичь ... распространять изменения в разных клонах? создание патчей? патчить файлы вне репозитория git?
knittl
Не патч, а точная структура копирования измененных файлов. Как патч, но со сплошными файлами
BazZy
И да, исправление файлов вне репозитория git - ближайшая цель для меня :)
BazZy
3
Прости. ЧТО? Вы хотите захватывать и воспроизводить изменения в файлах и изменениях в деревьях? это патч. git format-patchможет сделать это для диапазонов фиксации.
knittl
1
git diff commit1 commit2 > my.patchа потом cd other/path; patch -p1 < my.patch. Почему это должно быть сделано с полными копиями файлов? Если это потому, что вы думаете, что патч может не применяться, и, следовательно, другой каталог на самом деле не находится в commit1состоянии, вы действительно должны скопировать все из commit2состояния ...
Cascabel

Ответы:

118

Попробуйте следующую команду, которую я протестировал:

$ cp -pv --parents $(git diff --name-only) DESTINATION-DIRECTORY
Йорк
источник
2
Спасибо за cp --parentsподсказку, я хотел этот вариант в течение многих лет и никогда не знал, что он существует! ... очевидно, я никогда не удосужился его найти = \
Стефан Хеннингсен
2
Обратите внимание, что это не работает на Mac, так как --parentsопция cpнедоступна.
М. Джастин
Любые советы по использованию этого, если файлы имеют необычные символы? Пробелы, нордические символы.
Halvor Holsten Strand
@HalvorStrand, я не проверял это, но настройка в IFS=$'\n'первую очередь может сделать это. (Желательно в недолговечном виде, чтобы не испортить ваше первоначальное значение IFS.)
Wildcard
Я получаю сообщение об ошибке cp: cannot stat 'git diff --name-only': No such file or directoryна git bash на windows. Что я делаю не так? Каталог-
Шива
14

Следующее должно работать нормально:

git diff -z --name-only commit1 commit2 | xargs -0 -IREPLACE rsync -aR REPLACE /home/changes/protected/

Чтобы объяснить дальше:

  • Параметр -zto with git diff --name-onlyпозволяет выводить список файлов, разделенных байтами NUL, а не символами новой строки, на тот случай, если в именах ваших файлов есть необычные символы.

  • Параметр -0to xargsуказывает на интерпретацию стандартного ввода в виде списка параметров, разделенных NUL.

  • -IREPLACEТребуется , так как по умолчанию xargsбудет добавлять параметры в конце rsyncкоманды. Вместо этого это говорит, чтобы поместить их, где позже REPLACE. (Это хороший совет из этого ответа о сбое сервера .)

  • -aПараметр rsyncсредства для сохранения права, права собственности и т.д. , если это возможно. Способ -Rиспользования полного относительного пути при создании файлов в месте назначения.

Обновление: если у вас старая версия xargs, вам нужно использовать -iопцию вместо -I. (Первое не рекомендуется в более поздних версияхfindutils .)

Марк Лонгэйр
источник
Это странно - какую операционную систему вы используете? Если это дистрибутив Linux, какой и что он xargs --versionговорит?
Марк Лонгэйр
1
Ах, в той версии xargs, которую вы должны использовать -iвместо этого, которая устарела в более поздних версиях - 4.1 сейчас довольно старая. Я обновлю свой ответ.
Марк Лонгэйр
@Mark: я помню, что где-то читал, что -Iв некоторых версиях вам нужен пробел , так что, возможно, попробуйте -I REPLACEвместо этого.
Микель
Неважно. Это тоже не работает. -Iподдерживается только с findutils4.2.10, выпущенной в декабре 2004 года.
Mikel
Вы должны добавить, --diff-filter=dчтобы исключить удаленные файлы из списка. В противном случае вы получите ошибки при попытке скопировать их в папку изменений. В противном случае отличный ответ. Спасибо!
17
11

Вот одна строка:

Перечислите измененные файлы и упакуйте их как * .zip:

git diff --name-only | zip patched.zip -@

Перечислите последние подтвержденные измененные файлы и упакуйте их как * .zip:

git diff --name-only HEAD~ HEAD | zip patched.zip -@
kolypto
источник
Если вы используете Windows, вы можете скачать zip-файл командной строки с sourceforge.net/projects/gnuwin32/files/zip
Radon8472
@ Radon8472 что устанавливает sed.exe? Я все еще zipне найден на окнах.
Шива
нет, ссылка указывает на загрузку для zip.exe, а не для sed. Если вы не можете использовать zip в командной строке, вам следует добавить папку, в которой установлен zip.exe, в вашу PATHпеременную env.
Radon8472
6
zip update.zip $(git diff --name-only commit commit)
отметка
источник
2

Работает отлично.

git diff 1526043 82a4f7d --name-only | xargs zip update.zip

git diff 1526043 82a4f7d --name-only |xargs -n 10 zip update.zip
knight2016
источник
1

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

git diff --name-only $from..$to  | cpio -pld outdir
hexten
источник