Zwykle przesyłam listę do zatwierdzenia. Jeśli mam następujące zatwierdzenia:
HEAD
Commit3
Commit2
Commit1
... Wiem, że mogę modyfikować zatwierdzanie głowy git commit --amend
. Ale jak mogę zmodyfikować Commit1
, biorąc pod uwagę, że nie jest to HEAD
zatwierdzenie?
git
git-rewrite-history
Sam Liao
źródło
źródło
Odpowiedzi:
Możesz użyć git rebase . Na przykład, jeśli chcesz zmodyfikować zatwierdzenie
bbc643cd
, uruchomZwróć uwagę na daszek
^
na końcu polecenia, ponieważ tak naprawdę musisz cofnąć bazowanie do zatwierdzenia przed tym, które chcesz zmodyfikować .W edytorze domyślnym zmień
pick
naedit
w wierszu z opcją „bbc643cd”.Zapisz plik i zakończ: git zinterpretuje i automatycznie wykona polecenia w pliku. Znajdziesz się w poprzedniej sytuacji, w której właśnie utworzyłeś zatwierdzenie
bbc643cd
.W tym momencie
bbc643cd
jest twoje ostatnie zatwierdzenie i możesz je łatwo zmienić : wprowadź zmiany, a następnie zatwierdź je za pomocą polecenia:Następnie wpisz:
aby powrócić do poprzedniego zatwierdzenia HEAD.
OSTRZEŻENIE : Zauważ, że spowoduje to zmianę SHA-1 tego zatwierdzenia, a także wszystkich dzieci - innymi słowy, przepisuje historię od tego momentu. Możesz przerwać repozytorium, robiąc to , naciskając polecenie
git push --force
źródło
reword
akcji (automatycznie otwiera edytor i kontynuuje pozostałe kroki zmiany bazy; to eliminuje użycie i kiedy trzeba tylko zmienić komunikat zatwierdzenia, a nie treść ).git rebase -i
edit
git commit --ammend
git rebase --continue
git stash
przedgit rebase
igit stash pop
po, jeśli masz oczekujące zmiany.git commit --all --amend --no-edit
tego miejsca. Wszystko co musiałem zrobić pogit rebase -i ...
byłogit commit --amend
normalnie potemgit rebase --continue
.Skorzystaj z niesamowitej interaktywnej bazy:
Znajdź żądane zatwierdzenie, zmień
pick
nae
(edit
) oraz zapisz i zamknij plik. Git przewinie do tego zatwierdzenia, umożliwiając:git commit --amend
do wprowadzania zmian, lubgit reset @~
aby odrzucić ostatni zatwierdzenie, ale nie zmiany w plikach (tj. przejdź do punktu, w którym byłeś, kiedy edytowałeś pliki, ale jeszcze nie zatwierdziłeś).To drugie jest przydatne do wykonywania bardziej skomplikowanych czynności, takich jak dzielenie na wiele zatwierdzeń.
Następnie uruchom
git rebase --continue
, a Git odtworzy kolejne zmiany na zmodyfikowanym zatwierdzeniu. Możesz zostać poproszony o naprawienie niektórych konfliktów scalania.Uwaga:
@
jest skrótem dlaHEAD
i~
jest zatwierdzeniem przed określonym zatwierdzeniem.Przeczytaj więcej o przepisywaniu historii w dokumentach Git.
Nie bój się bazować
ProTip ™: Nie bój się eksperymentować z „niebezpiecznymi” poleceniami, które przepisują historię * - Git domyślnie nie usuwa twoich zobowiązań przez 90 dni; możesz je znaleźć w reflog:
* Uważaj na opcje takie jak
--hard
i--force
chociaż - mogą odrzucać dane.* Nie zapisuj także historii oddziałów, z którymi współpracujesz.
W wielu systemach
git rebase -i
domyślnie otworzy Vima. Vim nie działa jak większość współczesnych edytorów tekstu, więc spójrz, jak zmienić bazę danych za pomocą Vima . Jeśli wolisz użyć innego edytora, zmień go za pomocągit config --global core.editor your-favorite-text-editor
.źródło
@
jako skrótuHEAD
. Dzięki za opublikowanie tego.git reset @~
dokładnie to, co chciałem zrobić po wybraniu zatwierdzeniagit rebase ...
. Jesteś moim bohaterem)Interaktywny rebase z
--autosquash
jest czymś, z czego często korzystam, gdy muszę naprawić wcześniejsze zatwierdzenia głębiej w historii. Zasadniczo przyspiesza proces, który ilustruje odpowiedź ZelluX, i jest szczególnie przydatny, gdy masz więcej niż jeden zatwierdzenie, które musisz edytować.Z dokumentacji:
Załóżmy, że masz historię, która wygląda następująco:
i masz zmiany, które chcesz zmienić w Commit2, a następnie zatwierdzić je za pomocą
alternatywnie możesz użyć commit-sha zamiast komunikatu zatwierdzenia, więc
"fixup! e8adec4
lub nawet tylko prefiksu komunikatu zatwierdzenia.Następnie wcześniej zainicjuj interaktywny rebase na zatwierdzeniu
Twój edytor otworzy się z zatwierdzonymi już porządkami
wszystko, co musisz zrobić, to zapisać i wyjść
źródło
git commit --fixup=@~
zamiastgit commit -m "fixup! Commit2"
. Jest to szczególnie przydatne, gdy twoje komunikaty zatwierdzania są dłuższe i napisanie wszystkiego byłoby trudne.Biegać:
$ git rebase --interactive commit_hash^
każdy
^
wskazuje, ile zatwierdzeń z powrotem chcesz edytować, jeśli jest tylko jeden (hash zatwierdzenia, który podałeś), to po prostu dodajesz jeden^
.Korzystanie Vim zmienić słowa
pick
, abyreword
dla zatwierdzeń chcesz zmienić, zapisz i zamknij (:wq
). Następnie git wyświetli monit o każde zatwierdzenie oznaczone jako przeredagowanie, aby można było zmienić komunikat zatwierdzenia.Każdy komunikat zatwierdzenia należy zapisać i wyjść (
:wq
), aby przejść do następnego komunikatu zatwierdzeniaJeśli chcesz wyjść bez zastosowania zmian, naciśnij
:q!
EDYCJA : aby nawigować w
vim
tobie używaj,j
aby przejść w górę,k
zejść w dół,h
w lewo il
w prawo (wszystko wNORMAL
trybie, naciśnij,ESC
aby przejść doNORMAL
trybu). Aby edytować tekst, naciśniji
, aby przejść doINSERT
trybu, w którym wstawiasz tekst. Naciśnij,ESC
aby wrócić doNORMAL
trybu :)AKTUALIZACJA : Oto świetny link z listy github Jak cofnąć (prawie) cokolwiek za pomocą git
źródło
git push --force
?git push --force
robi jest zastąpienie pilotów zobowiązuje z lokalnymi zobowiązuje. Tak nie jest w tym temacie :)Jeśli z jakiegoś powodu nie lubisz interaktywnych edytorów, możesz użyć
git rebase --onto
.Powiedz, że chcesz zmodyfikować
Commit1
. Po pierwsze, gałąź z wcześniejCommit1
:Po drugie, złap
Commit1
zacherry-pick
:Teraz popraw swoje zmiany, tworząc
Commit1'
:I wreszcie, po skasowaniu jakichkolwiek innych zmian, przeszczep resztę swoich commits
master
na szczycie nowego zatwierdzenia:Przeczytaj: „rebase na gałęzi
amending
, wszystkie zatwierdzenia międzyCommit1
(nie włącznie) imaster
(włącznie)”. To znaczy Commit2 i Commit3, całkowicie odcinając stary Commit1. Możesz po prostu je wybrać, ale w ten sposób jest łatwiej.Pamiętaj, aby posprzątać swoje gałęzie!
źródło
git checkout -b amending Commit1~1
aby uzyskać wcześniejsze zatwierdzeniegit checkout -b amending Commit1
?Na podstawie dokumentacji
Poprawianie wiadomości starszych lub wielu wiadomości zatwierdzania
Powyżej wyświetla listę 3 ostatnich zatwierdzeń w bieżącej gałęzi, zmień 3 na coś innego, jeśli chcesz więcej. Lista będzie wyglądać podobnie do poniższej:
Zamień pick z przeredagowaniem przed każdą wiadomością zatwierdzenia, którą chcesz zmienić. Załóżmy, że zmienisz drugi zatwierdzenie na liście, plik będzie wyglądał następująco:
Zapisz i zamknij plik listy zmian, pojawi się nowy edytor, w którym możesz zmienić komunikat zmiany, zmienić komunikat zmiany i zapisać.
W końcu forsuj zmienione zatwierdzenia.
źródło
Całkowicie nieinteraktywne polecenie (1)
Pomyślałem, że udostępnię alias, którego używam do tego. Opiera się na nieinteraktywnym interaktywnym rebase. Aby dodać go do swojego gita, uruchom to polecenie (wyjaśnienie podane poniżej):
Największą zaletą tego polecenia jest fakt, że nie jest to vim .
(1) oczywiście biorąc pod uwagę, że nie ma żadnych konfliktów podczas bazy
Stosowanie
Nazwa
amend-to
wydaje się odpowiednia IMHO. Porównaj przepływ z--amend
:Wyjaśnienie
git config --global alias.<NAME> '!<COMMAND>'
- tworzy globalny alias git o nazwie<NAME>
, który wykona polecenie inne niż git<COMMAND>
f() { <BODY> }; f
- „anonimowa” funkcja bash.SHA=`git rev-parse "$1"`;
- konwertuje argument na wersję git i przypisuje wynik do zmiennejSHA
git commit --fixup "$SHA"
- fixup-commit dlaSHA
. Zobaczgit-commit
dokumentyGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
część została objęta innymi odpowiedziami.--autosquash
Czy to, co jest wykorzystywane w połączeniu zgit commit --fixup
, patrzgit-rebase
dokumenty , aby uzyskać więcej informacjiGIT_SEQUENCE_EDITOR=true
to sprawia, że całość nie jest interaktywna. Tego hacka nauczyłem się z tego postu na blogu .źródło
amend-to
obsłużyć pliki niestacjonarne:git config --global alias.amend-to '!f() { SHA=
git rev-; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
Zautomatyzowana interaktywna edycja bazy bazowej, po której następuje powrót do zatwierdzenia gotowy do zmiany
Naprawdę często naprawiałem wcześniejsze zatwierdzenie, więc napisałem dla niego skrypt.
Oto przepływ pracy:
Spowoduje to upuszczenie przy zatwierdzeniu, które chcesz edytować.
Napraw i dostosuj zatwierdzenie tak, jak chcesz.
(Możesz użyć,
git stash save
aby zachować wszelkie pliki, których nie popełniasz)Ponów zatwierdzenie za pomocą
--amend
, np .:Uzupełnij bazę:
Aby powyższe zadziałało, umieść poniższy skrypt w pliku wykonywalnym o nazwie
git-commit-edit
gdzieś w twoim$PATH
:źródło
Przyszło do tego podejścia (i prawdopodobnie jest to dokładnie to samo, co przy użyciu interaktywnego rebase), ale dla mnie jest to dość proste.
Uwaga: przedstawiam to podejście w celu zilustrowania tego, co możesz zrobić, zamiast codziennej alternatywy. Ponieważ ma wiele kroków (i ewentualnie pewne zastrzeżenia).
Powiedz, że chcesz zmienić zatwierdzenie
0
i jesteś aktualnie włączonyfeature-branch
Przejdź do tego zatwierdzenia i utwórz
quick-branch
. Możesz także sklonować gałąź funkcji jako punkt przywracania (przed rozpoczęciem).Będziesz teraz mieć coś takiego:
Zmieniaj scenę, przechowuj wszystko inne.
Zatwierdź zmiany i wróć do
feature-branch
Będziesz teraz mieć coś takiego:
Rebase
feature-branch
naquick-branch
(rozwiąż wszelkie konflikty po drodze). Zastosuj skrytkę i usuńquick-branch
.I kończysz na:
Git nie powieli się (chociaż nie mogę tak naprawdę powiedzieć, do jakiego stopnia) zatwierdzenie 0 podczas bazowania.
Uwaga: wszystkie skróty zatwierdzania są zmieniane, zaczynając od zatwierdzenia, które pierwotnie zamierzaliśmy zmienić.
źródło
Aby uzyskać nieinteraktywne polecenie, umieść skrypt z tą zawartością w ŚCIEŻCE:
Użyj go, wprowadzając zmiany (za pomocą
git add
), a następnie uruchomgit fixup <commit-to-modify>
. Oczywiście nadal będzie interaktywny, jeśli wystąpią konflikty.źródło
git stash
+rebase
automatyzacjaPonieważ kiedy muszę wielokrotnie modyfikować stare zatwierdzanie dla recenzji Gerrit, robiłem:
GitHub w górę .
Stosowanie:
git add
robić już w repogit-amend-old $old_sha
Podoba mi się to,
--autosquash
ponieważ nie niszczy innych niepowiązanych poprawek.źródło
git amend
zastosowania zmian do konkretnego zatwierdzenia za pomocą bieżącego skrytki, bardzo sprytnie!Rozwiązałem to
1) tworząc nowe zatwierdzenie ze zmianami, które chcę ..
2) wiem, które zobowiązanie muszę z nim połączyć. czyli zatwierdzenie 3.
więc
git rebase -i HEAD~4
# 4 reprezentuje ostatnie 4 zatwierdzenie (tutaj zatwierdzenie 3 jest na 4 miejscu)3) w bazie interaktywnej ostatnie zatwierdzenie będzie znajdować się na dole. będzie wyglądać podobnie,
4) tutaj musimy zmienić kolejność zatwierdzenia, jeśli chcesz połączyć się z konkretnym. powinno być jak
po Przegrupuj trzeba wymienić
p
pick
zf
( fixup połączą bez popełnienia wiadomości) lubs
( squash seryjnej z popełnić wiadomość może się zmienić w czasie wykonywania)a następnie zapisz swoje drzewo.
teraz scalanie wykonane z istniejącym zatwierdzeniem.
źródło
Najlepszą opcją jest użycie „Interaktywnego polecenia rebase” .
Teraz jak korzystać z tego polecenia?
-i
oznacza „interaktywny” . Zauważ, że możesz wykonać rebase w trybie nieinteraktywnym. dawny:HEAD
wskazuje twoją bieżącą lokalizację (może to być również nazwa oddziału lub zatwierdzenie SHA).~n
Środki „n beforeé, więcHEAD~n
będzie wykaz«n»zobowiązuje przed jednym jesteś obecnie.git rebase
ma inne polecenia, takie jak:p
lubpick
aby kontynuować, tak jak jest.r
lubreword
: aby zachować treść zatwierdzenia, ale zmienić komunikat zatwierdzenia.s
lubsquash
: aby połączyć zmiany tego zatwierdzenia z poprzednim zatwierdzeniem (zatwierdzenie nad nim na liście).... itd.
Uwaga: Lepiej jest, aby Git pracował z edytorem kodu, aby uprościć sprawę. Na przykład jeśli używasz kodu wizualnego, możesz dodać w ten sposób
git config --global core.editor "code --wait"
. Możesz też wyszukać w Google, jak powiązać preferowany edytor kodu z GIT.Przykład
git rebase
Chciałem zmienić ostatnie 2 zatwierdzenia, które zrobiłem, więc przetwarzam w następujący sposób:
Teraz używam
git rebase
do zmiany 2 ostatnich zatwierdzeń wiadomości:$git rebase -i HEAD~2
Otwiera edytor kodu i pokazuje to:Ponieważ chcę zmienić komunikat zatwierdzenia dla tych 2 zatwierdzeń. Więc napiszę
r
lubreword
zamiastpick
. Następnie zapisz plik i zamknij kartę. Pamiętaj, żerebase
jest wykonywany w procesie wieloetapowym, więc następnym krokiem jest aktualizacja wiadomości. Zauważ też, że zatwierdzenia są wyświetlane w odwrotnej kolejności chronologicznej, więc ostatnie zatwierdzenie jest wyświetlane w tym jednym, a pierwsze zatwierdzenie w pierwszej linii i tak dalej.Zaktualizuj wiadomości: Zaktualizuj pierwszą wiadomość:
zapisz i zamknij Edytuj drugą wiadomość
Zapisz i zamknij.
Otrzymasz taki komunikat do końca bazy:
Successfully rebased and updated refs/heads/documentation
co oznacza, że ci się uda. Możesz wyświetlić zmiany:Chciałbym, żeby to pomogło nowym użytkownikom :).
źródło
Dla mnie było to usunięcie niektórych danych uwierzytelniających z repozytorium. Próbowałem się opierać i natknąłem się na tonę pozornie niezwiązanych ze sobą konfliktów, gdy próbowałem zmienić podstawę - kontynuuj. Nie przejmuj się próbami zmiany bazy, użyj narzędzia o nazwie BFG (brew install bfg) na komputerze Mac.
źródło
Jeśli jeszcze nie wypchnąłeś zatwierdzeń, możesz wrócić do poprzedniego zatwierdzenia za pomocą
git reset HEAD^[1,2,3,4...]
Na przykład
Ups, zapomniałem dodać plik2 do pierwszego zatwierdzenia ...
Spowoduje to dodanie pliku2 do pierwszego zatwierdzenia.
źródło
Cóż, to rozwiązanie może wydawać się bardzo głupie, ale może cię uratować w pewnych warunkach.
Mój przyjaciel przypadkowo popełnił przypadkowe popełnienie bardzo dużych plików (cztery automatycznie wygenerowane pliki o wielkości od 3 GB do 5 GB każdy), a następnie dokonał dodatkowych zatwierdzeń kodu, zanim zdał sobie sprawę, że problem
git push
już nie działa!Pliki zostały wymienione,
.gitignore
ale po zmianie nazwy folderu kontenera zostały ujawnione i zatwierdzone! A teraz było jeszcze kilka zmian w kodzie, alepush
działało to wiecznie (próba przesłania GB danych!) I ostatecznie zakończyło się niepowodzeniem z powodu ograniczeń rozmiaru pliku Github .Problem z interaktywnym rebase'em lub czymkolwiek podobnym polegał na tym, że poradziliby sobie z przeszukiwaniem tych ogromnych plików i zajęłoby im wieczność. Niemniej jednak, po spędzeniu prawie godziny w interfejsie CLI, nie byliśmy pewni, czy pliki (i delty) zostały faktycznie usunięte z historii, czy po prostu nie zostały uwzględnione w bieżących zatwierdzeniach. Push też nie działał, a mój przyjaciel naprawdę utknął.
Tak więc rozwiązaniem, które wymyśliłem, było:
~/Project-old
.~/Project
).cp -r
pliki z~/Project-old
folderu do~/Project
.mv
edytowane i dołączone.gitignore
..git
folderu w ostatnio sklonowanym~/Project
przez stary. Tam właśnie żyją dzienniki problematycznej historii!push
edytować.Największym problemem z tym rozwiązaniem jest to, że zajmuje się ręcznym kopiowaniem niektórych plików, a także scala wszystkie ostatnie zatwierdzenia w jeden (oczywiście z nowym hashem zatwierdzającym). B
Dużymi zaletami jest to, że jest bardzo wyraźny na każdym kroku, działa świetnie w przypadku dużych plików (a także wrażliwych) i nie pozostawia po sobie żadnych śladów w historii!
źródło