Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
a1cdbd5
t0001: allow implicit bare repo discovery for aliased-command test
dscho Mar 28, 2026
7874460
t0001: replace `cd`+`git` with `git --git-dir` in `check_config`
dscho Mar 29, 2026
a4f7a6d
t0003: use `--git-dir` for bare repo attribute tests
dscho Mar 28, 2026
5b6bb18
t0056: allow implicit bare repo discovery for `-C` work-tree tests
dscho Mar 28, 2026
c38f0a6
t1020: use `--git-dir` instead of subshell for bare repo
dscho Mar 28, 2026
a084c39
t1900: avoid using `-C <dir>` for a bare repository
dscho Mar 28, 2026
6a7730c
t2400: explicitly specify bare repo for `git worktree add`
dscho Mar 29, 2026
2905e00
t2406: use `--git-dir=.` for bare repository worktree repair
dscho Mar 29, 2026
9001883
t5503: avoid discovering a bare repository
dscho Apr 1, 2026
6932658
t5505: export `GIT_DIR` after `git init --bare`
dscho Mar 29, 2026
2f1e745
t5509: specify bare repository path explicitly
dscho Mar 29, 2026
c8789bd
t5540/t5541: avoid accessing a bare repository via `-C <dir>`
dscho Apr 1, 2026
f09a96e
t5619: wrap `test_commit_bulk` in `GIT_DIR` subshell for bare repo
dscho Mar 29, 2026
08e031e
t4203: avoid implicit discovery of a bare repository
dscho Mar 29, 2026
01ec77c
t6020: use `-C` for worktree, `--git-dir` for bare repository
dscho Mar 29, 2026
34069ef
lib-commit-graph: teach `--bare` to graph helpers
dscho Mar 28, 2026
0147f2c
t5615: wrap bare alternate test in subshell with `GIT_DIR`
dscho Mar 29, 2026
c4e8548
Merge branch 'tests-explicit-bare-repo'
dscho Mar 28, 2026
00eaefb
t9210: pass `safe.bareRepository=all` to `scalar register`
dscho Mar 29, 2026
6b6f096
test-tool: add a `--git-dir` option
dscho Mar 29, 2026
15f0923
t5318: pass `--bare` to commit-graph helpers for bare repo tests
dscho Mar 29, 2026
c86ff6a
Merge branch 'cd-gitdir-subshell'
dscho Mar 29, 2026
45babd2
t2400, t5516: strip directory prefix from `--git-dir` path arguments
dscho Mar 29, 2026
890dfd0
t9700: stop relying on implicit bare repo discovery
dscho Apr 1, 2026
fbeec12
test_hook: add a `--git-dir` option
dscho Mar 29, 2026
0a23594
test_config, test_unconfig: add a `--git-dir` option
dscho Mar 29, 2026
b3028db
t1460: restructure helpers for `--git-dir` dispatch
dscho Mar 28, 2026
8262fcf
Merge branch 'lib-commit-graph-bare'
dscho Mar 28, 2026
7d8e7e7
t5310, t5510, t5516: adjust `git fetch .` in bare repositories
dscho Mar 29, 2026
139b9da
git p4 clone --bare: need to be explicit about the gitdir
dscho Apr 1, 2026
2e50497
t2400: pass through args in `post_checkout_hook` for `--git-dir`
dscho Mar 29, 2026
36d94f2
tests: use `test_config --git-dir` for bare repos
dscho Mar 29, 2026
6a02178
Merge branch 'test-tool-git-dir'
dscho Mar 29, 2026
fb3b053
tests: add set/unset GIT_DIR pairs where appropriate
dscho Mar 29, 2026
9a0f4ba
t5411: teach `test_cmp_refs` a `--git-dir` option
dscho Mar 29, 2026
6a47c97
tests: use `test_hook --git-dir` for bare repos
dscho Mar 29, 2026
8a25ad3
Merge branch 'test-config-git-dir'
dscho Mar 29, 2026
30a1073
t7103, t9903: export `GIT_CONFIG_PARAMETERS` in `.git` directory tests
dscho Mar 29, 2026
fe237a0
t5411: use `test_cmp_refs --git-dir` for bare repos
dscho Mar 29, 2026
c0862e7
Merge branch 'test-hook-git-dir'
dscho Mar 29, 2026
9413a6d
tests: replace `-C` to `--git-dir`, dropping `../` prefixes as needed
dscho Mar 29, 2026
98ebe56
tests: export `GIT_DIR=.` after `cd` into bare repos
dscho Mar 29, 2026
c385431
tests: use `--git-dir` instead of `-C` for bare repos
dscho Mar 29, 2026
79d046a
Merge branch 'test-cmp-refs-git-dir'
dscho Mar 29, 2026
5e488c2
Merge branch 'mechanical-fixes'
dscho Apr 1, 2026
435e350
safe.bareRepository: default to "explicit" with WITH_BREAKING_CHANGES
dscho Mar 23, 2026
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
24 changes: 24 additions & 0 deletions Documentation/BreakingChanges.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,30 @@ would be significant, we may decide to defer this change to a subsequent minor
release. This evaluation will also take into account our own experience with
how painful it is to keep Rust an optional component.

