Come viene impostato origin / HEAD?


144

Ho un ramo impostato per tenere traccia di un riferimento in origine. git checkout <branchname>passa a quel ramo e un git statusmi mostrerà quanto lontano o dietro il mio ramo è originario, ma sono sorpreso che origin/HEADpunti ancora origin/mastere nonorigin/<branchname>

Quindi la mia domanda è: in quali circostanze viene spostata l'origine / HEAD?

MODIFICARE:

Apprezzo le risposte su come spostare l'origine / HEAD, ma sono interessato a ciò che "organicamente" lo sposta, al di fuori di me che lo dico esplicitamente di farlo.

Ad esempio, quando cambio ramo, git fa in modo che HEAD punti sul ramo che sto controllando, quindi sono sorpreso che origin / HEAD non si muovano allo stesso modo.


Si noti che questa domanda riguarda riferimenti simbolici locali sui telecomandi, come refs/origin/HEAD. Non si tratta di come HEADviene impostato il riferimento simbolico proprio di un repository .
Clacke,

Risposte:


173

Nota prima che la tua domanda mostra un po 'di incomprensioni. origin / HEAD rappresenta il ramo predefinito sul telecomando , ovvero HEAD che si trova nel repository remoto che stai chiamando origin. Quando cambi ramo nel tuo repository, non lo stai influenzando. Lo stesso vale per i rami remoti; potresti avere mastere origin/masternel tuo repository, dove origin/masterrappresenta una copia locale del masterramo nel repository remoto.

origin's HEAD cambierà solo se tu o qualcun altro lo cambi effettivamente nel repository remoto , cosa che praticamente non dovrebbe mai accadere - vuoi che il ramo predefinito un repository pubblico rimanga costante, sul ramo stabile (probabilmente master). origin / HEAD è un riferimento locale che rappresenta una copia locale di HEAD nel repository remoto. (Il suo nome completo è refs / remotes / origin / HEAD.)

Penso che quanto sopra risponda a ciò che realmente volevi sapere, ma per andare avanti e rispondere alla domanda che hai esplicitamente posto ... origin / HEAD viene impostato automaticamente quando cloni un repository, e questo è tutto. Stranamente, non è impostato da comandi come git remote update: credo che l'unico modo in cui cambierà è se lo cambi manualmente. (Per cambio intendo indicare un ramo diverso; ovviamente il commit indica cambiamenti se quel ramo cambia, cosa che potrebbe accadere al recupero / pull / aggiornamento remoto.)


Modifica : il problema discusso di seguito è stato corretto in Git 1.8.4.3 ; vedi questo aggiornamento .


C'è un piccolo avvertimento, però. HEAD è un riferimento simbolico, che punta a un ramo anziché direttamente a un commit, ma i protocolli di trasferimento remoto git riportano solo commit per ref. Quindi Git conosce lo SHA1 del commit indicato da HEAD e da tutti gli altri riferimenti; deve quindi dedurre il valore di HEAD trovando un ramo che punta allo stesso commit. Ciò significa che se due rami sembrano puntare lì, è ambiguo. (Credo che scelga il master, se possibile, quindi ritorni al primo in ordine alfabetico.) Vedrai questo riportato nell'output di git remote show origin:

$ git remote show origin
* remote origin
  Fetch URL: ...
  Push  URL: ...
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    foo
    master

Stranamente, sebbene l'idea di HEAD stampata in questo modo cambierà se le cose cambiano sul telecomando (ad esempio se il foo viene rimosso), in realtà non si aggiorna refs/remotes/origin/HEAD. Questo può portare a situazioni davvero strane. Diciamo che nell'esempio sopra origin / HEAD in realtà indicavano foo, e quindi il ramo foo di origin è stato rimosso. Possiamo quindi fare questo:

$ git remote show origin
...
HEAD branch: master
$ git symbolic-ref refs/remotes/origin/HEAD
refs/remotes/origin/foo
$ git remote update --prune origin
Fetching origin
 x [deleted]         (none)     -> origin/foo
   (refs/remotes/origin/HEAD has become dangling)

