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
2b93e97
t0001: allow implicit bare repo discovery for aliased-command test
dscho Mar 28, 2026
917523f
t0001: replace `cd`+`git` with `git --git-dir` in `check_config`
dscho Mar 29, 2026
00daa10
t0003: use `--git-dir` for bare repo attribute tests
dscho Mar 28, 2026
8a65749
t0056: allow implicit bare repo discovery for `-C` work-tree tests
dscho Mar 28, 2026
3626a8a
t1020: use `--git-dir` instead of subshell for bare repo
dscho Mar 28, 2026
f3d66fa
t1900: avoid using `-C <dir>` for a bare repository
dscho Mar 28, 2026
70bd3e3
t2400: explicitly specify bare repo for `git worktree add`
dscho Mar 29, 2026
a54a7d7
t2406: wrap bare repo commands in subshell with `GIT_DIR`
dscho Mar 29, 2026
9320b4e
t5503: avoid discovering a bare repository
dscho Apr 1, 2026
92516cc
t5505: export `GIT_DIR` after `git init --bare`
dscho Mar 29, 2026
755be63
t5509: specify bare repository path explicitly
dscho Mar 29, 2026
d8e4e1b
t5540/t5541: avoid accessing a bare repository via `-C <dir>`
dscho Apr 1, 2026
79b6055
t5619: wrap `test_commit_bulk` in `GIT_DIR` subshell for bare repo
dscho Mar 29, 2026
f4492ad
t6020: use `-C` for worktree, `--git-dir` for bare repository
dscho Mar 29, 2026
239bb60
t9210: pass `safe.bareRepository=all` to `scalar register`
dscho Mar 29, 2026
b3902a4
t9700: stop relying on implicit bare repo discovery
dscho Apr 1, 2026
172c44a
t4203: avoid implicit discovery of a bare repository
dscho Mar 29, 2026
f5ec623
git p4 clone --bare: need to be explicit about the gitdir
dscho Apr 1, 2026
2aa1ab7
t5615: wrap bare alternate test in subshell with `GIT_DIR`
dscho Mar 29, 2026
5476168
lib-commit-graph: teach `--bare` to graph helpers
dscho Mar 28, 2026
c0b48cd
test-tool: add a `--git-dir` option
dscho Mar 29, 2026
0cd2c74
test_config, test_unconfig: add a `--git-dir` option
dscho Mar 29, 2026
25abbb4
test_hook: add a `--git-dir` option
dscho Mar 29, 2026
7539515
t5318: pass `--bare` to commit-graph helpers for bare repo tests
dscho Mar 29, 2026
feb9dbe
t1460: restructure helpers for `--git-dir` dispatch
dscho Mar 28, 2026
7da3f2f
tests: use `test_config --git-dir` for bare repos
dscho Mar 29, 2026
a961204
t2400: pass through args in `post_checkout_hook` for `--git-dir`
dscho Mar 29, 2026
01e3eb0
Merge branch 'standalone-fixes'
dscho Mar 28, 2026
8dffffc
t5411: teach `test_cmp_refs` a `--git-dir` option
dscho Mar 29, 2026
ffd5f4a
Merge branch 'cd-gitdir-subshell'
dscho Mar 29, 2026
367c28f
t5411: use `test_cmp_refs --git-dir` for bare repos
dscho Mar 29, 2026
c0d2322
Merge branch 'lib-commit-graph-bare'
dscho Mar 28, 2026
2252e55
Merge branch 'test-tool-git-dir'
dscho Mar 29, 2026
09a846f
Merge branch 'test-config-git-dir'
dscho Mar 29, 2026
22fae7b
tests: use `test_hook --git-dir` for bare repos
dscho Mar 29, 2026
ad141d4
t2400, t5516: strip directory prefix from `--git-dir` path arguments
dscho Mar 29, 2026
daeed0d
Merge branch 'test-hook-git-dir'
dscho Mar 29, 2026
e26e7ca
t5310, t5510, t5516: adjust `git fetch .` in bare repositories
dscho Mar 29, 2026
020a964
tests: add set/unset GIT_DIR pairs where appropriate
dscho Mar 29, 2026
5487aec
t7103, t9903: export `GIT_CONFIG_PARAMETERS` in `.git` directory tests
dscho Mar 29, 2026
6172b4c
tests: replace `-C` to `--git-dir`, dropping `../` prefixes as needed
dscho Mar 29, 2026
1faff2c
tests: export `GIT_DIR=.` after `cd` into bare repos
dscho Mar 29, 2026
a91251d
Merge branch 'test-cmp-refs-git-dir'
dscho Mar 29, 2026
910b2d8
tests: use `--git-dir` instead of `-C` for bare repos
dscho Mar 29, 2026
d73bb42
Merge branch 'mechanical-fixes'
dscho Apr 1, 2026
bda3baf
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 @@ -258,7 +258,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 @@ -269,7 +269,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 @@ -283,18 +283,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