Подтвердить что ты не робот

Git: программно знать, насколько ветка впереди/за удаленной ветвью

Я хотел бы извлечь информацию, напечатанную после git status, которая выглядит так:

# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.

Конечно, я могу разобрать вывод git status, но это не рекомендуется, так как этот человекочитаемый вывод может измениться.

Есть две проблемы:

  • Как узнать удаленную удаленную ветку? Это часто бывает origin/branch, но не обязательно.
  • Как получить номера? Как узнать, впереди? На сколько коммит? А как насчет случая с расходящимся ветвлением?
4b9b3361

Ответ 1

Обновление

Как отмечалось в amalloy, последние версии git поддерживают поиск соответствующей ветки отслеживания для данной ветки, предоставляя "branchname @{upstream}" (или "branchname @{u}" или "@{u}" для ветки отслеживания HEAD). Это эффективно отменяет script ниже. Вы можете сделать:

git rev-list @{u}..
git rev-list --left-right --boundary @{u}...
gitk @{u}...

и т.д.. Например, у меня git q с псевдонимом git log --pretty='...' @{u}.., чтобы показать, что я "поставил в очередь", готов к нажатию.

оригинальный ответ

Кажется, нет простого способа найти ветку отслеживания вообще, без синтаксического анализа большего количества git config, чем это практично в нескольких командах оболочки. Но для многих случаев это будет иметь большое значение:

# work out the current branch name
currentbranch=$(expr $(git symbolic-ref HEAD) : 'refs/heads/\(.*\)')
[ -n "$currentbranch" ] || die "You don't seem to be on a branch"
# look up this branch in the configuration
remote=$(git config branch.$currentbranch.remote)
remote_ref=$(git config branch.$currentbranch.merge)
# convert the remote ref into the tracking ref... this is a hack
remote_branch=$(expr $remote_ref : 'refs/heads/\(.*\)')
tracking_branch=refs/remotes/$remote/$remote_branch
# now $tracking_branch should be the local ref tracking HEAD
git rev-list $tracking_branch..HEAD

Другой, более грубый, подход:

git rev-list HEAD --not --remotes

Ответ jamessan объясняет, как найти относительные различия между $tracking_branch и HEAD, используя git rev-list. Одна забавная вещь, которую вы можете сделать:

git rev-list --left-right $tracking_branch...HEAD

(обратите внимание на три точки между $tracking_branch и HEAD). Это будет показывать фиксации на обоих "плечах" с отличительным знаком спереди: "<" для фиксации на $tracking_branch и " > " для фиксации на HEAD.

Ответ 2

git rev-list origin..HEAD покажет коммиты, которые находятся в вашей текущей ветки, но не происхождение - то есть, превысите ли вы начало и по каким-то причинам.

git rev-list HEAD..origin покажет обратное.

Если обе команды показывают фиксации, то у вас есть расходящиеся ветки.

Ответ 3

Вы можете попробовать git branch -v -v. Если флаг -v задан дважды, он выводит имена ветвей вверх по течению. Пример вывода:

* devel  7a5ff2c [origin/devel: ahead 1] smaller file status overlay icons
  master 37ca389 [origin/master] initial project check-in.

Я думаю, что этот формат более стабилен, чем git status.

Ответ 4

Edit: Мой первоначальный ответ на самом деле был не очень хорошим, потому что он полагался на пользователя, чтобы иметь удаленный вызов "происхождение". Он также потерпел неудачу, если в текущей ветке была ветвь отслеживания, кроме начального. Эти недостатки по существу сделали это бесполезным. Однако ответ @araqnid не самый эффективный метод, и способ, которым он достигает $tracking_branch, меньше, чем прорыв вперед. Самый эффективный (самый быстрый) метод, который я нашел, чтобы получить ту же функциональность, следующий:

# get the tracking-branch name
tracking_branch=$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))
# creates global variables $1 and $2 based on left vs. right tracking
# inspired by @adam_spiers
set -- $(git rev-list --left-right --count $tracking_branch...HEAD)
behind=$1
ahead=$2

оригинальный ответ: (нижний, но данный для ясности)

Возможно, самый простой способ, который я мог найти (вдохновленный @insidepower)

# count the number of logs
behind=$(git log --oneline HEAD..origin | wc -l)
ahead=$( git log --oneline origin..HEAD | wc -l)

Ранее я использовал метод @araqnid, но теперь я думаю, что я перенесу некоторые из своих сценариев в этот метод, поскольку он намного проще. Это должно работать в любой системе unix.

Ответ 5

git status имеет параметр --porcelain, предназначенный для синтаксического анализа по сценариям. Он основан на выходе --short - они почти идентичны на момент написания (см. Раздел "Формат фарфора" на странице состояния git). Основное отличие состоит в том, что --short имеет цветной выход.

По умолчанию не отображается информация о филиале, но если вы добавите опцию --branch, вы получите вывод, например:

git status --short --branch
## master...origin/master [ahead 1]
?? untrackedfile.txt
...

Если вы устарели (после выборки), линия ветвления будет только:

## master

Если вы впереди:

## master...origin/master [ahead 1]

Если вы позади:

## master...origin/master [behind 58]

И для обоих:

## master...origin/master [ahead 1, behind 58]

Обратите внимание, что git status --porcelain --branch доступен только в 1.7.10.3 или позже (хотя git status --short --branch доступен с 1.7.2).

Ответ 6

В современных версиях git, @{u} указывает на верхнюю часть текущей ветки, если она установлена.

Итак, чтобы подсчитать, сколько задержек вы находитесь за ветвью удаленного отслеживания:

git rev-list [email protected]{u} | wc -l

И чтобы увидеть, как далеко вы далеко от пульта, просто переключите порядок:

git rev-list @{u}..HEAD | wc -l

Для более удобного для чтения резюме вы можете запросить вместо него журнал:

git log --pretty=oneline @{u}..HEAD

В моих собственных целях я работаю над script, который заменит @{u} на соответствующую догадку, если восходящий поток еще не установлен. К сожалению, в это время нет @{d} для представления нисходящего потока (куда вы нажимаете).

Ответ 7

Верхняя часть кода в ответе araqnid не работает для меня, поэтому, возможно, что-то в git изменилось с тех пор, как было написано 18 месяцев назад. Он работает, если я меняю:

tracking_branch=refs/remotes/$remote/$remote_branch

к

tracking_branch=$remote/$remote_branch

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

tracking_branch=${tracking_branch#./}

Затем вы можете программно получить количество ревизий позади и вперед следующим образом:

set -- `git rev-list --left-right --count $tracking_branch...HEAD`
behind="$1"
ahead="$2"

Я написал сценарии, чтобы сделать все это (и многое другое - например, они также могут попытаться обнаружить удаленные объекты на другой стороне моста git -svn) и опубликовать их в my git -config репозиторий в github. Например, здесь git-compare-upstream. См. README для инструкций по установке и других удобных скриптов.

Ответ 8

Почему бы не работать:

#!/bin/sh
git diff origin/master..HEAD --quiet --exit-code
RETVAL=$?
if [ $RETVAL -gt 0 ]; then
    echo "You need to git push!"
else
    echo "No git push necessary!"
fi 

Ответ 9

Как узнать удаленную удаленную ветку? Это часто origin/branch, но не обязательно.

Git 2.5+ вводит новый ярлык, который ссылается на ветку, на которую вы нажимаете. @{push}: это будет ветвь удаленного отслеживания, которая здесь представляет интерес.

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

git for-each-ref --format="%(push:track)" refs/heads

Подробнее в разделе Просмотр Unpushed Git Commits"