* The default value of `safe.bareRepository` will change from `all` to
`explicit`. It is all too easy for an attacker to trick a user into cloning a
repository that contains an embedded bare repository with malicious hooks
configured. If the user enters that subdirectory and runs any Git command, Git
discovers the bare repository and the hooks fire. The user does not even need
to run a Git command explicitly: many shell prompts run `git status` in the
background to display branch and dirty state information, and `git status` in
turn may invoke the fsmonitor hook if so configured, making the user
vulnerable the moment they `cd` into the directory. The `safe.bareRepository`
configuration variable was introduced in 8959555cee (setup_git_directory():
add an owner check for the top-level directory, 2022-03-02) with a default of
`all` to preserve backwards compatibility.
+
Changing the default to `explicit` means that Git will refuse to work with bare
repositories that are discovered implicitly by walking up the directory tree.
Bare repositories specified explicitly via the `--git-dir` command-line option
or the `GIT_DIR` environment variable continue to work regardless of this
setting. Repositories that look like a `.git` directory, a worktree, or a
submodule directory are also unaffected.
+
Users who rely on implicit discovery of bare repositories can restore the
previous behavior by setting `safe.bareRepository=all` in their global or
system configuration.

=== Removals

* Support for grafting commits has long been superseded by git-replace(1).
Expand Down
10 changes: 8 additions & 2 deletions Documentation/config/safe.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@ safe.bareRepository::
Specifies which bare repositories Git will work with. The currently
supported values are:
+
* `all`: Git works with all bare repositories. This is the default.
* `all`: Git works with all bare repositories. This is the default in
Git 2.x.
* `explicit`: Git only works with bare repositories specified via
the top-level `--git-dir` command-line option, or the `GIT_DIR`
environment variable (see linkgit:git[1]).
environment variable (see linkgit:git[1]). This will be the default
in Git 3.0.
+
If you do not use bare repositories in your workflow, then it may be
beneficial to set `safe.bareRepository` to `explicit` in your global
config. This will protect you from attacks that involve cloning a
repository that contains a bare repository and running a Git command
within that directory.
+
If you use bare repositories regularly and want to preserve the current
behavior after upgrading to Git 3.0, set `safe.bareRepository` to `all`
in your global or system config.
+
This config setting is only respected in protected configuration (see
<<SCOPES>>). This prevents untrusted repositories from tampering with
this value.
Expand Down
2 changes: 1 addition & 1 deletion contrib/subtree/t/t7900-subtree.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ test_expect_success 'push sub dir/ with --rejoin from scratch' '
git init --bare "sub proj.git" &&
git subtree push --prefix="sub dir" --rejoin ./"sub proj.git" from-mainline &&
test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
test "$split_hash" = "$(git -C "sub proj.git" rev-parse --verify refs/heads/from-mainline)"
test "$split_hash" = "$(git --git-dir="sub proj.git" rev-parse --verify refs/heads/from-mainline)"
)
'

