"Git fetch --tags" include "git fetch"?


270

Una domanda piacevole e semplice: la funzione di "git fetch" è un sottoinsieme rigoroso di git fetch --tags?

Cioè se corro git fetch --tags, c'è mai un motivo per correre git fetchsubito dopo?

Che dire di git pulle git pull --tags? Stessa situazione?


11
A partire da Git 1..9 / 2.0 (Q1 2014), la risposta sarà . Vedi la mia risposta qui sotto
VonC

3
Per l'editore che "ha corretto il mio testo" con una modifica, non è necessario scrivere in maiuscolo dopo un trattino o un acronimo, quindi la tua modifica era grammaticalmente errata, motivo per cui l'ho rifiutata.
David,

Risposte:


176

Nota: a partire da git 1.9 / 2.0 (Q1 2014) , git fetch --tagsrecupera i tag oltre a quelli recuperati dalla stessa riga di comando senza l'opzione.

Vedi commit c5a84e9 di Michael Haggerty (mhagger) :

In precedenza, l' --tagsopzione " " di fetch era considerata equivalente alla specifica di refspec

refs/tags/*:refs/tags/*

sulla riga di comando; in particolare, ha fatto sì che la remote.<name>.refspecconfigurazione venisse ignorata.

Ma non è molto utile recuperare i tag senza recuperare anche altri riferimenti, mentre è abbastanza utile essere in grado di recuperare i tag oltre ad altri riferimenti.
Quindi cambia la semantica di questa opzione per fare quest'ultima.

Se un utente desidera recuperare solo tag, è comunque possibile specificare un refspec esplicito:

git fetch <remote> 'refs/tags/*:refs/tags/*'

Si noti che la documentazione precedente alla 1.8.0.3 era ambigua su questo aspetto del fetch --tagscomportamento " ".
Commit f0cb2f1 (2012-12-14) ha fetch --tagsfatto corrispondere la documentazione al vecchio comportamento.
Questo commit modifica la documentazione in modo che corrisponda al nuovo comportamento (vedi Documentation/fetch-options.txt).

Richiedi che tutti i tag vengano recuperati dal telecomando oltre a qualsiasi altro oggetto venga recuperato .


Poiché Git 2.5 (Q2 2015) git pull --tagsè più robusto:

Vedi commit 19d122b di Paul Tan ( pyokagan) , 13 maggio 2015.
(Unito da Junio ​​C Hamano - gitster- in commit cc77b99 , 22 maggio 2015)

pull: rimuove l' --tagserrore in nessun caso di candidati candidati

Poiché 441ed41 (" git pull --tags": errore con un messaggio migliore., 28-12-2007, Git 1.5.4+), git pull --tagsstampa un messaggio di errore diverso se git-fetchnon viene restituito alcun candidato di unione:

It doesn't make sense to pull all tags; you probably meant:
       git fetch --tags

Questo perché a quel tempo, git-fetch --tagsavrebbe ignorato qualsiasi refspec configurato, e quindi non ci sarebbero candidati per la fusione. Il messaggio di errore è stato quindi introdotto per evitare confusione.

Tuttavia, dal momento che c5a84e9 ( fetch --tags: recupera i tag oltre ad altre cose, 30-10-2013, Git 1.9.0+), git fetch --tagsrecupera i tag oltre a qualsiasi refspecs configurato.
Quindi, se non si verifica alcuna situazione di candidati senza unione, non è perché è --tagsstato impostato. Pertanto, questo messaggio di errore speciale è ora irrilevante.

Per evitare confusione, rimuovere questo messaggio di errore.


Con Git 2.11+ (Q4 2016) git fetchè più veloce.

Vedi commit 5827a03 (13 ott 2016) di Jeff King ( peff) .
(Unita da Junio ​​C Hamano - gitster- in commit 9fcd144 , 26 ott 2016)

fetch: usa "quick" has_sha1_fileper seguire i tag

Quando recuperiamo da un telecomando che ha molti tag che sono irrilevanti per i rami che stiamo seguendo, abbiamo usato per sprecare troppi cicli quando abbiamo verificato se l'oggetto puntato da un tag (che non stiamo andando a recuperare!) Esiste nel nostro repository troppo attentamente.

Questa patch insegna a recuperare come usare HAS_SHA1_QUICK per sacrificare l'accuratezza per la velocità, nei casi in cui potremmo essere audaci con un repack simultaneo.

Ecco i risultati dello script perf incluso, che imposta una situazione simile a quella sopra descritta:

Test            HEAD^               HEAD
----------------------------------------------------------
5550.4: fetch   11.21(10.42+0.78)   0.08(0.04+0.02) -99.3%

Ciò vale solo per una situazione in cui:

  1. Hai molti pacchetti sul lato client da rendere reprepare_packed_git()costosi (la parte più costosa è trovare duplicati in un elenco non ordinato, che è attualmente quadratico).
  2. È necessario un numero elevato di riferimenti tag sul lato server che sono candidati per l'auto-follow (ovvero, che il client non ha). Ognuno innesca una rilettura della directory del pacchetto.
  3. In circostanze normali, il client seguirà automaticamente quei tag e dopo un grande recupero, (2) non sarebbe più vero.
    Ma se quei tag indicano la cronologia che è disconnessa da ciò che il client recupera altrimenti, allora non seguirà mai automaticamente e quei candidati avranno un impatto su ogni recupero.

Git 2.21 (febbraio 2019) sembra aver introdotto una regressione quando la configurazione nonremote.origin.fetch è quella predefinita ( '+refs/heads/*:refs/remotes/origin/*')

fatal: multiple updates for ref 'refs/tags/v1.0.0' not allowed

Git 2.24 (Q4 2019) aggiunge un'altra ottimizzazione.

Vedi commit b7e2d8b (15 set 2019) di Masaya Suzuki ( draftcode) .
(Unito da Junio ​​C Hamano - gitster- in commit 1d8b0df , 07 ott 2019)

fetch: usare oidsetper mantenere gli OID desiderati per una ricerca più rapida

Durante git fetch, il client verifica se gli OID dei tag pubblicizzati sono già nel set OID desiderato della richiesta di recupero.
Questo controllo viene eseguito in una scansione lineare.
Per un repository che ha molti riferimenti, ripetere questa scansione richiede più di 15 minuti.

Per velocizzarlo, crea un oid_setOID per altri ref.


Questo thread in git-list discute la possibilità di modificare il comportamento di git fetch <remote> <branch>seguire automaticamente i tag (poiché aggiorna già i tracciamenti remoti CONTRO le intenzioni originali): public-inbox.org/git/…
ankostis

@ankostis Interessante: come menziona Junio ​​in public-inbox.org/git/… , "tornare al vecchio comportamento potrebbe essere un'opzione per affrontare il problema in discussione in questo thread". (ma non lo faranno: public-inbox.org/git/… )
VonC

Sarebbe stato possibile per Git esporre all'utente complessità non necessaria, richiedendo comandi pesanti di sintassi al punto da somigliare agli hack per eseguire operazioni comuni? Non credo ancora che sia necessaria una conoscenza sufficiente degli interni.
John Fantastico,

1
@JohnFantastico Posso capire quel punto di vista. L'ho già visto prima: news.ycombinator.com/item?id=16587496 . O hackernoon.com/… ("I comandi Git sono solo un'astrazione che perde sulla memorizzazione dei dati.")
VonC

1
@Vadorequest Grazie. Ho aggiornato la risposta e darò un'occhiata alla mailing list: public-inbox.org/git/?q=fetch
VonC

131

Nota: questa risposta è valida solo per git v1.8 e precedenti.

Gran parte di questo è stato detto nelle altre risposte e commenti, ma ecco una spiegazione concisa:

  • git fetchrecupera tutte le diramazioni (o tutte specificate dall'opzione di configurazione remote.fetch), tutti gli commit necessari per loro e tutti i tag che sono raggiungibili da questi rami. Nella maggior parte dei casi, tutti i tag sono raggiungibili in questo modo.
  • git fetch --tagsrecupera tutti i tag, tutti gli commit necessari per loro. Sarà Non aggiorna responsabili di filiali, anche se sono raggiungibili dai tag che erano inverosimile.

Riepilogo: se vuoi davvero essere completamente aggiornato, usando solo il recupero, devi fare entrambe le cose.

Inoltre, non è "due volte più lento" a meno che tu non intenda in termini di digitazione sulla riga di comando, nel qual caso gli alias risolvono il tuo problema. Non vi è sostanzialmente alcun sovraccarico nel formulare le due richieste, poiché richiedono informazioni diverse.


2
Grazie per il tuo commento. Sto eseguendo git in Cygwin su una rete ad alta latenza - è due volte più lento quando non c'è niente da recuperare per entrambi (circa 5 secondi).
David,

Oh wow. Git-remote funziona meglio? Osservando brevemente la fonte, penso che potrebbe fare solo una singola chiamata, ma non sono del tutto sicuro se prenderà i tag non sul ramo. Onestamente non so se ho mai visto tag non su un ramo. Con le cose da cui traggo, l'unico modo che accadrebbe se aspettassi così a lungo che mi mancava una versione di manutenzione, una versione di funzionalità e l'interruzione della manutenzione della vecchia versione.
Cascabel,

Penso che il problema sia che 'git fetch' recupera solo i tag sui rami tracciati . Abbiamo uno script che consente agli utenti di selezionare un ramo funzionante, quindi per impostazione predefinita ci sono molti rami che non sono attualmente tracciati da un individuo.
David,

Non ho ancora provato git-remote, ma è nella mia lista di cose da fare sempre crescente :)
davidA

7
Si noti che in git remote updaterealtà non è un sostituto di git fetche git fetch --tags. git remote updatenon aggiornerà i tag esistenti che sono stati modificati, sebbene introdurrà nuovi tag. git fetch --tagsAggiorna solo i tag già esistenti.
Larsks,

48

Ho intenzione di rispondere da solo.

Ho determinato che c'è una differenza. "git fetch --tags" potrebbe includere tutti i tag, ma non comporta alcun nuovo commit!

Si scopre che bisogna farlo per essere totalmente "aggiornati", ovvero replicare un "git pull" senza l'unione:

$ git fetch --tags
$ git fetch

È un peccato, perché è due volte più lento. Se solo "git fetch" avesse un'opzione per fare ciò che fa normalmente e portare tutti i tag.


Interessante, non l'ho sperimentato (probabilmente perché il mio repository era aggiornato al momento del mio test.) +1
VonC,

1
Che ne dici di un ' git remote update myRemoteRepo': sarebbe recuperare contenuti e tag remoti ?
VonC,

1
Faccio git fetchtutto il tempo e abbassa costantemente ogni nuovo commit e qualsiasi nuovo tag. Quale versione di Git stai eseguendo?
Tim Visher,

4
FTR, 'git remote update myRemoteRepo' non funziona bene - non sembra fare ciò che fa 'git fetch && git fetch --tags', soprattutto perché una successiva fusione non ha alcun effetto.
David,

1
@TimVisher git fetchnon afferrerà i tag che non sono nel registro di commit di un ramo. L'interfaccia utente di jQuery lo fa ad esempio su un tag di rilascio. Facciamo un git checkout -b temp-branch, facciamo la nostra versione, aggiungiamo i file necessari per la versione, la versione di aggiornamento, ecc. Quindi git commit -m "1.10.x" ; git tag 1.10.x; git push --tagscancelliamo il nostro ramo temporaneo locale. Non esiste un ramo remoto che raggiunga quel tag e git fetchnon lo scaricherà mai.
Gnarf,

31

Il problema generale qui è che git fetchverrà recuperato +refs/heads/*:refs/remotes/$remote/*. Se uno di questi commit ha tag, anche questi tag verranno recuperati. Tuttavia, se sono presenti tag non raggiungibili da alcun ramo sul telecomando, non verranno recuperati.

L' --tagsopzione commuta refspec su +refs/tags/*:refs/tags/*. Si potrebbe chiedere git fetchdi prendere entrambi. Sono abbastanza sicuro di fare solo un git fetch && git fetch -tche useresti il ​​seguente comando:

git fetch origin "+refs/heads/*:refs/remotes/origin/*" "+refs/tags/*:refs/tags/*"

E se si desidera rendere questo predefinito per questo repository, è possibile aggiungere un secondo refspec al recupero predefinito:

git config --local --add remote.origin.fetch "+refs/tags/*:refs/tags/*"

Ciò aggiungerà una seconda fetch =riga nel .git/configper questo telecomando.


Ho trascorso un po 'a cercare il modo di gestirlo per un progetto. Questo è quello che mi è venuto in mente.

git fetch -fup origin "+refs/*:refs/*"

Nel mio caso volevo queste funzionalità

  • Prendi tutte le teste e i tag dal telecomando quindi usa refspec refs/*:refs/*
  • Sovrascrivi i rami e i tag locali con l'avanzamento non rapido +prima del refspec
  • Se necessario, sovrascrivere il ramo attualmente estratto -u
  • Elimina rami e tag non presenti in remoto -p
  • E forza per essere sicuro -f

Questa dovrebbe essere la risposta.
redolente il

+1 per "L' --tagsopzione imposta refspec su +refs/tags/*:refs/tags/*". Anche se, man git-fetchsembra specificare che refspec senza il leader +( refs/tags/*:refs/tags/*).
Dmitry Minkovsky,

remote.origin.fetchper impostazione predefinita +refs/heads/*:refs/remotes/origin/*, ovvero la +versione, non è vero? (Ciò significa che l'origine / ramo verrà sovrascritto, indipendentemente da dove l'origine / ramo sia localmente in questo momento.)
Robert Siemer

... e al momento in cui scrivevo, i recenti git --tagsstavano recuperando i tag oltre a tutto il resto già. Vedi la risposta di @VonC.
Robert Siemer,

10

Nella maggior parte dei casi, git fetchdovresti fare quello che vuoi, ovvero "ottenere qualcosa di nuovo dal repository remoto e inserirlo nella tua copia locale senza unirti alle filiali locali". git fetch --tagsfa esattamente questo, tranne per il fatto che non ottiene nulla tranne i nuovi tag.

In tal senso, non git fetch --tagsè in alcun modo un superset di git fetch. In realtà è esattamente il contrario.

git pull, ovviamente, non è altro che un wrapper per a git fetch <thisrefspec>; git merge. Si consiglia di abituarsi a eseguire manualmente git fetching e git mergeing prima di fare il salto git pullsemplicemente perché ti aiuta a capire cosa git pullsta facendo in primo luogo.

Detto questo, la relazione è esattamente la stessa di git fetch. git pullè il superset di git pull --tags.


1
"git pull è il superset di git pull --tags" - ma ... 'git fetch' non è il superset di 'git fetch --tags' quindi la relazione non è esattamente la stessa ...?
David,

9
Ho appena trovato questa domanda ... beh, mi sembra che git pullnon si ottengano tutti i tag ma solo quelli raggiungibili dalle attuali diramazioni. Tuttavia, git pull --tagsrecupera tutti i tag ed è apparentemente equivalente a git fetch --tags.
Archimedix,

2
git fetch upstream --tags

funziona bene, otterrà solo nuovi tag e non otterrà nessun'altra base di codice.


1
upstreamviene normalmente chiamato origin. Penso che upstreamsia un nome usato da GitHub. In ogni caso, il nome da utilizzare è quello indicato da git remote.
Fabio dice di reintegrare Monica l'
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.