Сделать новую ветку git отслеживать ту же удаленную ветку - PullRequest
0 голосов
/ 15 мая 2019

Есть ли способ, чтобы новая ветка автоматически отслеживала тот же удаленный узел, что и существующая ветка, из которой она была создана?

Скажем, у меня есть локальная ветка foo, которая отслеживает удаленный origin/bar. Я могу явно иметь новую ветку baz на основе foo, а также отслеживать origin/bar, выполнив:

git checkout foo
git checkout -b baz origin/bar 

Но существует ли универсальный способ создания ветви baz из foo и отслеживания того же пульта, что и foo, независимо от того, что это за пульт?

Ответы [ 3 ]

2 голосов
/ 16 мая 2019

Но существует ли общий способ создания ветви baz из foo и отслеживания того же пульта, что и foo, независимо от того, что это за пульт?

Да, но это немного сложно. Будь то, что есть, есть около двенадцати дюжин 1 разных способов сделать это, но мы просто выберем один здесь.

Сначала давайте рассмотрим все важные части этого:

  • В вашем примере есть ваши собственные локальные имена филиалов, foo и baz.
  • Существуют имена для удаленного отслеживания, такие как origin/bar (полное имя refs/remotes/origin/bar).
  • Идентификатор хэша коммита, на который указывает имя каждой ветви или имя удаленного отслеживания.
  • И есть дополнительная восходящая настройка для любого (локального) имени ветви. Обычно восходящий поток какой-то локальной ветки - это имя удаленного отслеживания (Git называет это «удаленным отслеживанием») с тем же базовым именем, но с префиксом удаленного имени. Например, master обычно имеет origin/master в качестве восходящего потока. Однако, как в вашем примере, исходящий поток ветви не должен совпадать: исходящий поток foo может быть origin/bar.

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

Как упоминалось fphillipe , у нас есть git branch --set-upstream-to, который может установить восходящий канал любой ветви в любое время. Если уже есть какой-то восходящий набор, он заменяет его. Если не было никакого набора вверх по течению, теперь есть.

У нас также есть два разных способа создания нового имени ветви:

  • git branch <em>name</em> [<em>start-point</em>] создает новую (локальную) ветвь с именем name. Исходный хеш-идентификатор, хранящийся в этом имени, задается как start-point; если вы опустите start-point, начальный идентификатор хэша будет таким, который git rev-parse HEAD выдаст.

  • git checkout -b <em>name</em> [<em>start-point</em>] создает новую (локальную) ветвь с именем name, а затем делает git checkout этого имени, все в одном. По сути это эквивалентно запуску git branch, за которым следует git checkout.


1 "Ew, gross" ?


Цель

В этом случае вы хотите создать локальную ветвь с именем baz, установить ее хеш в соответствии с foo и установить ее восходящий поток в foo восходящий, что origin/bar. То есть после создания baz вы бы хотели:

git rev-parse baz

для получения того же результата, что и:

git rev-parse foo

- это означает, что один и тот же коммит является коммитом-наконечником каждой ветви - но вы хотите:

git rev-parse --symbolic-full-name baz@{upstream}

для производства refs/remotes/origin/bar.

Обе команды создания могут, но не всегда, также устанавливать восходящий поток недавно созданной ветви. Вы можете использовать аргумент --track, чтобы заставить их установить его, и вы можете использовать аргумент --no-track, чтобы заставить их не устанавливать его. Флаг --track использует имя удаленного слежения, поэтому, если вы сначала выясните, что восходящий поток foo равен origin/bar, вы можете написать:

git checkout -b baz origin/bar

(или то же самое с git branch, если вы не хотите также проверять новую ветку). Но это имеет две ошибки:

  • Требуется, чтобы вы вручную находили восходящий поток foo. Вы хотите автоматизировать это.
  • Возможно, более важно, он создает baz, указывая на тот же коммит, что и origin/bar. Если foo указывает на другой коммит, это нарушает одно из желаний.

