git push --force-with-lease vs. --force

182

Próbuję zrozumieć różnicę między

git push --force

i

git push --force-with-lease

Domyślam się, że ten ostatni wypycha do pilota tylko wtedy, gdy pilot nie ma zatwierdzeń, których nie ma lokalny oddział ?

Alexander Mills
źródło
„lokalny oddział zdalnego śledzenia ”. Zasadniczo oznacza to, że pilot musi wyglądać tak, jak oczekuje od niego klient. git help pushma przypadki użycia wyjaśniające jego cel (zasadniczo po to, aby nie zniszczyć zmiany, którą ktoś właśnie podniósł). To, co jest dla mnie trochę niejasne, to sposób działania gałęzi zdalnego śledzenia. Ale prawdopodobnie zazwyczaj będzie musiał wyglądać dokładnie, jak wyglądał ostatnim razem, gdy robiłeś fetchlub pullbez nowych zatwierdzeń.
zzxyz
4
@zzxyz: rzeczywista implementacja --force-with-leasejest podobna do instrukcji porównania i zamiany na nowoczesnych procesorach: ten, kto chce, aby nastąpiła zamiana, dostarcza oczekiwaną wartość i nową wartość. System dokonujący zamiany porównuje wartość oczekiwaną z rzeczywistą wartością bieżącą i dokonuje zamiany wtedy i tylko wtedy, gdy te dwie wartości są równe. W git pushprzypadku oczekiwaną wartością jest to, co znajduje się w nazwie zdalnego śledzenia, np. git push --force-with-lease origin XWysyła własną origin/Xwraz z nową żądaną wartością; originGit powie ci, czy dokonał wymiany, czy nie.
torek
1
Jeśli Git origindokonał wymiany, gotowe. Jeśli nie, możesz pobiec, git fetch originaby pobrać nową bieżącą wartość, przerobić zmiany, jeśli to konieczne, i przeprowadzić kolejne porównanie i zamianę typu wymuszenie z dzierżawą, aby spróbować ponownie.
torek

Odpowiedzi:

172

force zastępuje oddział zdalny oddziałem lokalnym.

--force-with-leasejest bezpieczniejszą opcją, która nie nadpisze żadnej pracy na zdalnym oddziale, jeśli więcej zatwierdzeń zostało dodanych do zdalnego oddziału (przez innego członka zespołu lub współpracownika lub przez kogo). Zapewnia to, że nie nadpisujesz czyjegoś działania poprzez naciskanie siły.

Myślę, że twój ogólny pomysł dotyczący polecenia jest poprawny. Jeśli zdalna gałąź ma taką samą wartość jak zdalna gałąź na twoim lokalnym komputerze - nadpiszesz zdalną gałąź. Jeśli nie ma tej samej wartości - oznacza zmianę, którą ktoś inny wprowadził w zdalnym oddziale, gdy pracowałeś nad swoim kodem, a tym samym nie nadpisze żadnego kodu. Oczywiście, jeśli w zdalnym są dodatkowe zatwierdzenia, wartości nie będą takie same.

Po prostu myślę o --force-with-leaseopcji do użycia, gdy chcę się upewnić, że nie nadpisuję żadnego kodu członków zespołu. Wiele zespołów w mojej firmie używa --force-with-leasedomyślnej opcji bezpieczeństwa. W większości przypadków jest to niepotrzebne, ale pozwoli Ci zaoszczędzić wiele bólu głowy, jeśli zdarzy ci się nadpisać coś, co inna osoba wniosła do pilota.

Jestem pewien, że spojrzałeś na dokumenty, ale może być tutaj trochę bardziej rozwlekłe wyjaśnienie:

https://git-scm.com/docs/git-push

chevybow
źródło
38

Szukasz odpowiedzi na podstawie wiarygodnych i / lub oficjalnych źródeł.

„Porównaj i zamień” wspomniane przez Torka w komentarzach oraz w innej odpowiedzi jest dodatkowo zilustrowane przez źródła samego Gita .

ten ostatni wypycha do pilota tylko wtedy, gdy pilot nie ma zatwierdzeń, których nie ma lokalna gałąź?

Ta funkcja została wprowadzona w tym zatwierdzeniu (grudzień 2013, Git v1.8.5-rc0)

--force-with-lease będzie chronić wszystkie zdalne referencje, które mają być aktualizowane, wymagając, aby ich aktualna wartość była taka sama jak rozsądna domyślna, chyba że określono inaczej;

