Git fork

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

+122 -63
+12
Documentation/git-receive-pack.adoc
··· 46 46 `$GIT_URL/info/refs?service=git-receive-pack` requests. See 47 47 `--http-backend-info-refs` in linkgit:git-upload-pack[1]. 48 48 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 + 49 61 PRE-RECEIVE HOOK 50 62 ---------------- 51 63 Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists
+22 -18
builtin/receive-pack.c
··· 81 81 static int auto_update_server_info; 82 82 static int auto_gc = 1; 83 83 static int reject_thin; 84 + static int skip_connectivity_check; 84 85 static int stateless_rpc; 85 86 static const char *service_dir; 86 87 static const char *head_name; ··· 1938 1939 return; 1939 1940 } 1940 1941 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 + } 1949 1951 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"; 1956 1958 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); 1959 1961 1960 - if (use_sideband) 1961 - finish_async(&muxer); 1962 + if (use_sideband) 1963 + finish_async(&muxer); 1964 + } 1962 1965 1963 1966 reject_updates_to_hidden(commands); 1964 1967 ··· 2519 2522 2520 2523 struct option options[] = { 2521 2524 OPT__QUIET(&quiet, N_("quiet")), 2525 + OPT_HIDDEN_BOOL(0, "skip-connectivity-check", &skip_connectivity_check, NULL), 2522 2526 OPT_HIDDEN_BOOL(0, "stateless-rpc", &stateless_rpc, NULL), 2523 2527 OPT_HIDDEN_BOOL(0, "http-backend-info-refs", &advertise_refs, NULL), 2524 2528 OPT_ALIAS(0, "advertise-refs", "http-backend-info-refs"),
+1 -1
t/meson.build
··· 629 629 't5407-post-rewrite-hook.sh', 630 630 't5408-send-pack-stdin.sh', 631 631 't5409-colorize-remote-messages.sh', 632 - 't5410-receive-pack-alternates.sh', 632 + 't5410-receive-pack.sh', 633 633 't5411-proc-receive-hook.sh', 634 634 't5500-fetch-pack.sh', 635 635 't5501-fetch-push-alternates.sh',
-44
t/t5410-receive-pack-alternates.sh
··· 1 - #!/bin/sh 2 - 3 - test_description='git receive-pack with alternate ref filtering' 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_done
+87
t/t5410-receive-pack.sh
··· 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