Chciałbym przenieść kilka ostatnich zatwierdzeń, które zobowiązałem się opanować do nowego oddziału i zabrać wzorca z powrotem, zanim te zatwierdzenia zostaną wykonane. Niestety mój Git-fu nie jest jeszcze wystarczająco silny, jakaś pomoc?
Tj. Jak mogę z tego wyjść
master A - B - C - D - E
do tego?
newbranch C - D - E
/
master A - B
git
git-branch
branching-and-merging
Mark A. Nicolosi
źródło
źródło
Odpowiedzi:
Przeprowadzka do istniejącego oddziału
Jeśli chcesz przenieść swoje commity do istniejącego oddziału , będzie to wyglądać następująco:
Ta
--keep
opcja zachowuje wszelkie niezatwierdzone zmiany, które możesz mieć w niepowiązanych plikach, lub przerywa, jeśli zmiany te musiałyby zostać zastąpione - podobnie jak togit checkout
robi. Jeśli zostanie przerwane,git stash
zmiany i spróbuj ponownie lub użyj,--hard
aby je utracić (nawet z plików, które nie zmieniły się między zatwierdzeniami!)Przeprowadzka do nowego oddziału
Ta metoda działa, tworząc nową gałąź za pomocą pierwszego polecenia (
git branch newbranch
), ale nie przełączając się na nią. Następnie wycofujemy bieżącą gałąź (master) i przełączamy na nową gałąź, aby kontynuować pracę.Ale upewnij się, ile cofnięć. Alternatywnie, zamiast
HEAD~3
, możesz po prostu podać hash zatwierdzenia (lub odnośnik podobnyorigin/master
), do którego chcesz wrócić, np .:OSTRZEŻENIE: W przypadku wersji Git 2.0 i nowszych, jeśli później
git rebase
nowa gałąź w gałęzi oryginalnej (master
), może być potrzebna wyraźna--no-fork-point
opcja podczas bazy, aby uniknąć utraty zatwierdzeń przeniesionych z gałęzi głównej. Pobranch.autosetuprebase always
ustawieniu jest to bardziej prawdopodobne. Szczegółowe informacje można znaleźć w odpowiedzi Johna Mellora .źródło
Dla tych, którzy zastanawiają się, dlaczego to działa (tak jak na początku byłem):
Chcesz wrócić do C i przenieść D i E do nowej gałęzi. Oto jak to wygląda na początku:
Po
git branch newBranch
:Po
git reset --hard HEAD~2
:Ponieważ gałąź jest tylko wskaźnikiem, master wskazał na ostatnie zatwierdzenie. Kiedy tworzysz newBranch , po prostu tworzysz nowy wskaźnik do ostatniego zatwierdzenia. Następnie za pomocą
git reset
przesunąłeś główny wskaźnik z powrotem o dwa zatwierdzenia. Ale ponieważ nie przeniosłeś newBranch , nadal wskazuje na zatwierdzenie, które pierwotnie zrobił.źródło
git push origin master --force
aby zmiana pojawiła się w głównym repozytorium.git rebase
, 3 commity zostaną po cichu odrzuconenewbranch
. Zobacz moją odpowiedź, aby uzyskać szczegółowe informacje i bezpieczniejsze alternatywy.origin/master
nie ma go na powyższym schemacie. Gdybyś naciskał na,origin/master
a następnie wprowadził powyższe zmiany, na pewno wszystko byłoby śmieszne. Ale to jest problem typu „Doktorze, boli mnie, kiedy to robię”. I to nie wchodzi w zakres tego, co zadało pierwotne pytanie. Sugeruję, abyś napisał własne pytanie, aby zbadać swój scenariusz, zamiast porywać go.git branch -t newbranch
”. Wróć i przeczytaj odpowiedzi ponownie. Nikt tego nie sugerował.newbranch
oprzeć się na swoim istniejącymmaster
oddziale lokalnym . Po wykonaniu zaakceptowanej odpowiedzi, gdy użytkownik pobiera około uruchomieniemgit rebase
wnewbranch
git przypomni im, że zapomniał ustawić upstream oddziału, więc będą działaćgit branch --set-upstream-to=master
wtedygit rebase
i mają ten sam problem. Mogą równie dobrze wykorzystaćgit branch -t newbranch
w pierwszej kolejności.Ogólnie...
Metoda ujawniona przez sykora jest w tym przypadku najlepszą opcją. Ale czasem nie jest najłatwiejszy i nie jest to ogólna metoda. Do ogólnej metody użyj git cherry-pick :
Aby osiągnąć to, czego chce OP, jest to dwuetapowy proces:
Krok 1 - zanotuj, które zatwierdzenia od mistrza chcesz na
newbranch
Wykonać
Zwróć uwagę na skróty (powiedzmy 3) zatwierdzeń, które chcesz
newbranch
. Tutaj użyję:C zatwierdzenia:
9aa1233
D zatwierdzenia:
453ac3d
E zatwierdzenia:
612ecb3
Krok 2 - Włóż je do
newbranch
LUB (w Git 1.7.2+ użyj zakresów)
git cherry-pick stosuje te trzy zmiany do newbranch.
źródło
Jeszcze inny sposób, aby to zrobić, używając tylko 2 poleceń. Utrzymuje również bieżące drzewo robocze nietknięte.
Stara wersja - zanim się dowiedziałam
git branch -f
Będąc w stanie
push
na.
to miły podstęp wiedzieć.źródło
git branch -f
tu różni ?.
jest obecnym dyrektorem. git może przekazywać do ZDALNYCH adresów URL lub adresów URL GIT.path to local directory
obsługiwana jest składnia adresów URL Git. Zobacz sekcję GIT URLS wgit help clone
.Większość poprzednich odpowiedzi jest niebezpiecznie błędna!
Nie rób tego:
Gdy następnym razem uruchomisz
git rebase
(lubgit pull --rebase
) te 3 zatwierdzenia zostaną po cichu odrzuconenewbranch
! (patrz wyjaśnienie poniżej)Zamiast tego zrób to:
--keep
jest jak--hard
, ale bezpieczniejsze, bo zawiedzie, zamiast odrzucać niezaangażowane zmiany).newbranch
.newbranch
. Skoro jesteśmy już nie odwołuje się oddział, to robi to za pomocą git za reflog :HEAD@{2}
jest popełnić, żeHEAD
odnosi się do 2 operacje temu, czyli zanim 1. wyrejestrowanynewbranch
i 2. używanegit reset
aby odrzucić 3 zobowiązuje.Ostrzeżenie: reflog jest domyślnie włączony, ale jeśli go ręcznie wyłączyłeś (np. Używając „gołego” repozytorium git), nie będziesz mógł odzyskać 3 zatwierdzeń po uruchomieniu
git reset --keep HEAD~3
.Alternatywą, która nie polega na logowaniu jest:
(jeśli wolisz, możesz pisać
@{-1}
- gałąź wcześniej wypisana - zamiastoldbranch
).Wyjaśnienie techniczne
Po co
git rebase
odrzucać 3 zatwierdzenia po pierwszym przykładzie? To dlatego, żegit rebase
bez argumentów włącza--fork-point
domyślnie opcję, która używa lokalnego reflogu, aby spróbować być odpornym na wymuszanie wypychania gałęzi upstream.Załóżmy, że rozgałęziłeś początek / wzorzec, gdy zawierał zatwierdzenia M1, M2, M3, a następnie sam dokonałeś trzech zatwierdzeń:
ale potem ktoś przepisuje historię, zmuszając źródło / master do usunięcia M2:
Korzystając z lokalnego dziennika,
git rebase
możesz zobaczyć, że rozwidliłeś się z wcześniejszej inkarnacji gałęzi origin / master, a zatem, że zatwierdzenia M2 i M3 tak naprawdę nie są częścią twojej gałęzi tematów. Stąd rozsądnie zakłada się, że skoro M2 zostało usunięte z gałęzi upstream, nie będzie już potrzebne w gałęzi tematu, gdy gałąź tematu zostanie ponownie wydana:Takie zachowanie ma sens i ogólnie jest właściwą rzeczą do zrobienia podczas bazowania.
Dlatego przyczyną niepowodzenia następujących poleceń:
to dlatego, że pozostawiają rejestr w złym stanie. Git widzi,
newbranch
że rozwidlił gałąź odgałęzienia w wersji, która zawiera 3 zatwierdzenia, a następniereset --hard
przepisuje historię pobierania w górę, aby usunąć zatwierdzenia, a więc następnym razem, gdygit rebase
go uruchomisz , odrzuca je jak każde inne zatwierdzenie, które zostało usunięte z pobierania.Ale w tym konkretnym przypadku chcemy, aby te 3 zatwierdzenia były traktowane jako część gałęzi tematu. Aby to osiągnąć, musimy oddzielić się od poprzedniej wersji, która nie obejmuje 3 zatwierdzeń. To właśnie robią moje sugerowane rozwiązania, dlatego oba pozostawiają rejestr w prawidłowym stanie.
Aby uzyskać więcej informacji, zobacz definicję
--fork-point
w dokumentacji git rebase i git merge-base .źródło
master
. Więc nie, nie są niebezpiecznie w błędzie.-t
którego się odnosisz,git branch
dzieje się niejawnie, jeśligit config --global branch.autosetuprebase always
ustawiłeś. Nawet jeśli nie, wyjaśniłem już , że ten sam problem występuje, jeśli skonfigurujesz śledzenie po wykonaniu tych poleceń, co OP prawdopodobnie zamierza zrobić, biorąc pod uwagę ich pytanie.Znacznie prostsze rozwiązanie za pomocą git stash
Oto o wiele prostsze rozwiązanie dla zatwierdzeń do niewłaściwej gałęzi. Począwszy od gałęzi,
master
która ma trzy błędne zatwierdzenia:Kiedy tego użyć?
master
Co to robi, według numeru linii
master
, ale pozostawia wszystkie działające pliki nietkniętemaster
drzewo robocze jest dokładnie równe stanowi HEAD ~ 3newbranch
Możesz teraz używać
git add
igit commit
jak zwykle. Wszystkie nowe zmiany zostaną dodane donewbranch
.Czego to nie robi
Cele
OP stwierdził, że celem było „przywrócenie mistrza przed dokonaniem tych zobowiązań” bez utraty zmian, a to rozwiązanie to robi.
Robię to przynajmniej raz w tygodniu, kiedy przypadkowo dokonuję nowych zobowiązań
master
zamiastdevelop
. Zwykle mam tylko jedno zatwierdzenie wycofania, w którym to przypadku korzystamgit reset HEAD^
w linii 1 jest prostszym sposobem na wycofanie tylko jednego zatwierdzenia.Nie rób tego, jeśli wprowadziłeś zmiany mistrza w górę
Ktoś inny mógł wyciągnąć te zmiany. Jeśli przepisujesz tylko swojego lokalnego mistrza, nie ma to wpływu, gdy zostanie on wypchnięty, ale przekazanie przepisanej historii współpracownikom może powodować problemy.
źródło
git add
igit commit
polecenia, więc wystarczyło mi trafić w strzałkę i wejść kilka razy i bum! Wszystko wróciło, ale teraz na właściwej gałęzi.Nie „przenosi” ich w sensie technicznym, ale ma ten sam efekt:
źródło
rebase
tego samego?rebase
na odłączonym oddziale w powyższym scenariuszu.Aby to zrobić bez przepisywania historii (tj. Jeśli już wypchnąłeś zatwierdzenia):
Obie gałęzie można następnie pchać bez użycia siły!
źródło
Miałem właśnie taką sytuację:
Wykonałem:
Spodziewałem się, że zatwierdzę, będę Głową, ale zatwierdzę L, czy to teraz ...
Aby mieć pewność, że wylądujesz we właściwym miejscu w historii, łatwiej jest pracować z hashem zatwierdzenia
źródło
Jak mogę z tego wyjść?
do tego?
Z dwoma poleceniami
dający
i
dający
źródło
Jeśli chcesz tylko przenieść wszystkie nieprzypisane zmiany do nowej gałęzi , musisz po prostu:
tworzyć się nowy oddział z bieżącej:
git branch new-branch-name
pchnij swój nowy oddział :
git push origin new-branch-name
przywrócić swoje stare (aktualne) oddział do ostatniej pchania / stan stabilny
git reset --hard origin/old-branch-name
Niektóre osoby mają też inne
upstreams
, niżorigin
powinny, powinny stosować odpowiednieupstream
źródło
1) Utwórz nową gałąź, która przeniesie wszystkie twoje zmiany do nowej_gałęzi.
2) Następnie wróć do starej gałęzi.
3) Czy git rebase
4) Następnie otwarty edytor zawiera 3 ostatnie informacje o zatwierdzeniu.
5) Zmień
pick
nadrop
wszystkie te 3 zmiany. Następnie zapisz i zamknij edytor.6) Teraz ostatnie 3 zatwierdzenia są usuwane z bieżącej gałęzi (
master
). Teraz wciśnij gałąź mocno, ze+
znakiem przed nazwą gałęzi.źródło
Możesz to zrobić, to tylko 3 prosty krok, którego użyłem.
1) Utwórz nowy oddział, w którym chcesz zatwierdzić ostatnią aktualizację.
git branch <branch name>
2) Znajdź identyfikator ostatniego zatwierdzenia dla zatwierdzenia w nowym oddziale.
git log
3) Skopiuj notatkę identyfikatora zatwierdzenia, że lista najnowszych zatwierdzeń ma miejsce na górze. więc możesz znaleźć swoje zatwierdzenie. znajdziesz to również za pośrednictwem wiadomości.
git cherry-pick d34bcef232f6c...
możesz także podać numer identyfikacyjny zatwierdzenia.
git cherry-pick d34bcef...86d2aec
Teraz twoja praca skończona. Jeśli wybierzesz prawidłowy identyfikator i poprawną gałąź, odniesiesz sukces. Zanim to zrobisz, bądź ostrożny. w przeciwnym razie może wystąpić inny problem.
Teraz możesz wcisnąć kod
git push
źródło
Inny sposób to zrobić:
[1] Zmień nazwę
master
gałęzi nanewbranch
(zakładając, że jesteś wmaster
gałęzi):[2] Utwórz
master
gałąź z zatwierdzenia, które chcesz:źródło