Skip to content

Commit b4847a4

Browse files
committed
Merge branch 'jt/receive-pack-skip-connectivity-check'
"git receive-pack" optionally learns not to care about connectivity check, which can be useful when the repository arranges to ensure connectivity by some other means. * jt/receive-pack-skip-connectivity-check: builtin/receive-pack: add option to skip connectivity check t5410: test receive-pack connectivity check
2 parents b5afd0a + 68cb0b5 commit b4847a4

File tree

5 files changed

+122
-63
lines changed

5 files changed

+122
-63
lines changed

Documentation/git-receive-pack.adoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ OPTIONS
4646
`$GIT_URL/info/refs?service=git-receive-pack` requests. See
4747
`--http-backend-info-refs` in linkgit:git-upload-pack[1].
4848

49+
--skip-connectivity-check::
50+
Bypasses the connectivity checks that validate the existence of all
51+
objects in the transitive closure of reachable objects. This option is
52+
intended for server operators that want to implement their own object
53+
connectivity validation outside of Git. This is useful in such cases
54+
where the server-side knows additional information about how Git is
55+
being used and thus can rely on certain guarantees to more efficiently
56+
compute object connectivity that Git itself cannot make. Usage of this
57+
option without a reliable external mechanism to ensure full reachable
58+
object connectivity risks corrupting the repository and should not be
59+
used in the general case.
60+
4961
PRE-RECEIVE HOOK
5062
----------------
5163
Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists

builtin/receive-pack.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ static int prefer_ofs_delta = 1;
8181
static int auto_update_server_info;
8282
static int auto_gc = 1;
8383
static int reject_thin;
84+
static int skip_connectivity_check;
8485
static int stateless_rpc;
8586
static const char *service_dir;
8687
static const char *head_name;
@@ -1938,27 +1939,29 @@ static void execute_commands(struct command *commands,
19381939
return;
19391940
}
19401941

1941-
if (use_sideband) {
1942-
memset(&muxer, 0, sizeof(muxer));
1943-
muxer.proc = copy_to_sideband;
1944-
muxer.in = -1;
1945-
if (!start_async(&muxer))
1946-
err_fd = muxer.in;
1947-
/* ...else, continue without relaying sideband */
1948-
}
1942+
if (!skip_connectivity_check) {
1943+
if (use_sideband) {
1944+
memset(&muxer, 0, sizeof(muxer));
1945+
muxer.proc = copy_to_sideband;
1946+
muxer.in = -1;
1947+
if (!start_async(&muxer))
1948+
err_fd = muxer.in;
1949+
/* ...else, continue without relaying sideband */
1950+
}
19491951

1950-
data.cmds = commands;
1951-
data.si = si;
1952-
opt.err_fd = err_fd;
1953-
opt.progress = err_fd && !quiet;
1954-
opt.env = tmp_objdir_env(tmp_objdir);
1955-
opt.exclude_hidden_refs_section = "receive";
1952+
data.cmds = commands;
1953+
data.si = si;
1954+
opt.err_fd = err_fd;
1955+
opt.progress = err_fd && !quiet;
1956+
opt.env = tmp_objdir_env(tmp_objdir);
1957+
opt.exclude_hidden_refs_section = "receive";
19561958

1957-
if (check_connected(iterate_receive_command_list, &data, &opt))
1958-
set_connectivity_errors(commands, si);
1959+
if (check_connected(iterate_receive_command_list, &data, &opt))
1960+
set_connectivity_errors(commands, si);
19591961

1960-
if (use_sideband)
1961-
finish_async(&muxer);
1962+
if (use_sideband)
1963+
finish_async(&muxer);
1964+
}
19621965

19631966
reject_updates_to_hidden(commands);
19641967

