Обучение Git: отслеживание и настройка upstream (-u) для пультов дистанционного управления?

Я изучаю Git и пытаюсь понять разницу между "отслеживанием" удаленного и определением отношения "вверх по течению" с ним (с тегом -u).

Для ведущего к исходному/ведущему я использовал

git push origin master

который, как представляется, автоматически определяет отношения (хотя я не уверен, что это такое).

Для ветвей я использовал

git branch newbranch
git push -u origin newbranch

Я знаю, что это устанавливает отношения вверх по течению, но опять же я не понимаю различия.

Может кто-нибудь объяснить разницу?

Ответ 1

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

Git разбивает эту "отслеживающую" информацию на две части: имя пульта - обычно слово origin, как и вы, - и затем имя, которое git на этом удаленном использовании назовите ветвь. 1 Другими словами, если у вас есть вход в систему для удаленного доступа, и вы заходите туда и заходите в репозиторий, вы можете запустить git log master, чтобы узнать, что было сделано.

Если вы заглянете в свой .git/config файл, вы увидите, что для каждой локальной ветки, которая "отслеживает" что-то, эти две части. Например, предположим, что у вас есть локальная ветвь с именем experiment, которую вы настроили для отслеживания origin/master. Это приведет к:

[branch "experiment"]
    remote = origin
    merge = master

Но в этом материале отслеживания есть еще одна часть: при запуске git fetch origin и там что-то новое в ветке master on origin, шаг fetch обновляет локальный origin/master. Это имя - сначала с именем remote origin, затем слэшем /, а затем именем ветки, которое появляется на пульте дистанционного управления, - как вы можете видеть, что произошло на пульте дистанционного управления. После выполнения git fetch он копирует удаленные имена ветвей (и их соответствующие SHA-1 для своих подсказок ветвления) в ваш локальный репозиторий, переименовывая их с удаленным именем спереди.

На самом деле это шаг git fetch, который обновляет origin/master и т.д., и только после этого делает этот "отслеживающий" материал полезным. git теперь может сказать вам, что вы впереди и/или отстаете от некоторого количества коммитов. И теперь вы можете запустить команду, например git log origin/master, чтобы увидеть, что происходит там - или более интересно, git log --oneline master..origin/master, чтобы увидеть "свои" фиксации, которых у вас еще нет: по существу, "что принесло извлечение" - и git log --oneline origin/master..master, чтобы увидеть "ваши", что они еще не сделали. (Если вы уже выполнили слияние или переадресацию, то слишком поздно, чтобы узнать, что принесла ваша выборка, потому что теперь у вас есть то, что у них было тогда, в результате слияния или переадресации.)

Честное слово во всем этом - git pull. Команда git pull - это всего лишь короткая строка, которая сначала запускает git fetch, а затем запускает git merge (или, если вы перенаправляете ее, git rebase). Чтобы выполнить эти шаги отдельно, вы запустите git fetch origin, затем git merge origin/master или git rebase origin/master. По историческим причинам 2git pull берет удаленное имя для ветки, в данном случае master, а не имя, которое оно переименовывает в ваш репозиторий.


Итак, с этим в качестве фона, давайте посмотрим на некоторые команды:

  • git fetch remote: Это вообще не требует никаких имен ветвей. Он вызывает данный удаленный доступ, спрашивает его, где находятся все его ветки, и обновляет ваш репозиторий, записывая все эти обновления под именами origin/ (чтобы не повлиять на какие-либо из ваших локальных ветвей). Другими словами, это обновляет имена ваших веток, которые могут (или не могут) отслеживаться, но ему не нужно ничего знать о том, что есть или что не отслеживает.

  • git status: Если он говорит, что вы "на ветке X", а ветвь X отслеживает origin/X, git status также может сообщить вам, есть ли у вас X которые не находятся на origin/X, и наоборот.

  • git merge и git rebase: им нужен какой-то способ узнать, что слить, или что нужно переделать. Вы можете назвать это явно, но если вы сообщите git, что ваша ветка X отслеживает origin/X, тогда всякий раз, когда вы находитесь в ветке X, git merge или git rebase, вы узнаете, что делать.

  • git branch --set-upstream-to origin/X: Это основная команда, которая устанавливает или изменяет отслеживание вашей текущей ветки. Другими словами, если вы сейчас находитесь в ветке X, это обновляет branch.X.remote и branch.X.merge для вас, так что вам не нужно использовать две отдельные команды git config. Вы также можете использовать git branch --unset-upstream для удаления информации отслеживания.

  • git push: если вы не даете ему дополнительной информации, он использует текущую ветвь "remote" - первую половину своей информации отслеживания - чтобы решить, какой удаленный вызов вызывает. Независимо от того, отдаете ли вы git push удаленное имя или нет, следующая часть зависит от того, укажите ли вы "refspec". Если вы этого не сделаете, git push использует push.default, чтобы решить, какой refspec использовать.

