Git fetch работает не так, как ожидалось ": ушел]" не добавляется в описание ветки - PullRequest
2 голосов
/ 06 марта 2019

Если мы выполним git fetch -p или git fetch --prune, он удалит ветви при удалении на удаленном компьютере.

После выполнения этой команды, если мы выполним git branch -vv, предполагается, что для локальных веток, удаленных с удаленного компьютера, будет отображаться : gone].

В моем случае иногда это работает, как ожидалось, но не всегда. Иногда он не добавляет : gone] к удаленным веткам.

Моя цель - удалить филиал, если удаленный филиал удален.

Мне интересно, почему это происходит?

1 Ответ

2 голосов
/ 06 марта 2019

Не обязательно разумно удалять вашу ветку с именем X только потому, что кто-то другой удалил его ветку с именем X. Если вы работаете над новой функцией и назвали ее feat, и Боб сдался на его новой функции, которую он вызывал feat, и Боб удаляет Боба feat, это не значит, что вы должны удалить feat!

Помимо этого, давайте посмотрим на особенность веток. Эта специальная функция только доступна для (локальных) ветвей, но не для таких вещей, как origin/master, какие части Git вызывают ветви удаленного отслеживания и которые перечислены в git branch -r output . 1 На самом деле у них есть несколько специальных функций - например, вы можете "включить" ветку, используя git checkout, как после git checkout master, команда git status скажет on branch master. Но это не та особенность, которую я имею в виду.

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

Чтобы убрать настройку ветки в восходящем направлении, используйте git branch --unset-upstream <em>name</em>. Ветвь с именем name теперь не имеет восходящего потока. Если вы пропустите часть name, она будет применяться к ветви current , т. Е. Той, к которой прикреплен ваш HEAD. Это не только способ его сброса, но обычно это лучший способ.

Чтобы установить или изменить восходящую настройку ветви, используйте git branch --set-upstream-to=<em>upstream</em> <em>name</em>. Ветвь с именем name теперь имеет восходящий поток; верхний поток имеет аргумент, который вы указали как upstream. Как и в случае --unset-upstream, пропуск name означает текущую ветвь (вам не разрешено пропускать upstream). Аналогично, это не only способ его установки, но обычно это best , потому что команда git branch проверяет, является ли upstream Аргумент имеет смысл, прежде чем он позволит вам установить его.

Иногда ветви имеют восходящий параметр прямо с самого начала , а иногда нет. Мы посмотрим, когда и почему в данный момент.


1 Я дошел до того, что стараюсь избегать слова branch для удаленного отслеживания. Теперь я просто называю имена для удаленного отслеживания , потому что они так сильно отличаются от имен локальных веток Обратите внимание, что git fetch -p, или git remote prune origin, или установка fetch.prune в true влияет только на эти имена для удаленного отслеживания .


Что именно является добычей?

Восходящий поток - это просто другое имя ветви, и здесь под ответвлением name я подразумеваю или локальную ветвь, такую ​​как master или develop, или имя удаленного слежения типа origin/master. Таким образом, вы можете установить для develop значение master, если хотите, или origin/master, или origin/develop. Операция git branch --set-upstream-to позволит вам установить все, что существует, и, по мнению Git, здесь имеет смысл.

У Git есть странный недостаток. Часть этого историческая. В древнем прошлом у Git не было пультов - не было origin - поэтому у Git не было имен для удаленного отслеживания без origin, не могло быть origin/master. Но отчасти это связано с тем простым фактом, что вы можете или не можете иметь и origin/xyz, а origin/xyz может даже уйти , пока вы усердно работаете над своим xyz ответвление (потому что Боб думал , что вы закончили и пошли и удалили xyz поверх источника).

ФлЭто означает, что если немного сказать слишком , то вышестоящий поток, который вы установили - назад, когда он существовал, и, следовательно, git branch --set-upstream-to позволил вам установить - может исчезнуть. И это тот случай, когда вы видите : gone в вашем git branch -vv выводе. В какой-то момент в прошлом вы сказали вашему Git, что ваша ветка xyz должна иметь origin/xyz в качестве восходящего потока, а origin/xyz существовало в то время. Итак, git branch проверил, что все хорошо, и сделал настройку. Но теперь имя исчезло, поэтому настройка больше не действительна, и git branch -vv отмечает это.

