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


183

Sto cercando di capire la differenza tra

git push --force

e

git push --force-with-lease

La mia ipotesi è che quest'ultimo spinga al telecomando solo se il telecomando non ha commit che la filiale locale non ha ?


il " ramo di localizzazione remoto locale ". Fondamentalmente significa che il telecomando deve assomigliare a quello che il tuo cliente si aspetta che assomigli. git help pushha casi d'uso che ne spiegano lo scopo (sostanzialmente per impedirti di cestinare un cambiamento che qualcuno ha appena spinto verso l'alto). Ciò che non è chiaro per me è come funziona il ramo di tracciamento remoto. Ma presumibilmente in genere dovrà apparire esattamente come appariva l'ultima volta che hai fatto fetcho pullsenza nuovi commit.
zzxyz,

4
@zzxyz: l'implementazione effettiva di --force-with-leaseè simile a quella delle istruzioni di confronto e scambio sulle CPU moderne: chi vuole che avvenga lo scambio fornisce il valore atteso e il nuovo valore. Il sistema che esegue lo scambio confronta il valore atteso con il valore corrente vero e lo scambio se e solo se i due sono uguali. Con git push, il valore atteso è quello che è nel nome di tracciamento remoto, ad esempio, git push --force-with-lease origin Xinvia il tuo origin/Xinsieme al nuovo valore desiderato; originGit ti dice se ha fatto lo scambio o no.
Torek,

1
Se lo Git ha originfatto lo scambio, il gioco è fatto. In caso contrario, è possibile eseguire git fetch originper raccogliere il nuovo valore corrente, rielaborare le modifiche, se necessario, ed eseguire un altro confronto forzato e scambio per riprovare.
Torek,

Risposte:


173

force sovrascrive un ramo remoto con il ramo locale.

--force-with-leaseè un'opzione più sicura che non sovrascriverà alcun lavoro sul ramo remoto se sono stati aggiunti più commit al ramo remoto (da un altro membro del team o collega o cosa hai). Ti assicura di non sovrascrivere il lavoro di qualcun altro forzando la forza.

Penso che la tua idea generale che circonda il comando sia corretta. Se il ramo remoto ha lo stesso valore del ramo remoto sul tuo computer locale, sovrascriverai il telecomando. Se non ha lo stesso valore, indica una modifica apportata da qualcun altro al ramo remoto mentre si stava lavorando sul codice e quindi non sovrascriverà alcun codice. Ovviamente se ci sono ulteriori commit in remoto, i valori non saranno gli stessi.

Penso solo --force-with-leaseall'opzione da usare quando voglio assicurarmi di non sovrascrivere il codice dei compagni di squadra. Molti team della mia azienda utilizzano --force-with-leasecome opzione predefinita un fail-safe. Non è necessario nella maggior parte dei casi, ma ti farà risparmiare un sacco di mal di testa se ti capita di sovrascrivere qualcosa che un'altra persona ha contribuito a remoto.

Sono sicuro che hai guardato i documenti, ma ci potrebbero essere alcune spiegazioni più prolifiche contenute qui:

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


39

Alla ricerca di una risposta attingendo da fonti credibili e / o ufficiali.

Il "confronto e scambio" menzionato da Torek nei commenti e nella sua altra risposta è ulteriormente illustrato dalle fonti di Git stesso .

quest'ultimo spinge al telecomando solo se il telecomando non ha commit che la filiale locale non ha?

Tale funzionalità è stata introdotta in questo commit (dicembre 2013, Git v1.8.5-rc0)

--force-with-lease proteggerà tutti i riferimenti remoti che verranno aggiornati richiedendo che il loro valore corrente sia lo stesso di un valore predefinito ragionevole, se non diversamente specificato;

Per ora, "qualche ragionevole default" è provvisoriamente definito come " il valore del ramo di monitoraggio remoto che abbiamo per il riferimento del telecomando da aggiornare ", ed è un errore se non abbiamo un ramo di monitoraggio remoto.

Quindi "contratto di locazione" significa:

" force-with-lease": Supponi di aver preso il contratto di locazione sull'arbitro quando hai recuperato per decidere quale dovrebbe essere la storia rinnovata e puoi respingere solo se il contratto di locazione non è stato rotto.

Le fonti menzionano ancora "cas":

  • Questa opzione era originariamente chiamata "cas " (per "confronta e scambia"), il nome che a nessuno piaceva perché era troppo tecnico.
  • Il secondo tentativo lo ha chiamato "lockref" (perché concettualmente è come spingere dopo aver preso un lucchetto) ma la parola "lucchetto" è stata odiata perché implicava che potesse rifiutare la spinta di altri, il che non è il modo in cui questa opzione funziona.
  • Questo round lo chiama "forza con leasing".
    Supponi di aver preso il contratto di locazione sull'arbitro quando hai recuperato per decidere quale dovrebbe essere la storia rinnovata e puoi respingere solo se il contratto di locazione non è stato rotto.

Quindi: " git push --force-with-leasevs.--force "

Come ho detto in " push --force-with-leaseper impostazione predefinita ", come menziona Git 2.13 (2 ° trimestre 2017), l'opzione --force-with-leasepuò essere ignorata se viene eseguito un processo in background (come quelli che trovi in ​​un IDE con un plugin Git) git fetch origin.
In tal caso, --forceprevale.


29

