Skip to content

Commit b7dfe39

Browse files
committed
find git-dir directly and look up work-tree
This enables mgitstatus to handle repositories with non-standard work tree locations (such as those used by yadm). It can discover these, or the user can explicitly list the path to the git-dir. Two broad strokes to this: 1. Instead of checking every sub-directory for a .git directory in the standard location, search directly for directories matching "*.git". - Since *standard* .git directories will be one level deeper in the tree, this adds 1 to DEPTH. - Since we're looking for the .git directory itself, I think we can use -prune to skip searching within those matching directories. 2. Use `git rev-parse --show-toplevel` to look up the work tree. As far as I can tell, this will report the path of a non-standard work tree. This will error (and print nothing) on a standard repo. If that fails to produce output, fall back on the existing guess that the work tree will be the parent directory of the git-dir. Most of the diff is from computing this once (as PROJ_DIR) and replacing instances of `$(dirname "$GIT_DIR")` with it.
1 parent 852ee02 commit b7dfe39

1 file changed

Lines changed: 28 additions & 13 deletions

File tree

mgitstatus

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,18 +156,35 @@ ID="$(id -n -u)"
156156
# infinitely deep
157157
FIND_OPTS=""
158158
if [ "$DEPTH" -ne 0 ]; then
159+
# 1 lvl deeper since we're searching for the .git directory inside the project
160+
((DEPTH=$DEPTH+1))
159161
FIND_OPTS="$FIND_OPTS -maxdepth $DEPTH"
160162
fi
161163

162-
# Go through positional arguments (DIRs) or '.' if no argumnets are given
164+
find_git_work_tree()(
165+
cd "$1"
166+
likely_gitdir="$PWD"
167+
worktree="$(git rev-parse --show-toplevel 2>/dev/null)"
168+
if [ -z "$worktree" ]; then
169+
# GIT_DIR doesn't know; guess:
170+
cd ..
171+
echo "$PWD"
172+
else
173+
# git told us, so we'll trust it
174+
echo "$worktree"
175+
return 0
176+
fi
177+
)
178+
179+
# Go through positional arguments (DIRs) or '.' if no arguments are given
163180
for DIR in "${@:-"."}"; do
164181
# We *want* to expand parameters, so disable shellcheck for this error:
165182
# shellcheck disable=SC2086
166-
find -L "$DIR" $FIND_OPTS -type d | while read -r PROJ_DIR
183+
find -L "$DIR" $FIND_OPTS -type d -name "*.git" -prune | while read -r GIT_DIR
167184
do
168-
GIT_DIR="$PROJ_DIR/.git"
169-
GIT_CONF="$PROJ_DIR/.git/config"
170-
185+
PROJ_DIR="$(find_git_work_tree "$GIT_DIR")"
186+
GIT_CONF="$GIT_DIR/config"
187+
171188
# Check if the repo is safe (https://github.blog/2022-04-12-git-security-vulnerability-announced/)
172189
if [ -d "$GIT_DIR" ]; then
173190
GIT_DIR_OWNER="$(ls -ld "$GIT_DIR" | awk 'NR==1 {print $3}')"
@@ -201,11 +218,11 @@ for DIR in "${@:-"."}"; do
201218

202219
# Do a 'git fetch' if requested
203220
if [ "$DO_FETCH" -eq 1 ]; then
204-
git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" fetch -q >/dev/null
221+
git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" fetch -q >/dev/null
205222
fi
206223

207224
# Refresh the index, or we might get wrong results.
208-
git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" update-index -q --refresh >/dev/null 2>&1
225+
git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" update-index -q --refresh >/dev/null 2>&1
209226

210227
# Find all remote branches that have been checked out and figure out if
211228
# they need a push or pull. We do this with various tests and put the name
@@ -269,12 +286,10 @@ for DIR in "${@:-"."}"; do
269286
NEEDS_UPSTREAM_BRANCHES=$(printf "$NEEDS_UPSTREAM_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/")
270287

271288
# Find out if there are unstaged, uncommitted or untracked changes
272-
UNSTAGED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" diff-index --quiet HEAD -- 2>/dev/null; echo $?)
273-
UNCOMMITTED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" diff-files --quiet --ignore-submodules --; echo $?)
274-
UNTRACKED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" ls-files --exclude-standard --others)
275-
cd "$(dirname "$GIT_DIR")" || exit
276-
STASHES=$(git stash list | wc -l)
277-
cd "$OLDPWD" || exit
289+
UNSTAGED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" diff-index --quiet HEAD -- 2>/dev/null; echo $?)
290+
UNCOMMITTED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" diff-files --quiet --ignore-submodules --; echo $?)
291+
UNTRACKED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" ls-files --exclude-standard --others)
292+
STASHES=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" stash list | wc -l)
278293

279294
# Build up the status string if not flattening. Otherwise, print
280295
# results immediately.

0 commit comments

Comments
 (0)