przenoszenie zatwierdzonych (ale nie wypychanych) zmian do nowej gałęzi po ściągnięciu

459

Zrobiłem sporo pracy („Twój oddział wyprzedza„ origin / master ”o 37 zatwierdzeń.)), Który naprawdę powinien był przejść do własnego oddziału, a nie do master. Te zatwierdzenia istnieją tylko na mojej lokalnej maszynie i nie zostały zepchnięte na origin, ale sytuacja jest nieco skomplikowana w tym sensie, że inni deweloperzy naciskali na origin/mastermnie i wyciągnąłem te zmiany.

Jak z mocą wsteczną przenieść moje 37 lokalnych zobowiązań do nowego oddziału? Na podstawie dokumentów wydaje się, że git rebase --onto my-new-branch masterlub ...origin/masterpowinien to zrobić, ale oba dają mi błąd „fatalny: Potrzebowałem jednej wersji”. man git-rebasenie mówi nic o zapewnieniu wersji, rebasea jej przykłady tego nie robią, więc nie mam pojęcia, jak rozwiązać ten błąd.

(Zauważ, że nie jest to kopia Przenieś istniejącą, niezaangażowaną pracę do nowej gałęzi w Git lub Jak scalić moje lokalne niezatwierdzone zmiany w inną gałąź Git? Ponieważ te pytania dotyczą niezatwierdzonych zmian w lokalnym drzewie roboczym, a nie zmian, które mają został popełniony lokalnie.)

Dave Sherohman
źródło
Sprawdź to rozwiązanie . Wydaje się być łatwe i czyste.
Tony
Sprawdź to rozwiązanie . Wydaje się być łatwe i czyste.
Tony

Odpowiedzi:

517

Powinno to być w porządku, ponieważ jeszcze nie wypchnąłeś swoich zobowiązań, i możesz później przepisać historię swojego oddziału origin/master. Najpierw uruchomiłbym, git fetch originaby upewnić się, że origin/masterjest aktualny. Zakładając, że jesteś obecnie włączony master, powinieneś być w stanie:

git rebase origin/master

... który będzie odtworzyć wszystkich zatwierdzeń, które nie są w origin/masterna origin/master. Domyślna akcja rebase polega na ignorowaniu zatwierdzeń scalania (np. Tych, które git pullprawdopodobnie wprowadziłeś) i po prostu spróbuje zastosować łatkę wprowadzoną przez każde z twoich zatwierdzeń origin/master. (Być może będziesz musiał rozwiązać niektóre konflikty po drodze.) Następnie możesz utworzyć nowy oddział na podstawie wyniku:

git branch new-work

... a następnie zresetuj masterplecy do origin/master:

# Use with care - make sure "git status" is clean and you're still on master:
git reset --hard origin/master

Kiedy robię tego rodzaju manipulowanie gałęziami za pomocą git branch, git resetitp., Często przydaje mi się przeglądanie wykresu zatwierdzeń za pomocą gitk --alllub podobnego narzędzia, tylko po to, aby sprawdzić, czy rozumiem, gdzie wskazują wszystkie różne referencje.

Alternatywnie, mógłbyś właśnie utworzyć gałąź tematów w oparciu o to, gdzie jest twój master w pierwszej kolejności ( git branch new-work-including-merges), a następnie zresetować masterjak powyżej. Ponieważ jednak gałąź tematu będzie zawierać scalenia, origin/mastera zmiany nie zostały jeszcze wprowadzone, sugeruję wykonanie zmiany bazy, aby historia była uporządkowana. (Ponadto, gdy w końcu scalisz gałąź tematu z powrotem do głównego, zmiany będą bardziej oczywiste).

