Почему мне нужно «git push --set-upstream origin <branch>»?

146

Я создал локальный филиал для тестирования Solaris и Sun Studio. Затем я подтолкнул ветку вверх по течению. После внесения изменений и попытки их изменения:

$ git commit blake2.cpp -m "Add workaround for missing _mm_set_epi64x"
[solaris 7ad22ff] Add workaround for missing _mm_set_epi64x
 1 file changed, 5 insertions(+)
$ git push
fatal: The current branch solaris has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin solaris

Почему я должен сделать что-то особенное для этого?

Существует ли какой-либо разумный вариант использования, когда кто-то может создать <branch>, <branch>передать удаленное устройство и затем заявить, что фиксация <branch>не предназначена для <branch>?


Я следовал за этим вопросом и ответом на переполнение стека: перенесите новую локальную ветку в удаленный Git-репозиторий и отследите его . Я предполагаю, что это еще один случай неполного или неправильно принятого ответа. Или это еще один пример того, как Git выполняет простую задачу и делает ее трудной.


Вот вид на другую машину. Ветвь явно существует, поэтому она была создана и нажата:

$ git branch -a
  alignas
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/alignas
  remotes/origin/arm-neon
  remotes/origin/det-sig
  remotes/origin/master
  remotes/origin/solaris
jww
источник
2
Спасибо @Alexi. К сожалению, процитированный dup не объясняет нелепый вариант использования, который представляется по умолчанию. (Это не риторические вопросы. Я искренне заинтересован в причине дизайна UX).
jww
1
Обратите внимание, что это настраивается. Если вы это сделаете git config --add push.default current, то git push автоматически создаст ветку в удаленном репо, если это необходимо.
Гогович

Ответы:

271

TL; DR: git branch --set-upstream-to origin/solaris


Ответ на заданный вами вопрос, который я немного перефразирую как «должен ли я установить восходящий поток», заключается в следующем: нет, вам вообще не нужно устанавливать восходящий поток.

Однако, если у вас нет восходящего потока для текущей ветки, Git меняет свое поведение git pushи на другие команды.

Полная история толчка здесь длинна и скучна и восходит к истории до Git версии 1.5. Чтобы сократить его в целом, git pushбыл реализован плохо. 1 Начиная с Git версии 2.0, Git теперь имеет записанную ручку конфигурации, push.defaultкоторая теперь установлена ​​по умолчанию simple. В нескольких версиях Git до и после 2.0, каждый раз, когда вы запускали git push, Git извергал много шума, пытаясь убедить вас установить push.defaultпросто git pushзаткнуться.

Вы не упоминаете, какую версию Git вы используете, ни настроили ли вы push.default, поэтому мы должны догадаться. Я предполагаю, что вы используете Git-версию с 2-мя точками, и что вы настроили push.defaultее, simpleчтобы заставить ее замолчать. Именно версию Git у вас есть, и что если что вы push.defaultустановлен, делает дело, из - за этого долго и скучно истории, но в конце концов, тот факт , что вы получаете еще одна жалоба от Git указывает на то, что ваш Git является настроен так, чтобы избежать одной из ошибок прошлого.

Что такое добыча?

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

Каждая ветвь имеет возможность иметь один (1) восходящий набор. То есть каждая ветвь либо имеет восходящий поток, либо не имеет восходящего. Ни одна ветвь не может иметь более одного восходящего потока.

Восходящий канал должен , но не должен быть, действительной ветвью (как удаленное отслеживание, так и локальное ). То есть, если текущая ветвь B имеет восходящий U , она должна работать. Если это не работает - если он жалуется, что U не существует - тогда большая часть Git действует так, как будто восходящий поток вообще не установлен. Несколько команд, например , покажут настройки восходящего направления, но пометят их как «пропавшие».origin/Bmastergit rev-parse U git branch -vv

Что хорошего в верхнем течении?

Если для вас push.defaultзадано значение simpleили upstream, настройка upstream сделает git push, без дополнительных аргументов, просто сработает.

Вот и все, для этого все git push. Но это довольно важно, так как git pushэто одно из мест, где простая опечатка вызывает серьезные головные боли.

Если для вас push.defaultустановлено значение nothing, matchingили current, настройка восходящего потока вообще ничего не делает для git push.

(Все это предполагает, что ваша версия Git не ниже 2.0.)

Аффект вверх по течению git fetch

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

