11. Sincronizzare modifiche locali e remote
11.1 git fetch — scaricare senza applicare
Section titled “11.1 git fetch — scaricare senza applicare”Scarica commit, branch e tag dal remote nel repository locale, senza applicarli alla working copy: operazione sicura, che non tocca il lavoro in corso.
$ git fetchc7ed69f..45e66a4 main -> origin/main* [new branch] some-feature -> origin/some-feature
$ git statusOn branch mainYour branch is behind 'origin/main' by 2 commits, and can be fast-forwarded.Esempio di situazione iniziale: si è clonato ieri un repository con il solo branch main (3 commit); la working copy ha estratto l’ultimo commit e il branch locale è collegato alla sua controparte remota:
$ git branch -vv* main c7ed69f [origin/main] implemented first featureNel frattempo un collaboratore ha aggiunto commit su main e creato un nuovo branch: dopo il fetch, i nuovi contenuti sono disponibili ma non applicati, perché Git mantiene separati i commit dei branch locali da quelli remoti (origin/main).
git log --oneline main..origin/main # cosa c'è di nuovo nel remotegit merge origin/main # applica i nuovi commit al branch locale# Fast-forward11.2 git pull — scaricare e applicare
Section titled “11.2 git pull — scaricare e applicare”git pull = git fetch + integrazione dei contenuti scaricati nella working copy. Sui branch divergenti (commit locali e remoti entrambi nuovi) esistono due strategie.
Scenario d’esempio: si è clonato un repository quando l’ultimo commit su main era il commit “B”. In locale si sono salvati i commit C, D, E; nel frattempo un altro sviluppatore ha inviato al remote i commit F, G, H. Il remote ospita la history “ufficiale”: i nuovi commit vanno recuperati e integrati con i propri, scegliendo la strategia.
Pull con rebase (git pull --rebase — tratta il remote come storia ufficiale):
- i commit locali (C-D-E) vengono messi da parte;
- fetch dei nuovi commit remoti (F-G-H);
- il branch locale e la working copy vengono aggiornati al remote;
- i commit locali vengono riapplicati come nuovi commit C’-D’-E’ (stesse differenze, nuovi snapshot).
git config pull.rebase true # imposta come strategia predefinitaPull con merge (git pull --no-rebase — dà “precedenza” al locale): dopo il fetch viene creato un dedicato merge commit (chiamiamolo I) che unisce le due history; Git chiede di salvarne il messaggio. Il risultato funziona e i branch non sono più divergenti, ma la history risulta meno lineare e la cronologia apparente meno coerente:
$ git log --graph --oneline* ece860f (HEAD -> main, origin/main) I - Merge branch 'main' of https://server.com/repository.git|\| * 09817f7 H - remote commit three| * 1e0e1d2 G - remote commit two| * b7d7502 F - remote commit one* | 4d49b1c E - local commit 3* | 6453336 D - local commit 2* | 24540dd C - local commit 1|/* 9cc4eee B - another commit* f46646f A - initial commitDal punto di vista cronologico del remote, l’ordine è risultato “invertito”: i commit F-G-H (già esistenti prima dei push di C-D-E) appaiono ora nel grafico dopo i commit locali.
git config pull.rebase false # imposta merge come strategia predefinitaConsiglio: quando si collabora su un branch, è preferibile la modalità con rebase, che mantiene la history più comprensibile.
Nelle versioni recenti di Git, un pull su branch divergenti senza strategia indicata viene interrotto proprio per costringere a scegliere.
11.3 git push — inviare al remote
Section titled “11.3 git push — inviare al remote”Carica i commit locali sul remote (solo i nuovi: Git sa già cosa c’è nel remote).
git push # invia il branch corrente al suo remote collegatogit push <remote> <branch> # invia un branch specifico a un remote specificogit push --tags # invia i tag (non vengono inviati automaticamente!)git push --all # invia tutti i branch localiPush forzato dopo aver riscritto la history: se si fa un amend (o un rebase) di commit già inviati, locale e remote divergono e il push normale viene rifiutato. Serve --force:
$ git commit --amend --no-edit$ git push --force+ 7b82870...5fb65cb main -> main (forced update)⚠️ --force sovrascrive interamente la history del branch remoto: se nel frattempo altri hanno inviato commit, andranno persi. Buone pratiche:
- fare sempre
fetch/pullprima di un push forzato; - usare
--force-with-leaseinvece di--force: avvisa se si stanno per rimuovere commit altrui, permettendo di recuperarli prima di riprovare.