Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Documentation/config/core.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,15 @@ core.excludesFile::
If `$XDG_CONFIG_HOME` is either not set or empty, `$HOME/.config/git/ignore`
is used instead. See linkgit:gitignore[5].

core.gitLocalIgnore::
If set to `true`, Git additionally reads ignore patterns from
a file named `.gitlocalignore` at the root of the working tree.
This file is meant for machine-local, uncommitted ignore rules:
it is ignored by Git itself (self-excluding) and is never tracked.
Its patterns are applied with lower precedence than
`.git/info/exclude` but higher than `core.excludesFile`.
Defaults to `false`. See linkgit:gitignore[5].

core.askPass::
Some commands (e.g. svn and http interfaces) that interactively
ask for a password can be told to use an external program given
Expand Down
25 changes: 20 additions & 5 deletions Documentation/gitignore.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ gitignore - Specifies intentionally untracked files to ignore

SYNOPSIS
--------
$XDG_CONFIG_HOME/git/ignore, $GIT_COMMON_DIR/info/exclude, .gitignore
$XDG_CONFIG_HOME/git/ignore, $GIT_COMMON_DIR/info/exclude, .gitignore, .gitlocalignore

DESCRIPTION
-----------
Expand All @@ -34,10 +34,17 @@ precedence, the last matching pattern decides the outcome):
includes such `.gitignore` files in its repository, containing patterns for
files generated as part of the project build.

* Patterns read from `$GIT_COMMON_DIR/info/exclude`.
* Patterns read from `$GIT_COMMON_DIR/info/exclude`.

* Patterns read from the file specified by the configuration
variable `core.excludesFile`.
* Patterns read from a `.gitlocalignore` file at the root of the
working tree, but only when the `core.gitLocalIgnore` configuration
variable is enabled (it is `false` by default). This file is intended
for machine-local, uncommitted ignore rules: Git ignores the file
itself (self-excluding) and never tracks it. Its precedence is below
`$GIT_COMMON_DIR/info/exclude` but above `core.excludesFile`.

* Patterns read from the file specified by the configuration
variable `core.excludesFile`.

Which file to place a pattern in depends on how the pattern is meant to
be used.
Expand All @@ -57,7 +64,15 @@ be used.
the user's editor of choice) generally go into a file specified by
`core.excludesFile` in the user's `~/.gitconfig`. Its default value is
$XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or
empty, $HOME/.config/git/ignore is used instead.
empty, $HOME/.config/git/ignore is used instead.

* Patterns which apply only to your local machine and which you do
not want to share or commit (e.g., paths that exist only in your
checkout) can go into a `.gitlocalignore` file at the root of the
working tree, once `core.gitLocalIgnore` is enabled. Unlike the
other files above, `.gitlocalignore` is ignored by Git itself and
will never be tracked or pushed.


The underlying Git plumbing tools, such as
'git ls-files' and 'git read-tree', read
Expand Down
29 changes: 29 additions & 0 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -3490,6 +3490,35 @@ void setup_standard_excludes(struct dir_struct *dir)
add_patterns_from_file_1(dir, excludes_file,
dir->untracked ? &dir->internal.ss_excludes_file : NULL);

/*
* .gitlocalignore: a discoverable, local-only ignore file at the
* worktree root, gated on core.gitLocalIgnore (off by default, to
* avoid surprising repositories that already contain a file with
* this name). Read here, between core.excludesFile and
* info/exclude, so its precedence ranks below info/exclude but
* above core.excludesFile.
*/
if (startup_info->have_repository) {
int git_local_ignore = 0;
if (repo_config_get_bool(the_repository, "core.gitLocalIgnore",
&git_local_ignore) >= 0 && git_local_ignore) {
const char *wt = the_repository->worktree;
if (wt) {
char *gl_path = mkpathdup("%s/.gitlocalignore", wt);
if (!access_or_warn(gl_path, R_OK, 0))
add_patterns_from_file_1(dir, gl_path, NULL);
{
struct pattern_list *self =
add_pattern_list(dir, EXC_CMDL,
".gitlocalignore");
add_pattern(".gitlocalignore", "", 0,
self, -1);
}
dir->internal.unmanaged_exclude_files++;
}
}
}

/* per repository user preference */
if (startup_info->have_repository) {
const char *path = git_path_info_exclude();
Expand Down
1 change: 1 addition & 0 deletions t/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ integration_tests = [
't0008-ignores.sh',
't0009-git-dir-validation.sh',
't0010-racy-git.sh',
't0011-gitlocalignore.sh',
't0012-help.sh',
't0013-sha1dc.sh',
't0014-alias.sh',
Expand Down
73 changes: 73 additions & 0 deletions t/t0011-gitlocalignore.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/bin/sh

test_description='.gitlocalignore support (core.gitLocalIgnore)'

TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

# off by default: .gitlocalignore is not consulted at all
test_expect_success 'off by default: .gitlocalignore is ignored' '
echo content >a.txt &&
printf "a.txt\n" >.gitlocalignore &&
test_must_fail git check-ignore a.txt
'

test_expect_success 'core.gitLocalIgnore enables .gitlocalignore' '
test_config core.gitLocalIgnore true &&
echo content >b.txt &&
printf "b.txt\n" >.gitlocalignore &&
git check-ignore b.txt
'

test_expect_success '.gitlocalignore is self-excluding' '
test_config core.gitLocalIgnore true &&
printf "b.txt\n" >.gitlocalignore &&
git check-ignore .gitlocalignore
'

test_expect_success 'info/exclude outranks .gitlocalignore' '
test_config core.gitLocalIgnore true &&
mkdir -p .git/info &&
echo "c.txt" >.git/info/exclude &&
echo content >c.txt &&
printf "c.txt\n" >.gitlocalignore &&
git check-ignore -v c.txt >out &&
grep "info/exclude" out
'

test_expect_success '.gitlocalignore outranks core.excludesFile' '
test_config core.gitLocalIgnore true &&
echo content >d.txt &&
printf "d.txt\n" >.gitlocalignore &&
echo "d.txt" >.git/excludes-extra &&
test_config core.excludesFile "$(pwd)/.git/excludes-extra" &&
git check-ignore -v d.txt >out &&
grep "\.gitlocalignore" out
'

test_expect_success 'nested .gitlocalignore contents are not read' '
test_config core.gitLocalIgnore true &&
rm -f .gitlocalignore &&
mkdir -p sub &&
echo content >sub/e.txt &&
printf "e.txt\n" >sub/.gitlocalignore &&
test_must_fail git check-ignore sub/e.txt
'

test_expect_success 'ignored files stay out of git status' '
test_config core.gitLocalIgnore true &&
echo content >f.txt &&
printf "f.txt\n" >.gitlocalignore &&
git status --porcelain >out &&
! grep f.txt out
'

test_expect_success 'git add refuses .gitlocalignore unless forced' '
test_config core.gitLocalIgnore true &&
printf "f.txt\n" >.gitlocalignore &&
test_must_fail git add .gitlocalignore &&
git add -f .gitlocalignore &&
git ls-files --error-unmatch .gitlocalignore
'

test_done
Loading