Mark Longair
źródło
8
@Olie: Nie, odpowiedź jest prawidłowa przy założeniach zawartych w pytaniu i tych, które przedstawiłem na początku odpowiedzi. Zatwierdzenia, które powinny znajdować się w oddzielnym nowym oddziale, już są w master; rebase przepisuje mastergałąź, tak aby nowe zatwierdzenia były liniowo na górze origin/master, a następnie git branch new-worktworzy new-workgałąź wskazującą na wierzchołku master(bieżącej gałęzi) bez przełączania bieżącej gałęzi new-work. Więc teraz new-workzawiera wszystkie nowe zmiany. Następnie reset powoduje przeniesienie bieżącej gałęzi (nadal master) z powrotem do origin/master.
Mark Longair,
1
@Quintesse: Bardzo mi przykro, jeśli straciłeś pracę, ale jestem pewien, że ta odpowiedź jest poprawna w sytuacji opisanej przez pierwotnego pytającego. (Właśnie odpowiedziałem na uwagi Olie, mam nadzieję, że wyjaśnię.) W każdym razie, na wypadek, gdyby to pomogło odzyskać twoją pracę, powinienem powiedzieć, że jeśli twoja praca została popełniona w ciągu ostatnich kilku dni (jedno z założeń w tym pytaniu i odpowiedzi ) powinieneś być w stanie łatwo go odzyskać poprzez dziennik git.
Mark Longair,
5
@Olie: być może lepszy sposób wyjaśnienia: gałęzie w git są jak etykiety wskazujące na konkretne zatwierdzenie; są one automatycznie przenoszone do nowych zatwierdzeń, jeśli utworzysz je w tej gałęzi lub można je przenosić na git resetwiele innych sposobów. git branch new-workJest tylko, że „utworzenie oddziału, wskazując na to popełnić podczas pozostaję na mojego obecnego oddziału (który jest mistrzem w tym przypadku).” Nie ma więc potrzeby posiadania polecenia, które przenosi zatwierdzenia z głównego do nowego oddziału - wystarczy utworzyć nowy oddział, a po zresetowaniu głównego nowy oddział pozostanie tam, gdzie był master
Mark Longair
1
nieco późno na imprezę, ale @Olie, tylko dlatego, że status git, gdy w nowym oddziale nie pokazuje zatwierdzeń przed mistrzem, nie oznacza, że ​​tak naprawdę ich nie ma (zakładając, że dlatego się martwiłeś). Spróbuj popchnąć nowy oddział do źródła: zobaczysz, że zatwierdzenia już istnieją
Félix Gagnon-Grenier
2
@ FélixGagnon-Grenier, nie martw się o „spóźnienie” - zawsze ludzie szukają starych pytań i każde wyjaśnienie pomaga. Dzięki! :)
Olie,
148

Jeśli masz niską liczbę zatwierdzeń i nie obchodzi Cię, czy są one połączone w jeden mega-zatwierdzenie, działa to dobrze i nie jest tak przerażające, jak git rebase:

wycofaj pliki z scen (zamień 1 na # zatwierdzeń)

git reset --soft HEAD~1

utworzyć nowy oddział

git checkout -b NewBranchName

dodaj zmiany

git add -A

dokonać zatwierdzenia

git commit -m "Whatever"
Stachu
źródło
5
Aby wyświetlić łatwy do zrozumienia wykres, użyj git log --all --decorate --oneline --graph.
EliuX
Hej @EliuX - Brakuje mi tutaj trafności. Czy potrafisz rozwinąć?
Stachu
Jest to przydatne do sprawdzenia, czy osiągnąłeś pożądany wynik w tym, co zrobiłeś
EliuX
4
Dziękuję!! to jest bardzo proste rozwiązanie i działało idealnie !!
Chris Sim
90

Utknąłem z tym samym problemem. Znalazłem najłatwiejsze rozwiązanie, którym lubię się dzielić.

1) Utwórz nowy oddział ze swoimi zmianami.

git checkout -b mybranch

2) (Opcjonalnie) Wciśnij nowy kod oddziału na zdalnym serwerze.

git push origin mybranch

3) Kasa z powrotem do oddziału głównego.

git checkout master

4) Zresetuj główny kod oddziału za pomocą zdalnego serwera i usuń zatwierdzenie lokalne.

git reset --hard origin/master
NiRmaL
źródło
10
To naprawdę najłatwiejszy sposób
zimowy
4
Możesz pominąć krok 2. Zakładam, że w czasie od najwyższej odpowiedzi git się zmienił i ta praktyka nie była wcześniej dozwolona.
Sebastian,
To jest najlepsza odpowiedź moim zdaniem.
Macindows,
1
Ta odpowiedź musi zostać przeniesiona na górę. Dziękuję Ci.
amit
27