Quindi, anche se lo spettacolo remoto sa che HEAD è il maestro, non aggiorna nulla. Il ramo foo viziata viene correttamente potata, e testa diventa penzoloni (indicando un ramo inesistente), e ancora non aggiorni per puntare a master. Se si desidera risolvere questo problema, utilizzare git remote set-head origin -a, che determina automaticamente HEAD di origine come sopra, quindi imposta origin / HEAD in modo che punti al ramo remoto appropriato.


@jefromi Risposta eccezionale! Solo un'osservazione: scrivi che HEAD è un riferimento simbolico, che punta a un ramo anziché direttamente a un commit [...] , ma potrebbe valere la pena menzionare "stato HEAD distaccato", per completezza.
jub0bs

2
@Jubobs Grazie! Se la mia risposta ha bisogno di essere aggiornata, non esitare a modificarla, comunque - sicuramente farà risparmiare tempo alle persone a leggere un breve riassunto di come funzionano effettivamente le cose, piuttosto che dover ordinare ciò che era vero due anni fa e ciò che è vero ora .
Cascabel,

l'ho letto almeno 5 volte e ancora non ne capisco un po '
krb686,

7
git remote set-head origin -aha fatto il lavoro per me
Shujito

75

È l'impostazione dell'utente come proprietario del repository locale. Modificalo in questo modo:

git remote set-head origin some_branch

E origin / HEAD punterà al tuo ramo invece che al master. Ciò si applicherebbe quindi solo al tuo repository e non ad altri. Per impostazione predefinita, punterà a master, a meno che non sia stato configurato qualcos'altro sul repository remoto.

L'inserimento manuale del set-head remoto fornisce alcune buone informazioni al riguardo.

Modifica: per enfatizzare: senza che tu te lo dica, l'unico modo in cui "si sposterà" sarebbe un caso come rinominare il ramo principale , che non credo sia considerato "organico". Quindi, direi organicamente che non si muove.


1
L'enfasi della modifica non è completamente corretta qui. Può anche cambiare se cloni da una copia locale che non si trova sul ramo principale.
mphair,

Non considero un clone "commovente", ma immagino che non possiamo essere d'accordo su questo :)
eis

24

Cosa muove l'origine / la TESTA "organicamente"?

  • git clone lo imposta una volta nel punto in cui si trova HEAD
    • funge da ramo predefinito per il checkout dopo la clonazione git clone

Cosa rappresenta HEAD all'origine?

  • su repository nudi (spesso repository “su server”) funge da marker per il ramo predefinito, perché lo git cloneutilizza in questo modo
  • su repository non bare (locali o remoti), riflette l'attuale checkout del repository

Cosa imposta origin / HEAD?

  • git clone lo recupera e lo imposta
  • avrebbe senso se lo git fetchaggiorna come qualsiasi altro riferimento, ma non lo fa
  • git remote set-head origin -a lo recupera e lo imposta
    • utile per aggiornare la conoscenza locale di ciò che il remoto considera il "ramo predefinito"

banalità

  • origin/HEAD può anche essere impostato su qualsiasi altro valore senza contattare il telecomando: git remote set-head origin <branch>
    • Non vedo alcun caso d'uso per questo, tranne che per i test
  • purtroppo nulla è in grado di impostare HEAD sul telecomando
  • le versioni precedenti di git non sapevano a quale ramo punta HEAD sul telecomando, solo quale hash di commit ha finalmente: quindi si spera solo che abbia scelto un nome di ramo che punta allo stesso hash

Avevo perso il riferimento origin/HEADe la tua soluzione mi ha aiutato. Grazie!
java_dude,

Non sono d'accordo con l' git fetchaggiornamento, poiché consente di configurare un collegamento (locale). Citando il documento: "Non è necessario disporre di un ramo predefinito per un telecomando, ma consente di specificare il nome del telecomando al posto di un ramo specifico". Sarebbe strano se una modifica remota aggiornasse le scorciatoie configurate localmente.
Micha Wiedenmann,

