检查当前目录是否为Git仓库

327
我正在为zsh编写Git管理脚本。如何检查当前目录是否是Git存储库?(当我不在Git存储库中时,我不想执行一堆命令并得到一堆“fatal: Not a git repository”响应)。

你是否看过bash完成文件(在contrib / completion / git-completion.bash中)以获取灵感?我在我的bash提示符中使用__git_ps1命令。实际上,大部分都将在zsh中源代码。 __gitdir函数可能是您想要的函数。 - jabbie
3
为什么不把那个作为一个回答呢? - amarillion
你已经检查过 zsh 发行版中的函数了吗? - MBO
1
可能是重复的问题:确定目录是否受Git控制 - Ciro Santilli OurBigBook.com
1
请注意:目前的回答都没有考虑到 $GIT_DIR$GIT_WORK_TREE 环境变量,以及它们之间的交互。 - o11c
13个回答

268

您可以使用:

git rev-parse --is-inside-work-tree

如果您在git仓库的工作树中,它将向STDOUT打印'true'。
请注意,如果您不在git仓库外,它仍会返回输出到STDERR(并且不会打印'false')。
摘自以下答案:https://dev59.com/y3I-5IYBdhLWcg3wCzpn#2044714

这是检查它的最简单方式。 - calbertts
12
对于没有工作树的裸仓库,这仍将打印出 false。 - noggin182
1
这不考虑子目录。我需要验证 git rev-parse --show-toplevel 是否与我正在检查的子文件夹匹配。 - alper
1
我们能否像William Pursell的回答那样做一些类似于if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then的事情? - alper
1
@ScottyBlades 在这个情境中,我会认为这意味着所选答案在其退出状态中报告结果并有意不打印任何内容,以便更直接/易于在shell脚本中使用。 难道不是这种情况吗? - mtraceur
显示剩余2条评论

209

从bash补全文件中复制,以下是一种朴素的方法

# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
# Distributed under the GNU General Public License, version 2.0.

if [ -d .git ]; then
  echo .git;
else
  git rev-parse --git-dir 2> /dev/null;
fi;
你可以将其封装在函数中或在脚本中使用。适用于和zsh的一行条件语句。
[ -d .git ] && echo .git || git rev-parse --git-dir > /dev/null 2>&1

5
为什么不需要分叉时还要分叉?主要是为了在简单情况下提高速度。 - jabbie
26
答案应更新为使用 git rev-parse --is-inside-git-dir。在设置我的 PS1 之前,我个人使用 git rev-parse --is-inside-work-tree - juliohm
21
--is-inside-git-dir 只有在你实际处于存储库的 .git 目录内部时才会返回真。我认为发帖者不是在寻找这个。 - alexia
10
当你不在一个 Git 仓库中时,--is-inside-work-tree--is-inside-git-dir 都无法工作。参见:https://groups.google.com/forum/#!topic/git-users/dWc23LFhWxE。 - fisherwebdev
14
如果git目录不是.git,那么这将失败。为了提高健壮性,请省略[ -d .git ]并使用git rev-parse ... - Peter John Acklam
显示剩余9条评论

72

使用 git rev-parse --git-dir

if git rev-parse --git-dir > /dev/null 2>&1; then
  : # This is a valid git repository (but the current working
    # directory may not be the top level.
    # Check the output of the git rev-parse command if you care)
else
  : # this is not a git repository
fi

编辑:git-rev-parse现在(自1.7.0起)支持--show-toplevel,因此您可以执行 if test "$(pwd)" = "$(git rev-parse --show-toplevel)"来确定当前目录是否为最顶层的目录。


> /dev/null 2>&1 是一个常见的 Linux 命令,用于将标准输出和标准错误输出重定向到 /dev/null 设备文件中,从而防止它们在终端上显示。这通常用于在后台运行命令或脚本时抑制输出。 - M Imam Pratama
@MImamPratama > /dev/null 将标准输出重定向到位桶。2>&1 将标准错误输出发送到相同的位置。 - William Pursell
--show-toplevel 真的解决了我的问题!非常感谢。 - Eyal Gerber
为什么 2> /dev/null 不起作用? - ocodo
1
@ocodo:git rev-parse --is-inside-work-tree 会将“true”或“false”打印到标准输出(stdout)。它会将错误消息(例如“fatal: not a git repository”)打印到标准错误(stderr)。 - William Pursell
显示剩余5条评论

36

或者你可以这样做:

inside_git_repo="$(git rev-parse --is-inside-work-tree 2>/dev/null)"

if [ "$inside_git_repo" ]; then
  echo "inside git repo"
else
  echo "not in git repo"
fi

