检查当前目录是否为Git存储库


197

我正在zsh中为Git管理编写一系列脚本。

如何检查当前目录是否为Git存储库?(当我不在Git存储库中时,我不想执行一堆命令并获得一堆fatal: Not a git repository响应)。


您是否看过bash完成文件(位于contrib / completion / git-completion.bash中)以获取灵感?我在bash提示中使用了__git_ps1命令。实际上,大多数将在zsh中提供。__gitdir函数可能是您想要的函数。
jabbie'2

1
@jabbie:你为什么不回答呢?
amarillion

您是否已经在zsh发行版中检查过功能?
MBO 2010年


1
注意:当前答案均未考虑$GIT_DIR$GIT_WORK_TREE环境变量,或它们如何相互作用。
o11c

Answers:


154

从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;

您可以将其包装在函数中或在脚本中使用。

浓缩为适合bashzsh的单行条件

[ -d .git ] && echo .git || git rev-parse --git-dir > /dev/null 2>&1

3
@William Pursell为何在不需要时进行分叉?在微不足道的情况下主要是为了提高速度。
jabbie 2010年

16
答案应该更新为使用git rev-parse --is-inside-git-dirgit rev-parse --is-inside-work-tree设置PS1之前,我个人使用过。
juliohm

11
@juliohm --is-inside-git-dir仅在您实际上位于存储库.git目录中时才返回true 。我不认为OP在寻找那个。
nyuszika7h 2014年

7
无论是--is-inside-work-tree也不--is-inside-git-dir当你是一个混帐回购协议之外会工作。请参阅:groups.google.com/forum
#!topic/git

7
如果git目录不是.git。,这将失败。为了增强鲁棒性,请省略[ -d .git ]和,然后使用git rev-parse ...
彼得·约翰·阿克兰

133

您可以使用:

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

如果您在git repos工作树中,它将显示“ true”。

请注意,如果您不在git repo之外,它仍会将输出返回到STDERR(并且不会显示“ false”)。

从此答案中获取:https : //stackoverflow.com/a/2044714/12983


这是签出的最简单方法。
calbertts

3
对于没有工作树的裸存储库,这仍将打印为false
noggin182

这不考虑子目录。我需要验证git rev-parse --show-toplevel与我正在检查的子文件夹是否匹配
Alper

选择的答案甚至没有打印出任何内容。这个工作了。
ScottyBlades

47

使用git rev-parse --git-dir

如果git rev-parse --git-dir> / dev / null 2>&1; 然后
  :#这是有效的git信息库(但当前有效
    #目录可能不是顶级目录。
    #如果需要,请检查git rev-parse命令的输出)
其他
  :#这不是git存储库
科幻


7

不确定是否有公开可访问/有文档记录的方式(有一些内部git函数可以在git源本身中使用/滥用)

你可以做类似的事情;

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

7

基于@Alex Cory的答案

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

不包含任何冗余操作,并且在-e模式下工作。

  • 正如@ go2null指出的那样,这在裸仓库中是行不通的。如果您出于某种原因想使用裸仓库,则只需检查一下git rev-parse成功,而忽略其输出。
    • 我不认为这是一个缺点,因为上面的行是为了编写脚本而设计的,并且实际上所有git命令仅在工作树中有效。因此,出于脚本目的,您最有可能不仅在“ git repo”中,而且在工作树中也很感兴趣。

这在一个裸露的git回购中失败了
go2null18年

