Jak wyodrębnić pojedynczy plik (lub zmiany w pliku) z magazynu git?

772

Chciałbym wiedzieć, czy można wyodrębnić pojedynczy plik lub różnicę pliku ze skrytki git bez odrywania zestawu zmian skrytki.

Czy ktoś może podać jakieś sugestie / pomysły na ten temat?

Danny
źródło

Odpowiedzi:

1130

Na stronie podręcznika git stash możesz przeczytać (w sekcji „Dyskusja”, zaraz po opisie „Opcje”), że:

Skrytka jest reprezentowana jako zatwierdzenie, którego drzewo rejestruje stan katalogu roboczego, a jej pierwszym nadrzędnym jest zatwierdzenie w HEAD podczas tworzenia skrytki.

Możesz więc traktować skrytkę (np. Skrytka stash@{0}pierwsza / najwyższa) jako zatwierdzenie scalania i użyj:

$ git diff stash@{0}^1 stash@{0} -- <filename>

Objaśnienie: stash@{0}^1oznacza pierwszego rodzica danej skrytki, który, jak stwierdzono w powyższym wyjaśnieniu, jest zmianą, przy której zmiany zostały ukryte. Używamy tej formy „git diff” (z dwoma zatwierdzeniami), ponieważ stash@{0}/ refs/stashjest zatwierdzeniem scalania i musimy powiedzieć git, z którym rodzicem chcemy się różnić. Bardziej tajemniczy:

$ git diff stash@{0}^! -- <filename>

powinien również działać (zobacz wyjaśnienie składni w git rev-parsowaniurev^! , w sekcji „Określanie zakresów”).

Podobnie, możesz użyć git checkout, aby sprawdzić pojedynczy plik poza skrytką:

$ git checkout stash@{0} -- <filename>

lub aby zapisać go pod inną nazwą pliku:

$ git show stash@{0}:<full filename>  >  <newfile>

lub

$ git show stash@{0}:./<relative filename> > <newfile>

