Как устанавливается origin / HEAD?

150

У меня есть ветка, настроенная для отслеживания ссылки в источнике. git checkout <branchname>переключается на эту ветвь, и a git statusпокажет мне, насколько далеко впереди или позади моя ветка от источника, но я удивлен, что origin/HEADвсе еще указывает на origin/master, а неorigin/<branchname>

Итак, мой вопрос: при каких обстоятельствах происходит перемещение origin / HEAD?

РЕДАКТИРОВАТЬ:

Я ценю ответы о том, как переместить origin / HEAD, но меня интересует, что «органически» перемещает его, помимо того, что я явно говорю ему это сделать.

Например, когда я переключаю ветки, git указывает HEAD на ветку, которую я проверяю, поэтому я удивлен, что origin / HEAD не перемещается таким же образом.

экоффи
источник
Обратите внимание, что этот вопрос касается локальных символических ссылок на пультах, например refs/origin/HEAD. Дело не в том, как устанавливается собственная символическая ссылка репозитория HEAD.
clacke

Ответы:

181

Во-первых, обратите внимание, что ваш вопрос свидетельствует о некотором недопонимании. origin / HEAD представляет ветвь по умолчанию на удаленном компьютере , то есть HEAD, который находится в том удаленном репозитории, который вы вызываете origin. Когда вы переключаете ветки в своем репо, вы не влияете на это. То же самое и с удаленными филиалами; у вас может быть masterи origin/masterв вашем репо, где origin/masterпредставляет собой локальную копию masterветки в удаленном репозитории.

HEAD origin будет изменяться только в том случае, если вы или кто-то другой действительно измените его в удаленном репозитории , что в принципе никогда не должно происходить - вы хотите, чтобы ветка по умолчанию в общедоступном репо оставалась постоянной в стабильной ветке (возможно, главной). origin / HEAD - это локальная ссылка, представляющая локальную копию HEAD в удаленном репозитории. (Его полное имя - refs / remotes / origin / HEAD.)

Я думаю, что приведенное выше отвечает на то, что вы действительно хотели знать, но, чтобы продолжить и ответить на вопрос, который вы явно задали ... origin / HEAD устанавливается автоматически, когда вы клонируете репозиторий, и это все. Как ни странно, он не задается такими командами, как git remote update- я считаю, что единственный способ его изменить - это изменить его вручную. (Под изменением я подразумеваю указание на другую ветку; очевидно, что фиксация указывает на изменения, если эта ветка изменяется, что может произойти при извлечении / извлечении / удаленном обновлении.)


Изменить : проблема, описанная ниже, была исправлена ​​в Git 1.8.4.3 ; см. это обновление .


Однако есть небольшая оговорка. HEAD - это символическая ссылка, указывающая на ветку, а не непосредственно на фиксацию, но протоколы удаленной передачи git сообщают только фиксации для ссылок. Итак, Git знает SHA1 коммита, на который указывает HEAD и все остальные ссылки; Затем он должен определить значение HEAD, найдя ветку, которая указывает на ту же фиксацию. Это означает, что если две ветви указывают туда, это неоднозначно. (Я считаю, что он выбирает мастер, если это возможно, а затем возвращается к первому в алфавитном порядке.) Вы увидите, что это сообщается в выводе 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

Как ни странно, хотя понятие HEAD, напечатанного таким образом, изменится, если что-то изменится на пульте дистанционного управления (например, если foo будет удален), на самом деле оно не обновляется refs/remotes/origin/HEAD. Это может привести к очень странным ситуациям. Скажем, в приведенном выше примере origin / HEAD фактически указывает на foo, а затем ветка foo origin была удалена. Затем мы можем сделать это:

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

Таким образом, даже если удаленное шоу знает, что HEAD является ведущим, оно ничего не обновляет. Устаревшая ветка foo правильно обрезана, а HEAD становится висящим (указывая на несуществующую ветку), но по- прежнему не обновляет ее, чтобы указать на master. Если вы хотите исправить это, используйте git remote set-head origin -a, который автоматически определяет HEAD источника, как указано выше, а затем фактически устанавливает origin / HEAD для указания на соответствующую удаленную ветку.

Каскабель
источник
@jefromi Замечательный ответ! Просто замечание: вы пишете, что HEAD - это символическая ссылка, указывающая на ветку, а не непосредственно на фиксацию [...] , но, возможно, для полноты стоит упомянуть «отдельное состояние HEAD».
jub0bs
2
@Jubobs Спасибо! Если мой ответ нуждается в обновлении, пожалуйста, не стесняйтесь просто отредактировать его - это, безусловно, сэкономит время людям, чтобы прочитать краткое изложение того, как все работает на самом деле, вместо того, чтобы разбираться в том, что было правдой два года назад и что верно сейчас .
Cascabel
прочитал это по крайней мере 5 раз и все еще немного не понял
krb686
9
git remote set-head origin -aсделал работу за меня
Сюдзито
79

Это ваша настройка как владельца вашего локального репо. Измените это так:

git remote set-head origin some_branch

И origin / HEAD будет указывать на вашу ветку вместо master. Тогда это будет относиться только к вашему репо, а не к другим. По умолчанию он будет указывать на master, если в удаленном репо не настроено что-то еще.

Хорошую информацию по этому поводу дает ручной ввод для удаленной установочной головки .