Фактически, исходный параметр ветки состоит из двух частей, и вы можете настроить одну или обе части с помощью git config или даже перенести свою конфигурацию в выбранный вами редактор (git config --edit) и связываться с ними непосредственно:

[branch "master"]
        remote = origin
        merge = refs/heads/master

Этот параметр в этом конкретном хранилище говорит, что восходящий поток master равен origin/master. Вы можете подумать, что можете просто взять часть origin из строки remote = и часть master из строки merge =, но это своего рода ловушка: есть секретное сложное отображение. Чтобы найти настройки восходящего потока для некоторой ветви, используйте git rev-parse с суффиксом @{upstream}:

$ git rev-parse --symbolic-full-name master@{upstream}
refs/remotes/origin/master

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

В любом случае, поскольку - это две части, подобные этой, и вы можете связываться с ним вне обычного механизма git branch --set-upstream-to, вы можете нарушить настройку восходящего потока , Если вы нарушите его - если вы установите что-то бессмысленное - git branch -vv будет перечислять вышестоящий поток как «пропавший», используя ту же технику, что и в обычном режиме, ежедневные операции Git прерывают его, потому что он действительно сделал go далеко. Git не волнует почему он сломан, только то, что он сломан или не сломан прямо сейчас: если он сломан прямо сейчас, Git говорит "ушел" и делает вид, что он не установлен.

Обратите внимание, что это также означает, что если Боб случайно удалил xyz из origin и Боб исправил свою ошибку и поставил xyz обратно , ваш Git может перейти с " ушел "до", не ушел, все нормально "за другим git fetch. Это еще одна причина, по которой вам не нужно, чтобы ваш Git удалял вашу локальную ветку только потому, что кто-то напутал с каким-то другим Git где-то еще.

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

Настройка восходящего потока предлагает только несколько незначительных функций. Иногда некоторым людям действительно нравятся эти функции, но им никогда не требуется . Так что в каком-то смысле восходящий поток вообще не годится. У вас нет , чтобы их использовать, когда-либо , при условии, что вы избегаете git pull.

Возможны следующие функции:

  • Более легкое нажатие: стандартная push.default настройка требует , чтобы ваша ветвь имела восходящий поток , если вы хотите запустить git push без дополнительных аргументов.

  • Упрощенное слияние и перебазирование: команды git merge и git rebase могут использовать его. Оболочка git pull, которую вы не должны использовать никогда и которую я рекомендую , избегая в любом случае , требует восходящего потока. Оболочка сначала запускается для вас git fetch, а затем сразу же, прежде чем вы сможете решить, будет ли это хорошая идея, основываясь на том, что сделал git fetch - для вас git merge или git rebase.

  • Более полезный git status: первая строка git status сообщает вам, находитесь ли вы в режиме отсоединенного HEAD, а если нет, то в какой ветке вы находитесь. Наличие восходящего потока означает, что есть вторая линия, сразу после той, которая находится на ветви, на которой вы находитесь, когда вы находитесь на ветви. Во второй строке сравнивается ветвь с ее восходящим потоком и сообщается, является ли он «актуальным» с его восходящим потоком.

ИтакВот для чего нужен апстрим: он делает некоторые вещи проще и / или более полезными.Но вы ограничены одним вверх по течению за раз.Иногда вы можете захотеть получить эквивалент вывода второй строки git status для некоторой произвольной пары имен.Есть способ сделать это, используя git rev-list --count, но мы оставим это для других ответов .

Почему некоторые ветви уже имеют восходящий набор,а другие нет?

Существует множество способов создавать ветки в Git.Каждый из них делает что-то немного отличное от других его альтернатив - именно поэтому каждый из этих методов существует , но также дает вам эту путаницу.

Две основные команды для создания новыхветви git branch и git checkout.Когда вы используете git branch для создания новой ветки, вы всегда находитесь под полным контролем:

git branch --track newbranch origin/upstreamname

или:

git branch --no-track newbranch origin/upstreamname

Несмотря на восходящий потокБудучи названным upstream , аргумент, управляющий им, записан --track - на самом деле другая историческая случайность или ошибка.

Если вы не используете --track или --no-track здесь, git branch использует все, что вы выбрали по умолчанию при настройке branch.autoSetupMerge.См. Ниже, что это значит.