Вверх по течению влияет git mergeи git rebaseтоже

Если вы запускаете git mergeили git rebaseбез дополнительных аргументов, Git использует текущую ветку upstream. Таким образом, это сокращает использование этих двух команд.

Аффект вверх по течению git pull

Вы никогда не должны использовать 2 вgit pull любом случае, но если вы это сделаете, git pullиспользуйте настройку восходящего потока, чтобы выяснить, с какого пульта выбрать, а затем с какой веткой слить или перебазировать. То есть, git pullделает то же самое, что и git fetch- потому что он на самом деле работает git fetch - и затем делает то же самое, что и git mergeили git rebase, потому что он на самом деле работает git merge или git rebase.

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

Аффект вверх по течению git status

Это на самом деле может быть самым важным. Как только вы установили восходящий git statusпоток , можете сообщить о разнице между вашей текущей веткой и ее восходящим потоком, с точки зрения коммитов.

Если, как это обычно бывает, вы находитесь на ветке Bс установленным восходящим потоком , и вы запускаете , вы сразу увидите, есть ли у вас коммиты, на которые вы можете нажать, и / или коммиты, на которые вы можете слить или перебазировать.origin/Bgit status

Это потому что git statusработает:

  • git rev-list --count @{u}..HEAD: сколько у вас коммитов на Bкоторые нет ?origin/B
  • git rev-list --count HEAD..@{u}: сколько у вас коммитов на которые нет ?origin/BB

Установка восходящего потока дает вам все эти вещи.

Почему же masterуже есть апстрим?

Когда вы впервые клонируете с какого-либо пульта, используйте:

$ git clone git://some.host/path/to/repo.git

или аналогичный, последний шаг Git делает это, по существу, git checkout master. Это проверка из вашего местного отделения master-только не имеют местное отделение master.

С другой стороны, у вас действительно есть пульт дистанционного слежения филиала по имени origin/master, потому что вы просто клонировать его.

Git предполагает , что вы должны иметь в виду: «заставить меня новый локальный , masterчто указывает на то передай как удаленный-трекинг origin/master, и, в то время как вы на него, установить вверх по течению для masterк origin/master

Это происходит для каждой ветви, git checkoutкоторой у вас еще нет. Git создает ветку и заставляет ее «отслеживать» (иметь в качестве восходящего потока) соответствующую ветку удаленного отслеживания.

Но это не работает для новых отраслей, то есть, филиалов, не имеющих удаленного отслеживания отрасли до сих пор .

Если вы создаете новую ветку:

$ git checkout -b solaris

пока нет origin/solaris. Ваш локальный solaris не может отследить ветку удаленного отслеживания, origin/solarisпотому что она не существует.

Когда вы впервые нажимаете на новую ветку:

$ git push origin solaris

что создает solaris на origin, и , следовательно , также создает origin/solarisв вашем собственном репозитории Git. Но уже слишком поздно: у вас уже есть местный житель solaris, у которого нет восходящего потока . 3

Разве Git не должен просто установить это, как восходящий поток автоматически?

Наверное. Смотрите «реализовано плохо» и сноска 1. Это трудно изменить в настоящее время : Есть миллионы 4 сценариев , которые используют Git и некоторые вполне могут зависеть от его текущего поведения. Для изменения поведения требуется новый основной выпуск, программное обеспечение, чтобы заставить вас установить поле конфигурации, и так далее. Короче говоря, Git является жертвой собственного успеха: какие бы ошибки он ни совершал сегодня, он может быть исправлен только в том случае, если изменение в большинстве случаев невидимо, явно намного лучше или выполняется медленно с течением времени.

Дело в том, что это не сегодня, если вы не используете --set-upstreamили -uво время git push. Это то, что говорится в сообщении.

Вы не должны делать это так. Что ж, как мы уже отмечали выше, вам совсем не обязательно это делать, но, скажем, вам нужен апстрим. Вы уже создали ветку solarisна originболее ранней версии, и, как git branchпоказывает ваш вывод, у вас уже есть origin/solaris локальный репозиторий.

Вы просто не установите его в качестве апстрима для solaris.

Чтобы установить его сейчас, а не во время первого нажатия, используйте git branch --set-upstream-to. --set-upstream-toСуб-команда берет имя любого существующего филиала, например origin/solaris, и устанавливает вверх по течению текущей ветви к этой другой отрасли.