@MichaWiedenmann Perché dovrebbe essere un collegamento configurato localmente? Per un collegamento configurato localmente origin/HEADè un brutto nome. E questo git cloneutilizza un nome remoto come predefinito per un "ramo configurato localmente" contraddice anche quello. Sui repository non bare non ha nemmeno senso usare la corrente del telecomando HEAD.
Robert Siemer,

10

Disclaimer : questo è un aggiornamento alla risposta di Jefromi , che sto scrivendo per salvare i curiosi un po 'di tempo.

Ho cercato invano di replicare (in Git 2.0.1) il remote HEAD is ambiguousmessaggio che Jefromi menziona nella sua risposta; così ho fatto un po 'di ricerche (clonando https://github.com/git/git e cercando nel registro). Era quello

Determining HEAD is ambiguous since it is done by comparing SHA1s.

In the case of multiple matches we return refs/heads/master if it
matches, else we return the first match we encounter. builtin-remote
needs all matches returned to it, so add a flag for it to request such.

(Commit 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771, datato 27 febbraio 2009, trovato con git log --reverse --grep="HEAD is ambiguous")

Tuttavia, l'ambiguità in questione è stata revocata da allora :

One long-standing flaw in the pack transfer protocol used by "git
clone" was that there was no way to tell the other end which branch
"HEAD" points at, and the receiving end needed to guess.  A new
capability has been defined in the pack protocol to convey this
information so that cloning from a repository with more than one
branches pointing at the same commit where the HEAD is at now
reliably sets the initial branch in the resulting repository.

(Commit 9196a2f8bd46d36a285bdfa03b4540ed3f01f671, datato 8 novembre 2013, trovato con git log --grep="ambiguous" --grep="HEAD" --all-match)

Modifica (grazie a torek ):

$ git name-rev --name-only 9196a2f8bd46d36a285bdfa03b4540ed3f01f671
tags/v1.8.4.3~3

Ciò significa che, se si utilizza Git v1.8.4.3 o versioni successive , non si dovrebbe riscontrare alcun problema HEAD ambiguo-remoto.


1
Basata sui tag nel sorgente git, questa correzione si applica alla versione 1.8.4.3 e successive di git.
Torek,

@RobertSiemer Non ne sono sicuro, ma penso di sì, sì.
jub0bs

8

Ricorda che stiamo parlando di due repository git indipendenti. Il repository locale con il codice e il telecomando in esecuzione altrove.

Hai ragione, quando cambi un ramo, HEAD punta al tuo ramo attuale. Tutto questo sta accadendo sul tuo repository git locale. Non il repository remoto, che potrebbe essere di proprietà di un altro sviluppatore, o ubicazione su un server nel proprio ufficio, o github, o un'altra directory sul filesystem, ecc.

Il computer (repository locale) non ha alcuna attività di modifica del puntatore HEAD sul repository git remoto. Potrebbe essere di proprietà di uno sviluppatore diverso, ad esempio.

Un'altra cosa, ciò che il tuo computer chiama origin / XXX è la comprensione del tuo computer dello stato del telecomando al momento dell'ultimo recupero.

Quindi cosa aggiornerebbe "organicamente" origin / HEAD? Sarebbe attività sul repository git remoto. Non il tuo repository locale.

Le persone hanno menzionato

git symbolic-ref HEAD refs / head / my_other_branch

Normalmente, viene usato quando esiste un repository git centrale condiviso su un server per l'utilizzo da parte del team di sviluppo. Sarebbe un comando eseguito sul computer remoto. Lo vedresti come attività sul repository git remoto.


1
Scusa, se sono un po 'ripetitivo. Voglio solo sottolineare il fatto che git è un sistema di controllo di versione distribuito e come tale i due repository sono indipendenti.
Pablo Maurin,

3

Esegui i seguenti comandi dalla CLI di git:

# move to the wanted commit
git reset --hard <commit-hash> 

# update remote
git push --force origin <branch-name> 

1
Fantastico, questo è ciò che mi ha aiutato!
Shay Zambrovski,
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.