Czy mogę uzyskać wyjście zgodne z poprawkami z git-diff?

160

Robię coś bardzo prostego złego. Próbuję przygotować zwykły plik poprawki, więc mogę ponownie zastosować kilka zmian:

$ git diff > before
$ git diff something_here > save.patch
$ git checkout . 
$ patch < save.patch
$ git diff > after
$ diff before after
$

Z something_here zaślepką prawie działa, ale nazwy plików nie są w porządku. Myślę, że po prostu brakuje mi jakiejś opcji.

W prawdziwym życiu zamierzam dokonać scalenia po wymeldowaniu, więc łatka może się tam nie udać, ale widzisz, do czego zmierzam.

Edytuj tutaj Mój błąd za zadanie niewłaściwego pytania. Właściwe pytanie brzmi: chcę zapisać swoje zmiany, wykonać scalenie, a następnie ponownie zastosować zmiany, jeśli to możliwe? Poprosiłem o to w niewłaściwy sposób, ponieważ jestem przyzwyczajony do używania łatki do rozwiązywania tego rodzaju problemów i git diffwyglądało na to, że właśnie tego chciałem.

Komentarz Charlesa Baileya zawierał właściwą odpowiedź. Dla mnie git-apply to właściwa rzecz (git-stash wygląda na cięższą niż potrzebuję, a zmiana bazy i pakiety zdecydowanie przekraczają mój obecny poziom umiejętności). Przyjmę odpowiedź, której udzielił Charles (ponieważ ty nie może przyjąć komentarza). Dzięki za wszystkie sugestie.

Edytuj, 6 lat później Jak każdy obeznany w temacie wie, przeszacowałem trudność git stash. Prawie każdego dnia będę używał następującej sekwencji:

$ git stash
$ git merge
$ git stash pop
Malvolio
źródło
8
Czy jest jakiś powód, dla którego chcesz patchraczej użyć niż git apply?
CB Bailey,
3
A nawet wtedy, czy naprawdę potrzebujesz łatek zamiast czegoś podobnego git stashlub innych narzędzi git?
CB Bailey,
3
Wydaje mi się, że po edycji git stashjest to najłatwiejsze rozwiązanie tego, co próbujesz zrobić, ale istnieje wiele podejść, które działają.
CB Bailey,
1
@Malvolio: Rzeczywiście, nie musisz nawet myśleć o tymczasowej nazwie pliku do przechowywania poprawki.
CB Bailey
4
@Charlse, czasami musisz wysłać łatkę do kogoś bez całego repozytorium git. Na przykład jeśli używasz git-svn.
Elazar Leibovich

Odpowiedzi:

139

Jeśli chcesz używać łatki, musisz usunąć a/ b/prefiksy używane domyślnie przez git. Możesz to zrobić za pomocą --no-prefixopcji (możesz to również zrobić za pomocą łatki-p opcją ):

git diff --no-prefix [<other git-diff arguments>]

Zwykle jednak łatwiej jest używać go prosto git diff a następnie używać wyjścia do podawania git apply.

Przez większość czasu staram się unikać poprawek tekstowych. Zwykle jedno lub więcej tymczasowych zatwierdzeń w połączeniu z rebase git stashi pakietami są łatwiejsze w zarządzaniu.

Myślę, że dla twojego przypadku użycia stashjest to najbardziej odpowiednie.

# save uncommitted changes
git stash

# do a merge or some other operation
git merge some-branch

# re-apply changes, removing stash if successful
# (you may be asked to resolve conflicts).
git stash pop
CB Bailey
źródło
7
git diff --no-prefix master > diff.patcha potemgit checkout master patch -p0 < diff.patch
Natim
1
@Natim Dla maksymalnego bezpieczeństwa polecam użycie go patch --dry-run < diff.patchprzed wydaniem ostatniej komendy.
ᴠɪɴᴄᴇɴᴛ
1
@ ᴠɪɴᴄᴇɴᴛ jaka byłaby korzyść z zrobienia tego? Ponieważ używamy gita, jest mało prawdopodobne, abyśmy coś stracili, prawda?
Natim
1
@Natim Jak powiedziałem, tylko dla maksymalnego bezpieczeństwa, nie trzeba niczego cofać w przypadku błędu. Myślałem także o ludziach, którzy to czytają i chcą używać patchpoza gitem (może używając pliku łatki wygenerowanej przez diff) w bardziej ogólnym przypadku użycia.
ᴠɪɴᴄᴇɴᴛ
Aby dołączyć nowe pliki do swojej łatki, musisz również dołączyć do łatki "git diff --no-prefix --cached". Może jest lepszy sposób?
jamshid
219

Po prostu użyj -p1: i tak będziesz musiał użyć -p0w --no-prefixetui, więc możesz po prostu pominąć --no-prefixi użyć -p1:

$ git diff > save.patch
$ patch -p1 < save.patch

$ git diff --no-prefix > save.patch
$ patch -p0 < save.patch
ndim
źródło
1
Jeśli zastanawiasz się dlaczego, doktorant podsumowuje to ładnie - źródło .
tutuDajuju
3
To nie zadziała w przypadku zmiany nazw; git diffwyprowadza linię, która patchignoruje. git applyjest droga do zrobienia.
hraban
17

Pliki różnicowe git mają dodatkowy segment ścieżki dołączony do ścieżek plików. Możesz usunąć ten wpis w ścieżce, podając -p1 z łatą, na przykład:

patch -p1 < save.patch
Henrik Gustafsson
źródło
10
  1. Zapisuję różnicę bieżącego katalogu (w tym niezatwierdzonych plików) z bieżącym HEAD.
  2. Następnie możesz przenieść save.patchplik w dowolne miejsce (w tym pliki binarne).
  3. Na komputerze docelowym zastosuj poprawkę za pomocą git apply <file>

Uwaga: różni się również od aktualnie przygotowanych plików.

$ git diff --binary --staged HEAD > save.patch
$ git reset --hard
$ <transport it>
$ git apply save.patch
Matej
źródło
Hahaha. Zabawne. Zadałem to pytanie prawie cztery lata temu i sposób, w jaki to robiłem, ewoluował, ale gdybyś zapytał mnie wczoraj, jak to zrobić, udzieliłbym twojej odpowiedzi i powiedziałbym, że otrzymałem ją z odpowiedzi na to pytanie. (Właściwie prawdopodobnie użyłbym gołego git diff > save.patchi git checkout .zamiast resetu, ale tak ...
Malvolio
Och, nie zauważyłem, że ma 4 lata: P. Przy okazji, reset jest tylko po to, by zademonstrować, że działa. Nie widzę też nikogo, kto używa git applylub czyni różnicę stosownym do twojego stanu i wskaźnika do ostatniego dostępnego zatwierdzenia. Po prostu git diffnic nie dało
Matej
Tak, teraz zastanawiam się, skąd się dowiedziałem git apply. Chodzi o git diffto (myślę), że chodzi o używanie git reset- problemem są relacje między repozytorium, indeksem i obszarem roboczym.
Malvolio,
8

Przydatna sztuczka pozwalająca uniknąć tworzenia tymczasowych plików poprawek:

git diff | patch -p1 -d [dst-dir]
slowstart
źródło
Dokładnie to, czego chciałem. Działa również doskonale ze skrytkami! git stash show -p stash@{3} | patch -p1 -d [dst-dir]
dtmland,