Как программно определить текущую извлеченную ветку Git

В среде сценариев Unix или GNU (например, дистрибутив Linux, Cygwin, OSX), каков наилучший способ определить, какая ветвь Git в настоящее время извлекается в рабочем каталоге?

Одним из применений этой техники будет автоматическая маркировка релиза (например, svnversion будет делать с Subversion).

Пожалуйста, посмотрите также мой связанный вопрос: Как программно определить, является ли Git checkout тегом, и если да, то каково имя тега?

20 ответов

Решение

Правильное решение состоит в том, чтобы взглянуть на contrib / завершении или git-extension.bash делает это для приглашения bash в __git_ps1, Удаление всех дополнений, таких как выбор способа описания ситуации отсоединенного HEAD, т.е. когда мы находимся в неназванной ветви, это:

branch_name="$(git symbolic-ref HEAD 2>/dev/null)" ||
branch_name="(unnamed branch)"     # detached HEAD

branch_name=${branch_name##refs/heads/}

git symbolic-ref используется для извлечения полного имени ветви из символической ссылки; мы используем его для HEAD, который в настоящее время проверен филиал.

Альтернативное решение может быть:

branch_name=$(git symbolic-ref -q HEAD)
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD}

где в последней строке мы имеем дело с ситуацией отсоединенного HEAD, используя просто "HEAD" для обозначения такой ситуации.


Добавлено 06.11.2013

В блоге Junio ​​C. Hamano (git keeper), посвященном программной проверке текущей ветки от 10 июня 2013 года, объясняется, почему (и как) более подробно.

Кто-нибудь видит что-то не так, просто попросив Git описать ветку, в которой вы находитесь?

git rev-parse --symbolic-full-name --abbrev-ref HEAD

Это можно использовать в $() и легко передавать в Bash, Powershell, Perl и т. Д. Это не обманывает, если у вас есть несколько веток на коммите, на котором вы находитесь, и если вы в данный момент не находитесь на ветке, это просто отвечает "ГОЛОВА".

Кроме того, вы можете использовать

git symbolic-ref --short -q HEAD

Который даст вам тот же результат, но он ничего не вернет, если вы отстранены. Это полезно, если вы хотите, чтобы при отсоединении возникла ошибка, просто удалите -q.

Ты можешь использовать git name-rev --name-only HEAD

Из этого ответа: /questions/36505409/pokazat-tolko-tekuschuyu-vetku-v-git/36505433#36505433:

$ git rev-parse --abbrev-ref HEAD
master

Видимо работает с Git 1.6.3 или новее.

Попробуйте с:

 git symbolic-ref --short -q HEAD

Или вы пытаетесь с git branch с --no-color заставить простую простую строку вывести:

 git branch  --no-color

С grep в режиме регулярных выражений (-E) вы можете проверить, существует ли символ '*':

 git branch  --no-color  | grep -E '^\*' 

Результаты его похожи на:

* currentBranch

Вы можете использовать следующие параметры:

sed 's/\*[^a-z]*//g'
cut -d ' ' -f 2
awk '{print $2}'

например:

 git branch  --no-color  | grep -E '^\*' | sed 's/\*[^a-z]*//g'
 git branch  --no-color  | grep -E '^\*' | sed cut -d ' ' -f 2
 git branch  --no-color  | grep -E '^\*' | awk '{print $2}'

если существует ошибка, вы не можете использовать значение по умолчанию:

  cmd || echo 'defualt value';

Все в функции bash:

function get_branch() {
      git branch --no-color | grep -E '^\*' | awk '{print $2}' \
        || echo "default_value"
      # or
      # git symbolic-ref --short -q HEAD || echo "default_value";
}

Использование:

branch_name=`get_branch`;
echo $branch_name;

Этот работал для меня в файле Bash.

git branch | grep '^*' | sed 's/* //'  


################bash file###################
#!/bin/bash
BRANCH=$(git branch | grep '^*' | sed 's/* //' )
echo $BRANCH

Адаптация принятого ответа к Windows PowerShell:

Split-Path -Leaf (git symbolic-ref HEAD)

Вот что я делаю:

git branch | sed --quiet 's/* \(.*\)/\1/p'

Вывод будет выглядеть так:

$ git branch | sed --quiet 's/* \(.*\)/\1/p'
master
$

Этот работает для меня. --no-color part важен или может быть важен, если вы хотите вернуть простую строку.

git branch --no-color | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'

Я пытаюсь найти самый простой и понятный способ:

git status | grep "On branch" | cut -c 11-

Использование --porcelain позволяет легко анализировать обратно-совместимые выходные данные:

git status --branch --porcelain | grep '##' | cut -c 4-

Из документации:

Фарфоровый формат подобен короткому формату, но гарантированно не изменится обратно-несовместимым способом между версиями Git или в зависимости от конфигурации пользователя. Это делает его идеальным для анализа скриптами.