( zwróć uwagę, że tutaj <pełna nazwa pliku> to pełna ścieżka do pliku w stosunku do głównego katalogu projektu (pomyśl: względem stash@{0}).


Konieczne może być zabezpieczenie stash@{0}przed rozszerzeniem powłoki, tj. Użycie "stash@{0}"lub 'stash@{0}'.

Jakub Narębski
źródło
8
Jest to całkiem fajne ... Ja nie bardzo rozumiem, jak ukryta pracował dopóki nie przeczytałem odpowiedź (która doprowadzi mnie do dodawania git-Checkout). Naprawdę tego nie dostałem, kiedy robisz skrytkę, git zapisuje DWIE zatwierdzenia - jeden dla stanu indeksu i jeden dla stanu kopii roboczej, która jest połączeniem między indeksem a oryginalną HEAD. To wyjaśnia dziwne drzewa, które widziałem, gdy wizualizuję repozytorium za pomocą „gitk --all”, gdy obecne są skrytki.
Pat Notz
4
Przeważnie uważam, że aplikacja git Checkout jest najlepszym sposobem na osiągnięcie tego, co chciałem zrobić. Byłem jednak ciekawy i sprawdziłem git checkoutstronę podręcznika użytkownika. Nie można upuścić pliku w innej lokalizacji. Istnieje odniesienie do tego w: stackoverflow.com/questions/888414/…
Danny
84
$ git Checkout stash @ {0} - <nazwa_pliku> jest bardzo przydatny, dzięki
grawitacja
43
Zauważ, że git checkoutpodejście kopiuje dokładny plik ze skrytki - nie łączy go z tym, co znajduje się w twoim katalogu roboczym, tak jak git stash applyzrobiłby to. (Jeśli więc wprowadzisz jakieś zmiany w podstawie, na której utworzono skrytkę, zostaną one utracone).
peterflynn
4
Zauważ, że git stash applyaby scalić zmiany w pliku, który został zmodyfikowany w drzewie roboczym od czasu ukrycia pliku, plik ten w drzewie roboczym musi zostać zainscenizowany. Aby automatyczne scalanie działało, te same pliki nie mogą być modyfikowane zarówno w kopii roboczej, jak i w ukrytej kopii do scalenia. Wreszcie zastosowanie ukrywania nie usuwa elementu ze schowka tak git stash pop, jak by to robił .
Ville,
46

Jeśli użyjesz git stash applyzamiast git stash poptego, zastosuje skrytkę do twojego drzewa roboczego, ale nadal zachowa skrytkę.

Po wykonaniu tego możesz add/ commitplik, który chcesz, a następnie zresetować pozostałe zmiany.

Tim Henigan
źródło
2
Pop konkretny zapas: git stash pop stash@{0}(wymień ukryty Zmiany: git stash list)
MrYoshiji
Jeśli inne pliki w skrytce powodują konflikt scalania, git nie pozwala mi zatwierdzić pliku, który chcę :(
kambunkcyjny
33

Istnieje prosty sposób na uzyskanie zmian z dowolnej gałęzi, w tym skrytek:

$ git checkout --patch stash@{0} path/to/file

Możesz pominąć specyfikację pliku, jeśli chcesz łatać w wielu częściach. Lub pomiń łatkę (ale nie ścieżkę), aby uzyskać wszystkie zmiany w jednym pliku. Zastąp 0numerem skrytki z git stash list, jeśli masz więcej niż jeden. Zauważ, że tak jest diffi oferuje zastosowanie wszystkich różnic między gałęziami. Aby uzyskać zmiany tylko z jednego zatwierdzenia / skrytki, spójrz na git cherry-pick --no-commit.

Walf
źródło
Czy to kopiuje dokładny plik ze skrytki, czy też się łączy? W przypadku kopiowania, jeśli wprowadzono jakieś zmiany od czasu utworzenia skrytki, zostaną one utracone.
Danijel
2
@Danijel Przeczytaj git help checkout. --patchwykonuje interaktywne scalanie, stosuje się do każdego kawałka, który zatwierdzisz w powłoce (lub cokolwiek, co zaoszczędzisz, jeśli zdecydujesz się eporzucić łatkę). Sama ścieżka nadpisze plik, jak napisałem „wszystkie zmiany”.
Walf
1
niewielka poprawa: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' - wtedy robi git applydiffat stash@{4}tylko pliki, które zmieniły się między skrytką a jej rodzicem.
Mark
25

Krótka odpowiedź

Aby zobaczyć cały plik: git show stash@{0}:<filename>

Aby zobaczyć różnicę: git diff stash@{0}^1 stash@{0} -- <filename>

Luboš Turek
źródło
1
Nie sądzę, żeby był zainteresowany przeglądaniem skrytki dla określonego pliku - tylko wyskakiwanie tego pliku.
Amalgovinus
1
Właśnie tego szukałem. Następnie można wymienić diffz difftoolużyć ulubionego diff zewnętrznego.
Peet Brits
19
$ git checkout stash@{0} -- <filename>

Uwagi:

  1. Upewnij się, że wstawiłeś spację po „-” i parametrze nazwy pliku

  2. Zamień zero (0) na określony numer skrytki. Aby uzyskać listę skrytek, użyj:

    git stash list
    

Na podstawie odpowiedzi Jakuba Narębskiego - krótsza wersja

Baran
źródło
11

Możesz uzyskać różnicę dla skrytki za pomocą „ git show stash@{0}” (lub jakiejkolwiek liczby skrytki; patrz „lista skrytek git”). Łatwo jest wyodrębnić sekcję pliku różnicowego dla pojedynczego pliku.

Nathan Kitchen
źródło
2
Jeszcze prostsze dla umysłów takich jak ja: użyj, git show stashaby pokazać najwyższą skrytkę (zwykle jedyną, którą masz). Podobnie możesz pokazać różnicę między bieżącą gałęzią a skrytką za pomocą git diff head stash.
Dizzley,
5

Najprostszym pojęciem do zrozumienia, choć może nie najlepszym, jest zmiana trzech plików i chowanie jednego pliku.

Jeśli zrobisz to, git stashaby ukryć je wszystkie, git stash applyprzywróć je ponownie, a następnie git checkout f.cw danym pliku, aby go skutecznie zresetować.

Jeśli chcesz odblokować to uruchomienie pliku, wykonaj git reset --harda następnie uruchom git stash applyponownie, korzystając z faktu, że git stash applynie usuwa różnic ze stosu ukrytych plików .

Philluminati
źródło
1

Jeśli ukryte pliki muszą zostać scalone z bieżącą wersją, skorzystaj z poprzednich sposobów, używając diff. W przeciwnym razie możesz użyć git popdo ich odtajnienia, git add fileWantToKeepdo przemieszczenia pliku i zrobienia git stash save --keep-index, do ukrycia wszystkiego oprócz tego, co jest na scenie. Pamiętaj, że różnica w ten sposób w porównaniu z poprzednimi polega na tym, że „wyskakuje” plik ze skrytki. Poprzednie odpowiedzi zachowują go, git checkout stash@{0} -- <filename>więc idzie zgodnie z Twoimi potrzebami.

Hola Soy Edu Feliz Navidad
źródło
0

Wykonaj poniższe czynności, aby zastosować zmiany do pliku w skrytce do drzewa roboczego.

git diff stash^! -- <filename> | git apply

Jest to ogólnie lepsze niż używanie, git checkoutponieważ nie utracisz żadnych zmian wprowadzonych do pliku od momentu utworzenia skrytki.

kambunkcyjny
źródło