Merge branch 'ps/reftable-backend' into kn/for-all-refs
* ps/reftable-backend: refs/reftable: fix leak when copying reflog fails ci: add jobs to test with the reftable backend refs: introduce reftable backend
This commit is contained in:
commit
c684b582bc
9
.github/workflows/main.yml
vendored
9
.github/workflows/main.yml
vendored
@ -266,6 +266,9 @@ jobs:
|
|||||||
- jobname: linux-sha256
|
- jobname: linux-sha256
|
||||||
cc: clang
|
cc: clang
|
||||||
pool: ubuntu-latest
|
pool: ubuntu-latest
|
||||||
|
- jobname: linux-reftable
|
||||||
|
cc: clang
|
||||||
|
pool: ubuntu-latest
|
||||||
- jobname: linux-gcc
|
- jobname: linux-gcc
|
||||||
cc: gcc
|
cc: gcc
|
||||||
cc_package: gcc-8
|
cc_package: gcc-8
|
||||||
@ -277,6 +280,9 @@ jobs:
|
|||||||
- jobname: osx-clang
|
- jobname: osx-clang
|
||||||
cc: clang
|
cc: clang
|
||||||
pool: macos-13
|
pool: macos-13
|
||||||
|
- jobname: osx-reftable
|
||||||
|
cc: clang
|
||||||
|
pool: macos-13
|
||||||
- jobname: osx-gcc
|
- jobname: osx-gcc
|
||||||
cc: gcc
|
cc: gcc
|
||||||
cc_package: gcc-13
|
cc_package: gcc-13
|
||||||
@ -287,6 +293,9 @@ jobs:
|
|||||||
- jobname: linux-leaks
|
- jobname: linux-leaks
|
||||||
cc: gcc
|
cc: gcc
|
||||||
pool: ubuntu-latest
|
pool: ubuntu-latest
|
||||||
|
- jobname: linux-reftable-leaks
|
||||||
|
cc: gcc
|
||||||
|
pool: ubuntu-latest
|
||||||
- jobname: linux-asan-ubsan
|
- jobname: linux-asan-ubsan
|
||||||
cc: clang
|
cc: clang
|
||||||
pool: ubuntu-latest
|
pool: ubuntu-latest
|
||||||
|
@ -26,6 +26,9 @@ test:linux:
|
|||||||
- jobname: linux-sha256
|
- jobname: linux-sha256
|
||||||
image: ubuntu:latest
|
image: ubuntu:latest
|
||||||
CC: clang
|
CC: clang
|
||||||
|
- jobname: linux-reftable
|
||||||
|
image: ubuntu:latest
|
||||||
|
CC: clang
|
||||||
- jobname: linux-gcc
|
- jobname: linux-gcc
|
||||||
image: ubuntu:20.04
|
image: ubuntu:20.04
|
||||||
CC: gcc
|
CC: gcc
|
||||||
@ -40,6 +43,9 @@ test:linux:
|
|||||||
- jobname: linux-leaks
|
- jobname: linux-leaks
|
||||||
image: ubuntu:latest
|
image: ubuntu:latest
|
||||||
CC: gcc
|
CC: gcc
|
||||||
|
- jobname: linux-reftable-leaks
|
||||||
|
image: ubuntu:latest
|
||||||
|
CC: gcc
|
||||||
- jobname: linux-asan-ubsan
|
- jobname: linux-asan-ubsan
|
||||||
image: ubuntu:latest
|
image: ubuntu:latest
|
||||||
CC: clang
|
CC: clang
|
||||||
@ -79,6 +85,9 @@ test:osx:
|
|||||||
- jobname: osx-clang
|
- jobname: osx-clang
|
||||||
image: macos-13-xcode-14
|
image: macos-13-xcode-14
|
||||||
CC: clang
|
CC: clang
|
||||||
|
- jobname: osx-reftable
|
||||||
|
image: macos-13-xcode-14
|
||||||
|
CC: clang
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- t/failed-test-artifacts
|
- t/failed-test-artifacts
|
||||||
|
@ -1 +1,3 @@
|
|||||||
* `files` for loose files with packed-refs. This is the default.
|
* `files` for loose files with packed-refs. This is the default.
|
||||||
|
* `reftable` for the reftable format. This format is experimental and its
|
||||||
|
internals are subject to change.
|
||||||
|
@ -103,5 +103,6 @@ GIT_COMMON_DIR/worktrees/<id>/config.worktree)
|
|||||||
|
|
||||||
==== `refStorage`
|
==== `refStorage`
|
||||||
|
|
||||||
Specifies the file format for the ref database. The only valid value
|
Specifies the file format for the ref database. The valid values are
|
||||||
is `files` (loose references with a packed-refs file).
|
`files` (loose references with a packed-refs file) and `reftable` (see
|
||||||
|
Documentation/technical/reftable.txt).
|
||||||
|
1
Makefile
1
Makefile
@ -1126,6 +1126,7 @@ LIB_OBJS += reflog.o
|
|||||||
LIB_OBJS += refs.o
|
LIB_OBJS += refs.o
|
||||||
LIB_OBJS += refs/debug.o
|
LIB_OBJS += refs/debug.o
|
||||||
LIB_OBJS += refs/files-backend.o
|
LIB_OBJS += refs/files-backend.o
|
||||||
|
LIB_OBJS += refs/reftable-backend.o
|
||||||
LIB_OBJS += refs/iterator.o
|
LIB_OBJS += refs/iterator.o
|
||||||
LIB_OBJS += refs/packed-backend.o
|
LIB_OBJS += refs/packed-backend.o
|
||||||
LIB_OBJS += refs/ref-cache.o
|
LIB_OBJS += refs/ref-cache.o
|
||||||
|
@ -367,7 +367,7 @@ linux-musl)
|
|||||||
MAKEFLAGS="$MAKEFLAGS NO_REGEX=Yes ICONV_OMITS_BOM=Yes"
|
MAKEFLAGS="$MAKEFLAGS NO_REGEX=Yes ICONV_OMITS_BOM=Yes"
|
||||||
MAKEFLAGS="$MAKEFLAGS GIT_TEST_UTF8_LOCALE=C.UTF-8"
|
MAKEFLAGS="$MAKEFLAGS GIT_TEST_UTF8_LOCALE=C.UTF-8"
|
||||||
;;
|
;;
|
||||||
linux-leaks)
|
linux-leaks|linux-reftable-leaks)
|
||||||
export SANITIZE=leak
|
export SANITIZE=leak
|
||||||
export GIT_TEST_PASSING_SANITIZE_LEAK=true
|
export GIT_TEST_PASSING_SANITIZE_LEAK=true
|
||||||
export GIT_TEST_SANITIZE_LEAK_LOG=true
|
export GIT_TEST_SANITIZE_LEAK_LOG=true
|
||||||
|
@ -37,6 +37,9 @@ linux-clang)
|
|||||||
linux-sha256)
|
linux-sha256)
|
||||||
export GIT_TEST_DEFAULT_HASH=sha256
|
export GIT_TEST_DEFAULT_HASH=sha256
|
||||||
;;
|
;;
|
||||||
|
linux-reftable|linux-reftable-leaks|osx-reftable)
|
||||||
|
export GIT_TEST_DEFAULT_REF_FORMAT=reftable
|
||||||
|
;;
|
||||||
pedantic)
|
pedantic)
|
||||||
# Don't run the tests; we only care about whether Git can be
|
# Don't run the tests; we only care about whether Git can be
|
||||||
# built.
|
# built.
|
||||||
|
@ -79,7 +79,7 @@ trap cleanup $siglist
|
|||||||
# create the links to the original repo. explicitly exclude index, HEAD and
|
# create the links to the original repo. explicitly exclude index, HEAD and
|
||||||
# logs/HEAD from the list since they are purely related to the current working
|
# logs/HEAD from the list since they are purely related to the current working
|
||||||
# directory, and should not be shared.
|
# directory, and should not be shared.
|
||||||
for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn
|
for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn reftable
|
||||||
do
|
do
|
||||||
# create a containing directory if needed
|
# create a containing directory if needed
|
||||||
case $x in
|
case $x in
|
||||||
|
2
path.c
2
path.c
@ -871,7 +871,7 @@ const char *enter_repo(const char *path, int strict)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int calc_shared_perm(int mode)
|
int calc_shared_perm(int mode)
|
||||||
{
|
{
|
||||||
int tweak;
|
int tweak;
|
||||||
|
|
||||||
|
1
path.h
1
path.h
@ -181,6 +181,7 @@ const char *git_path_shallow(struct repository *r);
|
|||||||
int ends_with_path_components(const char *path, const char *components);
|
int ends_with_path_components(const char *path, const char *components);
|
||||||
int validate_headref(const char *ref);
|
int validate_headref(const char *ref);
|
||||||
|
|
||||||
|
int calc_shared_perm(int mode);
|
||||||
int adjust_shared_perm(const char *path);
|
int adjust_shared_perm(const char *path);
|
||||||
|
|
||||||
char *interpolate_path(const char *path, int real_home);
|
char *interpolate_path(const char *path, int real_home);
|
||||||
|
1
refs.c
1
refs.c
@ -35,6 +35,7 @@
|
|||||||
*/
|
*/
|
||||||
static const struct ref_storage_be *refs_backends[] = {
|
static const struct ref_storage_be *refs_backends[] = {
|
||||||
[REF_STORAGE_FORMAT_FILES] = &refs_be_files,
|
[REF_STORAGE_FORMAT_FILES] = &refs_be_files,
|
||||||
|
[REF_STORAGE_FORMAT_REFTABLE] = &refs_be_reftable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ref_storage_be *find_ref_storage_backend(unsigned int ref_storage_format)
|
static const struct ref_storage_be *find_ref_storage_backend(unsigned int ref_storage_format)
|
||||||
|
@ -693,6 +693,7 @@ struct ref_storage_be {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern struct ref_storage_be refs_be_files;
|
extern struct ref_storage_be refs_be_files;
|
||||||
|
extern struct ref_storage_be refs_be_reftable;
|
||||||
extern struct ref_storage_be refs_be_packed;
|
extern struct ref_storage_be refs_be_packed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
2297
refs/reftable-backend.c
Normal file
2297
refs/reftable-backend.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -24,8 +24,9 @@ enum fetch_negotiation_setting {
|
|||||||
FETCH_NEGOTIATION_NOOP,
|
FETCH_NEGOTIATION_NOOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define REF_STORAGE_FORMAT_UNKNOWN 0
|
#define REF_STORAGE_FORMAT_UNKNOWN 0
|
||||||
#define REF_STORAGE_FORMAT_FILES 1
|
#define REF_STORAGE_FORMAT_FILES 1
|
||||||
|
#define REF_STORAGE_FORMAT_REFTABLE 2
|
||||||
|
|
||||||
struct repo_settings {
|
struct repo_settings {
|
||||||
int initialized;
|
int initialized;
|
||||||
|
887
t/t0610-reftable-basics.sh
Executable file
887
t/t0610-reftable-basics.sh
Executable file
@ -0,0 +1,887 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Google LLC
|
||||||
|
#
|
||||||
|
|
||||||
|
test_description='reftable basics'
|
||||||
|
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
||||||
|
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
if ! test_have_prereq REFTABLE
|
||||||
|
then
|
||||||
|
skip_all='skipping reftable tests; set GIT_TEST_DEFAULT_REF_FORMAT=reftable'
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
|
INVALID_OID=$(test_oid 001)
|
||||||
|
|
||||||
|
test_expect_success 'init: creates basic reftable structures' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_path_is_dir repo/.git/reftable &&
|
||||||
|
test_path_is_file repo/.git/reftable/tables.list &&
|
||||||
|
echo reftable >expect &&
|
||||||
|
git -C repo rev-parse --show-ref-format >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'init: sha256 object format via environment variable' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
GIT_DEFAULT_HASH=sha256 git init repo &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
sha256
|
||||||
|
reftable
|
||||||
|
EOF
|
||||||
|
git -C repo rev-parse --show-object-format --show-ref-format >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'init: sha256 object format via option' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init --object-format=sha256 repo &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
sha256
|
||||||
|
reftable
|
||||||
|
EOF
|
||||||
|
git -C repo rev-parse --show-object-format --show-ref-format >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'init: reinitializing reftable backend succeeds' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
|
||||||
|
git -C repo for-each-ref >expect &&
|
||||||
|
git init --ref-format=reftable repo &&
|
||||||
|
git -C repo for-each-ref >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'init: reinitializing files with reftable backend fails' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init --ref-format=files repo &&
|
||||||
|
test_commit -C repo file &&
|
||||||
|
|
||||||
|
cp repo/.git/HEAD expect &&
|
||||||
|
test_must_fail git init --ref-format=reftable repo &&
|
||||||
|
test_cmp expect repo/.git/HEAD
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'init: reinitializing reftable with files backend fails' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init --ref-format=reftable repo &&
|
||||||
|
test_commit -C repo file &&
|
||||||
|
|
||||||
|
cp repo/.git/HEAD expect &&
|
||||||
|
test_must_fail git init --ref-format=files repo &&
|
||||||
|
test_cmp expect repo/.git/HEAD
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_perms () {
|
||||||
|
local perms="$1"
|
||||||
|
local file="$2"
|
||||||
|
local actual=$(ls -l "$file") &&
|
||||||
|
|
||||||
|
case "$actual" in
|
||||||
|
$perms*)
|
||||||
|
: happy
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "$(basename $2) is not $perms but $actual"
|
||||||
|
false
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
for umask in 002 022
|
||||||
|
do
|
||||||
|
test_expect_success POSIXPERM 'init: honors core.sharedRepository' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
(
|
||||||
|
umask $umask &&
|
||||||
|
git init --shared=true repo &&
|
||||||
|
test 1 = "$(git -C repo config core.sharedrepository)"
|
||||||
|
) &&
|
||||||
|
test_expect_perms "-rw-rw-r--" repo/.git/reftable/tables.list &&
|
||||||
|
for table in repo/.git/reftable/*.ref
|
||||||
|
do
|
||||||
|
test_expect_perms "-rw-rw-r--" "$table" ||
|
||||||
|
return 1
|
||||||
|
done
|
||||||
|
'
|
||||||
|
done
|
||||||
|
|
||||||
|
test_expect_success 'clone: can clone reftable repository' '
|
||||||
|
test_when_finished "rm -rf repo clone" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo message1 file1 &&
|
||||||
|
|
||||||
|
git clone repo cloned &&
|
||||||
|
echo reftable >expect &&
|
||||||
|
git -C cloned rev-parse --show-ref-format >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_path_is_file cloned/file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'clone: can clone reffiles into reftable repository' '
|
||||||
|
test_when_finished "rm -rf reffiles reftable" &&
|
||||||
|
git init --ref-format=files reffiles &&
|
||||||
|
test_commit -C reffiles A &&
|
||||||
|
git clone --ref-format=reftable ./reffiles reftable &&
|
||||||
|
|
||||||
|
git -C reffiles rev-parse HEAD >expect &&
|
||||||
|
git -C reftable rev-parse HEAD >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git -C reftable rev-parse --show-ref-format >actual &&
|
||||||
|
echo reftable >expect &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git -C reffiles rev-parse --show-ref-format >actual &&
|
||||||
|
echo files >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'clone: can clone reftable into reffiles repository' '
|
||||||
|
test_when_finished "rm -rf reffiles reftable" &&
|
||||||
|
git init --ref-format=reftable reftable &&
|
||||||
|
test_commit -C reftable A &&
|
||||||
|
git clone --ref-format=files ./reftable reffiles &&
|
||||||
|
|
||||||
|
git -C reftable rev-parse HEAD >expect &&
|
||||||
|
git -C reffiles rev-parse HEAD >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git -C reftable rev-parse --show-ref-format >actual &&
|
||||||
|
echo reftable >expect &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git -C reffiles rev-parse --show-ref-format >actual &&
|
||||||
|
echo files >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: corrupted tables cause failure' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit file1 &&
|
||||||
|
for f in .git/reftable/*.ref
|
||||||
|
do
|
||||||
|
: >"$f" || return 1
|
||||||
|
done &&
|
||||||
|
test_must_fail git update-ref refs/heads/main HEAD
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: corrupted tables.list cause failure' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit file1 &&
|
||||||
|
echo garbage >.git/reftable/tables.list &&
|
||||||
|
test_must_fail git update-ref refs/heads/main HEAD
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: refuses to write ref causing F/D conflict' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo file &&
|
||||||
|
test_must_fail git -C repo update-ref refs/heads/main/forbidden
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: deleting ref with invalid name fails' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo file &&
|
||||||
|
test_must_fail git -C repo update-ref -d ../../my-private-file
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: can skip object ID verification' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_must_fail test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID 0 &&
|
||||||
|
test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: updating same ref multiple times fails' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
cat >updates <<-EOF &&
|
||||||
|
update refs/heads/main $A
|
||||||
|
update refs/heads/main $A
|
||||||
|
EOF
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
fatal: multiple updates for ref ${SQ}refs/heads/main${SQ} not allowed
|
||||||
|
EOF
|
||||||
|
test_must_fail git -C repo update-ref --stdin <updates 2>err &&
|
||||||
|
test_cmp expect err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: can delete symbolic self-reference with git-symbolic-ref(1)' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
git -C repo symbolic-ref refs/heads/self refs/heads/self &&
|
||||||
|
git -C repo symbolic-ref -d refs/heads/self
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: deleting symbolic self-reference without --no-deref fails' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
git -C repo symbolic-ref refs/heads/self refs/heads/self &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
error: multiple updates for ${SQ}refs/heads/self${SQ} (including one via symref ${SQ}refs/heads/self${SQ}) are not allowed
|
||||||
|
EOF
|
||||||
|
test_must_fail git -C repo update-ref -d refs/heads/self 2>err &&
|
||||||
|
test_cmp expect err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: deleting symbolic self-reference with --no-deref succeeds' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
git -C repo symbolic-ref refs/heads/self refs/heads/self &&
|
||||||
|
git -C repo update-ref -d --no-deref refs/heads/self
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: creating symbolic ref fails with F/D conflict' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
error: unable to write symref for refs/heads: file/directory conflict
|
||||||
|
EOF
|
||||||
|
test_must_fail git -C repo symbolic-ref refs/heads refs/heads/foo 2>err &&
|
||||||
|
test_cmp expect err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: ref deletion' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit file &&
|
||||||
|
HEAD_OID=$(git show-ref -s --verify HEAD) &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
$HEAD_OID refs/heads/main
|
||||||
|
$HEAD_OID refs/tags/file
|
||||||
|
EOF
|
||||||
|
git show-ref >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
test_must_fail git update-ref -d refs/tags/file $INVALID_OID &&
|
||||||
|
git show-ref >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git update-ref -d refs/tags/file $HEAD_OID &&
|
||||||
|
echo "$HEAD_OID refs/heads/main" >expect &&
|
||||||
|
git show-ref >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: writes cause auto-compaction' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
|
||||||
|
git init repo &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list &&
|
||||||
|
|
||||||
|
test_commit -C repo --no-tag A &&
|
||||||
|
test_line_count = 2 repo/.git/reftable/tables.list &&
|
||||||
|
|
||||||
|
test_commit -C repo --no-tag B &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
check_fsync_events () {
|
||||||
|
local trace="$1" &&
|
||||||
|
shift &&
|
||||||
|
|
||||||
|
cat >expect &&
|
||||||
|
sed -n \
|
||||||
|
-e '/^{"event":"counter",.*"category":"fsync",/ {
|
||||||
|
s/.*"category":"fsync",//;
|
||||||
|
s/}$//;
|
||||||
|
p;
|
||||||
|
}' \
|
||||||
|
<"$trace" >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: writes are synced' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo initial &&
|
||||||
|
|
||||||
|
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
|
||||||
|
GIT_TEST_FSYNC=true \
|
||||||
|
git -C repo -c core.fsync=reference \
|
||||||
|
-c core.fsyncMethod=fsync update-ref refs/heads/branch HEAD &&
|
||||||
|
check_fsync_events trace2.txt <<-EOF
|
||||||
|
"name":"hardware-flush","count":2
|
||||||
|
EOF
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pack-refs: compacts tables' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
|
||||||
|
test_commit -C repo A &&
|
||||||
|
ls -1 repo/.git/reftable >table-files &&
|
||||||
|
test_line_count = 4 table-files &&
|
||||||
|
test_line_count = 3 repo/.git/reftable/tables.list &&
|
||||||
|
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
ls -1 repo/.git/reftable >table-files &&
|
||||||
|
test_line_count = 2 table-files &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pack-refs: prunes stale tables' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
touch repo/.git/reftable/stale-table.ref &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
test_path_is_missing repo/.git/reftable/stable-ref.ref
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pack-refs: does not prune non-table files' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
touch repo/.git/reftable/garbage &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
test_path_is_file repo/.git/reftable/garbage
|
||||||
|
'
|
||||||
|
|
||||||
|
for umask in 002 022
|
||||||
|
do
|
||||||
|
test_expect_success POSIXPERM 'pack-refs: honors core.sharedRepository' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
(
|
||||||
|
umask $umask &&
|
||||||
|
git init --shared=true repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
test_line_count = 3 repo/.git/reftable/tables.list
|
||||||
|
) &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
test_expect_perms "-rw-rw-r--" repo/.git/reftable/tables.list &&
|
||||||
|
for table in repo/.git/reftable/*.ref
|
||||||
|
do
|
||||||
|
test_expect_perms "-rw-rw-r--" "$table" ||
|
||||||
|
return 1
|
||||||
|
done
|
||||||
|
'
|
||||||
|
done
|
||||||
|
|
||||||
|
test_expect_success 'packed-refs: writes are synced' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo initial &&
|
||||||
|
test_line_count = 2 table-files &&
|
||||||
|
|
||||||
|
: >trace2.txt &&
|
||||||
|
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
|
||||||
|
GIT_TEST_FSYNC=true \
|
||||||
|
git -C repo -c core.fsync=reference \
|
||||||
|
-c core.fsyncMethod=fsync pack-refs &&
|
||||||
|
check_fsync_events trace2.txt <<-EOF
|
||||||
|
"name":"hardware-flush","count":2
|
||||||
|
EOF
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref iterator: bogus names are flagged' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit --no-tag file &&
|
||||||
|
test-tool ref-store main update-ref msg "refs/heads/bogus..name" $(git rev-parse HEAD) $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
|
||||||
|
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
$ZERO_OID refs/heads/bogus..name 0xc
|
||||||
|
$(git rev-parse HEAD) refs/heads/main 0x0
|
||||||
|
EOF
|
||||||
|
test-tool ref-store main for-each-ref "" >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref iterator: missing object IDs are not flagged' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test-tool ref-store main update-ref msg "refs/heads/broken-hash" $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION &&
|
||||||
|
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
$INVALID_OID refs/heads/broken-hash 0x0
|
||||||
|
EOF
|
||||||
|
test-tool ref-store main for-each-ref "" >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: commit and list refs' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo file &&
|
||||||
|
test_write_lines refs/heads/main refs/tags/file >expect &&
|
||||||
|
git -C repo for-each-ref --format="%(refname)" >actual &&
|
||||||
|
test_cmp actual expect
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: can write large commit message' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
perl -e "
|
||||||
|
print \"this is a long commit message\" x 50000
|
||||||
|
" >commit-msg &&
|
||||||
|
git -C repo commit --allow-empty --file=../commit-msg
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: show-ref fails with empty repository' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_must_fail git -C repo show-ref >actual &&
|
||||||
|
test_must_be_empty actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: can check out unborn branch' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
git -C repo checkout -b main
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: peeled tags are stored' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo file &&
|
||||||
|
git -C repo tag -m "annotated tag" test_tag HEAD &&
|
||||||
|
for ref in refs/heads/main refs/tags/file refs/tags/test_tag refs/tags/test_tag^{}
|
||||||
|
do
|
||||||
|
echo "$(git -C repo rev-parse "$ref") $ref" || return 1
|
||||||
|
done >expect &&
|
||||||
|
git -C repo show-ref -d >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: for-each-ref can print symrefs' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit file &&
|
||||||
|
git branch &&
|
||||||
|
git symbolic-ref refs/heads/sym refs/heads/main &&
|
||||||
|
cat >expected <<-EOF &&
|
||||||
|
refs/heads/main
|
||||||
|
EOF
|
||||||
|
git for-each-ref --format="%(symref)" refs/heads/sym >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: notes' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
write_script fake_editor <<-\EOF &&
|
||||||
|
echo "$MSG" >"$1"
|
||||||
|
echo "$MSG" >&2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_commit 1st &&
|
||||||
|
test_commit 2nd &&
|
||||||
|
GIT_EDITOR=./fake_editor MSG=b4 git notes add &&
|
||||||
|
GIT_EDITOR=./fake_editor MSG=b3 git notes edit &&
|
||||||
|
echo b4 >expect &&
|
||||||
|
git notes --ref commits@{1} show >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: stash' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit file &&
|
||||||
|
git stash list >expect &&
|
||||||
|
test_line_count = 0 expect &&
|
||||||
|
|
||||||
|
echo hoi >>file.t &&
|
||||||
|
git stash push -m stashed &&
|
||||||
|
git stash list >expect &&
|
||||||
|
test_line_count = 1 expect &&
|
||||||
|
|
||||||
|
git stash clear &&
|
||||||
|
git stash list >expect &&
|
||||||
|
test_line_count = 0 expect
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: cherry-pick' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit message1 file1 &&
|
||||||
|
test_commit message2 file2 &&
|
||||||
|
git branch source &&
|
||||||
|
git checkout HEAD^ &&
|
||||||
|
test_commit message3 file3 &&
|
||||||
|
git cherry-pick source &&
|
||||||
|
test_path_is_file file2
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'basic: rebase' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit message1 file1 &&
|
||||||
|
test_commit message2 file2 &&
|
||||||
|
git branch source &&
|
||||||
|
git checkout HEAD^ &&
|
||||||
|
test_commit message3 file3 &&
|
||||||
|
git rebase source &&
|
||||||
|
test_path_is_file file2
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: can delete separate reflog entries' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
|
||||||
|
test_commit file &&
|
||||||
|
test_commit file2 &&
|
||||||
|
test_commit file3 &&
|
||||||
|
test_commit file4 &&
|
||||||
|
git reflog >actual &&
|
||||||
|
grep file3 actual &&
|
||||||
|
|
||||||
|
git reflog delete HEAD@{1} &&
|
||||||
|
git reflog >actual &&
|
||||||
|
! grep file3 actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: can switch to previous branch' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit file1 &&
|
||||||
|
git checkout -b branch1 &&
|
||||||
|
test_commit file2 &&
|
||||||
|
git checkout -b branch2 &&
|
||||||
|
git switch - &&
|
||||||
|
git rev-parse --symbolic-full-name HEAD >actual &&
|
||||||
|
echo refs/heads/branch1 >expect &&
|
||||||
|
test_cmp actual expect
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: copying branch writes reflog entry' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit file1 &&
|
||||||
|
test_commit file2 &&
|
||||||
|
oid=$(git rev-parse --short HEAD) &&
|
||||||
|
git branch src &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
${oid} dst@{0}: Branch: copied refs/heads/src to refs/heads/dst
|
||||||
|
${oid} dst@{1}: branch: Created from main
|
||||||
|
EOF
|
||||||
|
git branch -c src dst &&
|
||||||
|
git reflog dst >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: renaming branch writes reflog entry' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
git symbolic-ref HEAD refs/heads/before &&
|
||||||
|
test_commit file &&
|
||||||
|
git show-ref >expected.refs &&
|
||||||
|
sed s/before/after/g <expected.refs >expected &&
|
||||||
|
git branch -M after &&
|
||||||
|
git show-ref >actual &&
|
||||||
|
test_cmp expected actual &&
|
||||||
|
echo refs/heads/after >expected &&
|
||||||
|
git symbolic-ref HEAD >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: can store empty logs' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
|
||||||
|
test_must_fail test-tool ref-store main reflog-exists refs/heads/branch &&
|
||||||
|
test-tool ref-store main create-reflog refs/heads/branch &&
|
||||||
|
test-tool ref-store main reflog-exists refs/heads/branch &&
|
||||||
|
test-tool ref-store main for-each-reflog-ent-reverse refs/heads/branch >actual &&
|
||||||
|
test_must_be_empty actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: expiry empties reflog' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
|
||||||
|
test_commit initial &&
|
||||||
|
git checkout -b branch &&
|
||||||
|
test_commit fileA &&
|
||||||
|
test_commit fileB &&
|
||||||
|
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
commit: fileB
|
||||||
|
commit: fileA
|
||||||
|
branch: Created from HEAD
|
||||||
|
EOF
|
||||||
|
git reflog show --format="%gs" refs/heads/branch >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git reflog expire branch --expire=all &&
|
||||||
|
git reflog show --format="%gs" refs/heads/branch >actual &&
|
||||||
|
test_must_be_empty actual &&
|
||||||
|
test-tool ref-store main reflog-exists refs/heads/branch
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: can be deleted' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit initial &&
|
||||||
|
test-tool ref-store main reflog-exists refs/heads/main &&
|
||||||
|
test-tool ref-store main delete-reflog refs/heads/main &&
|
||||||
|
test_must_fail test-tool ref-store main reflog-exists refs/heads/main
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: garbage collection deletes reflog entries' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
|
||||||
|
for count in $(test_seq 1 10)
|
||||||
|
do
|
||||||
|
test_commit "number $count" file.t $count number-$count ||
|
||||||
|
return 1
|
||||||
|
done &&
|
||||||
|
git reflog refs/heads/main >actual &&
|
||||||
|
test_line_count = 10 actual &&
|
||||||
|
grep "commit (initial): number 1" actual &&
|
||||||
|
grep "commit: number 10" actual &&
|
||||||
|
|
||||||
|
git gc &&
|
||||||
|
git reflog refs/heads/main >actual &&
|
||||||
|
test_line_count = 0 actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reflog: updates via HEAD update HEAD reflog' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit main-one &&
|
||||||
|
git checkout -b new-branch &&
|
||||||
|
test_commit new-one &&
|
||||||
|
test_commit new-two &&
|
||||||
|
|
||||||
|
echo new-one >expect &&
|
||||||
|
git log -1 --format=%s HEAD@{1} >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: adding worktree creates separate stack' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
|
||||||
|
git -C repo worktree add ../worktree &&
|
||||||
|
test_path_is_file repo/.git/worktrees/worktree/refs/heads &&
|
||||||
|
echo "ref: refs/heads/.invalid" >expect &&
|
||||||
|
test_cmp expect repo/.git/worktrees/worktree/HEAD &&
|
||||||
|
test_path_is_dir repo/.git/worktrees/worktree/reftable &&
|
||||||
|
test_path_is_file repo/.git/worktrees/worktree/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: pack-refs in main repo packs main refs' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
git -C repo worktree add ../worktree &&
|
||||||
|
|
||||||
|
test_line_count = 3 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 4 repo/.git/reftable/tables.list &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
test_line_count = 3 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: pack-refs in worktree packs worktree refs' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
git -C repo worktree add ../worktree &&
|
||||||
|
|
||||||
|
test_line_count = 3 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 4 repo/.git/reftable/tables.list &&
|
||||||
|
git -C worktree pack-refs &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 4 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: creating shared ref updates main stack' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
|
||||||
|
git -C repo worktree add ../worktree &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
git -C worktree pack-refs &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list &&
|
||||||
|
|
||||||
|
git -C worktree update-ref refs/heads/shared HEAD &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 2 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: creating per-worktree ref updates worktree stack' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
|
||||||
|
git -C repo worktree add ../worktree &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
git -C worktree pack-refs &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list &&
|
||||||
|
|
||||||
|
git -C worktree update-ref refs/bisect/per-worktree HEAD &&
|
||||||
|
test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: creating per-worktree ref from main repo' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
|
||||||
|
git -C repo worktree add ../worktree &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
git -C worktree pack-refs &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list &&
|
||||||
|
|
||||||
|
git -C repo update-ref worktrees/worktree/refs/bisect/per-worktree HEAD &&
|
||||||
|
test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: creating per-worktree ref from second worktree' '
|
||||||
|
test_when_finished "rm -rf repo wt1 wt2" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
|
||||||
|
git -C repo worktree add ../wt1 &&
|
||||||
|
git -C repo worktree add ../wt2 &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
git -C wt1 pack-refs &&
|
||||||
|
git -C wt2 pack-refs &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/wt2/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list &&
|
||||||
|
|
||||||
|
git -C wt1 update-ref worktrees/wt2/refs/bisect/per-worktree HEAD &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list &&
|
||||||
|
test_line_count = 2 repo/.git/worktrees/wt2/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: can create shared and per-worktree ref in one transaction' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
|
||||||
|
git -C repo worktree add ../worktree &&
|
||||||
|
git -C repo pack-refs &&
|
||||||
|
git -C worktree pack-refs &&
|
||||||
|
test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 1 repo/.git/reftable/tables.list &&
|
||||||
|
|
||||||
|
cat >stdin <<-EOF &&
|
||||||
|
create worktrees/worktree/refs/bisect/per-worktree HEAD
|
||||||
|
create refs/branches/shared HEAD
|
||||||
|
EOF
|
||||||
|
git -C repo update-ref --stdin <stdin &&
|
||||||
|
test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
|
||||||
|
test_line_count = 2 repo/.git/reftable/tables.list
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: can access common refs' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo file1 &&
|
||||||
|
git -C repo branch branch1 &&
|
||||||
|
git -C repo worktree add ../worktree &&
|
||||||
|
|
||||||
|
echo refs/heads/worktree >expect &&
|
||||||
|
git -C worktree symbolic-ref HEAD >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
git -C worktree checkout branch1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'worktree: adds worktree with detached HEAD' '
|
||||||
|
test_when_finished "rm -rf repo worktree" &&
|
||||||
|
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
git -C repo rev-parse main >expect &&
|
||||||
|
|
||||||
|
git -C repo worktree add --detach ../worktree main &&
|
||||||
|
git -C worktree rev-parse HEAD >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'fetch: accessing FETCH_HEAD special ref works' '
|
||||||
|
test_when_finished "rm -rf repo sub" &&
|
||||||
|
|
||||||
|
git init sub &&
|
||||||
|
test_commit -C sub two &&
|
||||||
|
git -C sub rev-parse HEAD >expect &&
|
||||||
|
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo one &&
|
||||||
|
git -C repo fetch ../sub &&
|
||||||
|
git -C repo rev-parse FETCH_HEAD >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
26
t/t0611-reftable-httpd.sh
Executable file
26
t/t0611-reftable-httpd.sh
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='reftable HTTPD tests'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
. "$TEST_DIRECTORY"/lib-httpd.sh
|
||||||
|
|
||||||
|
start_httpd
|
||||||
|
|
||||||
|
REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
|
||||||
|
|
||||||
|
test_expect_success 'serving ls-remote' '
|
||||||
|
git init --ref-format=reftable -b main "$REPO" &&
|
||||||
|
cd "$REPO" &&
|
||||||
|
test_commit m1 &&
|
||||||
|
>.git/git-daemon-export-ok &&
|
||||||
|
git ls-remote "http://127.0.0.1:$LIB_HTTPD_PORT/smart/repo" | cut -f 2-2 -d " " >actual &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
HEAD
|
||||||
|
refs/heads/main
|
||||||
|
refs/tags/m1
|
||||||
|
EOF
|
||||||
|
test_cmp actual expect
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
@ -1755,6 +1755,8 @@ esac
|
|||||||
case "$GIT_DEFAULT_REF_FORMAT" in
|
case "$GIT_DEFAULT_REF_FORMAT" in
|
||||||
files)
|
files)
|
||||||
test_set_prereq REFFILES;;
|
test_set_prereq REFFILES;;
|
||||||
|
reftable)
|
||||||
|
test_set_prereq REFTABLE;;
|
||||||
*)
|
*)
|
||||||
echo 2>&1 "error: unknown ref format $GIT_DEFAULT_REF_FORMAT"
|
echo 2>&1 "error: unknown ref format $GIT_DEFAULT_REF_FORMAT"
|
||||||
exit 1
|
exit 1
|
||||||
|
Loading…
Reference in New Issue
Block a user