Na razie „jakieś rozsądne domyślne” jest wstępnie definiowane jako „ wartość gałęzi zdalnego śledzenia, którą mamy dla odniesienia do aktualizowanego pilota ” i jest to błąd, jeśli nie mamy takiej gałęzi zdalnego śledzenia.

Zatem „dzierżawa” oznacza:

force-with-lease”: Zakładasz, że wziąłeś dzierżawę referencji, kiedy pobierałeś decyzję o tym, jaka powinna być historia, i możesz wycofać tylko wtedy, gdy dzierżawa nie została zerwana.

Źródła wciąż wspominają o „cas”:

  • Ta opcja początkowo nosiła nazwę " cas" (od "porównaj i zamień"), nazwa, której nikt nie lubił, ponieważ była zbyt techniczna.
  • Druga próba nazywała to „lockref” (ponieważ koncepcyjnie przypomina pchanie po przejęciu blokady), ale słowo „blokowanie” było znienawidzone, ponieważ sugerowało, że może odrzucać pchanie innych, co nie jest sposobem, w jaki ta opcja działa.
  • Ta runda nazywa to „force-with-lease”.
    Zakładasz, że wziąłeś dzierżawę referencji, kiedy pobierałeś decyzję o tym, jaka powinna być historia ponownego bazowania, i możesz odrzucić tylko wtedy, gdy dzierżawa nie została zerwana.

A więc: „ git push --force-with-leasevs. --force

Jak wspomniałem w " push --force-with-leasedomyślnie ", jak wspomina Git 2.13 (Q2 2017), opcja ta --force-with-leasemoże zostać zignorowana, jeśli działa w tle proces (taki jak ten, który można znaleźć w IDE z wtyczką Git) git fetch origin.
W takim przypadku --forcema pierwszeństwo.

VonC
źródło
29

git push --force jest destrukcyjny, ponieważ bezwarunkowo nadpisuje zdalne repozytorium tym, co masz lokalnie. Polecenie push --force gita jest zdecydowanie odradzane, ponieważ może zniszczyć inne zatwierdzenia już przesłane do współużytkowanego repozytorium. Jedną z najczęstszych przyczyn pchnięć siłowych jest sytuacja, w której jesteśmy zmuszeni do przebudowania gałęzi.

Na przykład. Mamy projekt z gałęzią funkcji, nad którym będą pracować zarówno Alicja, jak i Bob. Oboje klonują to repozytorium i rozpoczynają pracę. Alice początkowo kończy swoją część funkcji i wypycha ją do głównego repozytorium. To wszystko jest w porządku. Bob również kończy swoją pracę, ale zanim ją przyspieszy, zauważa, że ​​niektóre zmiany zostały włączone do mastera. Chcąc zachować czyste drzewo, przeprowadza rebase przeciwko głównej gałęzi. Oczywiście, kiedy przejdzie do pchania tej gałęzi, która została zmieniona, zostanie odrzucona. Jednak nie zdając sobie sprawy, że Alicja już popchnęła swoją pracę, wykonuje pchnięcie - siłę. Niestety, spowoduje to wymazanie wszystkich zapisów zmian Alicji w centralnym repozytorium.

To, co robi --force-with-lease , to odmowa aktualizacji oddziału, chyba że jest to stan, którego oczekujemy; tj. nikt nie zaktualizował gałęzi w górę. W praktyce działa to sprawdzając, czy nadrzędny odnośnik jest tym, czego się spodziewamy, ponieważ refs to skróty i niejawnie koduje łańcuch rodziców do ich wartości.

Oto dobry post dotyczący git push --force i git push --force-with-lease.

