Jak dodać zmieniony plik do starszego (nie ostatniego) zatwierdzenia w Git


461

W ciągu ostatniej godziny zmieniłem kilka rzeczy i popełniłem je krok po kroku, ale właśnie zdałem sobie sprawę, że zapomniałem dodać zmieniony plik kilka zmian wcześniej.

Dziennik wygląda następująco:

    GIT TidyUpRequests u:1 d:0> git log 
    commit fc6734b6351f6c36a587dba6dbd9d5efa30c09ce 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:43:55 2010 +0200

        The Main program now tests both Webservices at once

    commit 8a2c6014c2b035e37aebd310a6393a1ecb39f463 
    Author: David Klein <>
    Date:   Tue Apr 27 09:43:27 2010 +0200

        ISBNDBQueryHandler now uses the XPath functions from XPath.fs too

    commit 06a504e277fd98d97eed4dad22dfa5933d81451f 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:30:34 2010 +0200

        AmazonQueryHandler now uses the XPath Helper functions defined in XPath.fs

    commit a0865e28be35a3011d0b6091819ec32922dd2dd8 <--- changed file should go here
    Author: David Klein <> 
    Date:   Tue Apr 27 09:29:53 2010 +0200

        Factored out some common XPath Operations

Jakieś pomysły?


Odpowiedzi:


693

Zastosowanie git rebase. Konkretnie:

  1. Służy git stashdo przechowywania zmian, które chcesz dodać.
  2. Użyj git rebase -i HEAD~10(lub jak wiele zatwierdzeń, które chcesz zobaczyć).
  3. Zaznacz zatwierdzony przedmiot ( a0865...) do edycji, zmieniając słowo pickna początku wiersza na edit. Nie usuwaj innych wierszy, ponieważ spowoduje to usunięcie zatwierdzeń. [^ Vimnote]
  4. Zapisz plik rebase, a git wróci do powłoki i poczeka na naprawienie tego zatwierdzenia.
  5. Pop skrytkę za pomocą git stash pop
  6. Dodaj swój plik za pomocą git add <file>.
  7. Zmień zatwierdzenie za pomocą git commit --amend --no-edit.
  8. Wykonaj polecenie, git rebase --continuektóre przepisze resztę twoich zobowiązań względem nowego.
  9. Powtórz czynności od kroku 2, jeśli zaznaczyłeś więcej niż jeden zatwierdzenie do edycji.

[^ vimnote]: Jeśli używasz vim, musisz nacisnąć Insertklawisz, aby edytować, a następnie Esci wpisać, :wqaby zapisać plik, wyjść z edytora i zastosować zmiany. Alternatywnie możesz skonfigurować przyjazny dla użytkownika edytor git commit za pomocą git config --global core.editor "nano".


23
Co zrobić, jeśli masz zmiany nieetapowe, które chcesz dodać do edycji? Gdybym je schował, nie mogłem git add.
Sam

15
Sam możesz po prostu rozpakować zmiany w danym zatwierdzeniu, będzie działać dobrze.
omnikron

17
Uwaga: Po zaznaczeniu zatwierdzenia editNIE USUWAJ innych zatwierdzeń wymienionych w pliku. Jeśli to zrobisz, zatwierdzenia zostaną usunięte i będziesz musiał wykonać następujące kroki, aby je odzyskać.
David Tuite,

2
Jeśli chodzi o to, co powiedział @DavidTuite, moim nawykiem przy robieniu rzeczy na git, których nie jestem pewien, jak się okaże, jest tworzenie gałęzi „branchname-ref”, aby zapisać bieżący stan osi czasu na wypadek, gdyby coś popsuło. Kiedy skończę, usuwam to.
Raphael

1
W kroku 6 dołącz. (kropka) w poleceniu. Prawidłowe polecenie:git add .
Tom

323

Aby „naprawić” stary zatwierdzenie z niewielką zmianą, bez zmiany komunikatu zatwierdzenia starego zatwierdzenia, gdzie OLDCOMMITjest coś takiego 091b73a:

git add <my fixed files>
git commit --fixup=OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^

Możesz także użyć git commit --squash=OLDCOMMITdo edycji starej wiadomości zatwierdzenia podczas zmiany bazy.


  • git rebase --interactivewyświetli edytor tekstu (który można skonfigurować ) w celu potwierdzenia (lub edycji) sekwencji instrukcji rebase . Plik zawiera informacje o zmianach instrukcji rebase ; po prostu zapisz i zamknij edytor ( :wqwvim ), aby kontynuować rebase.
  • --autosquashautomatycznie ustawi wszelkie --fixup=OLDCOMMITzatwierdzenia w żądanej kolejności. Uwaga: --autosquashobowiązuje tylko wtedy, gdy --interactiveużyta jest opcja.
  • ^W OLDCOMMIT^drodze jest to odniesienie do popełnienia tuż przed OLDCOMMIT.

