167 votes

Comment l'origine/la tête est-elle fixée ?

J'ai mis en place une branche pour suivre une référence dans l'origine. git checkout <branchname> passe à cette branche, et un git status me montrera à quel point ma branche est en avance ou en retard par rapport à l'origine, mais je suis surpris que origin/HEAD pointe toujours vers origin/master et non origin/<branchname>

Ma question est donc la suivante : dans quelles circonstances l'origine/la tête est-elle déplacée ?

EDIT :

J'apprécie les réponses concernant comment pour déplacer l'origine/la tête, mais je suis intéressé par ce qui le déplace "organiquement", sans que je lui dise explicitement de le faire.

Par exemple, lorsque je change de branche, git fait pointer HEAD sur la branche que je suis en train de vérifier, je suis donc surpris que origin/HEAD ne bouge pas de la même manière.

0 votes

Notez que cette question concerne les références symboliques locales sur les ordinateurs distants, comme par exemple refs/origin/HEAD . Il ne s'agit pas de la façon dont la référence symbolique propre à un référentiel HEAD se met en place.

204voto

Jefromi Points 127932

Notez d'abord que votre question témoigne d'une certaine incompréhension. origin/HEAD représente la branche par défaut sur le serveur distant. c'est-à-dire le HEAD qui se trouve dans le référentiel distant que vous appelez origine. Lorsque vous changez de branche dans votre dépôt, vous ne l'affectez pas. Il en va de même pour les branches distantes ; vous pouvez avoir master y origin/master dans votre dépôt, où origin/master représente une copie locale de l master dans le référentiel distant.

Le HEAD d'origine ne changera que si vous ou quelqu'un d'autre le modifie effectivement dans le référentiel distant. Vous voulez que la branche par défaut d'un dépôt public reste constante, sur la branche stable (probablement master). origin/HEAD est une référence locale représentant une copie locale du HEAD dans le référentiel distant. (Son nom complet est refs/remotes/origin/HEAD.)

Je pense que ce qui précède répond à ce que vous vouliez vraiment savoir, mais pour aller de l'avant et répondre à la question que vous avez explicitement posée... origin/HEAD est défini automatiquement lorsque vous clonez un dépôt, et c'est à peu près tout. Bizarrement, que ce soit no définies par des commandes telles que git remote update - Je crois que le seul moyen de le modifier est de le faire manuellement. (Par changer, je veux dire pointer vers une branche différente ; évidemment le commit vers lequel il pointe change si cette branche change, ce qui peut arriver lors d'un fetch/pull/mise à jour à distance).


Editar : Le problème évoqué ci-dessous a été corrigé dans Git 1.8.4.3 ; voir cette actualisation .


Il y a cependant un petit bémol. HEAD est une référence symbolique, pointant vers une branche plutôt que directement vers un commit, mais les protocoles de transfert à distance de Git ne rapportent que les commits pour les refs. Ainsi, Git connaît le SHA1 du commit pointé par HEAD et tous les autres refs ; il doit ensuite déduire la valeur de HEAD en trouvant une branche qui pointe vers le même commit. Cela signifie que si deux branches pointent vers HEAD, c'est ambigu. (Je crois qu'il choisit master si possible, puis retombe sur la première dans l'ordre alphabétique). Vous verrez cela dans la sortie de 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

Curieusement, bien que la notion de HEAD imprimée de cette façon change si les choses changent sur le distant (par exemple si foo est supprimé), elle ne met pas réellement à jour refs/remotes/origin/HEAD . Cela peut conduire à des situations vraiment étranges. Disons que dans l'exemple ci-dessus, origin/HEAD pointait en fait vers foo, et que la branche foo d'origin a ensuite été supprimée. Nous pouvons alors faire ceci :

$ 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)

Ainsi, même si le show distant sait que HEAD est master, il ne met rien à jour. La branche foo qui est périmée est correctement élaguée, et HEAD est en suspens (pointant vers une branche inexistante). toujours ne le met pas à jour pour pointer vers le maître. Si vous voulez corriger cela, utilisez git remote set-head origin -a qui détermine automatiquement le HEAD de l'origine comme ci-dessus, puis définit effectivement origin/HEAD pour pointer vers la branche distante appropriée.

0 votes

@jefromi Réponse géniale ! Juste une remarque : tu écris que HEAD est une référence symbolique, pointant vers une branche plutôt que directement vers un commit [...]. mais il peut être utile de mentionner "l'état détaché de la tête", pour être complet.

2 votes

@Jubobs Merci ! Si ma réponse doit être mise à jour, n'hésitez pas à l'éditer. Les gens gagneront certainement du temps en lisant un bref résumé de la façon dont les choses fonctionnent réellement, plutôt que d'avoir à trier ce qui était vrai il y a deux ans et ce qui l'est maintenant.

0 votes

J'ai lu ce texte au moins 5 fois et je n'en comprends toujours pas un mot.

92voto

eis Points 14687

Il s'agit de votre paramètre en tant que propriétaire de votre repo local. Changez-le comme ceci :