最好不要检查输出,而是检查返回值。根本不要调用[。随便做if git rev-parse --is-inside-work-tree; then ...(根据需要进行重定向。)
William Pursell,

1
@WilliamPursell检查退出值在这里不起作用:stackoverflow.com/questions/2180270/…–
ivan_pozdeev,

@Ivan_pozdeev取决于您对“工作”的定义。在这种情况下,我会说检查返回值确实有效,而检查输出无效。无论哪种情况,从在shell中编写代码的最佳实践的角度来看,检查返回值都更合适。
威廉·普塞尔

@WilliamPursell,如果您阅读链接的注释,您将在这里知道我的意思是“不起作用”。
ivan_pozdeev,

6

另一个解决方案是检查命令的退出代码。

git rev-parse 2> /dev/null; [ $? == 0 ] && echo 1

如果您位于git资料夹文件夹中,则会显示1。


请注意,即使您位于.git目录中,该目录也将具有rc 0 ,您可能想要也可能不想要。
ivan_pozdeev

Git写得不错,所以您可以关闭不需要的文件git rev-parse 2>&-
jthill

3

该答案提供了一个示例POSIX Shell函数和一个用法示例,以补充@jabbie的答案

is_inside_git_repo() {
    git rev-parse --is-inside-work-tree >/dev/null 2>&1
}

git返回ERRORLEVEL 0如果它是一个Git仓库里面,否则返回错误级别128。(它也返回,true或者false它是否在git存储库中。)

使用范例

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

@ivan_pozdeev:如果git rev-parse --is-inside-work-tree退货truefalse一个git仓库内,而这正是该函数返回。也就是说,该功能是正确的
go2null18年

要展开,请参见答案中的描述,将从git返回的值忽略,使用的错误级别。
go2null18年

2

这对我有用。您仍然会收到错误,但是它们很容易消除。它也可以在子文件夹中使用!

git status> / dev / null 2>&1 &&回声Hello World!

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


2
也许在很多情况下都足够好,但是它在一个简单的git repo上失败了。
2015年

3
git status大/旧仓库可能非常慢。我不会将其用于此目的。
henrebotha

1

为什么不使用退出代码?如果当前目录中存在git存储库,则git branchgit tag命令返回退出代码0;否则,命令返回0。否则,将返回非零的退出代码。这样,您可以确定git存储库是否存在。简单地,您可以运行:

git tag > /dev/null 2>&1 && [ $? -eq 0 ]

优势:Flexibe。它适用于裸仓库和非裸仓库,以及sh,zsh和bash。

说明

  1. git tag:获取存储库的标签以确定是否存在。
  2. > /dev/null 2>&1:防止打印任何东西,包括正常和错误输出。
  3. [ $? -eq 0 ]:检查前一个命令是否返回了退出代码0。您可能知道,每个非零出口都意味着发生了一些不好的事情。$?获取上一个命令的退出代码[-eq然后]执行比较。

例如,您可以创建一个check-git-repo具有以下内容的文件,使其可执行并运行:

#!/bin/sh

if git tag > /dev/null 2>&1 && [ $? -eq 0 ]; then
    echo "Repository exists!";
else
    echo "No repository here.";
fi

0

#检查git repo

if [ $(git rev-parse --is-inside-work-tree) = true ]; then
    echo "yes, is a git repo"
    git pull
else
    echo "no, is not a git repo"
    git clone url --depth 1
fi

这不是最佳实践。如果在工作目录之外运行,您将在stderr上收到“致命:不是git存储库(或任何父目录):. git”,而在stdout上得到“否,不是git repo”。根本不需要在[这里调用。只需做:if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then ....
威廉·普塞尔

就我而言,我对此很满意,我想在我的日志中跟踪此故障。干杯!
Pascal Andy

0
if ! [[ $(pwd) = *.git/* || $(pwd) = *.git ]]; then 
  if type -P git >/dev/null; then
    ! git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
     printf '\n%s\n\n' "GIT repository detected." && git status
    }
  fi
fi

谢谢ivan_pozdeev,现在我可以测试一下.git目录中的代码是否将无法运行,因此不会输出任何错误或错误的退出状态。

![[$(pwd)= .git / || $(pwd)= * .git]] ”会测试您是否不在.git存储库中,它将运行git命令。内置类型命令用于检查您是否已安装git或它是否在PATH中。查看帮助类型


0

怎么回事:

if git status -s 2>/dev/null;then
    echo "this is a git repo"
else
    echo "this is NOT a git repo"
fi

-1

您可以使用一个另一个 git-prompt工具在zshrc中添加或替换$ PS1 。这样,您可以方便地得知自己是否在git repo中,并且该repo的状态为in。


3
OP的整个问题是如何从脚本中完成操作
Andrew C

怎么不能在脚本中使用__git_ps1?git-prompt的全部目的是检查当前目录的git状态,这就是所要求的。
jxqz 2014年

-1
! git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { 
  printf '%s\n\n' "GIT repository detected." && git status
}

!求反,因此即使您在不是git repo的目录中运行此命令,也不会给您带来致命错误

>的/ dev / null的2>&1将消息发送到的/ dev / null的,因为你只是退出状态之后是。的{}是用于命令分组,以便经过所述的所有命令|| 如果使用git rev-parse成功,它将运行!否定了git rev-parse的退出状态。该printf的仅仅是打印一些消息和git状态打印回购的状态。

将其包装在函数中或放入脚本中。希望这可以帮助


1
还不够 在内部.git,它将成功但可以打印false
ivan_pozdeev
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.