323

I am writing a series of scripts for Git management in zsh.

How do I check if the current directory is a Git repository? (When I'm not in a Git repo, I don't want to execute a bunch of commands and get a bunch of fatal: Not a git repository responses).

Marlon Richert
  • 5,250
  • 1
  • 18
  • 27
anon
  • 41,035
  • 53
  • 197
  • 293
  • Have you looked at the bash completion file (in contrib/completion/git-completion.bash ) for inspiration? I use the __git_ps1 command as part of my bash prompt. In fact most of it will source within zsh. The __gitdir function is probably the one you want. – jabbie Feb 01 '10 at 21:49
  • 3
    @jabbie: why don't you make that an answer? – amarillion Feb 01 '10 at 21:52
  • 1
    possible duplicate of [Determine if directory is under git control](http://stackoverflow.com/questions/2044574/determine-if-directory-is-under-git-control) – Ciro Santilli OurBigBook.com Dec 12 '14 at 19:50
  • 1
    Note: none of the current answers consider the `$GIT_DIR` or `$GIT_WORK_TREE` environment variables, or how they interact. – o11c Dec 17 '18 at 05:27
  • Have you checked functions already in zsh distribution? – MBO Feb 04 '10 at 18:57

13 Answers13

259

You can use:

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

Which will print 'true' to STDOUT if you are in a git repos working tree.

Note that it still returns output to STDERR if you are outside of a git repo (and does not print 'false').

Taken from this answer: https://stackoverflow.com/a/2044714/12983

ocodo
  • 29,401
  • 18
  • 105
  • 117
TM.
  • 108,298
  • 33
  • 122
  • 127
  • This is te simplest way to check it out. – calbertts Apr 14 '17 at 15:27
  • 10
    This will still print false for a bare repository that has no working tree – noggin182 Jul 28 '17 at 14:50
  • This does not consider the sub-directory. I need to verify does `git rev-parse --show-toplevel` matches with the subfolder I am checking – alper Mar 21 '20 at 10:53
  • The chosen answer didn't even print out anything. This one worked. – ScottyBlades May 20 '20 at 16:52
  • 1
    Can we do something like: `if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then` like `William Pursell`s answer? – alper Jul 25 '21 at 14:16
  • 1
    @ScottyBlades In context, I would assume that means the chosen answer reports the result in its exit status and intentionally doesn't print anything, to be more directly/easily usable in shell scripts. Was that not the case? – mtraceur Apr 10 '23 at 23:52
  • I am wondering why not simply run the command "git status" instead of running "git rev-parse --is-inside-work-tree" – Akshay Katiha Aug 20 '23 at 10:41
206

Copied from the bash completion file, the following is a naive way to do it

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

You could either wrap that in a function or use it in a script.

Condensed into a one line condition suitable for bash and zsh

[ -d .git ] && echo .git || git rev-parse --git-dir > /dev/null 2>&1
hoijui
  • 3,615
  • 2
  • 33
  • 41
jabbie
  • 2,606
  • 1
  • 17
  • 9
  • 3
    Why not just use git rev-parse? – William Pursell Feb 02 '10 at 15:51
  • 5
    @William Pursell Why fork when you don't need to? Mainly for speed in the trivial case. – jabbie Feb 25 '10 at 03:46
  • Added a simple `$PWD` so the output path always is absolute (like the `git` command): `([ -d .git ] && echo "$PWD/.git") || (git rev-parse --git-dir 2> /dev/null)` – Joel Purra Oct 11 '12 at 19:10
  • 26
    The answer should be updated to use `git rev-parse --is-inside-git-dir`. I personally use `git rev-parse --is-inside-work-tree` before set my PS1. – juliohm Aug 10 '13 at 13:53
  • @JoelPurra `git rev parse --git-dir` prints just `.git` for me on Git 1.9.1.286.g5172cb3. – alexia May 21 '14 at 19:24
  • 21
    @juliohm `--is-inside-git-dir` will only return true if you are actually inside the **`.git` directory** of a repository. I don't think the OP is looking for that. – alexia May 21 '14 at 19:32
  • 3
    @nyuszika7h, that is why I also mentioned `--is-inside-work-tree`. – juliohm May 21 '14 at 20:42
  • @nyuszika7h: works for me in git 1.9.3 on Mac, but doesn't in 1.9.0 on FreeBSD. Hmm. YMMV, I guess. – Joel Purra May 22 '14 at 09:25
  • 9
    Neither `--is-inside-work-tree` nor `--is-inside-git-dir` will work when you are outside of a git repo. see: https://groups.google.com/forum/#!topic/git-users/dWc23LFhWxE – fisherwebdev Jul 19 '14 at 06:30
  • 3
    @fisherwebdev That error is the same output I get from `git rev-parse --git-dir` when outside a git repo. That's why stderr is redirected. The test still works for this purpose. – Andrew Ensley Jan 13 '16 at 15:53
  • 14
    This will fail if the git directory is something other than `.git`. For robustness, omit the `[ -d .git ]` and just use `git rev-parse ...`. – Peter John Acklam Jun 15 '18 at 09:14
  • @PeterJohnAcklam you mean, if there is a `.git` directory, but the git repo dir is somewhere else? Technically possible maybe, but ... why would you ever setup something like that? – hoijui Apr 15 '20 at 05:24
  • This command fails if we have a repository inside a master repository. Not like a submodule but when one repository clones other repositories inside it. – Soundararajan Dec 23 '20 at 05:41
  • 2
    Beware that this will work as expected ONLY IF you're currently in the repository root. Subdirectories are not supported. – xZero Jun 24 '21 at 13:59
72

Use 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

edit: git-rev-parse now (as of 1.7.0) supports --show-toplevel, so you could do if test "$(pwd)" = "$(git rev-parse --show-toplevel)" to determine if the current directory is the top-level dir.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
36

Or you could do this:

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
Alex Cory
  • 10,635
  • 10
  • 52
  • 62
  • 3
    I like this one because it works from a sub directory too – joehanna Feb 28 '17 at 08:43
  • 6
    [No redundant operations and works in `-e` mode: `[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" == "true" ]`](https://stackoverflow.com/questions/2180270/check-if-current-directory-is-a-git-repository/53367550#53367550) – ivan_pozdeev Nov 19 '18 at 02:33
21

Based on @Alex Cory's answer:

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

doesn't contain any redundant operations and works in -e mode.

  • As @go2null noted, this will not work in a bare repo. If you want to work with a bare repo for whatever reason, you can just check for git rev-parse succeeding, ignoring its output.
    • I don't consider this a drawback because the above line is indended for scripting, and virtually all git commands are only valid inside a worktree. So for scripting purposes, you're most likely interested in being not just inside a "git repo" but inside a worktree.
ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
  • 1
    this fails inside of a bare git repo – go2null Nov 29 '18 at 10:50
  • 4
    Rather than checking the output, it is better practice to check the return value. Do not invoke `[` at all. Just do `if git rev-parse --is-inside-work-tree; then ...` (with redirections as desired.) – William Pursell Feb 07 '19 at 15:37
  • 1
    @WilliamPursell checking the exit value doesn't work here: https://stackoverflow.com/questions/2180270/check-if-current-directory-is-a-git-repository/53367550#comment93611897_52938461 – ivan_pozdeev Feb 07 '19 at 15:40
  • 2
    @Ivan_pozdeev Depends on your definition of "work". In this case, I would say that checking the return value does work, while checking the output does not. In either case, from the perspective of best practice for writing code in the shell, it is more appropriate to check the return value. – William Pursell Feb 07 '19 at 15:45
  • @WilliamPursell if you read the linked comment, you'd know what I meant by "doesn't work" here. – ivan_pozdeev Feb 07 '19 at 15:46
  • This seems to be the best answer, except that there is a typo: you need `=`, not `==` (which gives errors like `sh: 1: [: false: unexpected operator`). – vinc17 Nov 08 '21 at 15:04
  • @vinc17 Fixed. In Bash, there's no difference, but outside of Linux, there may be... – ivan_pozdeev Nov 08 '21 at 20:13
  • 1
    @ivan_pozdeev Thanks, but note that even under Linux, not all users use bash (the `==` is also invalid in zsh). – vinc17 Nov 09 '21 at 11:27
9

Not sure if there is a publicly accessible/documented way to do this (there are some internal git functions which you can use/abuse in the git source itself)

You could do something like;

if ! git ls-files >& /dev/null; then
  echo "not in git"
fi
James
  • 245
  • 1
  • 5
9

This answer provides a sample POSIX shell function and a usage example to complement @jabbie's answer.

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

git returns errorlevel 0 if it is inside a git repository, else it returns errorlevel 128. (It also returns true or false if it is inside a git repository.)

Usage example

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
go2null
  • 2,080
  • 1
  • 21
  • 17
  • Not sufficient. Inside `.git`, it will succeed but print `false`. – ivan_pozdeev Nov 19 '18 at 02:45
  • 1
    @ivan_pozdeev: If `git rev-parse --is-inside-work-tree` returns `true` or `false` then it *is* inside a git repo, and that is what the function returns. that is, the function is *correct* – go2null Nov 29 '18 at 10:46
  • 1
    to expand, see the description in the answer, the value returned from git is ignored, the errorlevel is what is used. – go2null Nov 29 '18 at 10:47
8

Why not using exit codes? If a git repository exists in the current directory, then git branch and git tag commands return exit code of 0 (even if there are no tags or branches); otherwise, a non-zero exit code will be returned. This way, you can determine if a git repository exist or not. Simply, you can run:

git tag > /dev/null 2>&1

Advantage: Portable. It works for both bare and non-bare repositories, and in sh, zsh and bash.

Explanation

  1. git tag: Getting tags of the repository to determine if exists or not.
  2. > /dev/null 2>&1: Preventing from printing anything, including normal and error outputs.

TLDR (Really?!): check-git-repo

As an example, you can create a file named check-git-repo with the following contents, make it executable and run it:

#!/bin/sh

if git tag > /dev/null 2>&1; then
    echo "Repository exists!";
else
    echo "No repository here.";
fi
MAChitgarha
  • 3,728
  • 2
  • 33
  • 40
7

Another solution is to check for the command's exit code.

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

This will print 1 if you're in a git repository folder.

  • 1
    Note that this will have rc 0 even if you're inside the `.git` directory -- which you may or may not want. – ivan_pozdeev Nov 19 '18 at 01:58
  • 1
    Git's written sanely so you can just close files you don't want, `git rev-parse 2>&-`. – jthill Aug 03 '19 at 16:42
  • 2
    `[ $? == 0 ]` is redundant here; that's the implied test that `&&` already does. The above command is equivalent to `git rev-parse 2>/dev/null && echo 1`. – Deven T. Corzine Jul 27 '21 at 16:22
  • `[ $? == 0 ]` is not exactly redundant. If you are using a version of `[` that supports `==`, then it is exactly equivalent to `git rev-parse 2> /dev/null && echo 1`. But if you are using a version of `[` that does not recognize `==`, then this version is an error. – William Pursell Apr 09 '23 at 12:33
3

This works for me. You still get the errors but they're easy enough to suppress. it also works from within subfolders!

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

You can put this in an if then statement if you need to conditionally do more.

Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76
CharlesTWall3
  • 548
  • 4
  • 12
  • 3
    Good enough for many cases perhaps, but it fails on a bare git repo. – Wildcard Dec 07 '15 at 22:46
  • 7
    `git status` can be very slow on a big/old repo. I wouldn't use it for this purpose. – henrebotha Jan 21 '20 at 09:39
  • @henrebotha I totally agree and I am still doing it, because I would need the output for processing anyways: `git_status="$(git status --porcelain --branch 2> /dev/null)"; if [ $? -eq 0 ]; then echo something with $git_status; fi` – Michael Feb 13 '21 at 08:47
3

# check if 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
Pradeep
  • 9,667
  • 13
  • 27
  • 34
  • 3
    This is not best practice. If run outside of a working directory, you'll get "fatal: not a git repository (or any of the parent directories): .git" written on stderr, and "no, is not a git repo" on stdout. There's no need to invoke `[` here at all. Just do: `if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then ....` – William Pursell Feb 07 '19 at 15:35
  • In my case, I'm comfortable with this, and I want to track this glitch in my logs. Cheers! – Pascal Andy Apr 14 '19 at 21:45
0

This questions is really old, and there are some nice answers. Yet there is missing one thing: The solution how it is handled by git itself inside it's git-prompt.sh with __git_ps (). Here is the snippet taken from there:

    # [...]
    local repo_info rev_parse_exit_code
    repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
        --is-bare-repository --is-inside-work-tree \
        --short HEAD 2>/dev/null)"
    rev_parse_exit_code="$?"

    if [ -z "$repo_info" ]; then
        return $exit
    fi

    local short_sha=""
    if [ "$rev_parse_exit_code" = "0" ]; then
        short_sha="${repo_info##*$'\n'}"
        repo_info="${repo_info%$'\n'*}"
    fi
    # [...]

This is pretty nice, as it seems to handle all the mentioned issues to the other answers given here. Simply by combining the already known parameters in one call of git rev-parse. Maybe this script (git-prompt.sh with __git_ps ()) wasn't available 13 years ago, when this question was asked, but I thought it could be still interesting for people who want to create their own ps1.

-1
##Current branch
echo $(git branch --show-current 2> /dev/null && echo '')
echo $(git branch --show-current 2> /dev/null)

##OR
GIT_DIR=$(git rev-parse --git-dir 2> /dev/null)
DEV Tiago França
  • 1,271
  • 9
  • 9