Вот и все - это все, что он делает, - но он имеет все те последствия, отмеченные выше. Это означает, что вы можете просто бежать git fetch, затем оглядываться вокруг, затем бегать git mergeили, git rebaseпри необходимости, делать новые коммиты и бегать git push, без лишних суеты.


1 Чтобы быть справедливым, тогда не было ясно, что первоначальная реализация была подвержена ошибкам. Это стало ясно только тогда, когда каждый новый пользователь каждый раз совершал одни и те же ошибки. Теперь он «менее беден», что нельзя сказать «здорово».

2 «Никогда» немного сильно, но я обнаружил, что новички в Git понимают вещи намного лучше, когда я разделяю шаги, особенно когда я могу показать им, что на git fetchсамом деле сделал, и тогда они смогут увидеть, что git mergeили git rebaseбудет делать дальше.

3 Если вы запустите свой первый git push как git push -u origin solaris-ie, если вы добавите -uфлаг - Git установит origin/solarisв качестве восходящего потока для вашей текущей ветки, если (и только если) нажатие выполнено успешно. Таким образом, вы должны поставлять -uс первого нажатия. Фактически, вы можете поставить его при любом последующем нажатии, и он установит или изменит восходящий поток в этой точке. Но я думаю, что git branch --set-upstream-toпроще, если ты забыл.

4 Измеряется методом Остина Пауэрса / доктора Зла, когда он просто говорит «один МИЛЛЛЛ-ЮН».

Торек
источник
2
Если распространенным случаем является {создать ветку / push ветку / использовать ветку}, то не должен ли результат Push новой локальной ветки в удаленный Git-репозиторий и отследить, что это тоже что-то, что действительно работает? И если кто-то хочет {создать ветку / push ветку / не использовать ветку}, то не должен ли он делать что-то особенное, например --set-upstream /dev/null? Почему бремя ложится на общий случай? Я действительно не понимаю некоторые из этих технических решений и удобство использования.
jww
1
@VonC: Хорошо, что это точка git push -u, но это действительно кажется , что git push -uдолжно быть по умолчанию, или , по крайней мере , по умолчанию , если там нет вверх по течению еще и должно быть , git push --no-set-upstreamкогда нет в настоящее время вверх по течению , и вы хотите сохранить это так (по непонятной причине :-)).
Торек
2
«Вы продолжаете задавать подобные вопросы, потому что, я думаю, вы списали Git как« действительно неприятного »». Пожалуйста, держите такие предположения при себе. Я столкнулся с этим вопросом, потому что я также продолжаю задавать себе такие вопросы. Я не лучший UX-дизайнер в мире, но даже я понимаю, что поведение по умолчанию в этом конкретном сценарии может быть лучше.
Стивен Бикс
4
@torek - Спасибо. Ваш ответ был фантастическим; хорошо продуманный, хорошо структурированный и чрезвычайно информативный. :-)
Стивен Бикс
6
Обратите внимание, что это настраивается. Если вы это сделаете git config --add push.default current, то git push автоматически создаст ветку в удаленном репо, если это необходимо.
Gogowitsch
31

Разница между
git push origin <branch>
и
git push --set-upstream origin <branch>
заключается в том, что они оба очень хорошо передают в удаленный репозиторий, но когда вы тянете, вы замечаете разницу.

Если вы делаете:
git push origin <branch>
когда вы тянете, вы должны сделать:
git pull origin <branch>

Но если вы делаете:
git push --set-upstream origin <branch>
тогда, когда вы тянете, вам нужно только сделать:
git pull

Таким образом, добавление в --set-upstreamпозволяет не указывать, из какой ветви вы хотите тянуть каждый раз, когда вы делаете git pull.

Адам
источник
разница между двумя версиями "git push", которую я не знаю, почему я хотел бы / нужно использовать их. Бессмысленно!
Фрэнк Пук
17

В основном полная команда, как git push <remote> <local_ref>:<remote_ref>. Если вы просто запускаете git push, git не знает, что именно делать, если вы не выполнили конфигурацию, которая поможет git принять решение. В git-репо мы можем настроить несколько пультов. Также мы можем нажать локальную ссылку на любую удаленную ссылку. Полная команда - самый простой способ сделать толчок. Если вы хотите набрать меньше слов, сначала нужно выполнить настройку, например --set-upstream.

ElpieKay
источник