2009-02-18 10 views
68

Mam oddział, który powinien być dostępny dla innych współpracowników i który powinien stale być na bieżąco z mistrzem.git rebase i git push: non-fast forward, po co używać?

Niestety za każdym razem, gdy robię "git rebase", a następnie próbuję pchać, powoduje to komunikat "nie do przodu" i przerwanie pchania. Jedynym sposobem, aby tu popchnąć, jest użycie --force. Czy to oznacza, że ​​powinienem użyć "git merge" zamiast ponownego tłumaczenia, jeśli mój oddział został opublikowany, a inni pracują nad nim?

Odpowiedz

99

Kilka notatek na jak git działa (nie techniczne):

Gdy zmieniają bazę, git bierze rewizje w pytaniu, a „recommits” je w górnej części czystej historii. Ma to na celu zapobiec historię wyświetlanie:

Description: tree -> mywork -> merge -> mywork -> merge -> mywork -> merge 
Commit SHA1: aaaa -> bbbb -> cccc -> dddd -> eeee -> ffff -> gggg 

Po rebase, może wyglądać następująco (lub podobny):

Description: tree -> rebase 
Commit SHA1: aaaa -> hhhh 

Problem jest, że nowy commit próbujesz wypchnąć tam jest NIE potomka z zatwierdzenia na czubku oddziału, do którego naciskasz.

Teraz wiesz, że te same informacje znajdują się w zatwierdzeniach, ale git jest odpowiedzialny za nie tylko nadpisanie tych zatwierdzeń (bbbb-gggg w powyższym przykładzie).


Shared Repo model

Jeśli używasz współdzielonego repozytorium, a następnie takie rzeczy można dostać potężny mylące. Pozwól mi wyjaśnić, dlaczego. Powiedzmy, że inny deweloper sprowadził oddział, a oni mają w swoich oddziałach aaaa -> gggg. Potem zrobić popełnić IIII

W międzyczasie pan rebased i zmuszony push, powodując drzewo wyglądać następująco:

Description: tree -> rebase 
Commit SHA1: aaaa -> hhhh 

Kiedy drugi deweloper stara się wcisnąć, dostaje " nie-szybki ". Kiedy robi scalanie, a następnie obie historie są RELINKED razem, a kończy się z bałagan

coś takiego (brudny):

Description: tree -> rebase -> mywork -> merge -> mywork -> merge -> mywork -> merge -> devwork -> merge 
Commit SHA1: aaaa -> hhhh -> bbbb -> cccc -> dddd -> eeee -> ffff -> gggg -> iiii -> jjjj 

Innymi słowy, jeśli inni są ciągnięcia i pchania , lepiej jest trzymać się git merge, lub UNIKAĆ PUSHING, aż po podstawie rebase (i tylko zmienić swoją pracę).


publicznie dostępne repozytorium modelu

Być może używasz innego modelu (więcej gittish) gdzie chcesz po prostu ludzie, aby móc wyciągnąć z repo. W tym przypadku git push --force nie jest zbyt zły, ponieważ wtedy mogą sobie poradzić z nadążaniem za nim. Mogą ponownie wprowadzać zmiany ich zmiany, aby być na szczycie swoich zmian przed podaniem ich łatki.Zapobiega ponownemu pomyłkom w repozytorium.

Jednak może istnieć lepszy sposób dla ciebie. git Push --mirror

From http://www.kernel.org/pub/software/scm/git/docs/git-push.html

Zamiast nazywania każdego ref do pchania, określa, że ​​wszystkie pozycje literatury pod $ GIT_DIR/sędziowie/(co obejmuje, ale nie jest ograniczone do bibl/głowic/, refs/remote /, i refs/tags /) być dublowany do zdalnego repozytorium. Nowo utworzony lokalny numer referencyjny będzie przekazany na zdalny koniec, lokalnie zaktualizowane informacje zostaną zaktualizowane na na końcu zdalnym, a usunięte odwołania zostaną usunięte z odległego końca na . Ten jest domyślny, jeśli ustawiono opcję remote.mirror konfiguracji .


Jednym z wielkich rzeczy o git jest to, że jest bardzo elastyczny i pozwala na wiele różnego rodzaju organizacji pracy. Ale to prawdziwa siła polega na tym, że jest to model rozproszony, więc uważam, że najwięcej ROI można zebrać, używając go w ten sposób.

+7

Błąd, w rzeczywistości scalanie tworzy scalające zatwierdzenia, których brak wyjaśnienia jest niepotrzebny. Zamiast tego, jest to świetne do 'git fetch, git rebase origin/master', rozwiń wszystkie lokalne konflikty z master (scentralizowaną) gałęzią, a następnie wypchnij czyste zatwierdzenia, które tylko posuwają się naprzód. 'git pull --rebase' ma podobny przepływ pracy. Jest to potężna opcja, ale trzeba być ostrożnym z nią, ponieważ odradzanie niewłaściwych rzeczy może przepisać zatwierdzenia, które są już pochodzenia/wzorca. Na przykład. nie należy ponownie umieszczać gałęzi w innych gałęziach, chyba że zostaną one ponownie utworzone na podstawie bieżącego źródła/wzorca. – Kzqai

+0

Zgadzam się, należy unikać łączenia przy wykonywaniu ciągnięcia git. Sądzę jednak, że są one dobre do utrzymania, gdy celowo łączą gałąź funkcji z wzorcem. – ndbroadbent

+3

Podoba mi się wyjaśnienie, dlaczego jest problem, pchanie gałęzi opartej na rebased. Ale nie jestem pewien, co osiąga --mirror. Czytanie opisu - "określa, że ​​* wszystkie refs * będą odzwierciedlone" - przeszkadza mi. Nie chcę * wszystkich refs * dublowanych, tylko jednej gałęzi. :) Czy nazwanie oddziału będzie tylko lustrzanym odbiciem? Nie jest to dla mnie jasne z dokumentów git. –

2

Nie, zmiana jest całkowicie zgodna z repozytoriami publicznymi i może być nawet pożądana, aby historia była płynna. Pamiętaj, że nie możesz używać rebase do przepisywania historii zdalnie publikowanych zatwierdzeń. Oznacza to, że rebase może być zastosowane tylko do twoich własnych, lokalnych, zatwierdzeń, których nigdy nie opublikowałeś. Używasz rebase, aby umieszczać swoje zatwierdzenia na nich podczas pobierania, a następnie, być może, dostosowywać je tam. Innym powodem, dla którego możesz otrzymać taką wiadomość jest to, że oddział, który wypychasz, został zaktualizowany i musisz zsynchronizować - pobierz i zmień swoje zatwierdzenia na podstawie pobranych.