Когда вы используете git checkout, вы можете использовать --track или --no-track, но если вы не используете или вариант, это становится все сложнее.Параметр branch.autoSetupMerge все еще имеет значение, но ... хорошо:

  • git checkout -b <em>newbranch</em> создает newbranch, но создает его из HEAD, поэтому он неУстановил вверх по течению.То есть, новое имя newbranch теперь идентифицирует тот же коммит, который HEAD определил непосредственно перед этим.

  • git checkout -b <em>newbranch</em> origin/<em>name</em> создает newbranch и создает его, используя origin/<em>name</em>.То есть новое имя newbranch теперь идентифицирует тот же коммит, что и origin/<em>name</em>.Это соответствует вашей конфигурации branch.autoSetupMerge.

    git checkout -b <em>newbranch</em> <em>existing-branch</em> создает newbranch, используя existing-branch в качестве отправной точки.То есть новое имя и существующее имя теперь идентифицируют один и тот же коммит.Это также соответствует вашей branch.autoSetupMerge конфигурации, но см. Ниже, почему я выделил это.

  • git checkout <em>name</em> либо использует существующий name, или создает новую ветвь с именем name, используя origin/<em>name</em>.Если он создает новую ветвь, он подчиняется branch.autoSetupMerge.

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

  • git checkout --track origin/<em>name</em> создает новую ветвь с именем name, а устанавливает ее восходящий поток.

  • git checkout --no-track origin/<em>name</em> создаетновая ветвь с именем name и гарантирует, что она имеет нет в восходящем направлении.

Итак, как вы можете видеть, это сложно!Точный метод создания ветви частично определяет наличие восходящего потока, а остальная часть определения основывается на вашей конфигурации branch.autoSetupMerge.Эта настройка имеет три возможных значения:

  • true: установить восходящий поток, когда отправной точкой является имя для удаленного слежения.
  • false: не устанавливатьupstream.
  • always: установите восходящий поток, если начальная точка либо имя удаленного отслеживания или (локальное) имя ветви.

По умолчанию, если вы вообще не установили branch.autoSetupMerge, это делать вид, что вы установили true.Так что по умолчанию , все эти опции создания веток действуют так, как вы сказали --track , если вы даете им имя origin/* или любое другое имя для удаленного слежения в качестве ихотправная точка.Это верно, даже если отправная точка просто подразумевается , как в:

git checkout develop

случай, когда у вас нет локального develop, но есть дистанционное отслеживание origin/develop: этот создает ваш новый локальный develop из ваше дистанционное отслеживание origin/develop, и если branch.autoSetupMerge равно true - включая, если вы его вообще не установили - теперь ваши develop «отслеживают» - как его восходящий поток - ваш origin/develop.

Резюме

В некоторых из ваших веток установлены апстримы. Какие ветки имеют восходящие потоки, и что это за восходящие потоки, зависит от вас, управляется вашей конфигурацией и / или параметрами командной строки и / или дополнительными командами git branch --set-upstream-to или git branch --unset-upstream.

Те ветви, которые делают с установленными восходящими потоками, получат некоторые полезные функции. Если восходящий поток, который установлен , «исчезает» каким-либо процессом, git branch -vv перечислит ваши локальные ветви и скажет, что их восходящий поток «пропал». Другие команды Git просто сделают вид, что вы сбросили свой апстрим. Если обратный поток снова вернется, обратный поток возобновит свою полезность.

Удаление только локальной ветки , поскольку ее восходящий канал пропал, является ошибкой. Удалить его, потому что вы сделали с ним это нормально. Вам не нужно , чтобы иметь локальную ветвь с именем develop или даже с именем master, если с ними покончено, , даже если они все еще существуют в восходящем направлении origin/develop или origin/master имена . Вы можете просто использовать origin/master, чтобы обратиться к памяти вашего Git master на origin - вам не нужно , чтобы иметь свой собственный master вообще.

Иногда вы покончили с веткой из-за какой-то основной причины, которая также означает, что восходящий поток исчезнет или уже исчез. В этом случае удаление вашей локальной ветки - это нормально - вы удаляете ее , потому что с ней покончено . Тот факт, что он будет удален origin или уже был удален origin, здесь не имеет значения!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...