https://git-scm.com/docs/git-status

Я нашел два действительно простых способа сделать это:

$ git status | head -1 | cut -d ' ' -f 4

а также

$ git branch | grep "*" | cut -d ' ' -f 2

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

branch_name=$((git symbolic-ref HEAD 2>/dev/null || echo "(unnamed branch)")|cut -d/ -f3-)

Вот мое решение, подходящее для использования в PS1 или для автоматической маркировки релиза

Если вы проверены в филиале, вы получите название филиала.

Если вы находитесь в проекте initit git, вы просто получаете '@'

Если вы без головы, вы получите хорошее человеческое имя относительно какой-либо ветви или тега, с символом "@" перед именем.

Если вы без головы и не являетесь предком какой-либо ветви или тега, вы просто получаете короткий SHA1.

function we_are_in_git_work_tree {
    git rev-parse --is-inside-work-tree &> /dev/null
}

function parse_git_branch {
    if we_are_in_git_work_tree
    then
    local BR=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD 2> /dev/null)
    if [ "$BR" == HEAD ]
    then
        local NM=$(git name-rev --name-only HEAD 2> /dev/null)
        if [ "$NM" != undefined ]
        then echo -n "@$NM"
        else git rev-parse --short HEAD 2> /dev/null
        fi
    else
        echo -n $BR
    fi
    fi
}

Вы можете удалить if we_are_in_git_work_tree немного, если хотите; Я просто использую его в другой функции в моей PS1, которую вы можете посмотреть здесь полностью: строка PS1 с текущей веткой git и цветами

Если вы используете старую командную строку NT, вы можете использовать следующее:

@for /f "usebackq" %i in (`git symbolic-ref -q HEAD`) do @echo %~ni

Чтобы использовать в командном файле, вам придется удвоить%:

@for /f "usebackq" %%i in (`git symbolic-ref -q HEAD`) do @echo %%~ni

Кто-то упоминал, что делает это в bash менее чем с тремя назначениями... как насчет некоторого грязного потока управления, подобного этому:

branch_name="$(b=$(git symbolic-ref -q HEAD); { [ -n "$b" ] && echo ${b##refs/heads/}; } || echo HEAD)"

Если вы используете Gradle,

`` `

def gitHash = new ByteArrayOutputStream()    
project.exec {
                commandLine 'git', 'rev-parse', '--short', 'HEAD'
                standardOutput = gitHash
            }

def gitBranch = new ByteArrayOutputStream()   
project.exec {
                def gitCmd = "git symbolic-ref --short -q HEAD || git branch -rq --contains "+getGitHash()+" | sed -e '2,\$d'  -e 's/\\(.*\\)\\/\\(.*\\)\$/\\2/' || echo 'master'"
                commandLine "bash", "-c", "${gitCmd}"
                standardOutput = gitBranch
            }

`` `

Я обнаружил, что вызов git довольно медленный (любая из подкоманд), особенно для обновления приглашения. Время варьируется от 0,1 до 0,2 секунды в корневом каталоге репо и более 0,2 секунды вне репо на высококлассном компьютере (рейд 1, оперативная память 8 Гб, 8 аппаратных потоков). Тем не менее, он запускает Cygwin.

Поэтому я написал этот скрипт для скорости:

#!/usr/bin/perl

$cwd=$ENV{PWD}; #`pwd`;
chomp $cwd;

while (length $cwd)
{
        -d "$cwd/.git" and do {
                -f "$cwd/.git/HEAD" and do {
                        open IN, "<", "$cwd/.git/HEAD";
                        $_=<IN>;
                        close IN;
                        s@ref: refs/heads/@@;
                        print $_;
                };
                exit;
        };

        $cwd=~s@/[^/]*$@@;
}

Может понадобиться немного подправить.

Это одно решение. Если вы добавите его в ваш.bashrc, он отобразит текущую ветку в консоли.

# git branch
parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1) /'
}
$PS1="\$(parse_git_branch)$PS1"

Однако это довольно ограничено. Но есть отличный проект под названием git sh, который делает именно это (и многое другое).

Если у вас отдельная голова (то есть вы вынули релиз) и у вас есть выход из состояния git, например:

HEAD detached at v1.7.3.1

И вы хотите версию выпуска, мы используем следующую команду...

git status --branch | head -n1 | tr -d 'A-Za-z: '

Это возвращает 1.7.3.1, который мы заменим в нашем parameters.yml (Symfony) на

# RevNum=`svn status -u | grep revision | tr -d 'A-Za-z: '`  # the old SVN version
RevNum=`git status --branch | head -n1 | tr -d 'A-Za-z: '` # Git (obvs)

sed -i "/^    app_version:/c\    app_version:$RevNum" app/config/parameters.yml

Надеюсь, это поможет:) Очевидно, что если в имени вашей ветки есть нечисловые значения, вам необходимо изменить аргументы команды tr.

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