Подождите, что такое refspec?

Вторая простейшая форма refspec - это всего лишь два имени ветки с двоеточием между ними, например master:master. Для git push имя слева - это имя вашей ветки, а имя справа - другое имя другой ветки git. Если вы опустите :, вы получите простейшую форму, в которой имя удаленной стороны, которое будет следовать за :, выбрано в несколько сложном процессе (описанном в git push documentation), что фактически зависит от большего количества переменных конфигурации и от того, настроен ли вы вверх.

Как насчет git push -u? Это просто удобный ярлык: во многом, что git branch --set-upstream-to является ярлыком для выполнения двух команд git config, git push -u refspec является ярлыком для нажатия, а затем делает git branch --set-upstream-to. Вы должны дать push refspec для этого, чтобы сделать что-нибудь полезное.

Что делать, если вы даете "половину refspec", например master? Ну, как указано выше, имя, которое ваш git хочет передать удаленному git, найден сложным процессом, но если вы еще не установили восходящий поток (что довольно вероятно, если вы делаете git push -u в первую очередь), это будет то же самое, что и ваше местное имя. Таким образом, git push -u origin master возможно "означает" git push -u origin master:master, а затем означает git branch --set-upstream-to origin/master, в конце.

Если вы дадите более полный refspec, например git push -u origin experiment:feature, это приведет к тому, что ваша ветка experiment будет origin, попросив origin вызвать ее feature, а затем сделать --set-upstream-to origin/feature. Обратите внимание, что на данный момент имя вашего локального ветки восходящего потока отличается от локального имени. git в порядке; просто убедитесь, что вы тоже.: -)

Есть более умные трюки, которые git имеет:

  • Если вы запустите git checkout branch и branch еще не существует, и там одна "очевидная" ветвь удаленного отслеживания, такая как origin/branch, git, создаст новый локальный branch который уже отслеживает origin/branch. (То есть локальная ветвь будет иметь свой remote, установленный в origin, а ее merge - branch.)

  • Если вы запустите git branch local-name remote-tracking-name, git автоматически настроит локальную ветвь для отслеживания соответствующей ветки удаленного отслеживания. (Вы можете настроить git в отношении того, хотите ли вы этого, но по умолчанию.)