git push - force è distruttivo perché sovrascrive incondizionatamente il repository remoto con qualsiasi cosa uno abbia localmente. git's push - force forza è fortemente scoraggiata in quanto può distruggere altri commit già trasferiti in un repository condiviso. Una delle cause più comuni di spinte di forza è quando siamo costretti a ribattere un ramo.

Per esempio. Abbiamo un progetto con un ramo di funzioni su cui lavoreranno sia Alice che Bob. Entrambi clonano questo repository e iniziano a lavorare. Inizialmente Alice completa la sua parte della funzione e la inserisce nel repository principale. Va tutto bene. Anche Bob termina il suo lavoro, ma prima di sollevarlo nota che alcuni cambiamenti sono stati fusi in master. Volendo mantenere un albero pulito, esegue un rebase contro il ramo principale. Certo, quando andrà a spingere questo ramo ribassato verrà respinto. Tuttavia, non rendendosi conto che Alice ha già spinto il suo lavoro, esegue una forza di spinta. Sfortunatamente, questo cancellerà tutti i record delle modifiche di Alice nel repository centrale.

Ciò che fa - force-with-lease è rifiutare di aggiornare una filiale a meno che non sia lo stato che ci aspettiamo; cioè nessuno ha aggiornato il ramo a monte. In pratica, questo funziona verificando che il riferimento a monte sia quello che ci aspettiamo, perché i riferimenti sono hash e codificano implicitamente la catena di genitori nel loro valore.

Ecco un buon post per quanto riguarda git push - force e git push --force-with-lease.


2
cosa non capisco - se ti ribassi con il maestro, dovresti essere in grado di spingere senza --force-with-lease ? Perché è --force-with-leasenecessario dopo il rebasing con il maestro?
Alexander Mills,

3
@AlexanderMills potrebbe esserci qualche possibilità che causi problemi. Se sei l'ultima persona che spinge questo a padroneggiare, allora nessun problema, ma c'è un'altra persona che lavora con un'altra attività, potrebbe causare seri problemi. Di 'che all'inizio A - B - C era in maestro, all'inizio Alice ce la fa A - B - C - D - E e allo stesso tempo Bob ce la fa A - B - C - F - G. Se Alice è l'ultima persona a spingere in master dopo aver riequilibrato A - B - C - D - E - F - G non causerà alcun problema, ma un'altra persona Tom prova a spingere A - B - C - D - E - R contemporaneamente accadrà nel disastro principale !! !
Shakil,

3
--forcenon perde impegni, li distacca e basta. Possono essere resuscitati dai loro hash, come in git checkout <SHA>o git reset --hard <SHA>, supponendo che il manutentore del repository remoto non esegua operazioni GC o di potatura.
Keith Russell,

1
"git's push - la forza è fortemente scoraggiata in quanto può distruggere altri commit già trasferiti in un repository condiviso" questa affermazione è fortemente basata sull'opinione. Fare una spinta forzata fa parte di un normale flusso di lavoro di revisione del codice di rebase git. Inoltre, come già detto, puoi recuperare i commit anche dopo averlo fatto.
Étienne,

9

Supponendo che tutti gli hook di pre-ricezione sul server accettino il push, questo avrà sempre successo:

git push --force

Considerando che questo esegue uno specifico controllo sul lato client prima di procedere:

git push --force-with-lease

È possibile eseguire manualmente il controllo specifico. Ecco l'algoritmo di "controllo del leasing":

  1. Scopri il tuo ramo attuale.

  2. Corri git for-each-ref refs/remotes. Prendi nota del commit-id che il tuo client git ritiene corrisponda allo stato upstream del tuo ramo corrente.

Ad esempio, se sei sul ramo "pippo", prendi nota del commit-id associato a "refs / telecomandi / origine / pippo".

  1. Determinare subito l'ID commit effettivo del ramo remoto sul server git upstream.

  2. Lascia che "git push" proceda solo se i commit-id che hai estratto dal passaggio 2 e passaggio 3 sono d'accordo. In altre parole, procedi solo se la nozione di upstream del clone git locale concorda con l'upstream effettivo.

C'è una triste conseguenza qui: poiché git fetchaggiorna tutti i ref in "refs / remotes / origin / *" alle loro ultime versioni, questa combinazione di comandi è essenzialmente identica a 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

Per ovviare a questa intrinseca debolezza, git push --force-with-leasecerco di non correre mai git fetch. Invece corro sempre git pull --rebaseogni volta che ho bisogno di sincronizzarmi con l'upstream, poiché git pullaggiorna solo un singolo riferimento sotto refs / telecomandi, mantenendo utile il "contratto di locazione" --force-with-lease.


1
se il controllo è lato client, esiste un potenziale per una gara? cioè qualcun altro spinge i cambiamenti dopo il controllo ma prima della spinta forzata?
craq,

2

La forza con contratto di locazione non è necessariamente sicura. Funziona come ha detto Sylvie. Una nota: in git un ramo è solo un puntatore su un commit. E i commit indicano zero o più commit dei genitori. Anche se hai cambiato completamente il ramo con un hard git reset e una push forzata o una push con - - force-with-lease senza volerlo, non è necessariamente un grosso problema. Puoi usare il tuo reflog git locale per vedere come il tuo suggerimento locale sui rami (dov'era HEAD in quel momento?) È cambiato e resettato e spingi di nuovo il ramo. Quindi perdi solo nuovi commit nella filiale remota, ma anche loro potrebbero essere ripristinati dai membri del team.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.