HРабота должна состоять из нескольких частей. Сначала вы создадите ветку (и, если хотите, переключитесь на нее), используя локальное имя foo, чтобы установить начальную точку. И git branch, и git checkout будут не устанавливать восходящий поток новой ветви в этом случае, по крайней мере по умолчанию, но вы можете быть полностью явным с помощью --no-track, или вы можете включить foo в необработанный хэш-идентификатор. Обычно все это не нужно, 2 , но если вы хотите использовать необработанный хэш-идентификатор, вот фрагмент оболочки, чтобы сделать это:

name=baz
start=foo

hash=$(git rev-parse ${start}^{commit}) || exit

Если git rev-parse не удается выполнить синтаксический анализ foo для необработанного хеш-идентификатора или foo не идентифицирует фиксацию, git rev-parse выдаст сообщение об ошибке для stderr и выйдет с ненулевым значением, и || exit будет иметь в этот момент ваш фрагмент оболочки завершился.

Тогда:

git branch $name $hash || exit

попытается создать имя ветви $name, указывающее на нужный хеш.

Нам также нужно найти вышестоящее имя, для которого git rev-parse снова является командой для использования:

upstream=$(git rev-parse --symbolic-full-name ${start}@{upstream}) || exit

Как и прежде, у нас есть наш фрагмент оболочки, выходящий из строя, если git rev-parse не удался, позволяя git rev-parse напечатать соответствующую ошибку. Теперь, когда у нас есть восходящий поток, мы можем установить его, используя git branch --set-upstream-to:

git branch --set-upstream-to $name $upstream

2 В командной строке вы просто запускаете команду и наблюдаете: если она сделала то, что вы хотите, хорошо, если нет, вы исправляете по ходу дела. Однако из сценария часто трудно понять, что произошло или может произойти. Лучше всего использовать то, что имеет как можно меньше побочных эффектов. Поэтому мы по возможности разбиваем каждую команду Git на прямые команды. Я не довожу это до крайности, в этом примере, так как это слишком раздражает, но я покажу операции git rev-parse.


код

Объединение частей в правильном порядке, плюс небольшая проверка аргументов и использование -e, чтобы избежать всех || exit s, дает нам полный (но полностью непроверенный) сценарий оболочки:

#! /bin/sh -e

usage() {
    echo "usage: $0 branch-name start-point"
}

case "$#" in
2) ;;
*) usage 1>&2; exit 1;;
esac

name="$1"
start="$2"
hash=$(git rev-parse ${start}^{commit})
upstream=$(git rev-parse --symbolic-full-name ${start}@{upstream})
git branch $name $hash
git branch --set-upstream-to $name $upstream

После тестирования напишите его как исполняемый скрипт оболочки где-то в вашем $PATH, назвав его (например) git-branch-with-upstream, а затем:

git branch-with-upstream baz foo

вызовет скрипт, который создаст baz, указывающий на тот же коммит, что и foo, и имеющий foo в восходящем направлении как baz в восходящем.

Теперь вы знаете, как писать новые команды Git!

0 голосов
/ 16 мая 2019

Чтобы скопировать все настройки одной ветви в другую:

git config --local --get-regexp ^branch\\.$one \
| sed "s,^,git config ,;s,$one,$another," \
# | sh -x

Чтобы сделать это только для настроек remote и merge, которые вы можете получить более конкретно,

git config --local --get-regexp "^branch\\.$one\\.(remote|merge)" 

Я склонен делать это, создавая списки команд, как указано выше, другие могут предпочесть

git config --local --get-regexp "^branch\\.$one\\.(remote|merge)" \
| while read config value; do
        git config ${config/.$one./.$another.} "$value"
  done
0 голосов
/ 15 мая 2019

Посмотрите на --set-upstream-to из git branch:

git branch (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]

Из документов:

-u <upstream>, --set-upstream-to=<upstream>

Set up <branchname>'s tracking information so <upstream> is
considered <branchname>'s upstream branch. If no <branchname> is
specified, then it defaults to the current branch.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...