git rebase -i <any earlier commit>. Spowoduje to wyświetlenie listy zatwierdzeń w skonfigurowanym edytorze tekstu.
Znajdź zatwierdzenie, po którym chcesz wstawić (załóżmy, że jest a1b2c3d). W edytorze dla tego wiersza zmień pickna edit.
Rozpocznij rebase, zamykając edytor tekstu (zapisz zmiany). To pozostawia cię w wierszu polecenia z zatwierdzeniem, które wybrałeś wcześniej ( a1b2c3d), tak jakby zostało właśnie zatwierdzone .
Wprowadź zmiany i git commit( NIE zmieniaj, w przeciwieństwie do większości edit). Tworzy to nowe zatwierdzenie po tym, które wybrałeś.
git rebase --continue. Powoduje to odtworzenie kolejnych zatwierdzeń, pozostawiając nowe zatwierdzenie wstawione we właściwym miejscu.
Uważaj, bo to odmieni historię i złamie każdego, kto spróbuje pociągnąć.
Dodało to nowe zatwierdzenie po zatwierdzeniu, czyli po tym, do którego ponownie bazowałem (także ostatnim zatwierdzeniu), zamiast zaraz po tym, na którym ponownie bazowałem. Rezultat był taki sam, jak gdybym po prostu dokonał nowego zatwierdzenia na końcu ze zmianami, które chciałem wstawić. Moja historia stała się A -- B -- C -- Dpożądana A -- D -- B -- C.
XedinUnknown
2
@XedinUnknown: Wtedy nie użyłeś poprawnie Rebase.
SLaks
3
Teraz Dmoże być zatwierdzeniem wszędzie. Załóżmy, że mamy A - B - Ci mamy pewne zmiany, Dktórych nie ma nawet w tej gałęzi. Znamy jego SHA, jednak możemy to zrobić git rebase -i HEAD~3. Teraz między wierszami Ai Bpickwstawiamy nowąpick linię, która mówi pick SHA, podając skrót żądanego D. Nie musi to być pełny hash, tylko skrócony. git rebase -ipo prostu wiśnia wybiera wszystkie zatwierdzenia wymienione w pickwierszach w buforze; nie muszą to być oryginalne, wymienione dla Ciebie.
Kaz
1
@Kaz To wygląda na inną, prawidłową odpowiedź.
BartoszKP
3
Jeszcze łatwiej, możesz użyć breaksłowa kluczowego w edytorze w osobnym wierszu między dwoma zatwierdzeniami (lub w pierwszym wierszu, aby wstawić zatwierdzenie przed określonym zatwierdzeniem).
SimonT
30
Okazuje się być całkiem proste, odpowiedź znaleźć tutaj . Załóżmy, że jesteś na gałęzi branch. Wykonaj następujące kroki:
utwórz tymczasową gałąź z zatwierdzenia po tym, jak chcesz wstawić nowy zatwierdzenie (w tym przypadku zatwierdzenie A):
git checkout -b temp A
wprowadź zmiany i zatwierdź je, tworząc zatwierdzenie, nazwijmy to N:
git commit -a -m "Message"
(lub git addnastępuje git commit)
przebuduj zatwierdzenia, które chcesz mieć po nowym zatwierdzeniu (w tym przypadku zatwierdzeniach Bi C) na nowe zatwierdzenie:
Nie mogłem zastosować się do zaakceptowanej przez SLaków odpowiedzi, ale to zadziałało. Po uzyskaniu żądanej historii git push --forcezmian musiałem zmienić zdalne repozytorium.
znak ucieczki
1
Podczas korzystania z rebase z opcją -Xtheirs automatycznie rozwiązuje konflikty, więc git rebase temp branch -Xtheirs. Pomocna odpowiedź na wstrzyknięcie w skrypcie!
David C
Dla noobów takich jak ja chciałbym to dodać później git rebase temp branch, ale wcześniej git branch -d tempwszystko, co musisz zrobić, to naprawić i scalić konflikty i problemy git rebase --continue, tj. Nie trzeba niczego zatwierdzać itp.
Pugsley
19
Jeszcze łatwiejsze rozwiązanie:
Utwórz nowe zatwierdzenie na końcu, D. Teraz masz:
A -- B -- C -- D
Następnie uruchomić:
$ git rebase -i hash-of-A
Git otworzy twój edytor i będzie wyglądał tak:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
Po prostu przenieś D na górę w ten sposób, a następnie zapisz i zakończ
Niezły pomysł, jednak wprowadzenie D na C może być trudne, jeśli zamierzasz wprowadzić te zmiany. do A.
BartoszKP
Mam sytuację, w której mam 3 zmiany, które chcę razem zmienić, i zatwierdzenie w środku, które jest niezwiązane. To bardzo fajne, że można po prostu przesunąć to zatwierdzenie wcześniej lub później w dół wiersza zatwierdzeń.
unflores
13
Zakładając, że historia zatwierdzeń to preA -- A -- B -- C, jeśli chcesz wstawić zatwierdzenie między Ai B, kroki są następujące:
git rebase -i hash-of-preA
Git otworzy twój edytor. Treść może wyglądać następująco:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
Zmień pierwszą pickna edit:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
Zapisz i wyjdź.
Zmodyfikuj swój kod, a następnie git add . && git commit -m "I"
git rebase --continue
Teraz twoja historia zatwierdzania Git to preA -- A -- I -- B -- C
Jeśli napotkasz konflikt, Git zatrzyma się na tym zatwierdzeniu. Możesz użyć git diffdo zlokalizowania znaczników konfliktów i ich rozwiązania. Po rozwiązaniu wszystkich konfliktów musisz użyć, git add <filename>aby powiedzieć Gitowi, że konflikt został rozwiązany, a następnie ponownie uruchomić git rebase --continue.
Jeśli chcesz cofnąć zmianę bazy, użyj git rebase --abort.
Oto strategia, która pozwala uniknąć robienia „hackowania edycji” podczas rebase, co jest widoczne w innych odpowiedziach, które przeczytałem.
Używając git rebase -i, otrzymujesz listę zatwierdzeń od tego zatwierdzenia. Po prostu dodaj „przerwę” na początku pliku, co spowoduje, że rebase przestanie działać w tym momencie.
Po uruchomieniu git rebasezatrzyma się teraz w miejscu „przerwy”. Możesz teraz edytować swoje pliki i normalnie tworzyć zmiany. Następnie możesz kontynuować rebase za pomocą git rebase --continue. Może to powodować konflikty, które będziesz musiał naprawić. Jeśli się zgubisz, nie zapomnij, że zawsze możesz przerwać używanie git rebase --abort.
Tę strategię można uogólnić, aby wstawić zatwierdzenie w dowolnym miejscu, po prostu wstaw „przerwę” w miejscu, w którym chcesz wstawić zatwierdzenie.
Po przepisaniu historii nie zapomnij o tym git push -f. Obowiązują zwykłe ostrzeżenia, że inne osoby pobierają Twój oddział.
Przepraszamy, ale mam problem ze zrozumieniem, jak to się ma do „unikania ponownej bazy”. Ci są wyświetlane rebasetutaj. Nie ma dużej różnicy, czy utworzysz zatwierdzenie podczas rebase, czy wcześniej.
BartoszKP
Ups, miałem na myśli unikanie "hackowania edycji" podczas rebase, myślę, że źle to sformułowałem.
axerologementy
Dobrze. Moja odpowiedź również nie korzysta z funkcji „edytuj” w rebase. Jest to jednak kolejne ważne podejście - dzięki! :-)
BartoszKP
To zdecydowanie najlepsze rozwiązanie!
Theodore R. Smith
6
Wiele dobrych odpowiedzi już tutaj. Chciałem tylko dodać rozwiązanie „bez rebase” w 4 prostych krokach.
Podsumowanie
git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
Wyjaśnienie
(Uwaga: jedną z zalet tego rozwiązania jest to, że nie dotykasz swojej gałęzi aż do ostatniego kroku, kiedy jesteś w 100% pewien, że jesteś w porządku z końcowym wynikiem, więc masz bardzo przydatny krok „wstępnego potwierdzenia” pozwalające na testowanie AB .)
Stan początkowy (założyłem masternazwę twojego oddziału)
A -- B -- C <<< master <<< HEAD
1) Zacznij od wskazania HEAD we właściwym miejscu
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(Opcjonalnie tutaj, zamiast odłączać HEAD, moglibyśmy utworzyć tymczasową gałąź, z git checkout -b temp Aktórą musielibyśmy usunąć na końcu procesu. Oba warianty działają, rób tak, jak wolisz, ponieważ wszystko inne pozostaje takie samo)
2) Utwórz nowe zatwierdzenie D do wstawienia
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) Następnie przynieś kopie ostatnich brakujących zatwierdzeń B i C (byłaby ta sama linia, gdyby było więcej zatwierdzeń)
git cherry-pick A..C
# (if any, resolve any potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(w razie potrzeby wygodne badanie AB)
Nadszedł czas, aby sprawdzić swój kod, przetestować wszystko, co powinno zostać przetestowane, a także porównać / porównać / sprawdzić, co masz i co otrzymasz po operacjach.
4) W zależności od wyników testów pomiędzy Ci C', albo jest OK, albo jest KO.
(ALBO) 4-OK) Na koniec przesuń ref zmaster
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(LUB) 4-KO) Po prostu zostaw masterbez zmian
Jeśli utworzyłeś tymczasową gałąź, po prostu usuń ją za pomocą git branch -d <name>, ale jeśli wybrałeś odłączoną trasę HEAD, w tym momencie nie jest wymagana żadna akcja, nowe zatwierdzenia będą kwalifikować się do czyszczenia pamięci zaraz po ponownym podłączeniu HEADzgit checkout master
W obu tych przypadkach (OK lub KO), w tym momencie po prostu sprawdź masterponownie, aby ponownie podłączyć HEAD.
Odpowiedzi:
To jeszcze łatwiejsze niż w odpowiedzi OP.
git rebase -i <any earlier commit>
. Spowoduje to wyświetlenie listy zatwierdzeń w skonfigurowanym edytorze tekstu.a1b2c3d
). W edytorze dla tego wiersza zmieńpick
naedit
.a1b2c3d
), tak jakby zostało właśnie zatwierdzone .git commit
( NIE zmieniaj, w przeciwieństwie do większościedit
). Tworzy to nowe zatwierdzenie po tym, które wybrałeś.git rebase --continue
. Powoduje to odtworzenie kolejnych zatwierdzeń, pozostawiając nowe zatwierdzenie wstawione we właściwym miejscu.Uważaj, bo to odmieni historię i złamie każdego, kto spróbuje pociągnąć.
źródło
A -- B -- C -- D
pożądanaA -- D -- B -- C
.D
może być zatwierdzeniem wszędzie. Załóżmy, że mamyA - B - C
i mamy pewne zmiany,D
których nie ma nawet w tej gałęzi. Znamy jego SHA, jednak możemy to zrobićgit rebase -i HEAD~3
. Teraz między wierszamiA
iB
pick
wstawiamy nowąpick
linię, która mówipick SHA
, podając skrót żądanegoD
. Nie musi to być pełny hash, tylko skrócony.git rebase -i
po prostu wiśnia wybiera wszystkie zatwierdzenia wymienione wpick
wierszach w buforze; nie muszą to być oryginalne, wymienione dla Ciebie.break
słowa kluczowego w edytorze w osobnym wierszu między dwoma zatwierdzeniami (lub w pierwszym wierszu, aby wstawić zatwierdzenie przed określonym zatwierdzeniem).Okazuje się być całkiem proste, odpowiedź znaleźć tutaj . Załóżmy, że jesteś na gałęzi
branch
. Wykonaj następujące kroki:utwórz tymczasową gałąź z zatwierdzenia po tym, jak chcesz wstawić nowy zatwierdzenie (w tym przypadku zatwierdzenie
A
):wprowadź zmiany i zatwierdź je, tworząc zatwierdzenie, nazwijmy to
N
:(lub
git add
następujegit commit
)przebuduj zatwierdzenia, które chcesz mieć po nowym zatwierdzeniu (w tym przypadku zatwierdzeniach
B
iC
) na nowe zatwierdzenie:(być może trzeba użyć
-p
, aby zachować scala, gdyby nie było w ogóle - dzięki a już istniejącym komentarzu przez Ciekawy )usuń tymczasową gałąź:
Po tym historia wygląda następująco:
Jest oczywiście możliwe, że podczas przebudowy pojawią się pewne konflikty.
Jeśli twoja gałąź nie jest lokalna - wprowadzi to przepisywanie historii, więc może spowodować poważne problemy.
źródło
git push --force
zmian musiałem zmienić zdalne repozytorium.git rebase temp branch -Xtheirs
. Pomocna odpowiedź na wstrzyknięcie w skrypcie!git rebase temp branch
, ale wcześniejgit branch -d temp
wszystko, co musisz zrobić, to naprawić i scalić konflikty i problemygit rebase --continue
, tj. Nie trzeba niczego zatwierdzać itp.Jeszcze łatwiejsze rozwiązanie:
Utwórz nowe zatwierdzenie na końcu, D. Teraz masz:
Następnie uruchomić:
Git otworzy twój edytor i będzie wyglądał tak:
Po prostu przenieś D na górę w ten sposób, a następnie zapisz i zakończ
Teraz będziesz mieć:
źródło
Zakładając, że historia zatwierdzeń to
preA -- A -- B -- C
, jeśli chcesz wstawić zatwierdzenie międzyA
iB
, kroki są następujące:git rebase -i hash-of-preA
Git otworzy twój edytor. Treść może wyglądać następująco:
Zmień pierwszą
pick
naedit
:Zapisz i wyjdź.
Zmodyfikuj swój kod, a następnie
git add . && git commit -m "I"
git rebase --continue
Teraz twoja historia zatwierdzania Git to
preA -- A -- I -- B -- C
Jeśli napotkasz konflikt, Git zatrzyma się na tym zatwierdzeniu. Możesz użyć
git diff
do zlokalizowania znaczników konfliktów i ich rozwiązania. Po rozwiązaniu wszystkich konfliktów musisz użyć,git add <filename>
aby powiedzieć Gitowi, że konflikt został rozwiązany, a następnie ponownie uruchomićgit rebase --continue
.Jeśli chcesz cofnąć zmianę bazy, użyj
git rebase --abort
.źródło
Oto strategia, która pozwala uniknąć robienia „hackowania edycji” podczas rebase, co jest widoczne w innych odpowiedziach, które przeczytałem.
Używając
git rebase -i
, otrzymujesz listę zatwierdzeń od tego zatwierdzenia. Po prostu dodaj „przerwę” na początku pliku, co spowoduje, że rebase przestanie działać w tym momencie.Po uruchomieniu
git rebase
zatrzyma się teraz w miejscu „przerwy”. Możesz teraz edytować swoje pliki i normalnie tworzyć zmiany. Następnie możesz kontynuować rebase za pomocągit rebase --continue
. Może to powodować konflikty, które będziesz musiał naprawić. Jeśli się zgubisz, nie zapomnij, że zawsze możesz przerwać używaniegit rebase --abort
.Tę strategię można uogólnić, aby wstawić zatwierdzenie w dowolnym miejscu, po prostu wstaw „przerwę” w miejscu, w którym chcesz wstawić zatwierdzenie.
Po przepisaniu historii nie zapomnij o tym
git push -f
. Obowiązują zwykłe ostrzeżenia, że inne osoby pobierają Twój oddział.źródło
rebase
tutaj. Nie ma dużej różnicy, czy utworzysz zatwierdzenie podczas rebase, czy wcześniej.Wiele dobrych odpowiedzi już tutaj. Chciałem tylko dodać rozwiązanie „bez rebase” w 4 prostych krokach.
Podsumowanie
Wyjaśnienie
(Uwaga: jedną z zalet tego rozwiązania jest to, że nie dotykasz swojej gałęzi aż do ostatniego kroku, kiedy jesteś w 100% pewien, że jesteś w porządku z końcowym wynikiem, więc masz bardzo przydatny krok „wstępnego potwierdzenia” pozwalające na testowanie AB .)
Stan początkowy (założyłem
master
nazwę twojego oddziału)1) Zacznij od wskazania HEAD we właściwym miejscu
(Opcjonalnie tutaj, zamiast odłączać HEAD, moglibyśmy utworzyć tymczasową gałąź, z
git checkout -b temp A
którą musielibyśmy usunąć na końcu procesu. Oba warianty działają, rób tak, jak wolisz, ponieważ wszystko inne pozostaje takie samo)2) Utwórz nowe zatwierdzenie D do wstawienia
3) Następnie przynieś kopie ostatnich brakujących zatwierdzeń B i C (byłaby ta sama linia, gdyby było więcej zatwierdzeń)
(w razie potrzeby wygodne badanie AB)
Nadszedł czas, aby sprawdzić swój kod, przetestować wszystko, co powinno zostać przetestowane, a także porównać / porównać / sprawdzić, co masz i co otrzymasz po operacjach.
4) W zależności od wyników testów pomiędzy
C
iC'
, albo jest OK, albo jest KO.(ALBO) 4-OK) Na koniec przesuń ref z
master
(LUB) 4-KO) Po prostu zostaw
master
bez zmianJeśli utworzyłeś tymczasową gałąź, po prostu usuń ją za pomocą
git branch -d <name>
, ale jeśli wybrałeś odłączoną trasę HEAD, w tym momencie nie jest wymagana żadna akcja, nowe zatwierdzenia będą kwalifikować się do czyszczenia pamięci zaraz po ponownym podłączeniuHEAD
zgit checkout master
W obu tych przypadkach (OK lub KO), w tym momencie po prostu sprawdź
master
ponownie, aby ponownie podłączyćHEAD
.źródło