Сводка: git fetch обновляет информацию о том, что использует отслеживание (записи origin/*, для удаленного origin). После этого, если это будет сделано с помощью git pull, который запускает git fetch 3 тогда вы увидите больше информации из таких команд, как git status; и команды, подобные git rebase, используют его, чтобы знать, как сделать rebase, без необходимости говорить об этом больше.

Там еще один интересный поворот: любая ветка "вверх по течению" может быть в вашем собственном локальном репозитории. Чтобы получить это, вы установите для remote для этой ветки значение . (буквальная точка), а merge - имя ветки. Вам не обязательно знать, как это сделать, потому что вы можете сделать git branch --set-upstream-to master, например, чтобы ваша текущая ветка отслеживала ваш собственный master.

"Входящие" и "исходящие"

Пользователи Mercurial могут задаться вопросом, как вы можете получить эффект hg incoming или hg outgoing. Первый говорит вам, что у вас вверх по течению, что у вас нет. Последний говорит вам, что у вас есть, что они этого не делают. Как оказалось, это легко сделать в современном git, потому что git имеет специальный синтаксис @{u}, чтобы найти текущую ветвь вверх по течению.

Другими словами, если вы находитесь на master и master дорожках origin/master, @{u} (который вы можете указать как @{upstream}), это просто еще один способ написать origin/master. Таким образом, origin/master..master - это еще один способ написать @{u}..master. И, если вы находитесь на master, HEAD также называет master, и опускание имени ветки сообщает git использовать HEAD, поэтому @{u}.. хватает.

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

Итак:

git config --global alias.incoming '!git fetch && git log --oneline [email protected]{u}'
git config --global alias.outgoing '!git fetch && git log --oneline @{u}..'

(в некоторых оболочках вам может понадобиться \ перед ! или другими трюками цитаты, и может быть проще просто вставить псевдонимы в ваш редактор, запустив git config --global --edit).

Вы можете, конечно, изменить часть --oneline на любые параметры, которые вы предпочитаете. (И мне нравится оставить шаг git fetch для меня, чтобы он вручную запускал себя в любом случае, что упрощает псевдоним только alias.incoming = log --oneline [email protected]{u}, например. 4 Это в основном просто избегает постоянно приставать вверх по течению.)


1Если вы сохраняете имена своих веток такими же, как и они, вы не сможете увидеть это. Но как только вы начнете использовать ветки сильно, вы, вероятно, столкнетесь с несколькими ветвями, которые все отслеживают один и тот же поток вверх, а затем это действительно имеет значение.

2git pull фактически предшествует удаленным пулам и ветвям удаленного отслеживания. Из-за этого у него все еще есть все виды странности.

3 Если ваша версия git старше 1.8.4, когда git pull работает git fetch, шаг fetch не обновляет ветки удаленного отслеживания. Это было предназначено как функция, но это была плохая функция, а новые версии версии git. Это означает, однако, что если у вас есть старый git, вы должны быть осторожны с использованием pull script: это неудобное удобство.

4 Исправлено в редактировании: я случайно написал alias.incoming = git log .... Алиасы git считаются другими командами git (например, log), поэтому вы хотите оставить часть git, если весь псевдоним не начинается с восклицательного знака !, и в этом случае целое псевдоним передается в оболочку для запуска. На самом деле я забыл, как сработали псевдонимы, когда все команды были написаны как git-log, git-branch, git-fetch и т.д., Но это, должно быть, было менее сложным...: -)

Ответ 2

git push origin master явно говорит: "Надавите локальную ветвь" хозяин "на удаленный с именем" origin ". Это не определяет постоянные отношения, а просто выполняет одно нажатие. Обратите внимание, что удаленная ветвь считается названной" master".

git push -u origin master - это одно и то же, за исключением того, что оно сначала добавляет постоянную связь отслеживания между вашей локальной ветвью "master" и удаленным именем "origin". Как и раньше, предполагается, что удаленная ветвь называется "ведущим".

Если вы уже сделали push с -u, тогда связь уже определена. В будущем вы можете просто сказать git push или git pull, а git будет автоматически использовать определенную ветку удаленного отслеживания, не указывая явно.

Вы можете просмотреть ваши отношения отслеживания с помощью git branch -vv, в котором будут перечислены ваши локальные ветки вместе с их текущим фиксатором HEAD и, если таковая установлена, ветвью удаленного отслеживания. Вот пример.

$ git branch -vv
* master                   58a0d68 [origin/master] Fix CSS regression bug
  migration_tool           2a24ff7 [origin/migration_tool] [#906] Fix table layout problem
  topic-ajax-timeouts      fe854f2 Adjust timeouts to be more realistic

Здесь показаны 3 ветки вместе с их текущими HEAD-фиксациями и фиксацией сообщений. В первых двух указана ветвь отслеживания, но третья ветвь не отслеживает удаленную ветвь.

Ответ 3

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

git push -u origin newbranch

устанавливает информацию отслеживания вашего локального newbranch, так что newbranch, который живет в удаленном репо, называемом origin (т.е. удаленное репо, которое ваше местное репо знает под псевдонимом origin), считается upstream вашего локального newbranch... и выполняет push.

Если вы получили свой локальный репозиторий, клонировав его, вам не нужно запускать

git push -u origin master

поскольку origin/master уже настроен как ветвь master вверх по течению. Другими словами, master уже настроен на отслеживание origin/master.