Powyższe kroki są dobre do weryfikacji i / lub modyfikacji sekwencji instrukcji rebase , ale możliwe jest również pominięcie / zautomatyzowanie interaktywnego edytora tekstu rebase poprzez:

Zobacz git commit i git rebase . Jak zawsze, przy przepisywaniu historii git , powinieneś naprawiać lub zatwierdzać zmiany, które nie zostały jeszcze opublikowane nikomu innemu (w tym losowym użytkownikom Internetu i budowaniu serwerów).


18
Znacznie wyraźniejsze niż inne opcje i zadziałało jak urok
Chris Mitchelmore

5
@Jonah: edytor nie jest otwarty w celu edycji komunikatu zatwierdzenia , ale w celu potwierdzenia (lub edycji) kroków zmiany bazy . Nie da się tego uniknąć; --autosquashjest ważny tylko wtedy, gdy --interactiveużywana jest opcja .
Joel Purra

5
Korzystając z tego rozwiązania, utknąłem git pokazujący VIM. Mój problem polega na tym, że nie wiem, jak korzystać z VIM. Jak do cholery mam z tego wyjść, jak mogę kontrolować to, to takie mylące.
Neon Warge

2
@NeonWarge: edytor do wyboru można skonfigurować na przykład za pomocą git config --global core.editor "pico". Istnieje kilka innych sposobów konfiguracji git i / lub zmiany domyślnego edytora systemu itp.
Joel Purra

2
jeden wiersz fajny alias tutaj
idanp 27.04.18

61

z git 1.7 istnieje naprawdę łatwy sposób używania git rebase:

wystaw swoje pliki:

git add $files

utwórz nowe zatwierdzenie i ponownie użyj komunikatu zatwierdzenia swojego „zepsutego” zatwierdzenia

git commit -c master~4

wstaw fixup!przed wierszem tematu (lub squash!jeśli chcesz edytować zatwierdzenie (wiadomość)):

fixup! Factored out some common XPath Operations

służy git rebase -i --autosquashdo naprawy zatwierdzenia


2
+1. Ładne zastosowanie nowej dyrektywy w sprawie poprawek (1.7+): stackoverflow.com/questions/2302736/trimming-git-checkins/…
VonC

@knittl Próbowałem twojej metody, aby dodać kolejny plik do mojego starego zatwierdzenia (nie wypchniętego), ale kiedy się zmieniałem, dostaję, You asked me to rebase without telling me which branch you want to rebase against, and 'branch.master.merge'a jeśli go używam git rebase -i --autosquash, po prostu otrzymuję noopwiersz tematu, zmieniając zatwierdzenie na sobie. Masz pojęcie, co robię źle?
oschrenk

7
@oschrenk: Musisz podać zatwierdzenie, którego git rebase -i --autosquash HEAD~10
podstawę

1
Dobra odpowiedź, ale musiałem również dodać zatwierdzenie, na podstawie którego można dokonać zmiany. Byłoby świetnie, gdybyś mógł go zaktualizować.
Paul Odeon

@PaulOdeon: Nie rozumiem twojego pytania. Co próbujesz zrobić i gdzie masz problemy?
knittl

8

Możesz spróbować rebase --interactivesesji, aby zmienić swoje stare zatwierdzenie (pod warunkiem , że nie wypchnąłeś już tych zatwierdzeń do innego repo).

Czasami rzecz naprawiona w b.2. nie można go zmienić na niezupełnie naprawione zmiany, ponieważ zmiany są głęboko zakopane w serii łatek .
Właśnie do tego służy interaktywny rebase: użyj go po wielu „a” i „b”, zmieniając rozmieszczenie i edycję zatwierdzeń oraz zgniatając wiele zatwierdzeń w jeden.

Rozpocznij od ostatniego zatwierdzenia, które chcesz zachować na obecnym poziomie:

git rebase -i <after-this-commit>

Edytor zostanie uruchomiony ze wszystkimi zatwierdzeniami w bieżącym oddziale (ignorując zatwierdzenia scalania), które pojawiają się po danym zatwierdzeniu.
Możesz zmienić kolejność zatwierdzeń na tej liście do zawartości twojego serca i możesz je usunąć. Lista wygląda mniej więcej tak:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

Opisy online są wyłącznie dla twojej przyjemności; git rebase nie będzie na nie patrzył, ale na nazwy zatwierdzeń (w tym przykładzie „deadbee” i „fa1afe1”), więc nie usuwaj ani nie edytuj nazw.

Zastępując polecenie „pick” poleceniem „edit”, możesz powiedzieć git rebase, aby przestał działać po zastosowaniu tego zatwierdzenia, abyś mógł edytować pliki i / lub komunikat zatwierdzenia, zmienić zatwierdzenie i kontynuować bazowanie .

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.