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

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

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.)


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 -@

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)


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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.