@@ -2519,6 +2522,7 @@ int cmd_receive_pack(int argc,
25192522

25202523
struct option options[] = {
25212524
OPT__QUIET(&quiet, N_("quiet")),
2525+
OPT_HIDDEN_BOOL(0, "skip-connectivity-check", &skip_connectivity_check, NULL),
25222526
OPT_HIDDEN_BOOL(0, "stateless-rpc", &stateless_rpc, NULL),
25232527
OPT_HIDDEN_BOOL(0, "http-backend-info-refs", &advertise_refs, NULL),
25242528
OPT_ALIAS(0, "advertise-refs", "http-backend-info-refs"),

t/meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ integration_tests = [
629629
't5407-post-rewrite-hook.sh',
630630
't5408-send-pack-stdin.sh',
631631
't5409-colorize-remote-messages.sh',
632-
't5410-receive-pack-alternates.sh',
632+
't5410-receive-pack.sh',
633633
't5411-proc-receive-hook.sh',
634634
't5500-fetch-pack.sh',
635635
't5501-fetch-push-alternates.sh',

t/t5410-receive-pack-alternates.sh

Lines changed: 0 additions & 44 deletions
This file was deleted.

t/t5410-receive-pack.sh

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/bin/sh
2+
3+
test_description='git receive-pack'
4+
5+
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6+
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7+
8+
. ./test-lib.sh
9+
10+
test_expect_success 'setup' '
11+
test_commit base &&
12+
git clone -s --bare . fork &&
13+
git checkout -b public/branch main &&
14+
test_commit public &&
15+
git checkout -b private/branch main &&
16+
test_commit private
17+
'
18+
19+
extract_haves () {
20+
depacketize | sed -n 's/^\([^ ][^ ]*\) \.have/\1/p'
21+
}
22+
23+
test_expect_success 'with core.alternateRefsCommand' '
24+
write_script fork/alternate-refs <<-\EOF &&
25+
git --git-dir="$1" for-each-ref \
26+
--format="%(objectname)" \
27+
refs/heads/public/
28+
EOF
29+
test_config -C fork core.alternateRefsCommand ./alternate-refs &&
30+
git rev-parse public/branch >expect &&
31+
printf "0000" | git receive-pack fork >actual &&
32+
extract_haves <actual >actual.haves &&
33+
test_cmp expect actual.haves
34+
'
35+
36+
test_expect_success 'with core.alternateRefsPrefixes' '
37+
test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
38+
git rev-parse private/branch >expect &&
39+
printf "0000" | git receive-pack fork >actual &&
40+
extract_haves <actual >actual.haves &&
41+
test_cmp expect actual.haves
42+
'
43+
44+
test_expect_success 'receive-pack missing objects fails connectivity check' '
45+
test_when_finished rm -rf repo remote.git setup.git &&
46+
47+
git init repo &&
48+
git -C repo commit --allow-empty -m 1 &&
49+
git clone --bare repo setup.git &&
50+
git -C repo commit --allow-empty -m 2 &&
51+
52+
# Capture git-send-pack(1) output sent to git-receive-pack(1).
53+
git -C repo send-pack ../setup.git --all \
54+
--receive-pack="tee ${SQ}$(pwd)/out${SQ} | git-receive-pack" &&
55+
56+
# Replay captured git-send-pack(1) output on new empty repository.
57+
git init --bare remote.git &&
58+
git receive-pack remote.git <out >actual 2>err &&
59+
60+
test_grep "missing necessary objects" actual &&
61+
test_grep "fatal: Failed to traverse parents" err &&
62+
test_must_fail git -C remote.git cat-file -e $(git -C repo rev-parse HEAD)
63+
'
64+
65+
test_expect_success 'receive-pack missing objects bypasses connectivity check' '
66+
test_when_finished rm -rf repo remote.git setup.git &&
67+
68+
git init repo &&
69+
git -C repo commit --allow-empty -m 1 &&
70+
git clone --bare repo setup.git &&
71+
git -C repo commit --allow-empty -m 2 &&
72+
73+
# Capture git-send-pack(1) output sent to git-receive-pack(1).
74+
git -C repo send-pack ../setup.git --all \
75+
--receive-pack="tee ${SQ}$(pwd)/out${SQ} | git-receive-pack" &&
76+
77+
# Replay captured git-send-pack(1) output on new empty repository.
78+
git init --bare remote.git &&
79+
git receive-pack --skip-connectivity-check remote.git <out >actual 2>err &&
80+
81+
test_grep ! "missing necessary objects" actual &&
82+
test_must_be_empty err &&
83+
git -C remote.git cat-file -e $(git -C repo rev-parse HEAD) &&
84+
test_must_fail git -C remote.git rev-list $(git -C repo rev-parse HEAD)
85+
'
86+
87+
test_done

0 commit comments

Comments
 (0)