【问题标题】:How to programmatically determine the current checked out Git branch [duplicate]如何以编程方式确定当前签出的 Git 分支 [重复]
【发布时间】:2010-12-08 06:16:08
【问题描述】:

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

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

另请参阅我的相关问题:How to programmatically determine whether a Git checkout is a tag, and if so what is the tag name?

【问题讨论】:

标签: git bash shell


【解决方案1】:

这是我的工作:

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

输出如下所示:

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

【讨论】:

  • git-branch 是 porcelain(用户界面)命令,其输出不应在脚本中使用
  • 不适用于我的 MacOS 10.6.8 系统。
  • 使用 git-branch 非常糟糕。但是如果你喜欢 sed 你可以做的更简单:) git branch | sed -n "/\*/ s/.* // p"
【解决方案2】:

这是一种解决方案。如果将其添加到 .bashrc,它将在控制台中显示当前分支。

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

但是它非常有限。但是有一个很棒的项目叫做git sh,它就是这样做的(还有更多)。

【讨论】:

  • 哇,这太疯狂了。这正是我在 .bashrc 中的代码。我缩短了它以使用 GNU sed 选项,我一直在想,这看起来不像我的代码。我很好奇,您发布的代码是从某种公开示例中发布的吗?
  • 另外 +1 是因为,虽然我没有测试过,但我很确定您的答案与 GNU 不兼容,因此它可能在 Darwin、Solaris 等平台上更受欢迎。
  • 这段代码来自 GitHub:github.com/guides/put-your-git-branch-name-in-your-shell-prompt 我只在 Darwin 和 Ubuntu 上使用过。它对他们俩都有效。
  • git-branch 是 porcelain(用户界面)命令,其输出不应在脚本中使用
【解决方案3】:

这个对我有用。 --no-color 部分很重要,或者可以很重要,如果你想要一个简单的字符串返回。

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

【讨论】:

  • git-branch 是 porcelain (用户界面)命令,其输出不应在脚本中使用。尽管您会因“--no-color”而获得奖励积分。
  • 输出连接到管道时不产生颜色,尝试:git branch | cat
  • @Thor 取决于您对 git config color.branch 的值...
【解决方案4】:

正确的解决方案是查看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 symbolic-ref 用于从符号引用中提取完全限定的分支名称;我们将它用于 HEAD,目前已签出分支。

替代解决方案可能是:

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

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


添加于 2013 年 11 月 6 日

Junio C. Hamano(git 维护者)博客文章 Checking the current branch programatically,自 2013 年 6 月 10 日起更详细地解释了为什么(以及如何)。

【讨论】:

  • 不要使用cat .git/refs/heads/branch;使用git rev-parse --verify refs/heads/branch。 Refs 可以打包cat 的解决方案会失败。​​
  • 对所有 bash 字符串艺术家来说都是一个挑战:当然 一定有一个很好的方法可以在少于三个变量分配的情况下做到这一点? :-D
  • @conny git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3 应该可以一次性得到你的分支名称
  • @Thr4wn 它删除(修剪)字符串的开头,在此处从 $branch_name 字符串值中删除 'refs/heads/'。见thegeekstuff.com/2010/07/bash-string-manipulationtldp.org/LDP/abs/html/string-manipulation.html
  • 从 Git 1.7.10 开始,您可以将 --short 选项指定为 git-symbolic-ref,这会在输出中为您删除 refs/heads
【解决方案5】:

有人提到在 bash 中完成的任务少于三个......像这样的一些混乱的控制流怎么样:

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

【讨论】:

    【解决方案6】:

    将接受的答案改编为 windows powershell:

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

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        有人认为让 Git 描述你所在的分支有什么问题吗?

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

        这可以在 $() 中使用,并且可以在 Bash、Powershell、Perl 等中轻松传递。如果您在提交时有多个分支,并且当前不在分支上,则不会被愚弄,它只是简单地回复“HEAD”。

        或者,您可以使用

        git symbolic-ref --short -q HEAD
        

        这将为您提供相同的输出,但如果您被分离,它根本不会返回任何内容。如果你想在分离时出错,这个很有用,只需删除 -q。

        【讨论】:

        • 抱歉,我猜 synbolic-ref 的 --short 选项仅在 Git 1.7.10 (MSYS) 中可用。第二个选项不适用于 1.7.9 (CygWin)。
        • 你将如何使用命令git rev-parse --symbolic-full-name --abbrev-ref HEAD 并将其放入 bash 的 PS1 变量或 csh 的提示符中?
        • 对于 PowerShell,我只使用: function Git-GetCurrentBranch() { return (&$git rev-parse --symbolic-full-name --abbrev-ref HEAD) } 其中 $git 是我的 Git.exe 的路径
        • 为什么需要--symbolic-full-name
        【解决方案9】:

        这是我的解决方案,适合在 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 line with git current branch and colors

        【讨论】:

          【解决方案10】:

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

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

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

          【讨论】:

          • 我不确定第一个命令(例如,似乎不适用于 Git 2.11.1 / MacOS),但第二个命令有效。
          【解决方案11】:

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

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

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

          【讨论】:

          • 如果你处于分离的头部状态它不起作用。
          • @Eimantas - 它只是在我的系统上以分离的头部状态打印“HEAD”:gist.github.com/johnnyutahh/2f4db5c755bc032b106b。你在运行 Git >= 1.6.3 吗?
          • 我喜欢这个答案,因为它适用于旧版本的 git,而不是接受的答案。谢谢。
          【解决方案12】:

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

          【讨论】:

          • 如果 HEAD 被标记,这将输出标记,而不是分支名称
          • 另外,如果多个分支指向同一个提交,这可能会返回错误的分支。
          【解决方案13】:

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

          可能需要一些调整。

          【讨论】:

          • 发帖已经5年了,git快了很多。我只是在 bash 中运行了一个循环,比 git rev-parse --abbrev-ref HEAD 运行了 1000 次,并且 git 命令快了 ~2.5 倍(!)[git 2.17 vs perl 5.18,macOS]
          【解决方案14】:

          尝试:

           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;
          

          【讨论】:

            【解决方案15】:

            使用 --porcelain 可提供易于解析的向后兼容输出:

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

            来自文档:

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

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

            【讨论】:

              【解决方案16】:

              这个在 bash 文件中对我有用。

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

              【讨论】:

              • ^* 应该被引用以避免被扩展,即 git branch | grep '^*' | sed 's/* //'
              • @MingjiangShi 感谢您的建议。我已经更新了答案
              【解决方案17】:

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

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

              【讨论】:

              • git status : 它刷新索引,所以这个解决方案会导致性能不佳
              【解决方案18】:

              如果你使用的是 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
                          }
              

              ```

              【讨论】:

              • 这解决了所有情况,包括分离模式。太好了~~~~!
              【解决方案19】:

              如果你处于一个分离的头上(即你已经签出了一个版本)并且有来自 git status 的输出,例如

              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 命令的参数。

              【讨论】:

                【解决方案20】:

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

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

                【讨论】:

                • 保持简单:branch_name=`git rev-parse --abbrev-ref HEAD`
                • 如果 repo 没有提交则不起作用
                猜你喜欢
                • 2014-04-20
                • 1970-01-01
                • 1970-01-01
                • 2021-08-02
                • 1970-01-01
                • 2011-02-27
                • 2010-12-19
                相关资源
                最近更新 更多