在Unix或GNU脚本环境(例如Linux发行版、Cygwin、OSX)中,确定当前在工作目录中签出哪个Git分支的最佳方法是什么?

这种技术的一个用途是自动标记版本(就像svnversion对Subversion所做的那样)。

请参阅我的相关问题:如何以编程方式确定Git签出是否是标记,如果是,标记的名称是什么?


我是这样做的:

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

输出如下所示:

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

这是一个解。如果您将它添加到.bashrc中,它将在控制台中显示当前分支。

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

然而,这是相当有限的。但是有一个叫做git sh的伟大项目,它正在做这些事情(甚至更多)。


这个适合我。如果您希望返回纯字符串,那么——no-color部分非常重要。

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

正确的解决方案是查看contrib/completions/git-completion。Bash在__git_ps1中为Bash提示符执行此操作。删除所有额外的内容,比如选择如何描述分离的HEAD情况,即当我们在未命名的分支上时,它是:

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

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

Git symbol -ref用于从符号引用中提取完全限定的分支名称;我们将它用于HEAD,它目前已签出分支。

替代方案可以是:

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

在最后一行中,我们处理了分离的HEAD情况,简单地使用“HEAD”来表示这种情况。


增加了11-06-2013

Junio C. Hamano (git维护者)2013年6月10日的博客文章,以编程方式检查当前分支,更详细地解释了为什么(以及如何)。


有人提到在bash中做不到三个任务…像这样混乱的控制流怎么样:

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

将接受的答案调整为Windows powershell:

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

如果您正在使用旧的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

有人觉得让Git描述你所在的分支有什么不对吗?

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

它可以在$()中使用,并且可以在Bash、Powershell、Perl等中轻松传递。如果你在提交过程中有几个分支,它不会被愚弄,如果你目前不在一个分支上,它会简单地返回“HEAD”。

或者,您可以使用

git symbolic-ref --short -q HEAD

它会给你相同的输出,但如果你是分离的,它根本不会返回任何东西。如果你想在分离时出现错误,这个选项很有用,只需要删除-q。


下面是我的解决方案,适用于PS1,或者自动标记一个版本

如果您在分支签出,您将得到分支名称。

如果你在一个刚初始化的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当前分支和颜色


我发现了两种非常简单的方法:

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

and

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

从这个答案:https://stackoverflow.com/a/1418022/605356:

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

显然适用于Git 1.6.3或更新版本。


你可以使用 git name-rev—name-only HEAD


我发现调用git相当慢(任何子命令), 特别是更新提示符。在顶级机器(raid 1, 8 gb ram, 8个硬件线程)上,回购根目录内的时间变化在0.1到0.2秒之间,而在回购外部的时间变化在0.2秒以上。不过,它确实运行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@/[^/]*$@@;
}

可能需要一些调整。


试一试:

 git symbolic-ref --short -q HEAD

或者你试着用git分支——no-color force简单的纯字符串输出:

 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";
}

Use:

branch_name=`get_branch`;
echo $branch_name;

使用——porcelain提供了一个易于解析的向后兼容输出:

Git status——branch——porcelain | grep '##' | cut -c 4-

从文档中可以看到:

瓷格式类似于短格式,但保证不会在Git版本之间或基于用户配置以向后不兼容的方式更改。这使得它非常适合通过脚本进行解析。

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


我在bash文件中使用了这个方法。

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


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

我在这里尝试最简单和最不言自明的方法:

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

如果你正在使用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状态,如

HEAD detached at v1.7.3.1

你想要发布版本,我们使用下面的命令…

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

这将返回1.7.3.1,我们在参数中替换它。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命令的参数。


结果与单行变量赋值中接受的答案相同:

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