git remote set-head origin some_branch

Et origin/HEAD pointera vers votre branche au lieu de master. Cela ne s'appliquera alors qu'à votre repo et pas aux autres. Par défaut, il pointera vers master, sauf si quelque chose d'autre a été configuré sur le repo distant.

Entrée manuelle pour la tête de set à distance fournit de bonnes informations à ce sujet.

Edit : pour souligner : sans que vous lui disiez de le faire, le seul moyen pour qu'il "bouge" serait un cas comme le suivant renommer la branche principale ce qui, à mon avis, n'est pas considéré comme "biologique". Donc, je dirais qu'organiquement, il ne bouge pas.

1 votes

L'accentuation de l'édition n'est pas tout à fait correcte ici. Elle peut aussi changer si vous clonez à partir d'une copie locale qui n'est pas sur la branche master.

0 votes

Je ne considère pas un clone comme "mobile", mais je suppose que nous ne sommes pas d'accord sur ce point :)

32voto

Robert Siemer Points 1323

Qu'est-ce qui fait bouger origin/HEAD "organiquement" ?

  • git clone le place une fois à l'endroit où HEAD est sur l'origine
    • elle sert de branche par défaut à vérifier après le clonage avec git clone

Que représente HEAD on origin ?

  • sur des dépôts nus (souvent des dépôts "sur serveurs"), il sert de marqueur pour la branche par défaut, car git clone l'utilise de manière à ce que
  • sur les dépôts non nus (locaux ou distants), il reflète le checkout actuel du dépôt.

Qu'est-ce qui fixe l'origine/la tête ?

  • git clone le récupère et le fixe
  • il serait logique que git fetch le met à jour comme n'importe quelle autre référence, mais il n'est pas
  • git remote set-head origin -a le récupère et le fixe
    • utile de mettre à jour la connaissance locale de ce que le distant considère comme la "branche par défaut".

Trivia

  • origin/HEAD peut également être réglé sur toute autre valeur sans contacter la télécommande : git remote set-head origin <branch>
    • Je ne vois pas d'utilité à cela, sauf pour les tests.
  • malheureusement rien n'est capable de mettre HEAD sur le distant
  • les anciennes versions de git ne savaient pas vers quelle branche HEAD pointait sur le distant, mais seulement vers quel hash de commit il se trouvait finalement : il fallait donc espérer qu'il choisisse un nom de branche pointant vers le même hash.

12voto

Jubobs Points 1246

Avis de non-responsabilité : il s'agit d'une mise à jour de La réponse de Cascabel que j'écris pour faire gagner du temps aux curieux.

J'ai essayé en vain de reproduire (dans Git 2.0.1) l'opération suivante remote HEAD is ambiguous que Cascabel mentionne dans sa réponse ; j'ai donc creusé un peu (en clonant https://github.com/git/git et la recherche dans le journal). Avant, c'était

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 daté du 27 février 2009, trouvé avec git log --reverse --grep="HEAD is ambiguous" )

Cependant, l'ambiguïté en question a depuis été levée :

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 daté du 8 novembre 2013, trouvé avec git log --grep="ambiguous" --grep="HEAD" --all-match )

Editar (merci à torek ) :

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

Cela signifie que, si vous utilisez Git v1.8.4.3 ou plus récent vous ne devriez pas rencontrer de problème d'ambiguïté.

1 votes

D'après les balises dans la source git, cette correction s'applique à la version 1.8.4.3 de git et aux versions ultérieures.

8voto

Pablo Maurin Points 569

N'oubliez pas qu'il y a dos dépôts git indépendants dont nous parlons. Votre dépôt local avec votre code et le dépôt distant fonctionnant ailleurs.

Vous avez raison, lorsque vous changez de branche, HEAD pointe vers votre branche actuelle. Tout cela se passe sur votre dépôt git local. Pas sur le repo distant, qui pourrait appartenir à un autre développeur, ou se trouver sur un serveur dans votre bureau, ou sur github, ou dans un autre répertoire du système de fichiers, ou etc...

Votre ordinateur (repo local) n'a pas à modifier le pointeur HEAD sur le repo git distant. Il pourrait appartenir à un autre développeur par exemple.

Une dernière chose, ce que votre ordinateur appelle origine/XXX est sa compréhension de l'état de la télécommande au moment de la dernière extraction.

Alors qu'est-ce qui mettrait "organiquement" à jour l'origine/la tête ? Ce serait l'activité sur le dépôt git distant. Pas votre dépôt local.

Les gens ont mentionné

git symbolic-ref HEAD refs/head/my_other_branch

Normalement, cela est utilisé lorsqu'il y a un dépôt git central partagé sur un serveur à l'usage de l'équipe de développement. Il s'agit d'une commande exécutée sur l'ordinateur distant. Vous le verriez comme une activité sur le dépôt git distant.

1 votes

Désolé, si je suis un peu répétitif. Je veux juste souligner le fait que git est un système de contrôle de version distribué, et qu'en tant que tel les deux dépôts sont indépendants.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X