diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
index 7f8e78d..fd4a178 100644
--- a/Documentation/technical/api-directory-listing.txt
+++ b/Documentation/technical/api-directory-listing.txt
@@ -90,8 +90,8 @@ marked. If you to exclude files, make sure you have loaded index first.
`add_exclude()`.
* To add patterns from a file (e.g. `.git/info/exclude`), call
- `add_excludes_from_file()` , and/or set `dir.exclude_per_dir`. A
- short-hand function `setup_standard_excludes()` can be used to set
+ `add_excludes_from_file()` , and/or set `dir.exclude_per_dir`. The
+ short-hand function `setup_standard_excludes()` must be used to set
up the standard set of exclude settings.
* Set options described in the Data Structure section above.
diff --git a/dir.c b/dir.c
index 797805d..3f57e34 100644
--- a/dir.c
+++ b/dir.c
@@ -1608,11 +1608,44 @@ int remove_dir_recursively(struct strbuf *path, int flag)
return remove_dir_recurse(path, flag, NULL);
}
+static void add_git_dir_exclude(struct dir_struct *dir)
+{
+ const char *r_git, *gitdir = get_git_dir();
+ char *n_git;
+ int len;
+
+ r_git = real_path(absolute_path(gitdir));
+ n_git = xmalloc(strlen(r_git) + 1 + 1);
+ normalize_path_copy(n_git, r_git);
+ len = strlen(n_git);
+
+ /* only add it if GIT_DIR does not end with '.git' or '/.git' */
+ if (!(len >= 4 && !strcmp(n_git + len - 4, ".git") &&
+ (len == 4 || n_git[len - 5] == '/'))) {
+ const char *worktree = get_git_work_tree();
+
+ if (!worktree ||
+ dir_inside_of(n_git, worktree) >= 0) {
+ struct exclude_list *el = add_exclude_list(dir, EXC_CMDL,
+ "GIT_DIR setup");
+ char *reldir = worktree ? n_git + strlen(worktree) : n_git;
+
+ /* append a trailing slash to exclude directories only */
+ n_git[len] = '/';
+ n_git[len + 1] = '\0';
+ add_exclude(reldir, "", 0, el, 0);
+ }
+ }
+ free(n_git);
+}
+
void setup_standard_excludes(struct dir_struct *dir)
{
const char *path;
char *xdg_path;
+ add_git_dir_exclude(dir);
+
dir->exclude_per_dir = ".gitignore";
path = git_path("info/exclude");
if (!excludes_file) {diff --git a/t/t2205-add-gitdir.sh b/t/t2205-add-gitdir.sh
new file mode 100755
index 0000000..c48a845
--- /dev/null
+++ b/t/t2205-add-gitdir.sh
@@ -0,0 +1,187 @@
+#!/bin/sh
+#
+# Copyright (c) 2014 Pasha Bolokhov
+#
+
+test_description='alternative repository path specified by --git-dir is ignored by add and status'
+
+. ./test-lib.sh
+
+#
+# Create a tree:
+#
+# repo-inside/ repo-outside/
+#
+#
+# repo-inside:
+# a b c d dir1/ dir2/ [meta/]
+#
+# repo-inside/dir1:
+# e f g h meta/ ssubdir/
+#
+# repo-inside/dir1/meta:
+# aa
+#
+# repo-inside/dir1/ssubdir:
+# meta/
+#
+# repo-inside/dir1/ssubdir/meta:
+# aaa
+#
+# repo-inside/dir2:
+# meta
+#
+#
+#
+# repo-outside:
+# external/ tree/
+#
+# repo-outside/external:
+# [meta/]
+#
+# repo-outside/tree:
+# n o p q meta/ sub/
+#
+# repo-outside/tree/meta:
+# bb
+#
+# repo-outside/tree/sub:
+# meta/
+#
+# repo-outside/tree/sub/meta:
+# bbb
+#
+#
+# (both of the above [meta/] denote the actual repositories)
+#
+
+#
+# First set of tests (in "repo-inside/"):
+# ---------------------------------------
+#
+# Name the repository "meta" and see whether or not "git status" includes or
+# ignores directories named "meta". Directory "meta" at the top level of
+# "repo-inside/"is the repository and appears upon the first "git init"
+#
+#
+# Second set of tests (in "repo-outside/"):
+# -----------------------------------------
+#
+# Put the work tree into "tree/" and repository into "external/meta"
+# (the latter directory appears upon the corresponding "git init").
+# The work tree again contains directories named "meta", but those ones are
+# tested not to be ignored now
+#
+
+test_expect_success "setup" '
+ mkdir repo-inside/ &&
+ (
+ cd repo-inside/ &&
+ for f in a b c d
+ do
+ echo "DATA" >"$f" || exit 1
+ done &&
+ mkdir -p dir1/meta dir1/ssubdir/meta &&
+ for f in e f g h
+ do
+ echo "MORE DATA" >"dir1/$f" || exit 1
+ done &&
+ echo "EVEN more Data" >dir1/meta/aa &&
+ echo "Data and BAIT" >dir1/ssubdir/meta/aaa &&
+ mkdir dir2 &&
+ echo "Not a Metadata File" >dir2/meta &&
+ git --git-dir=meta init
+ ) &&
+ mkdir repo-outside/ repo-outside/external repo-outside/tree &&
+ (
+ cd repo-outside/tree &&
+ for f in n o p q
+ do
+ echo "Literal Data" >"$f" || exit 1
+ done &&
+ mkdir -p meta sub/meta &&
+ echo "Sample data" >meta/bb &&
+ echo "Stream of data" >sub/meta/bbb &&
+ git --git-dir=../external/meta init
+ )
+'
+
+
+#
+# The first set of tests (the repository is inside the work tree)
+#
+test_expect_success "'git status' ignores the repository directory" '
+ (
+ cd repo-inside &&
+ git --git-dir=meta --work-tree=. status --porcelain --untracked=all >actual+ &&
+ grep meta actual+ | sort >actual &&
+ cat >expect <<-\EOF &&
+ ?? dir1/meta/aa
+ ?? dir1/ssubdir/meta/aaa
+ ?? dir2/meta
+ EOF
+ test_cmp expect actual
+ )
+'
+
+test_expect_success "'git add -A' ignores the repository directory" '
+ (
+ cd repo-inside &&
+ git --git-dir=meta --work-tree=. add -A &&
+ git --git-dir=meta --work-tree=. status --porcelain >actual+ &&
+ grep meta actual+ | sort >actual &&
+ cat >expect <<-\EOF &&
+ A dir1/meta/aa
+ A dir1/ssubdir/meta/aaa
+ A dir2/meta
+ EOF
+ test_cmp expect actual
+ )
+'
+
+test_expect_success "'git grep --exclude-standard' ignores the repository directory" '
+ (
+ cd repo-inside &&
+ test_might_fail git --git-dir=meta \
+ grep --no-index --exclude-standard BAIT >actual &&
+ cat >expect <<-\EOF &&
+ dir1/ssubdir/meta/aaa:Data and BAIT
+ EOF
+ test_cmp expect actual
+ )
+'
+
+#
+# The second set of tests (the repository is outside of the work tree)
+#
+test_expect_success "'git status' acknowledges directories 'meta' \
+if repo is not within work tree" '
+ rm -rf meta/ &&
+ (
+ cd repo-outside/tree &&
+ git --git-dir=../external/meta init &&
+ git --git-dir=../external/meta --work-tree=. status --porcelain --untracked=all >actual+ &&
+ grep meta actual+ | sort >actual &&
+ cat >expect <<-\EOF &&
+ ?? meta/bb
+ ?? sub/meta/bbb
+ EOF
+ test_cmp expect actual
+ )
+'
+
+test_expect_success "'git add -A' adds 'meta' if the repo is outside the work tree" '
+ (
+ cd repo-outside/tree &&
+ git --git-dir=../external/meta --work-tree=. add -A &&
+ git --git-dir=../external/meta --work-tree=. status --porcelain --untracked=all >actual+ &&
+ grep meta actual+ | sort >actual &&
+ cat >expect <<-\EOF &&
+ A meta/bb
+ A sub/meta/bbb
+ EOF
+ test_cmp expect actual
+ )
+'
+
+test_done
--
1.9.1