Git Push:в чем разница между HEAD: refs/heads/ and?

что делает команда 1, что команда 2 не делает?

1. git push <projectpath> HEAD:refs/heads/<branch>
2. git push <projectpath> <branch>

что означает " HEAD: refs/heads/"?

3 ответов


VonC ответ правильно (и upvoted), но я думаю, что другой способ взглянуть на это может иметь больше смысла.

обратите внимание, что все это при условии, что вы используете четыре-словоформа git push, то есть,git push remote refspec. The remote часть здесь обычно просто имя origin. Определим refspec лучше через минуту.

что git push тут

что git push нужно сделать (и поэтому делает), чтобы вызвать другой экземпляр Git на другой машине,1 тогда дайте этому другому мерзавцу набор ссылки (обычно имена ветвей, иногда имена тегов) для обновления. А ссылка это просто имя, как master или v1.2, что в идеале должны быть полное (refs/heads/master или refs/tags/v1.2) так что мы можем быть уверены, что вид ссылки-ветвь, бирка, или что угодно.

для того, чтобы другой Git обновить ссылки, которые ваш Git передает, ваш Git должен и передайте некоторые из этих больших уродливых хэшей SHA-1: по одному на ссылку. Другими словами, ваш Git попросит их git установить их refs/heads/master, например, ed4f38babf3d81693a68d06cd0f5872093c009f6. (В этот момент-на самом деле, немного раньше этого момента, действительно-ваш Git и их Git имеют разговор о том, какие объекты ваши хотят отправить им, и какие объекты они уже есть, все сделано этими большими уродливыми хэш-идентификаторами. Как только два гита договорятся о том, что будет отправлено, ваш делает counting objects и compressing objects и затем отправляет им объекты. Часть "теперь, пожалуйста, установите некоторые имена" происходит почти последним.)

получение имени и хэш-частей

обратите внимание, что в запросе вашего Git есть две части: (1) полная ссылка и (2) большой уродливый хэш. (На самом деле, есть и третья часть,--force флаг, но это часть проста, и мы можем просто игнорировать ее.) Но где же код Git получить это?

если вы пишете:

git push origin somename

вы дали код Git две части информации: имя origin, который ваш Git использует для поиска URL-адреса и имени somename. Ваш git использует это, чтобы выяснить полное имя. Is somename тег? Если так, то полное имя refs/tags/somename. Is somename филиала? Если да, то полное имя refs/heads/somename. В любом случае работает. Конечно, вы также можете написать полное имя самостоятельно-и если имя является одновременно ветвью и тег, вы можете хочу сделать это, а не позволить Git выбрать один для вас.2

Итак, где ваш Git получает большой уродливый хэш? Ответ: от того же имени. Имя somename, будь то ветка или тег, просто называет какой-то конкретный объект Git. Если вы хотите увидеть хэш самостоятельно, вы можете сделать это в любое время:

git rev-parse somename

покажет его вам. Вот, собственно, как я получил ed4f38babf3d81693a68d06cd0f5872093c009f6: я пошел в репозиторий Git для Git и сделал git rev-parse v2.1.1 и он распечатал этот хэш, потому что v2.1.1 является допустимым тегом в любой полной копии репозитория Git с момента выхода версии 2.1.1.

обратите внимание, что когда вы do используйте эту форму-это git push remote name форма-Git смотрит вверх nameвсегда,3HEAD можно превратить в commit:

$ git rev-parse HEAD
2b9288cc90175557766ef33e350e0514470b6ad4

, потому что HEAD - это имя ветви (который затем является фиксацией наконечника), или у вас есть "отдельная голова", в этом случае Git хранит текущий идентификатор фиксации непосредственно в HEAD.

нажатие, когда голова отсоединена

помните, что для того, чтобы нажать, Git должен получить эти две части информации: хэш и (полное) имя. Когда HEAD не "отсоединенный", Git может получить от него оба: HEAD имеет имя ветви-в форме полного имени, на самом деле-и имя ветви имеет хэш. Но когда вы находитесь в режиме" отсоединенная голова",HEAD только хэш. Git не могу найти название филиала в HEAD. А может, и нет!--107-- > be one: возможно, вы проверили фиксацию по ID или, возможно, вы проверили по имени тега, как в:

$ git checkout v2.1.1

который поставил вас в этот режим" отсоединенной головы".

в этом случае Git требует, чтобы вы предоставили как исходный хэш src - вы все еще можете использовать имя HEAD получить это-и на dst название пункта назначения. И, если вы используете HEAD как источник, Git действительно нуждается вы чтобы изложить полный пункт назначения, потому что Git не может сказать, на данный момент, если это должна быть ветка (refs/heads/dst) или тег (refs/tags/dst).4

другие формы git push

вы можете запустить git push С меньшим количеством аргументов, например:

git push origin

или даже так:

git push

что бывает вот что без refspec, Git консультируется с вашим push.default настройки в первую очередь. Обычно это simple (по умолчанию начиная с Git версии 2.0). В этом случае Git просто использует HEAD чтобы выяснить, что нажимать-что, конечно, работает только тогда, когда HEAD - это не отдельно стоящее. Именно это мы и описали выше.

(три других параметра также используют HEAD. Один из них-тот, который был по умолчанию до git версии 2.0-нет, но это конкретная настройка оказалась слишком подверженной ошибкам, поэтому значение по умолчанию изменилось. Вы, вероятно, не должны использовать его, по крайней мере, если вы не мастер Git.)

(и, если вы покидаете remote, Git снова использует HEAD чтобы выяснить, куда нажать, по умолчанию, если необходимо, чтобы origin.)

