I want to loop over all the directories and find out all the git repositories (both Bare and non-Bare). However, I need to identify which one is Bare and which one is non-Bare so that I can run different operations on them.
I checked Check if current directory is a Git repository and How do I check if a repository is bare?.
The script I came up with is:
#!/bin/bash
for d in $(find /media/ismail/8TBRaid0/ABC -path '*/.git*' -prune -o -print -type d); do
if git --git-dir=$d rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo ${d} is a non-Bare Repository
elif git --git-dir=$d rev-parse --is-bare-repository > /dev/null 2>&1; then
echo ${d} is a is a Bare Repository
fi
done
The output I am getting is:
/media/ismail/8TBRaid0/ABC/d is a non-Bare Repository
/media/ismail/8TBRaid0/ABC/e is a non-Bare Repository
The problem is:
ABC has 5 directories.
ABC% ls -la
total 28
drwxrwxr-x 7 ismail ismail 4096 Jun 9 16:44 .
drwxr--r-- 16 ismail ismail 4096 Jun 9 16:44 ..
drwxrwxr-x 3 ismail ismail 4096 Jun 9 16:44 a
drwxrwxr-x 3 ismail ismail 4096 Jun 9 16:44 b
drwxrwxr-x 3 ismail ismail 4096 Jun 9 16:44 c
drwxrwxr-x 7 ismail ismail 4096 Jun 9 16:44 d
drwxrwxr-x 7 ismail ismail 4096 Jun 9 16:44 e
Here a,b,c are non-Bare Repositories with .git directory. And d,e are Bare Repositories without .git directory.
So, the output I am getting is definitely wrong. What i need for my case is:
a is a non-Bare Repository
b is a non-Bare Repository
c is a non-Bare Repository
d is a Bare Repository
e is a Bare Repository
How can I get the expected result?
Update 1:
My directory structure is actually deeper and scattered. The structure I gave above is as an example. For example: the structure can be:
.
├── 1
│ └── a
├── 2
│ └── 3
│ ├── b
│ └── e
│ ├── branches
│ ├── config
│ ├── description
│ ├── HEAD
│ ├── hooks
│ │ ├── applypatch-msg.sample
│ │ ├── commit-msg.sample
│ │ ├── fsmonitor-watchman.sample
│ │ ├── post-update.sample
│ │ ├── pre-applypatch.sample
│ │ ├── pre-commit.sample
│ │ ├── pre-merge-commit.sample
│ │ ├── prepare-commit-msg.sample
│ │ ├── pre-push.sample
│ │ ├── pre-rebase.sample
│ │ ├── pre-receive.sample
│ │ └── update.sample
│ ├── info
│ │ └── exclude
│ ├── objects
│ │ ├── info
│ │ └── pack
│ └── refs
│ ├── heads
│ └── tags
├── c
├── d
│ ├── branches
│ ├── config
│ ├── description
│ ├── HEAD
│ ├── hooks
│ │ ├── applypatch-msg.sample
│ │ ├── commit-msg.sample
│ │ ├── fsmonitor-watchman.sample
│ │ ├── post-update.sample
│ │ ├── pre-applypatch.sample
│ │ ├── pre-commit.sample
│ │ ├── pre-merge-commit.sample
│ │ ├── prepare-commit-msg.sample
│ │ ├── pre-push.sample
│ │ ├── pre-rebase.sample
│ │ ├── pre-receive.sample
│ │ └── update.sample
│ ├── info
│ │ └── exclude
│ ├── objects
│ │ ├── info
│ │ └── pack
│ └── refs
│ ├── heads
│ └── tags
└── f
└── ADOC Document.adoc
CodePudding user response:
For starters, look at the output of your find
command:
$ find ABC -path '*/.git*' -prune -o -print -type d
ABC
ABC/a
ABC/b
ABC/c
ABC/d
ABC/d/branches
ABC/d/hooks
ABC/d/hooks/applypatch-msg.sample
ABC/d/hooks/commit-msg.sample
ABC/d/hooks/post-update.sample
[...]
That's not really useful at all. If everything contained in .../ABC
is a git repository, you can just get a list of directories:
$ find ABC/* -maxdepth 0 -type d
ABC/a
ABC/b
ABC/c
ABC/d
ABC/e
That's going to be much easier to work with. We can then iterate over those results like this:
find ABC/* -maxdepth 0 -type d |
while read dir; do
# note that --is-bare-repository returns results as a string
# not an exit code
is_bare=$(git -C $dir rev-parse --is-bare-repository 2> /dev/null)
if [ "$is_bare" = true ]; then
echo "$dir is a bare repository"
else
echo "$dir is not a bare repository"
fi
done
Running that code produces:
ABC/a is not a bare repository
ABC/b is not a bare repository
ABC/c is not a bare repository
ABC/d is a bare repository
ABC/e is a bare repository
If some things in ABC
may not be git
repositories, we can add an
additional clause inside the while
loop:
...
is_bare=$(git -C $dir rev-parse --is-bare-repository 2> /dev/null)
if [ $? -ne 0 ]; then
echo "$dir is not a git repository"
continue
fi
...
Update
If your directory structure is more varied, we can find git repositories by looking for a file named HEAD
:
$ find ABC -name HEAD -printf "%h\n"
ABC/c/.git
ABC/1/a/.git
ABC/1/d
ABC/2/b/.git
ABC/2/e
That means we can rewrite the script to look like:
find ABC -name HEAD -printf "%h\n" |
while read dir; do
if [[ $dir =~ /\.git/ ]]; then
dir=${dir%/.*}
fi
# note that --is-bare-repository returns results as a string
# not an exit code
is_bare=$(git -C "$dir" rev-parse --is-bare-repository 2> /dev/null)
if [[ $is_bare = true ]]; then
echo "$dir is a bare repository"
else
echo "$dir is not a bare repository"
fi
done
Note that I'm using some bash-specific syntax here to make our lives easier, but that shouldn't be a problem in most environments.
Given this directory tree:
ABC/
├── 1
│ ├── a # non-bare repository
│ └── d # bare repository
├── 2
│ ├── b # non-bare repository
│ └── e # bare repository
├── c # non-bare repository
└── z # not a repository
The script above produces:
ABC/c is not a bare repository
ABC/1/a is not a bare repository
ABC/1/d is a bare repository
ABC/2/b is not a bare repository
ABC/2/e is a bare repository
CodePudding user response:
You can probably do all this with a bit of find bash
machinery:
$ cat myScript
#!/usr/bin/env bash
iiwt() {
[[ $(git -C "$1" rev-parse --is-inside-work-tree 2> /dev/null) == "true" ]] &&
echo "$1 is a non-Bare Repository"
}
ibr() {
[[ $(git -C "$1" rev-parse --is-bare-repository 2> /dev/null) == "true" ]] &&
echo "$1 is a Bare Repository"
}
export -f iiwt ibr
find . -type d -exec bash -c 'iiwt "$1" || ibr "$1"' _ {} \; -prune
Explanations:
The
iiwt
helper function tests if its parameter is inside a working tree. If yes it prints a message and its exit status is true. Else its exit status is false.The
ibr
helper function tests if its parameter is inside a bare repository. If yes it prints a message and its exit status is true. Else its exit status is false.The find command searches all directories and executes the bash script
iiwt "$1" || ibr "$1"
on each of them. If the exit status is true find stops the recursion here (this is what-prune
is for). Else it recurses inside.
Demo:
$ mkdir -p foobar/bar foobar/a/b/c; cd foobar
$ git init --bare foo.git
$ git clone foo.git
$ git init --bare bar/foo.git
$ git clone bar/foo.git bar/foo
$ find . -type d
.
./a
./a/b
./a/b/c
./foo.git
./foo.git/refs
./foo.git/refs/heads
...
./foo/.git/refs/heads
./foo/.git/refs/tags
./foo/.git/branches
$ myScript .
./foo is a non-Bare Repository
./foo.git is a Bare Repository
./bar/foo.git is a Bare Repository
./bar/foo is a non-Bare Repository
Note that we could also use one single helper function:
$ cat myScript
#!/usr/bin/env bash
hlp() {
if [[ $(git -C "$1" rev-parse --is-inside-work-tree 2> /dev/null) == "true" ]]; then
echo "$1 is a non-Bare Repository"
elif [[ $(git -C "$1" rev-parse --is-bare-repository 2> /dev/null) == "true" ]]; then
echo "$1 is a Bare Repository"
else
return 1
fi
}
export -f hlp
find . -type d -exec bash -c 'hlp "$1"' _ {} \; -prune