Nie rozumiem, jak używać git-rebase
i rozważam następujący przykład.
Zacznijmy repozytorium w ~/tmp/repo
:
$ git init
Następnie dodaj plik foo
$ echo "hello world" > foo
który jest następnie dodawany i zatwierdzany:
$ git add foo
$ git commit -m "Added foo"
Następnie uruchomiłem zdalne repozytorium. W ~/tmp/bare.git
pobiegłem
$ git init --bare
Aby połączyć się repo
z bare.git
tym, pobiegłem
$ git remote add origin ../bare.git/
$ git push --set-upstream origin master
Następnie pozwala rozgałęzić, dodać plik i ustawić upstream dla nowego oddziału b1
:
$ git checkout -b b1
$ echo "bar" > foo2
$ git add foo2
$ git commit -m "add foo2 in b1"
$ git push --set-upstream origin b1
Teraz nadszedł czas, aby wrócić master
i zmienić coś tam:
$ echo "change foo" > foo
$ git commit -a -m "changed foo in master"
$ git push
W tym momencie master
plik foo
zawiera zmienione foo , podczas gdy w b1
nim jest jeszcze witaj świecie . Wreszcie chcę zsynchronizować b1
z postępem dokonanym w master
.
$ git checkout b1
$ git fetch origin
$ git rebase origin/master
W tym momencie git st
zwraca:
# On branch b1
# Your branch and 'origin/b1' have diverged,
# and have 2 and 1 different commit each, respectively.
# (use "git pull" to merge the remote branch into yours)
#
nothing to commit, working directory clean
W tym momencie zawartość foo
w branży b1
jest zmiana foo również. Co oznacza to ostrzeżenie? Spodziewałem się, że powinienem zrobić git push
, git sugeruje zrobić git pull
... Zgodnie z tą odpowiedzią , to mniej więcej tak, aw swoim komentarzu @FrerichRaabe wyraźnie mówi, że nie muszę tego robić. Co tu się dzieje? Jakie jest niebezpieczeństwo, jak należy postępować? Jak zachować spójność historii? Jaka jest wzajemna zależność między przypadkiem opisanym powyżej a następującym cytatem:
Nie zmieniaj baz danych, które zostały przekazane do publicznego repozytorium.
zaczerpnięte z książki pro git .
Myślę, że jest to jakoś powiązane, a jeśli nie, chciałbym wiedzieć, dlaczego. Jaki jest związek między powyższym scenariuszem a procedurą opisaną w tym poście .
źródło
git st
tego jest to, że git wie, że twój lokalnyb1
oddział śledziorigin/b1
, więc na tym chcesz się opierać. Uciekłeśgit rebase origin/master
chociaż, więc rebased ( „odtwarzane”) swojeb1
rewizje na górzeorigin/master
.origin/master
imaster
są aktualizowane, mam rebaseorigin/b1
naorigin/master
, a następnie zrobićgit pull
gdyb1
jest wyrejestrowany wyciągnąć rebase do lokalnego repozytorium?git pull
i nigdy nie opierasz zdalnej gałęzi (np.origin/master
) Na czymkolwiek innym.origin/b1
ib1
nie są takie same. Jest to raczej oczywiste, ale jaki jest właściwy sposób, aby to naprawić? Czy też naprawienie go oznacza zepsucie historii, jak wyjaśnił @heavyd?Odpowiedzi:
Powodem, dla którego nie chcesz zmieniać bazy zatwierdzeń, które zostały wypchnięte do publicznego repozytorium, jest to, że
git-rebase
polecenie zmienia historię.Co to znaczy i dlaczego jest złe? Po pierwsze, sugerowałbym przeczytanie tego rozdziału książki Git. Z tego dowiesz się, że zatwierdzenia składają się ze wskaźnika do obiektu drzewa (migawki plików) i wskaźnika do zatwierdzenia nadrzędnego. Teraz, kiedy „zmieniasz historię”, wprowadzając zmiany na początku nowych zatwierdzeń, zmieniasz wskaźnik nadrzędny już zatwierdzonych zmian, co z kolei zmienia identyfikator twoich zobowiązań.
Powodem tego jest to, że jeśli publicznie udostępniasz swoje commity, a inni rozpoczynają dodatkową pracę na podstawie tych commits, to zmieniasz te commity, twoje drzewa nie są już zsynchronizowane.
Możesz to wszystko zobaczyć, wydając niektóre
git-log
polecenia podczas wykonywania przykładu. Uruchomiłem je tuż przed uruchomieniem polecenia rebase:A teraz po wykonaniu rebase
origin/master
iorigin/b1
są takie same, aleb1
teraz:Zauważysz, że zatwierdzenie „dodane foo2 w b1” ma inny identyfikator niż w poprzednich poleceniach dziennika. Jeśli zatwierdzisz tę zmianę w swoim publicznym repozytorium, masz teraz dwa zatwierdzenia, które wykonują w nich tę samą pracę i powoduje problemy.
Załóżmy teraz, że zamiast polegać na dodaniu b1 na master, po prostu połączyłeś master z b1, twój log wyglądałby następująco:
Zauważysz dodatkowe zatwierdzenie, które reprezentuje scalenie dwóch poprzednich zatwierdzeń. Tę historię można teraz udostępnić i wszyscy będą zadowoleni.
git-log --graph
może także pomóc rzucić dodatkowe światło na to, co się dzieje.źródło
origin/b1
jest on używany wyłącznie przeze mnie - zakładając, że jest to pewnego rodzaju kopia zapasowab1
. Jaki wpływ ma to założenie na sytuację? Czy ma sens w tym przypadku robićgit push --force
coś podobnego zaraz po zmianie bazy?git merge master
gdyfoo
gałąź jest wyewidencjonowana. Ponownie spróbuj tego sam igit-log
sprawdź, co się dzieje.master
jest uważana za gałąź stabilną, podczas gdyfoo
(lub jakakolwiek inna gałąź) jest niestabilna. Łączenie stabilnego w niestabilny jest niepożądane, dlatego dodatkowa praca. Próbuję dowiedzieć się, czy istnieją skróty.Późno na przyjęciu, ale oto odpowiedź na potomstwo:
git rebase
jest przeznaczony do użytku lokalnego. Ponownie zapisuje historię, co pozwala na bardzo ładną „linię główną”, ale jest niebezpieczny w środowisku wielu użytkownikówJeśli:
Wtedy może to mieć sens, zmuszając do ponownego napisania historii. Zrób rebase, a następnie:
Jeśli któreś z tych założeń nie zostanie spełnione, możesz żałować tego działania :-)
Przeczytaj więcej w tym poście na blogu
źródło