вы также можете нажать несколько refspecs:

git push origin branch1 branch2 tag1 HEAD:refs/tags/tag2

в этом случае, каждый refspec обрабатывается обычным способом: сделать его полным имя при необходимости, так что ваш Git может дать их Git полное имя каждый раз; и найдите его хэш-идентификатор, если вы не использовали src:dst форма (или если вы сделал использовать src:dst форма, посмотри srcс ID вместо).

вы можете использовать подстановочные знаки в refspecs:

git push origin 'refs/heads/*:refs/heads/*'

(некоторые раковины будут есть, калечить,сложить, веретено или изуродовать на *s поэтому вам может понадобиться использовать кавычки, как в этом примере; другие оболочки не будут-или по крайней мере, обычно не будет-но это не помешает процитировать). Это подтолкнет все ваши ветви, или, по крайней мере, попытаться. Это имеет тенденцию быть чрезмерно восторженным, подталкивая все ваши временные ветви работы и экспериментов, и, вероятно, не то, что вы хотите, но это то, что Git сделал по умолчанию до версии 2.0.

и, вы можете использовать пустой src:

git push origin :refs/heads/deleteme

который является синтаксисом специального случая, что означает: "пусть мой Git попросит их Git удалить эта ссылка" (чтобы удалить тег, напишите тег). Как и с отделенной головой, отсутствие полного имени на код сторона означает, что вы должны полностью квалифицировать имя их стороне. (См. сноску 4 раз.)

флаг законную силу

если добавить --force на git push команда, Ваш Git передает этот флаг на их Git. Вместо вежливой просьбы: "пожалуйста, сэр, не могли бы вы установить refs/heads/master to ed4f38babf3d81693a68d06cd0f5872093c009f6?- ...ваш мерзавец пришлет его как довольно настойчивое требование. Их Git все еще может отказаться в любом случае, но их Git по умолчанию сделает это, даже если это не разумно.

Refspecs позволяют контролировать этот флаг более плотно. Флаг силы в отдельном refspec является ведущим знаком плюс +. Например, предположим, что у вас есть новые коммиты как master и develop отделения, а также новый набор rebased идет experiment, которым все остальные согласились с тем, что вам позволено давить.

вы могли бы сделать это:

git push origin develop master; git push -f origin experiment

но вы можете объединить все это в один большой толчок:

git push origin develop +experiment master

ведущий + on experiment делает это одна команда ("update experiment!"), оставляя других вежливыми просьбами ("Пожалуйста, сэр, если хотите, обновите develop и master").

(это все немного сложно для push, но на самом деле что-то вы используете регулярно каждый день с git fetch, который использует refspecs с + флаги для создания и обновления ветвей удаленного отслеживания.)


1если "другое РЕПО" находится на вашей же машине, и вы используете file:// или локальный URL-адрес на основе пути, это не совсем верно, но принцип тот же, и операции идут одинаково.

2еще лучше, не попадайте в эту ситуацию в первую очередь. Очень запутанно иметь одно имя, которое является одновременно именем ветви и имя тега. (Есть похожие запутанные ситуации, которых следует избегать из-за привычки git сокращать: не называйте ветви именами, которые напоминают удаленные имена, например. Git справится с ними просто отлично, но вы не может. : -))

3на самом деле, есть одно исключение из этого правила, которые большинство людей никогда не заметит: когда HEAD имен "нерожденный филиал." В основном это происходит в новом репозитории, который вообще не имеет коммитов. Очевидно, что если нет коммитов, нет идентификатора фиксации, который HEAD мог бы назвать. Это также происходит, когда вы используете git checkout --orphan для создания новой сиротской ветви.

4если вы используете неквалифицированное имя, их Git будет искать имя, чтобы квалифицировать его. Это означает, что вы можете не знать, какое имя вы пытаетесь обновить или удалить. В любом случае, это не очень хорошая идея.


правильная ветвь (что означает не отрезанная голова) является фиксацией, хранящейся в имени refname, на которое ссылается HEAD.
Это значит HEAD является символическим ref to refname (который, в свою очередь, содержит фактическую фиксацию), или непосредственно к фиксации (отрезанная голова). См. также "HEAD: текущая фиксация".

HEAD:refs/heads/<branch> это refspec С <src>:<dst>, где <src> часто это имя ветви, которую вы хотите нажать, но это может быть любое произвольное выражение" SHA-1", такое как master~4 или HEAD и <dst> сообщает, какой ref на удаленной стороне обновляется с помощью этого нажатия.

если у вас следующие состояния:

   git checkout abranch

   --x--Y--W--Y--Z (HEAD abranch)
     |
  (origin/abranch)

A git push origin aBranch будет толкать головку ветви (здесь Z) или происхождение, в результате чего;

   --x--Y--W--Y--Z (FEAD, abranch, origin/abranch)

но если вы ходите напрямую в одну из новых фиксаций ветвь:

git checkout abranch~2

         (HEAD)
           |
   --x--Y--W--Y--Z (abranch)
     |
  (origin/abranch)

а потом ты нажмите со вторым синтаксисом, вы обновите ветку удаленного отслеживания до этого W только commit:

git push origin HEAD:refs/heads/abranch

         (HEAD)
           |
   --x--Y--W--Y--Z (abranch)
           |
  (origin/abranch)

git push origin aBranch все равно толкнул бы полную ветку, хотя, даже если бы голова не ссылалась abranch.


первая команда явно толкает ветку с заданным именем. Если бы у вас был, например, тег с идентичным именем для одной из ваших ветвей, вторая команда была бы неоднозначной.