Изменить: подчеркнуть: без вашего ведома, единственный способ «переместить» - это переименование основной ветки , которая, как мне кажется, не считается «органической». Итак, я бы сказал, что органически он не движется.

eis
источник
1
Акцент редактирования здесь не совсем правильный. Это также может измениться, если вы клонируете из локальной копии, которая не находится в основной ветке.
mphair
Я не считаю клон «движущимся», но я думаю, мы можем не согласиться с этим :)
eis
26

Что движет origin / HEAD «органично»?

  • git clone устанавливает его один раз в то место, где HEAD находится в исходной точке
    • он служит ветвью по умолчанию для проверки после клонирования с помощью git clone

Что представляет собой HEAD по происхождению?

  • на голых репозиториях (часто репозиториях «на серверах») он служит маркером для ветки по умолчанию, потому что git cloneиспользует его таким образом
  • в репозиториях, отличных от голых (локальных или удаленных), он отражает текущую проверку репозитория

Что устанавливает origin / HEAD?

  • git clone выбирает и устанавливает это
  • было бы разумно git fetchобновлять его, как и любую другую ссылку, но это не
  • git remote set-head origin -a выбирает и устанавливает это
    • полезно для обновления местных знаний о том, что удаленное устройство считает «ветвью по умолчанию»

Мелочи

  • origin/HEAD также можно установить любое другое значение, не обращаясь к пульту дистанционного управления: git remote set-head origin <branch>
    • Я не вижу для этого варианта использования, кроме тестирования
  • к сожалению, ничто не может установить HEAD на пульте дистанционного управления
  • более старые версии git не знали, на какую ветку указывает HEAD на пульте дистанционного управления, только на какой хэш фиксации он, наконец, имеет: поэтому он просто, надеюсь, выбрал имя ветки, указывающее на тот же хеш
Роберт Симер
источник
Я потерял ссылку, origin/HEADи ваше решение помогло. Благодарность!
java_dude
Я не согласен с git fetchего обновлением, так как он позволяет настроить (локальный) ярлык. Цитата из документа: «Наличие ветки по умолчанию для удаленного устройства не требуется, но позволяет указать имя удаленного устройства вместо конкретной ветки». Было бы странно, если бы удаленное изменение обновляло локально настроенные ярлыки.
Micha Wiedenmann
@MichaWiedenmann Почему это должен быть локально настроенный ярлык? Для локально настроенного ярлыка origin/HEAD- плохая репутация. И то, git cloneчто по умолчанию для «локально настроенной ветки» используется удаленное имя, это тоже противоречит этому. В репозиториях non-bare даже нет смысла использовать удаленный ток HEAD.
Роберт Симер,
11

Отказ от ответственности : это обновление ответа Джефроми , которое я пишу, чтобы сэкономить время любопытным.

Я тщетно пытался воспроизвести (в Git 2.0.1) remote HEAD is ambiguousсообщение, которое Джефроми упоминает в своем ответе; поэтому я немного покопался (клонировав https://github.com/git/git и выполнив поиск в журнале). Раньше было так

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.

(Коммит 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771от 27 февраля 2009 г., обнаружен с git log --reverse --grep="HEAD is ambiguous")

Однако с тех пор обсуждаемая двусмысленность снята :

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.

(Коммит 9196a2f8bd46d36a285bdfa03b4540ed3f01f671от 8 ноября 2013 г., обнаружен с git log --grep="ambiguous" --grep="HEAD" --all-match)

Изменить (спасибо torek ):

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

Это означает, что если вы используете Git v1.8.4.3 или новее , вы не должны столкнуться с какой-либо проблемой неоднозначного удаленного HEAD.

jub0bs
источник
1
На основе тегов в исходном коде git это исправление применяется к git версии 1.8.4.3 и более поздних.
torek
@RobertSiemer Я не уверен, но думаю, да.
jub0bs
8

Помните, что мы говорим о двух независимых репозиториях git. Ваше локальное репо с вашим кодом и удаленное управление где-то еще.

Вы правы, когда вы меняете ветку, HEAD указывает на вашу текущую ветку. Все это происходит в вашем локальном репозитории git. Не удаленное репо, которое может принадлежать другому разработчику, или размещаться на сервере в вашем офисе, или github, или другом каталоге в файловой системе, и т. Д.

Ваш компьютер (локальное репо) не имеет права изменять указатель HEAD на удаленном репозитории git. Например, он может принадлежать другому разработчику.

Еще одна вещь, то, что ваш компьютер называет origin / XXX, - это понимание вашим компьютером состояния пульта дистанционного управления во время последней выборки.

Так что же «органично» обновить origin / HEAD? Это будет активность в удаленном репозитории git. Не ваше местное репо.

Люди упомянули

git symbolic-ref HEAD refs / head / my_other_branch

Обычно это используется, когда на сервере есть общий центральный репозиторий git для использования командой разработчиков. Это будет команда, выполняемая на удаленном компьютере. Вы увидите это как активность в удаленном репозитории git.

Пабло Маурин
источник
1
Извините, если я немного повторяюсь. Я просто хочу отметить тот факт, что git - это распределенная система контроля версий, и поэтому два репозитория независимы.
Пабло Маурин,
4

Выполните следующие команды из git CLI:

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

# update remote
git push --force origin <branch-name> 
Якир Гилади Эдри
источник
1
Отлично, вот что мне помогло!
Шай Замбровски