Rebase pojedyncze zatwierdzenie Git

116

Czy istnieje sposób na przeniesienie pojedynczego zatwierdzenia z gałęzi na inną gałąź?

Mam taką strukturę gałęzi:

-- -- -- -- -- (Master)
            \
              -- -- -- -- -- XX (Feature-branch)

Wszystko, co chcę zrobić, to zmienić bazę ostatniego zatwierdzenia Feature-branchna główny i cofnąć Feature-branchjeden zatwierdzenie.

-- -- -- -- -- XX (Master)
            \
              -- -- -- -- -- (Feature-branch)

W jaki sposób mogę to zrobić?

Kevin Meyer
źródło
3
Jeśli możesz zmienić bazę dowolnej liczby zatwierdzeń, to dlaczego pytasz o zmianę bazy pojedynczego? Gdybym mógł zadawać pytania w SO, zapytałbym, jaka jest różnica między ponownym bazowaniem (pojedynczym zatwierdzeniem) a wybieraniem wiśni.
Val
9
Ponieważ nie wiedziałem, że istnieje selekcja najlepszych wyników, robię „Faff about on branch”, „Get request for fix on different branch”, „fix it”, „Commit to evil branch”, „D'OH!” wystarczy, że zadawanie tego pytania było przydatne.
Kevin Meyer

Odpowiedzi:

116

Możesz wybrać wiśniowy XX do opanowania.

git checkout master
git cherry-pick <commit ID of XX>

I usuń ostatnie zatwierdzenie z gałęzi funkcji za pomocą git reset.

git checkout Feature-branch
git reset --hard HEAD^
tewe
źródło
64
w jaki sposób pytanie konkretnie zwane „git rebase…” może mieć akceptowaną odpowiedź, niż zawiera najlepszy wybór, który jest zupełnie inną koncepcją i czasami sam w sobie jest uważany za nieczysty?
Bondax
1
Nie jestem pewien, czy to ma znaczenie, ale zatwierdzenie, które chciałem zmienić, zawierało kilka plików, które zostały przeniesione i cherry-picksprawiło, że wyglądały tak, jakby zostały usunięte ze starej lokalizacji i utworzone w nowej lokalizacji. Przypuszczam, że rebase by się tym zajął, ale do tej pory przeszedłem na wyższy poziom, więc nie mogę tego przetestować. W każdym razie uważaj, jeśli masz podobną sytuację.
waldyrious
Uwaga: aby wypchnąć zmiany w Feature-branchźródle, musisz to zrobić, git push -f origin Feature-branchponieważ Feature-branchjest teraz uważany za 1 zatwierdzenie za origin/Feature-branch.
jojo
1
Jaka jest praktyczna różnica między tym rozwiązaniem a rozwiązaniem CharlesB ?
Lii
97
git rebase --onto master branch~1 branch 

To mówi: „Zmień bazę zatwierdzeń między ostatnią przed gałęzią a rozgałęzieniem (czyli XX zatwierdzeniem) na końcu gałęzi głównej”

Po tej operacji branchwskazówka jest przenoszona na zatwierdzenie XX, więc chcesz ją ustawić z powrotem za pomocą

git checkout branch
git reset --hard branch@{1}^

Który mówi „zresetuj końcówkę gałęzi do zatwierdzenia przed jej poprzednim stanem”

Więc wiśnia jest prostszym rozwiązaniem ...

Charles B.
źródło
5
Wydaje mi się, że to nie działa, tracę zatwierdzenia przed XX, a gałąź jest przebudowywana na master z pojedynczym zatwierdzeniem, ale nigdy --ontowcześniej nie używałem, więc może robię coś źle. BTW, OP powiedział rebase, ale wygląda na to, że chce zrobić najlepszy wybór.
tewe
1
mój błąd, rebase rzeczywiście przenosi gałąź na master, trzeba ją zresetować
CharlesB
1
Jaka jest praktyczna różnica pomiędzy tym roztworze i jednego przez tewe ?
Lii
1
@Lii, jedyne, co widzę, to to, że używa 3 kroków zamiast 4
CharlesB
52

