Как прочитать текущий апстрим для ветки git

Я ищу команду git, чтобы узнать восходящий поток, связанный с существующей веткой (если есть).
(какая-то команда "read", связанная с командой "write" git branch --set-upstream-to=...)
Причина в том, что я использую ветку, связанную с несколькими удаленными репозиториями, и я хотел бы проверить, не связана ли ветка с правым восходящим потоком, прежде чем менять ее.

4 ответа

Решение

TL;DR: использовать git rev-parse

$ git rev-parse --abbrev-ref master@{u}
weird/master

Если восходящий поток не установлен, вы получите:

fatal: no upstream configured for branch 'master'

(и ненулевой код выхода). Перенаправить stderr на /dev/null чтобы отменить сообщение об ошибке, если оно вам не нужно:

if master_upstream=$(git rev-parse --abbrev-ref master@{u} 2>/dev/null); then
    master_has_upstream=true
else
    master_has_upstream=false
fi

например.

объяснение

Ответ Энтони Соттиля обычно дает вам правильное имя, но не всегда. В частности, смотрите, что происходит, когда remote.origin.fetch установка для origin это не норма

$ git init
Initialized empty Git repository in .../tmp/tt/.git/
$ git remote add origin git://github.com/git/git
$ git config remote.origin.fetch '+refs/heads/*:refs/remotes/weird/*'
$ git fetch
remote: Counting objects: 231294, done.
remote: Compressing objects: 100% (663/663), done.
remote: Total 231294 (delta 0), reused 662 (delta 0), pack-reused 230631
Receiving objects: 100% (231294/231294), 93.03 MiB | 3.54 MiB/s, done.
Resolving deltas: 100% (170261/170261), done.
From git://github.com/git/git
 * [new branch]          maint      -> weird/maint
 * [new branch]          master     -> weird/master
 * [new branch]          next       -> weird/next
 * [new branch]          pu         -> weird/pu
 * [new branch]          todo       -> weird/todo
 * [new tag]             v2.14.2    -> v2.14.2
[lots more tags snipped]

Обратите внимание, что хотя пульт называется origin, ветви удаленного отслеживания названы weird/master, weird/next, и так далее. И это на самом деле работает:

$ git checkout master
Branch master set up to track remote branch master from origin.
Already on 'master'
$ git status
On branch master
Your branch is up-to-date with 'weird/master'.

nothing to commit, working tree clean

Но что в .git/config все еще выглядит так, как вы ожидаете, если origin/master:

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

С помощью:

 branch="$(git branch | grep '\*' | cut -d' ' -f2-)"

работает достаточно хорошо (хотя часто следует использовать git symbolic-ref --short HEAD чтобы получить текущее название ветви: см. ниже).

remote="$(git config "branch.${branch}.remote")"

Эта часть работает отлично - она ​​получает имя пульта.

remote_branch="$(git config "branch.${branch}.merge" | cut -d/ -f3-)"

Это где мы идем не так. Что нам нужно, это использовать git rev-parse плюс синтаксис gitrevisions для "восходящего потока указанной ветки", который должен добавить @{u} или же @{upstream} на имя филиала. Обычно git rev-parse превращает это в хэш-идентификатор, но с --abbrev-ref, он печатает краткую версию названия или с --symbolic-full-name, он печатает длинную версию:

$ git rev-parse --symbolic-full-name master@{u}
refs/remotes/weird/master

(Я понятия не имею, почему это пишется --abbrev-ref в одном случае и --symbolic-full-name в другой.)

Обратите внимание, что при использовании git rev-parse на HEAD, если HEAD отсоединен, ответ является символом HEAD, То есть в любом репозитории Git, git rev-parse HEAD всегда удается, даже при печати символических имен. Это не верно для git symbolic-ref хоть:

$ git checkout --detach
HEAD is now at ea220ee40... The eleventh batch for 2.15
$ git rev-parse --abbrev-ref HEAD
HEAD
$ git rev-parse --symbolic-full-name HEAD
HEAD
$ git symbolic-ref HEAD
fatal: ref HEAD is not a symbolic ref

Так что для разрешения HEAD (чтобы найти текущую ветвь), выберите, какую команду использовать, основываясь на желаемом поведении в случае "нет текущей ветки".

Вот как я нашел тот же ответ, что и git status но дружественным к сценарию образом:

 $ branch="$(git branch | grep '\*' | cut -d' ' -f2-)"
 $ remote="$(git config "branch.${branch}.remote")"
 $ remote_branch="$(git config "branch.${branch}.merge" | cut -d/ -f3-)"
 $ echo "${branch} is tracking ${remote}/${remote_branch}"
 print_locking_less is tracking origin/master

Информация для удаленного отслеживания ветки хранится в .git/configэто выглядит так:

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

Просто используйте git branch -vv:

      foo    03b325f Commit on untracked branch
master b7da42b [origin/master] Initial commit

Восходящий поток (если есть) красиво отображается в квадратных скобках.

Выдержка из руководства с добавлением акцента:

-v
-vv
--verbose
В режиме списка показывать sha1 и строку темы фиксации для каждой главы, а также отношение к вышестоящей ветке (если есть). Если указано дважды, напечатайте путь к связанному рабочему дереву (если есть), а также имя вышестоящей ветки (см. также git remote show). Обратите внимание, что путь к HEAD текущего рабочего дерева не будет напечатан (это всегда будет ваш текущий каталог).

Обратите внимание, что -vvболее подробный, чем --verboseчто то же самое, что -v.

На самом деле, я нашел первый трюк, используя git status команда:
Я ветвь является текущей ветвью и есть восходящий, я получаю строку, как Your branch is up-to-date with 'the_repo/the branch'Но у меня есть более прямой способ узнать это.

Другие вопросы по тегам