3
我喜欢这个,因为它也可以在子目录中工作。 - joehanna
6
-e模式下不要进行冗余操作和作业:[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" == "true" ],该命令用于检查当前目录是否为Git仓库。 - ivan_pozdeev

21

根据@Alex Cory的回答:

[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]

该操作不包含任何冗余步骤,并在-e模式下运行。

  • 正如@go2null所指出的,这将无法在裸仓库中工作。如果您想以任何原因使用裸仓库,只需检查git rev-parse是否成功,忽略其输出即可。
    • 我不认为这是一个缺点,因为上面的代码行旨在用于脚本编写,而几乎所有的git命令都仅在工作树内有效。因此,对于脚本编写目的,您最有可能关心的是不仅在“git repo”内部,而且还在工作树内部。

1
这在裸的 git 仓库内会失败。 - go2null
4
与其检查输出,最好的做法是检查返回值。完全不要调用 [ 。只需执行 if git rev-parse --is-inside-work-tree; then ... (根据需要进行重定向)。 - William Pursell
1
@WilliamPursell 在这里检查退出值不起作用:https://dev59.com/6XI95IYBdhLWcg3wtwf4#1vQkoYgBc1ULPQZF178o - ivan_pozdeev
2
@Ivan_pozdeev 取决于你对“工作”的定义。在这种情况下,我会说检查返回值是有效的,而检查输出则不是。无论哪种情况,从编写shell代码的最佳实践的角度来看,检查返回值更为合适。 - William Pursell
1
@ivan_pozdeev 谢谢,但请注意即使在Linux下,也不是所有用户都使用bash(在zsh中==也无效)。 - vinc17
显示剩余3条评论

9
这个答案提供了一个示例 POSIX shell 函数和一个使用示例,以补充 @jabbie 的 回答
is_inside_git_repo() {
    git rev-parse --is-inside-work-tree >/dev/null 2>&1
}

git在Git仓库内返回错误级别0,否则返回错误级别128。(如果在Git仓库中,它还会返回truefalse。)

用法示例

for repo in *; do
    # skip files
    [ -d "$repo" ] || continue
    # run commands in subshell so each loop starts in the current dir
    (
        cd "$repo"
        # skip plain directories
        is_inside_git_repo || continue
        printf '== %s ==\n' "$repo"
        git remote update --prune 'origin' # example command
        # other commands here
    )
done

不够完整。在 .git 内部,它会成功但打印 false - ivan_pozdeev
1
如果 git rev-parse --is-inside-work-tree 返回 truefalse,那么它 就在 git 存储库内,这就是该函数的返回值。也就是说,该函数是正确的 - go2null
1
要进行扩展,请查看答案中的描述,忽略从git返回的值,使用errorlevel。 - go2null

9

不确定是否存在公开可访问/文档化的方法来实现此操作(在git源代码中有一些可以使用/滥用的内部git函数)

你可以尝试如下操作:

if ! git ls-files >& /dev/null; then
  echo "not in git"
fi

8
为什么不使用退出代码呢?如果当前目录中存在git存储库,则git branchgit tag命令将返回0的退出代码(即使没有标签或分支);否则,将返回非零退出代码。这样,您就可以确定git存储库是否存在。简单地说,您可以运行:
git tag > /dev/null 2>&1

优点:便携。它适用于裸库和非裸库,并且在sh、zsh和bash中都可以使用。

说明

  1. git tag:获取存储库的标签以确定是否存在。
  2. > /dev/null 2>&1:防止打印任何内容,包括正常和错误输出。

简而言之 (Really?!):check-git-repo

例如,您可以创建一个名为check-git-repo的文件,其中包含以下内容,使其可执行并运行:

#!/bin/sh

if git tag > /dev/null 2>&1; then
    echo "Repository exists!";
else
    echo "No repository here.";
fi

1
&& [ $? -eq 0 ] 是多余的,特别是如果你已经在一个 if 中了。 - mtraceur
1
即使没有标签,git tag 命令是否有效? - jave.web
1
@jave.web,是的。谢谢提醒,已添加为附注。 - MAChitgarha

7
另一个解决方案是检查命令的退出代码。
git rev-parse 2> /dev/null; [ $? == 0 ] && echo 1

如果您处于git仓库文件夹中,这将打印1。

1
请注意,即使您在.git目录内部,此命令也将返回rc 0 -- 这可能是您想要的,也可能不是。 - ivan_pozdeev
1
Git的编写非常合理,因此您可以关闭不需要的文件,git rev-parse 2>&- - jthill
2
这里的 [ $? == 0 ] 是多余的;因为 && 已经隐含了测试。上述命令等同于 git rev-parse 2>/dev/null && echo 1 - Deven T. Corzine
[ $? == 0 ] 并不完全多余。如果你正在使用支持 ==[ 版本,那么它与 git rev-parse 2> /dev/null && echo 1 是完全等价的。但是如果你正在使用不认识 ==[ 版本,则这个版本就是一个错误。 - William Pursell

3
这对我来说很有效。你仍然会收到错误提示,但它们很容易被忽略。而且它也可以在子文件夹中使用!
git status >/dev/null 2>&1 && echo Hello World!

你可以将这个放在 if then 语句中,如果需要有条件地执行更多操作。

3
在许多情况下可能足够好,但是在裸的 git 仓库中会失败。 - Wildcard
7
在大型/旧版存储库上,"git status"可能非常缓慢。我不建议用它来达到这个目的。 - henrebotha
@henrebotha 我完全同意,而且我仍在这样做,因为我无论如何都需要处理输出:git_status="$(git status --porcelain --branch 2> /dev/null)"; if [ $? -eq 0 ]; then echo something with $git_status; fi - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接