Git diff --name-only i skopiuj tę listę

151

Chcę tylko uzyskać listę zmienionych plików między dwiema wersjami, co jest proste:

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

Ale co mam napisać, jeśli chcę skopiować wszystkie wymienione pliki w inne miejsce? I potrzebuję całkowicie identycznej struktury katalogów dla kopiowanych plików.

Na przykład zmodyfikowałem i dodałem pliki:

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

Chcę mieć w /home/changes/tych wszystkich zmienionych i dodanych plikach:

/home/changes/protected/texts/file1.txt
/home/changes/protected/scripts/index.php
/home/changes/public/pics/pic1.png
BazZy
źródło
1
nie do końca rozumiem, co próbujesz osiągnąć… propagując zmiany do różnych klonów? tworzenie łatek? łatanie plików poza repozytorium git?
knittl
Nie łatka, ale dokładna struktura kopii zmienionych plików. Jak łatka, ale z solidnymi plikami
BazZy
I tak, łatanie plików poza repozytorium git - najbliższy cel dla mnie :)
BazZy
3
Przepraszam. CO? chcesz przechwytywać i odtwarzać zmiany w plikach i zmiany w drzewach? to jest poprawka. git format-patchmoże to zrobić dla zakresów zatwierdzeń.
knittl
1
git diff commit1 commit2 > my.patcha potem cd other/path; patch -p1 < my.patch. Dlaczego trzeba to robić z pełnymi kopiami plików? Jeśli to dlatego, że myślisz, że łatka może nie mieć zastosowania, a tym samym inny katalog nie jest w commit1stanie, naprawdę powinieneś skopiować wszystko ze commit2stanu ...
Cascabel Kwietnia

Odpowiedzi:

118

Wypróbuj następujące polecenie, które przetestowałem:

$ cp -pv --parents $(git diff --name-only) DESTINATION-DIRECTORY
York
źródło
2
Dzięki za cp --parentspodpowiedź, chciałem tej opcji od lat i nigdy nie wiedziałem, że istnieje! .. oczywiście nigdy nie zawracałem sobie głowy szukaniem tego = \
Stephan Henningsen
2
Zauważ, że to nie działa na Macu, ponieważ --parentsopcja cpnie jest dostępna.
M. Justin
Jakieś wskazówki dotyczące używania tego, jeśli pliki mają nietypowe znaki? Białe znaki, znaki nordyckie.
Halvor Holsten Strand
@HalvorStrand, nie testowałem tego, ale ustawienie IFS=$'\n'pierwsze może to zrobić. (Najlepiej w podpowłoce, aby nie zepsuć oryginalnej wartości IFS.)
Wildcard
Otrzymuję błąd cp: cannot stat 'git diff --name-only': No such file or directorypodczas git bash w systemie Windows. Co ja robię źle? Katalog docelowy istnieje
Shiva
14

Poniższe powinny działać dobrze:

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

Aby wyjaśnić dalej:

  • To -zwith git diff --name-onlyoznacza wyświetlenie listy plików oddzielonych bajtami NUL zamiast znakami nowej linii, na wypadek gdyby nazwy plików miały w sobie nietypowe znaki.

  • -0Się xargsmówi interpretować jako standardowe wejście liście NUL oddzielonych parametrów.

  • Jest -IREPLACEto potrzebne, ponieważ domyślnie xargsdodaje parametry na końcu rsyncpolecenia. Zamiast tego mówi się, aby umieścić je tam, gdzie REPLACEjest później . (To miła wskazówka z odpowiedzi na błąd serwera ).

  • -aParametr do rsyncśrodków w celu zachowania uprawnień, własności, itp jeśli to możliwe. Sposób -Rużycia pełnej ścieżki względnej podczas tworzenia plików w miejscu docelowym.

Aktualizacja: jeśli masz starą wersję xargs, musisz użyć tej -iopcji zamiast -I. (Pierwsza jest przestarzała w nowszych wersjach findutils.)

Mark Longair
źródło
To dziwne - jakiego systemu operacyjnego używasz? Jeśli jest to dystrybucja Linuksa, to która z nich i co xargs --versionmówi?
Mark Longair,
1
Ach, w tej wersji xargs musisz użyć -izamiast tego, co jest przestarzałe w późniejszych wersjach - 4.1 jest teraz dość stary. Zaktualizuję odpowiedź.
Mark Longair
@Mark: Pamiętam, że czytałem gdzieś, że -Iw niektórych wersjach potrzebujesz spacji , więc może spróbuj -I REPLACEzamiast tego.
Mikel
Nieważne. To też nie działa. -Ijest obsługiwany tylko od findutils4.2.10, wydanego w grudniu 2004.
Mikel
Należy dodać, --diff-filter=daby wykluczyć usunięte pliki z listy. W przeciwnym razie wystąpią błędy podczas próby skopiowania ich do folderu zmian. W przeciwnym razie świetna odpowiedź. Dzięki!
taymless
11

Oto jedna linijka:

Wyświetl zmienione pliki i spakuj je jako * .zip:

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

Wyświetl ostatnio zatwierdzone zmienione pliki i spakuj je jako * .zip:

git diff --name-only HEAD~ HEAD | zip patched.zip -@
kolypto
źródło
Jeśli używasz systemu Windows, możesz pobrać zip z wiersza poleceń ze strony sourceforge.net/projects/gnuwin32/files/zip
Radon8472
@ Radon8472 Który instaluje sed.exe? Nadal zipnie jestem wykrywany w systemie Windows.
Shiva
nie, odsyłacz wskazuje na pobranie pliku zip.exe, a nie seda. Jeśli nie możesz użyć zip w linii poleceń, powinieneś dodać folder, w którym jest zainstalowany plik zip.exe, do PATHzmiennej env.
Radon8472,
6
zip update.zip $(git diff --name-only commit commit)
znak
źródło
2

Działa doskonale.

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

git diff 1526043 82a4f7d --name-only |xargs -n 10 zip update.zip
rycerz 2016
źródło
1

Nikt nie wspomniał o tym, cpioktóry jest łatwy do wpisania, tworzy twarde linki i obsługuje spacje w nazwach plików:

git diff --name-only $from..$to  | cpio -pld outdir
hexten
źródło