Jeszcze jeden sposób zakłada, że ​​gałąź 1 - jest gałąź z zatwierdzonymi zmianami gałąź 2 - jest gałąź pożądaną

git fetch && git checkout branch1
git log

wybierz identyfikatory zatwierdzenia, które chcesz przenieść

git fetch && git checkout branch2
git cherry-pick commit_id_first..commit_id_last
git push

Teraz przywróć niepotrzebne zatwierdzenia z początkowej gałęzi

git fetch && git checkout branch1
git reset --soft HEAD~1
Andrij
źródło
5
Cherry-pick jest naprawdę najlepszym poleceniem „kopiuj / przenieś pojedynczy zatwierdzenie”, szczególnie. gdy historia jest bagażem dla twoich celów.
John Neuhaus
To jak dotąd najwygodniejsza odpowiedź na pytanie. Dziękuję za polecenie!
Farah,
czy możesz zaktualizować swój ostatni komentarz, gdzie 1 lub n to liczba niepochodzących zatwierdzeń? To wciąż bardzo dobre rozwiązanie tego pytania.
chAlexey
9

Alternatywnie, zaraz po zatwierdzeniu do niewłaściwej gałęzi, wykonaj następujące kroki:

  1. git log
  2. git diff {previous to last commit} {latest commit} > your_changes.patch
  3. git reset --hard origin/{your current branch}
  4. git checkout -b {new branch}
  5. git apply your_changes.patch

Mogę sobie wyobrazić, że istnieje prostsze podejście do kroków pierwszego i drugiego.

Andreas B.
źródło
6

Co powiesz na:

  1. Oddział z obecnej HEAD.
  2. Upewnij się, że jesteś mistrzem , a nie nowym oddziałem.
  3. git reset powrót do ostatniego zatwierdzenia przed rozpoczęciem wprowadzania zmian.
  4. git pull aby ponownie wyciągnąć tylko zdalne zmiany, które wyrzuciłeś za pomocą resetowania.

Czy może to wybuchnie, gdy spróbujesz ponownie połączyć gałąź?

Tim Keating
źródło
2
Ach, to jest w zasadzie opcja B opisana przez @ Mark-Longair powyżej
Tim Keating
2

Oto o wiele prostszy sposób:

  1. Utwórz nowy oddział

  2. Na swoim nowym oddziale wykonaj git merge master- spowoduje to scalenie zatwierdzonych (nie wypchniętych) zmian do nowego oddziału

  3. Usuń lokalną gałąź główną git branch -D masterUżyj -Dzamiast zamiast, -dponieważ chcesz wymusić usunięcie gałęzi.

  4. Po prostu zrób git fetchna swoim głównym oddziale i zrób git pullna swoim głównym oddziale, aby upewnić się, że masz najnowszy kod zespołów.

Kok
źródło
1

Prostsze podejście, którego użyłem (zakładając, że chcesz przenieść 4 zatwierdzenia):

git format-patch HEAD~4

(Zajrzyj do katalogu, z którego wykonałeś ostatnie polecenie dla 4 .patchplików)

git reset HEAD~4 --hard

git checkout -b tmp/my-new-branch

Następnie:

git apply /path/to/patch.patch

W dowolnej kolejności.

użytkownik1429980
źródło
0
  1. Zamów świeżą kopię swoich źródeł

    git clone ........

  2. Zrób gałąź z pożądanej pozycji

    git checkout {position} git checkout -b {branch-name}

  3. Dodaj zdalne repozytorium

    git remote add shared ../{original sources location}.git

  4. Uzyskaj zdalne źródła

    git fetch shared

  5. Zapłać żądany oddział

    git checkout {branch-name}

  6. Scal źródła

    git merge shared/{original branch from shared repository}

Sergey Kabashnyuk
źródło
0

Dla mnie był to najlepszy sposób:

  1. Sprawdź zmiany i scal konflikty git fetch
  2. Utwórz nowy oddział git branch my-changesi przekaż zdalnie
  3. Zmień upstream na nowo utworzony oddział git master -u upstream-branch remotes/origin/my-changes
  4. Przekaż swoje zobowiązania do nowego oddziału.
  5. Wróć z powrotem do poprzedniego git branch master --set-upstream-to remotes/origin/master
Sebastian
źródło