Shakil
źródło
2
czego nie rozumiem - jeśli rebase z mistrzem, to powinieneś być w stanie pushować bez --force-with-lease ? Dlaczego jest to --force-with-leasekonieczne po zmianie bazy z mistrzem?
Alexander Mills
3
@AlexanderMills może istnieć jakaś możliwość, która powoduje problem. Jeśli jesteś ostatnią osobą, która popycha to do opanowania, nie ma problemu, ale jest inna osoba, która pracuje nad innym zadaniem, może to spowodować poważny problem. Powiedz na początku, że A - B - C był w trybie master, na początku Alice to A - B - C - D - E i jednocześnie Bob to A - B - C - F - G. Jeśli Alice jest ostatnią osobą, pchnij w master po zmianie bazy A - B - C - D - E - F - G nie spowoduje żadnego problemu, ale inna osoba, którą Tom spróbuje naciskać A - B - C - D - E - R w tym samym czasie w master, nastąpi katastrofa !! !
Shakil
3
--forcenie traci zatwierdzeń, po prostu je odłącza. Mogą zostać wskrzeszone przez ich skróty, tak jak w git checkout <SHA>lub git reset --hard <SHA>, zakładając, że opiekun zdalnego repozytorium nie wykonuje żadnych operacji GC ani przycinania.
Keith Russell
1
„Git push --force jest zdecydowanie odradzany, ponieważ może zniszczyć inne zatwierdzenia już przesłane do współdzielonego repozytorium” to stwierdzenie jest mocno oparte na opiniach. Wykonywanie wymuszonego wypychania jest częścią normalnego przepływu pracy przeglądu kodu Git rebase. Jak już wspomniano, możesz pobrać zmiany nawet po wykonaniu tej czynności.
Étienne
9

Zakładając, że jakiekolwiek przechwyty przed odebraniem na serwerze akceptują wypychanie, zawsze się powiedzie:

git push --force

Podczas gdy to uruchamia określone sprawdzenie po stronie klienta przed kontynuowaniem:

git push --force-with-lease

Możesz ręcznie uruchomić określone sprawdzenie. Oto algorytm „sprawdzania leasingu”:

  1. Określ swoją obecną gałąź.

  2. Biegać git for-each-ref refs/remotes . Zwróć uwagę na identyfikator zatwierdzenia, który klient git uważa, że ​​odpowiada aktualnemu stanowi twojej bieżącej gałęzi.

Na przykład, jeśli jesteś w gałęzi "foo", zwróć uwagę na identyfikator zatwierdzenia powiązany z "refs / remotes / origin / foo".

  1. Określ teraz rzeczywisty identyfikator zatwierdzenia zdalnej gałęzi na nadrzędnym serwerze git.

  2. Pozwól "git push" kontynuować tylko wtedy, gdy identyfikatory zatwierdzeń wyodrębnione z kroku 2 i kroku 3 zgadzają się. Innymi słowy, kontynuuj tylko wtedy, gdy koncepcja twojego lokalnego git clona dotycząca upstream zgadza się z rzeczywistym upstreamem.

Jest tu smutna sugestia: ponieważ git fetchaktualizuje wszystkie odwołania w „refs / remotes / origin / *” do ich najnowszych wersji, ta kombinacja poleceń jest zasadniczo identyczna z git push --force:

git fetch

# The command below behaves identically to "git push --force"
# if a "git fetch" just happened!

git push --force-with-lease

Aby obejść tę wrodzoną słabość git push --force-with-lease, staram się nigdy nie biegać git fetch. Zamiast tego zawsze uruchamiam, git pull --rebasegdy potrzebuję synchronizacji z nadrzędnym, ponieważ git pullaktualizuje tylko jeden odnośnik w refs / remotes, zachowując „dzierżawę” --force-with-leaseprzydatnych.

G. Sylvie Davies
źródło
1
jeśli kontrola jest przeprowadzana po stronie klienta, czy istnieje możliwość wystąpienia sytuacji wyścigu? tj. ktoś inny wprowadza zmiany po sprawdzeniu, ale przed wymuszonym pchnięciem?
craq
2

Force-with-Lease niekoniecznie jest bezpieczne. Po prostu działa tak, jak powiedziała Sylvie. Jedna uwaga: w git gałąź jest po prostu wskaźnikiem na zatwierdzeniu. A zatwierdzenia wskazują na zero lub więcej zatwierdzeń rodzica. Nawet jeśli całkowicie zmieniłeś gałąź poprzez twardy reset git i wymuszony push lub push z - - force-with-lease bez chęci tego, niekoniecznie jest to duży problem. Możesz użyć lokalnego git reflog, aby zobaczyć, jak zmieniła się lokalna wskazówka dotycząca gałęzi (Gdzie był wtedy HEAD?), Zresetować i ponownie przesunąć gałąź. Wtedy tracisz tylko nowe zatwierdzenia w zdalnej gałęzi, ale nawet one mogą zostać przywrócone przez członków zespołu.

Ryba
źródło