Expand Down
1 change: 1 addition & 0 deletions git-p4.py
Original file line number Diff line number Diff line change
Expand Up @@ -4360,6 +4360,7 @@ def run(self, args):
init_cmd = ["git", "init"]
if self.cloneBare:
init_cmd.append("--bare")
os.environ["GIT_DIR"] = os.getcwd()
retcode = subprocess.call(init_cmd)
if retcode:
raise subprocess.CalledProcessError(retcode, init_cmd)
Expand Down
4 changes: 4 additions & 0 deletions setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,11 @@ static int allowed_bare_repo_cb(const char *key, const char *value,

static enum allowed_bare_repo get_allowed_bare_repo(void)
{
#ifdef WITH_BREAKING_CHANGES
enum allowed_bare_repo result = ALLOWED_BARE_REPO_EXPLICIT;
#else
enum allowed_bare_repo result = ALLOWED_BARE_REPO_ALL;
#endif
git_protected_config(allowed_bare_repo_cb, &result);
return result;
}
Expand Down
4 changes: 2 additions & 2 deletions t/annotate-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ test_expect_success 'blame with --contents' '
test_expect_success 'blame with --contents in a bare repo' '
git clone --bare . bare-contents.git &&
(
cd bare-contents.git &&
cd bare-contents.git && GIT_DIR=. && export GIT_DIR &&
echo "1A quick brown fox jumps over the" >contents &&
check_count --contents=contents A 1
)
Expand All @@ -101,7 +101,7 @@ test_expect_success 'blame with --contents changed' '
test_expect_success 'blame in a bare repo without starting commit' '
git clone --bare . bare.git &&
(
cd bare.git &&
cd bare.git && GIT_DIR=. && export GIT_DIR &&
check_count A 2
)
'
Expand Down
8 changes: 7 additions & 1 deletion t/helper/test-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
#include "test-tool-utils.h"
#include "trace2.h"
#include "parse-options.h"
#include "environment.h"

static const char * const test_tool_usage[] = {
"test-tool [-C <directory>] <command [<arguments>...]]",
"test-tool [-C <directory>] [--git-dir=<path>] <command [<arguments>...]]",
NULL
};

Expand Down Expand Up @@ -107,9 +108,12 @@ static NORETURN void die_usage(void)
int cmd_main(int argc, const char **argv)
{
const char *working_directory = NULL;
const char *git_dir = NULL;
struct option options[] = {
OPT_STRING('C', NULL, &working_directory, "directory",
"change the working directory"),
OPT_STRING(0, "git-dir", &git_dir, "path",
"set the path to the repository"),
OPT_END()
};

Expand All @@ -123,6 +127,8 @@ int cmd_main(int argc, const char **argv)

if (working_directory && chdir(working_directory) < 0)
die("Could not cd to '%s'", working_directory);
if (git_dir)
setenv(GIT_DIR_ENVIRONMENT, git_dir, 1);

for (size_t i = 0; i < ARRAY_SIZE(cmds); i++) {
if (!strcmp(cmds[i].name, argv[1])) {
Expand Down
2 changes: 1 addition & 1 deletion t/lib-bitmap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ basic_bitmap_tests () {
rm -fr partial-clone.git &&
git clone --no-local --bare --filter=blob:none . partial-clone.git &&
(
cd partial-clone.git &&
cd partial-clone.git && GIT_DIR=. && export GIT_DIR &&
pack=$(echo objects/pack/*.pack) &&
git verify-pack -v "$pack" >have &&
awk "/blob/ { print \$1 }" <have >blobs &&
Expand Down
32 changes: 27 additions & 5 deletions t/lib-commit-graph.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,41 @@ graph_git_two_modes() {
# NOTE: it is a bug to call this function with <directory> containing
# any characters in $IFS.
graph_git_behavior() {
BARE=
if test "$1" = "--bare"
then
BARE=t
shift
fi
MSG=$1
DIR=$2
BRANCH=$3
COMPARE=$4
test_expect_success "check normal git operations: $MSG" '
graph_git_two_modes "${DIR:+-C $DIR} log --oneline $BRANCH" &&
graph_git_two_modes "${DIR:+-C $DIR} log --topo-order $BRANCH" &&
graph_git_two_modes "${DIR:+-C $DIR} log --graph $COMPARE..$BRANCH" &&
graph_git_two_modes "${DIR:+-C $DIR} branch -vv" &&
graph_git_two_modes "${DIR:+-C $DIR} merge-base -a $BRANCH $COMPARE"
if test -n "$BARE"
then
DIR_ARGS="${DIR:+--git-dir=$DIR}"
else
DIR_ARGS="${DIR:+-C $DIR}"
fi &&
graph_git_two_modes "$DIR_ARGS log --oneline $BRANCH" &&
graph_git_two_modes "$DIR_ARGS log --topo-order $BRANCH" &&
graph_git_two_modes "$DIR_ARGS log --graph $COMPARE..$BRANCH" &&
graph_git_two_modes "$DIR_ARGS branch -vv" &&
graph_git_two_modes "$DIR_ARGS merge-base -a $BRANCH $COMPARE"
'
}

graph_read_expect() {
OPTIONAL=""
NUM_CHUNKS=3
DIR="."
BARE=
if test "$1" = "--bare"
then
BARE=t
shift
fi
if test "$1" = -C
then
shift
Expand Down Expand Up @@ -68,6 +86,10 @@ graph_read_expect() {
EOF
(
cd "$DIR" &&
if test -n "$BARE"
then
GIT_DIR=. && export GIT_DIR
fi &&
test-tool read-graph >output &&
test_cmp expect output
)
Expand Down
4 changes: 2 additions & 2 deletions t/lib-diff-alternative.sh
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,14 @@ EOF
'

test_expect_success "diff from attributes with bare repo with source" '
git -C bare.git --attr-source=branchA -c diff.driver.algorithm=myers \
git --git-dir=bare.git --attr-source=branchA -c diff.driver.algorithm=myers \
-c diff.driverA.algorithm=$STRATEGY \
diff HEAD:file1 HEAD:file2 >output &&
test_cmp expect output
'

test_expect_success "diff from attributes with bare repo with invalid source" '
test_must_fail git -C bare.git --attr-source=invalid-branch diff \
test_must_fail git --git-dir=bare.git --attr-source=invalid-branch diff \
HEAD:file1 HEAD:file2
'

Expand Down
12 changes: 5 additions & 7 deletions t/lib-httpd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ test_http_push_nonff () {

test_expect_success 'non-fast-forward push fails' '
cd "$REMOTE_REPO" &&
HEAD=$(git rev-parse --verify HEAD) &&
HEAD=$(git --git-dir=. rev-parse --verify HEAD) &&

cd "$LOCAL_REPO" &&
git checkout $BRANCH &&
Expand All @@ -270,7 +270,7 @@ test_http_push_nonff () {
(
cd "$REMOTE_REPO" &&
echo "$HEAD" >expect &&
git rev-parse --verify HEAD >actual &&
git --git-dir=. rev-parse --verify HEAD >actual &&
test_cmp expect actual
)
'
Expand All @@ -284,18 +284,16 @@ test_http_push_nonff () {
'

test_expect_${EXPECT_CAS_RESULT} 'force with lease aka cas' '
HEAD=$( cd "$REMOTE_REPO" && git rev-parse --verify HEAD ) &&
HEAD=$(git --git-dir="$REMOTE_REPO" rev-parse --verify HEAD) &&
test_when_finished '\''
(cd "$REMOTE_REPO" && git update-ref HEAD "$HEAD")
git --git-dir="$REMOTE_REPO" update-ref HEAD "$HEAD"
'\'' &&
(
cd "$LOCAL_REPO" &&
git push -v --force-with-lease=$BRANCH:$HEAD origin
) &&
git rev-parse --verify "$BRANCH" >expect &&
(
cd "$REMOTE_REPO" && git rev-parse --verify HEAD
) >actual &&
git --git-dir="$REMOTE_REPO" rev-parse --verify HEAD >actual &&
test_cmp expect actual
'
}
Expand Down
32 changes: 16 additions & 16 deletions t/lib-proto-disable.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ test_allow_var () {

test_expect_success "fetch $desc (enabled)" '
(
cd tmp.git &&
cd tmp.git && GIT_DIR=. && export GIT_DIR &&
GIT_ALLOW_PROTOCOL=$proto &&
export GIT_ALLOW_PROTOCOL &&
git fetch
Expand All @@ -26,7 +26,7 @@ test_allow_var () {

test_expect_success "push $desc (enabled)" '
(
cd tmp.git &&
cd tmp.git && GIT_DIR=. && export GIT_DIR &&
GIT_ALLOW_PROTOCOL=$proto &&
export GIT_ALLOW_PROTOCOL &&
git push origin HEAD:pushed
Expand All @@ -35,7 +35,7 @@ test_allow_var () {

test_expect_success "push $desc (disabled)" '
(
cd tmp.git &&
cd tmp.git && GIT_DIR=. && export GIT_DIR &&
GIT_ALLOW_PROTOCOL=none &&
export GIT_ALLOW_PROTOCOL &&
test_must_fail git push origin HEAD:pushed
Expand All @@ -44,7 +44,7 @@ test_allow_var () {

test_expect_success "fetch $desc (disabled)" '
(
cd tmp.git &&
cd tmp.git && GIT_DIR=. && export GIT_DIR &&
GIT_ALLOW_PROTOCOL=none &&
export GIT_ALLOW_PROTOCOL &&
test_must_fail git fetch
Expand Down Expand Up @@ -83,19 +83,19 @@ test_config () {
'

test_expect_success "fetch $desc (enabled)" '
git -C tmp.git -c protocol.$proto.allow=always fetch
git --git-dir=tmp.git -c protocol.$proto.allow=always fetch
'

test_expect_success "push $desc (enabled)" '
git -C tmp.git -c protocol.$proto.allow=always push origin HEAD:pushed
git --git-dir=tmp.git -c protocol.$proto.allow=always push origin HEAD:pushed
'

test_expect_success "push $desc (disabled)" '
test_must_fail git -C tmp.git -c protocol.$proto.allow=never push origin HEAD:pushed
test_must_fail git --git-dir=tmp.git -c protocol.$proto.allow=never push origin HEAD:pushed
'

test_expect_success "fetch $desc (disabled)" '
test_must_fail git -C tmp.git -c protocol.$proto.allow=never fetch
test_must_fail git --git-dir=tmp.git -c protocol.$proto.allow=never fetch
'

test_expect_success "clone $desc (disabled)" '
Expand All @@ -110,16 +110,16 @@ test_config () {
'

test_expect_success "fetch $desc (enabled)" '
git -C tmp.git -c protocol.$proto.allow=user fetch
git --git-dir=tmp.git -c protocol.$proto.allow=user fetch
'

test_expect_success "push $desc (enabled)" '
git -C tmp.git -c protocol.$proto.allow=user push origin HEAD:pushed
git --git-dir=tmp.git -c protocol.$proto.allow=user push origin HEAD:pushed
'

test_expect_success "push $desc (disabled)" '
(
cd tmp.git &&
cd tmp.git && GIT_DIR=. && export GIT_DIR &&
GIT_PROTOCOL_FROM_USER=0 &&
export GIT_PROTOCOL_FROM_USER &&
test_must_fail git -c protocol.$proto.allow=user push origin HEAD:pushed
Expand All @@ -128,7 +128,7 @@ test_config () {

test_expect_success "fetch $desc (disabled)" '
(
cd tmp.git &&
cd tmp.git && GIT_DIR=. && export GIT_DIR &&
GIT_PROTOCOL_FROM_USER=0 &&
export GIT_PROTOCOL_FROM_USER &&
test_must_fail git -c protocol.$proto.allow=user fetch
Expand All @@ -153,22 +153,22 @@ test_config () {

test_expect_success "fetch $desc (enabled)" '
test_config_global protocol.allow always &&
git -C tmp.git fetch
git --git-dir=tmp.git fetch
'

test_expect_success "push $desc (enabled)" '
test_config_global protocol.allow always &&
git -C tmp.git push origin HEAD:pushed
git --git-dir=tmp.git push origin HEAD:pushed
'

test_expect_success "push $desc (disabled)" '
test_config_global protocol.allow never &&
test_must_fail git -C tmp.git push origin HEAD:pushed
test_must_fail git --git-dir=tmp.git push origin HEAD:pushed
'

test_expect_success "fetch $desc (disabled)" '
test_config_global protocol.allow never &&
test_must_fail git -C tmp.git fetch
test_must_fail git --git-dir=tmp.git fetch
'

test_expect_success "clone $desc (disabled)" '
Expand Down
Loading
Loading