git: программно знать, насколько ветка впереди / позади удаленной ветки - PullRequest
45 голосов
/ 03 июня 2010

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

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

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

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

  1. Как узнать удаленную отслеживаемую ветку? Это часто origin/branch, но не обязательно.
  2. Как получить цифры? Как узнать, впереди / позади? На сколько коммитов? А как обстоят дела с разветвленной ветвью?

Ответы [ 9 ]

22 голосов
/ 04 июня 2010

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

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

Если обе команды показывают коммиты, значит, у вас разошлись ветви.

18 голосов
/ 04 июня 2010

обновление

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

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.

11 голосов
/ 04 июня 2010

Вы можете попробовать 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.

7 голосов
/ 01 ноября 2012

Изменить: Мой первоначальный ответ был на самом деле не очень хорошим, потому что он полагался на пользователя, у которого был пульт, называемый «происхождение». Это также не удавалось, если бы у текущей ветви была отслеживающая ветвь кроме origin-head. Эти недостатки по существу сделали его бесполезным. Однако ответ @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 голосов
/ 13 декабря 2013

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

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

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

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

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

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

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

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

5 голосов
/ 19 августа 2013

git status имеет опцию --porcelain, предназначенную для анализа сценариями. Он основан на выводе --short - они практически идентичны на момент написания (подробности см. В разделе «Формат фарфора» справочной страницы git status). Основное отличие состоит в том, что --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 ).

2 голосов
/ 04 июня 2012

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

#!/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 
1 голос
/ 09 июня 2015

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

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

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

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

Подробнее на " Просмотр невыгруженных Git Commits "

1 голос
/ 28 ноября 2011

Верхняя часть кода в ответе 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) и опубликовал их в моем репозитории git-config на github . Например, вот мой git-compare-upstream . См. README для инструкций по установке и других полезных связанных скриптов.

...