Właściwie jest to całkiem proste. Rozwiązaniem jest wykonanie interaktywnej rebase i „porzucenie” wszystkich zatwierdzeń, których nie chcesz umieszczać w rebase.

git rebase -i <target_branch>gdzie target_branchjest gałąź, na której chcesz się oprzeć

Następnie edytujesz plik, który jest otwierany i pickwybrane zatwierdzenia i drop(lub dw skrócie) wszystkie zatwierdzenia, których nie chcesz przynosić.

hrdwdmrbl
źródło
6
IMO jest znacznie lepszym rozwiązaniem i faktycznie odpowiada na to pytanie.
GabrielOshiro
Powinno to być przyjęte rozwiązanie, biorąc pod uwagę jego ogólną, intuicyjną i krótką charakterystykę.
Pablo Arias
1

Odpowiedź @Charles jest poprawna. W każdym razie skończyło się na tym, że korzystałem z tego wiele razy, przede wszystkim do zmiany bazy konfiguracji w projekcie

  * a8f9182 (HEAD -> produkcja) konfiguracja produkcyjna
  | * daa18b7 (pre) konfiguracja przedprodukcyjna
  | /  
  | * d365f5f (lokalna) konfiguracja lokalna
  | /  
  * 27d2835 (dev) niesamowita nowa funkcja, która uratuje świat
* | 56d2467 (master) nudny stan sztuki dla projektu
| /

że tworzę dla niego nowe polecenie:

$ cat ~ / bin / git-rebaseshot 
COMMIT = 1 $
DEST = $ {2: -HEAD}
git rebase $ {COMMIT} ^ $ {COMMIT} --onto $ DEST

normalnie chcesz automatycznie uzupełniać nazwy gałęzi dla tego polecenia, więc dodaj to źródło tej funkcji (dodając do .bashrc lub .profile):

_git_rebaseshot () 
{ 
    __gitcomp_nl "$ (__ git_refs)"
}

autouzupełnianie git wyszuka go

możesz użyć tego polecenia w następujący sposób:

# rebase config on prepro on actual HEAD
$ git rebaseshot prepro 
# rebase config on local onto dev
$ git rebaseshot local dev
# rebase production config on master
$ git rebaseshot pro master

Kiedy poprawnie podzielisz cechy, możliwości są nieograniczone.

* a8f9182 (HEAD -> postgres) Konfiguracja BBDD
* a8f9182 (lokalna) konfiguracja lokalna
* a8f9182 (debugowanie) konfiguracja poziomu dziennika
* a8f9182 (dev) nowa funkcja
|

Myślę, że to jest to, co kołdra ludzie lubią robić.

to polecenie i tak będzie działać z dowolnym sha / ref, który podasz:

$ git rebaseshot <Feature branch> master
$ git rebaseshot <commit of XX> master
albfan
źródło
//, Czy możesz podać link do dowolnego projektu, w którym możemy to zobaczyć w akcji?
Nathan Basanese
Ze względu na swój charakter gałęzie dostępne do rebaseshotu nie są zatwierdzane poza lokalnym repozytorium. Po prostu utwórz kilka gałęzi na szczycie mastera (poziom dziennika, połączenie z bazą danych, konfiguracja) i użyj poleceń między nimi. Widać efekt.
albfan
//, napotkałem pewne problemy. Spróbuję jeszcze raz.
Nathan Basanese
0

Oto inna opcja:

  1. Upewnij się, że masz pilota z kopią gałęzi funkcji
  2. Usuń lokalną gałąź funkcji
  3. Utwórz i wyewidencjonuj nową gałąź o tej samej nazwie, co stara gałąź funkcji, którą właśnie usunąłeś z wzorca
  4. wybierz jedno zatwierdzenie ze zdalnej kopii gałęzi funkcji, którą chcesz.

Polecenia wyglądają następująco:

git checkout Feature-branch
git push -u origin HEAD
git checkout master
git branch -D Feature-branch
git checkout -b Feature-branch
git cherry-pick HASH-OF-XX

To nie jest polecenie rebase, nie, ale jest to rebase w duchu.

cdmo
źródło