2017-12-06 00:58:44 +08:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='partial clone'
|
|
|
|
|
2024-09-30 17:13:40 +08:00
|
|
|
TEST_PASSES_SANITIZE_LEAK=true
|
2017-12-06 00:58:44 +08:00
|
|
|
. ./test-lib.sh
|
2024-05-25 18:09:27 +08:00
|
|
|
. "$TEST_DIRECTORY"/lib-terminal.sh
|
2017-12-06 00:58:44 +08:00
|
|
|
|
2021-10-16 04:16:29 +08:00
|
|
|
# When enabled, some commands will write commit-graphs. This causes fsck
|
|
|
|
# to fail when delete_object() is called because fsck will attempt to
|
|
|
|
# verify the out-of-sync commit graph.
|
|
|
|
GIT_TEST_COMMIT_GRAPH=0
|
2021-09-01 04:52:33 +08:00
|
|
|
|
2017-12-06 00:58:44 +08:00
|
|
|
delete_object () {
|
|
|
|
rm $1/.git/objects/$(echo $2 | sed -e 's|^..|&/|')
|
|
|
|
}
|
|
|
|
|
|
|
|
pack_as_from_promisor () {
|
|
|
|
HASH=$(git -C repo pack-objects .git/objects/pack/pack) &&
|
2017-12-08 23:27:16 +08:00
|
|
|
>repo/.git/objects/pack/pack-$HASH.promisor &&
|
|
|
|
echo $HASH
|
2017-12-06 00:58:44 +08:00
|
|
|
}
|
|
|
|
|
2017-12-06 00:58:45 +08:00
|
|
|
promise_and_delete () {
|
|
|
|
HASH=$(git -C repo rev-parse "$1") &&
|
|
|
|
git -C repo tag -a -m message my_annotated_tag "$HASH" &&
|
|
|
|
git -C repo rev-parse my_annotated_tag | pack_as_from_promisor &&
|
2017-12-08 23:27:16 +08:00
|
|
|
# tag -d prints a message to stdout, so redirect it
|
|
|
|
git -C repo tag -d my_annotated_tag >/dev/null &&
|
2017-12-06 00:58:45 +08:00
|
|
|
delete_object repo "$HASH"
|
|
|
|
}
|
|
|
|
|
2018-06-12 05:51:26 +08:00
|
|
|
test_expect_success 'extensions.partialclone without filter' '
|
|
|
|
test_create_repo server &&
|
|
|
|
git clone --filter="blob:none" "file://$(pwd)/server" client &&
|
2019-06-25 21:40:32 +08:00
|
|
|
git -C client config --unset remote.origin.partialclonefilter &&
|
2018-06-12 05:51:26 +08:00
|
|
|
git -C client fetch origin
|
|
|
|
'
|
|
|
|
|
2020-06-05 17:10:02 +08:00
|
|
|
test_expect_success 'convert shallow clone to partial clone' '
|
|
|
|
rm -fr server client &&
|
|
|
|
test_create_repo server &&
|
|
|
|
test_commit -C server my_commit 1 &&
|
|
|
|
test_commit -C server my_commit2 1 &&
|
|
|
|
git clone --depth=1 "file://$(pwd)/server" client &&
|
|
|
|
git -C client fetch --unshallow --filter="blob:none" &&
|
|
|
|
test_cmp_config -C client true remote.origin.promisor &&
|
|
|
|
test_cmp_config -C client blob:none remote.origin.partialclonefilter &&
|
|
|
|
test_cmp_config -C client 1 core.repositoryformatversion
|
|
|
|
'
|
|
|
|
|
2024-02-15 16:25:34 +08:00
|
|
|
test_expect_success DEFAULT_REPO_FORMAT 'convert to partial clone with noop extension' '
|
2020-06-05 17:10:04 +08:00
|
|
|
rm -fr server client &&
|
|
|
|
test_create_repo server &&
|
|
|
|
test_commit -C server my_commit 1 &&
|
|
|
|
test_commit -C server my_commit2 1 &&
|
|
|
|
git clone --depth=1 "file://$(pwd)/server" client &&
|
|
|
|
test_cmp_config -C client 0 core.repositoryformatversion &&
|
Revert "check_repository_format_gently(): refuse extensions for old repositories"
This reverts commit 14c7fa269e42df4133edd9ae7763b678ed6594cd.
The core.repositoryFormatVersion field was introduced in ab9cb76f661
(Repository format version check., 2005-11-25), providing a welcome
bit of forward compatibility, thanks to some welcome analysis by
Martin Atukunda. The semantics are simple: a repository with
core.repositoryFormatVersion set to 0 should be comprehensible by all
Git implementations in active use; and Git implementations should
error out early instead of trying to act on Git repositories with
higher core.repositoryFormatVersion values representing new formats
that they do not understand.
A new repository format did not need to be defined until 00a09d57eb8
(introduce "extensions" form of core.repositoryformatversion,
2015-06-23). This provided a finer-grained extension mechanism for
Git repositories. In a repository with core.repositoryFormatVersion
set to 1, Git implementations can act on "extensions.*" settings that
modify how a repository is interpreted. In repository format version
1, unrecognized extensions settings cause Git to error out.
What happens if a user sets an extension setting but forgets to
increase the repository format version to 1? The extension settings
were still recognized in that case; worse, unrecognized extensions
settings do *not* cause Git to error out. So combining repository
format version 0 with extensions settings produces in some sense the
worst of both worlds.
To improve that situation, since 14c7fa269e4
(check_repository_format_gently(): refuse extensions for old
repositories, 2020-06-05) Git instead ignores extensions in v0 mode.
This way, v0 repositories get the historical (pre-2015) behavior and
maintain compatibility with Git implementations that do not know about
the v1 format. Unfortunately, users had been using this sort of
configuration and this behavior change came to many as a surprise:
- users of "git config --worktree" that had followed its advice
to enable extensions.worktreeConfig (without also increasing the
repository format version) would find their worktree configuration
no longer taking effect
- tools such as copybara[*] that had set extensions.partialClone in
existing repositories (without also increasing the repository format
version) would find that setting no longer taking effect
The behavior introduced in 14c7fa269e4 might be a good behavior if we
were traveling back in time to 2015, but we're far too late. For some
reason I thought that it was what had been originally implemented and
that it had regressed. Apologies for not doing my research when
14c7fa269e4 was under development.
Let's return to the behavior we've had since 2015: always act on
extensions.* settings, regardless of repository format version. While
we're here, include some tests to describe the effect on the "upgrade
repository version" code path.
[*] https://github.com/google/copybara/commit/ca76c0b1e13c4e36448d12c2aba4a5d9d98fb6e7
Reported-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-07-16 14:24:29 +08:00
|
|
|
git -C client config extensions.noop true &&
|
2020-07-16 14:28:18 +08:00
|
|
|
git -C client fetch --unshallow --filter="blob:none"
|
Revert "check_repository_format_gently(): refuse extensions for old repositories"
This reverts commit 14c7fa269e42df4133edd9ae7763b678ed6594cd.
The core.repositoryFormatVersion field was introduced in ab9cb76f661
(Repository format version check., 2005-11-25), providing a welcome
bit of forward compatibility, thanks to some welcome analysis by
Martin Atukunda. The semantics are simple: a repository with
core.repositoryFormatVersion set to 0 should be comprehensible by all
Git implementations in active use; and Git implementations should
error out early instead of trying to act on Git repositories with
higher core.repositoryFormatVersion values representing new formats
that they do not understand.
A new repository format did not need to be defined until 00a09d57eb8
(introduce "extensions" form of core.repositoryformatversion,
2015-06-23). This provided a finer-grained extension mechanism for
Git repositories. In a repository with core.repositoryFormatVersion
set to 1, Git implementations can act on "extensions.*" settings that
modify how a repository is interpreted. In repository format version
1, unrecognized extensions settings cause Git to error out.
What happens if a user sets an extension setting but forgets to
increase the repository format version to 1? The extension settings
were still recognized in that case; worse, unrecognized extensions
settings do *not* cause Git to error out. So combining repository
format version 0 with extensions settings produces in some sense the
worst of both worlds.
To improve that situation, since 14c7fa269e4
(check_repository_format_gently(): refuse extensions for old
repositories, 2020-06-05) Git instead ignores extensions in v0 mode.
This way, v0 repositories get the historical (pre-2015) behavior and
maintain compatibility with Git implementations that do not know about
the v1 format. Unfortunately, users had been using this sort of
configuration and this behavior change came to many as a surprise:
- users of "git config --worktree" that had followed its advice
to enable extensions.worktreeConfig (without also increasing the
repository format version) would find their worktree configuration
no longer taking effect
- tools such as copybara[*] that had set extensions.partialClone in
existing repositories (without also increasing the repository format
version) would find that setting no longer taking effect
The behavior introduced in 14c7fa269e4 might be a good behavior if we
were traveling back in time to 2015, but we're far too late. For some
reason I thought that it was what had been originally implemented and
that it had regressed. Apologies for not doing my research when
14c7fa269e4 was under development.
Let's return to the behavior we've had since 2015: always act on
extensions.* settings, regardless of repository format version. While
we're here, include some tests to describe the effect on the "upgrade
repository version" code path.
[*] https://github.com/google/copybara/commit/ca76c0b1e13c4e36448d12c2aba4a5d9d98fb6e7
Reported-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-07-16 14:24:29 +08:00
|
|
|
'
|
|
|
|
|
2024-02-15 16:25:34 +08:00
|
|
|
test_expect_success DEFAULT_REPO_FORMAT 'converting to partial clone fails with unrecognized extension' '
|
Revert "check_repository_format_gently(): refuse extensions for old repositories"
This reverts commit 14c7fa269e42df4133edd9ae7763b678ed6594cd.
The core.repositoryFormatVersion field was introduced in ab9cb76f661
(Repository format version check., 2005-11-25), providing a welcome
bit of forward compatibility, thanks to some welcome analysis by
Martin Atukunda. The semantics are simple: a repository with
core.repositoryFormatVersion set to 0 should be comprehensible by all
Git implementations in active use; and Git implementations should
error out early instead of trying to act on Git repositories with
higher core.repositoryFormatVersion values representing new formats
that they do not understand.
A new repository format did not need to be defined until 00a09d57eb8
(introduce "extensions" form of core.repositoryformatversion,
2015-06-23). This provided a finer-grained extension mechanism for
Git repositories. In a repository with core.repositoryFormatVersion
set to 1, Git implementations can act on "extensions.*" settings that
modify how a repository is interpreted. In repository format version
1, unrecognized extensions settings cause Git to error out.
What happens if a user sets an extension setting but forgets to
increase the repository format version to 1? The extension settings
were still recognized in that case; worse, unrecognized extensions
settings do *not* cause Git to error out. So combining repository
format version 0 with extensions settings produces in some sense the
worst of both worlds.
To improve that situation, since 14c7fa269e4
(check_repository_format_gently(): refuse extensions for old
repositories, 2020-06-05) Git instead ignores extensions in v0 mode.
This way, v0 repositories get the historical (pre-2015) behavior and
maintain compatibility with Git implementations that do not know about
the v1 format. Unfortunately, users had been using this sort of
configuration and this behavior change came to many as a surprise:
- users of "git config --worktree" that had followed its advice
to enable extensions.worktreeConfig (without also increasing the
repository format version) would find their worktree configuration
no longer taking effect
- tools such as copybara[*] that had set extensions.partialClone in
existing repositories (without also increasing the repository format
version) would find that setting no longer taking effect
The behavior introduced in 14c7fa269e4 might be a good behavior if we
were traveling back in time to 2015, but we're far too late. For some
reason I thought that it was what had been originally implemented and
that it had regressed. Apologies for not doing my research when
14c7fa269e4 was under development.
Let's return to the behavior we've had since 2015: always act on
extensions.* settings, regardless of repository format version. While
we're here, include some tests to describe the effect on the "upgrade
repository version" code path.
[*] https://github.com/google/copybara/commit/ca76c0b1e13c4e36448d12c2aba4a5d9d98fb6e7
Reported-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-07-16 14:24:29 +08:00
|
|
|
rm -fr server client &&
|
|
|
|
test_create_repo server &&
|
|
|
|
test_commit -C server my_commit 1 &&
|
|
|
|
test_commit -C server my_commit2 1 &&
|
|
|
|
git clone --depth=1 "file://$(pwd)/server" client &&
|
|
|
|
test_cmp_config -C client 0 core.repositoryformatversion &&
|
|
|
|
git -C client config extensions.nonsense true &&
|
2020-06-05 17:10:04 +08:00
|
|
|
test_must_fail git -C client fetch --unshallow --filter="blob:none"
|
|
|
|
'
|
|
|
|
|
2017-12-06 00:58:44 +08:00
|
|
|
test_expect_success 'missing reflog object, but promised by a commit, passes fsck' '
|
2018-06-12 05:51:26 +08:00
|
|
|
rm -rf repo &&
|
2017-12-06 00:58:44 +08:00
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo my_commit &&
|
|
|
|
|
|
|
|
A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
|
|
|
|
C=$(git -C repo commit-tree -m c -p $A HEAD^{tree}) &&
|
|
|
|
|
|
|
|
# Reference $A only from reflog, and delete it
|
|
|
|
git -C repo branch my_branch "$A" &&
|
|
|
|
git -C repo branch -f my_branch my_commit &&
|
|
|
|
delete_object repo "$A" &&
|
|
|
|
|
|
|
|
# State that we got $C, which refers to $A, from promisor
|
|
|
|
printf "$C\n" | pack_as_from_promisor &&
|
|
|
|
|
|
|
|
# Normally, it fails
|
|
|
|
test_must_fail git -C repo fsck &&
|
|
|
|
|
|
|
|
# But with the extension, it succeeds
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo fsck
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'missing reflog object, but promised by a tag, passes fsck' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo my_commit &&
|
|
|
|
|
|
|
|
A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
|
|
|
|
git -C repo tag -a -m d my_tag_name $A &&
|
|
|
|
T=$(git -C repo rev-parse my_tag_name) &&
|
|
|
|
git -C repo tag -d my_tag_name &&
|
|
|
|
|
|
|
|
# Reference $A only from reflog, and delete it
|
|
|
|
git -C repo branch my_branch "$A" &&
|
|
|
|
git -C repo branch -f my_branch my_commit &&
|
|
|
|
delete_object repo "$A" &&
|
|
|
|
|
|
|
|
# State that we got $T, which refers to $A, from promisor
|
|
|
|
printf "$T\n" | pack_as_from_promisor &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo fsck
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'missing reflog object alone fails fsck, even with extension set' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo my_commit &&
|
|
|
|
|
|
|
|
A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
|
|
|
|
B=$(git -C repo commit-tree -m b HEAD^{tree}) &&
|
|
|
|
|
|
|
|
# Reference $A only from reflog, and delete it
|
|
|
|
git -C repo branch my_branch "$A" &&
|
|
|
|
git -C repo branch -f my_branch my_commit &&
|
|
|
|
delete_object repo "$A" &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
test_must_fail git -C repo fsck
|
|
|
|
'
|
|
|
|
|
2017-12-06 00:58:45 +08:00
|
|
|
test_expect_success 'missing ref object, but promised, passes fsck' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo my_commit &&
|
|
|
|
|
|
|
|
A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
|
|
|
|
|
|
|
|
# Reference $A only from ref
|
|
|
|
git -C repo branch my_branch "$A" &&
|
|
|
|
promise_and_delete "$A" &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo fsck
|
|
|
|
'
|
|
|
|
|
2017-12-06 00:58:46 +08:00
|
|
|
test_expect_success 'missing object, but promised, passes fsck' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo 1 &&
|
|
|
|
test_commit -C repo 2 &&
|
|
|
|
test_commit -C repo 3 &&
|
|
|
|
git -C repo tag -a annotated_tag -m "annotated tag" &&
|
|
|
|
|
|
|
|
C=$(git -C repo rev-parse 1) &&
|
|
|
|
T=$(git -C repo rev-parse 2^{tree}) &&
|
|
|
|
B=$(git hash-object repo/3.t) &&
|
|
|
|
AT=$(git -C repo rev-parse annotated_tag) &&
|
|
|
|
|
|
|
|
promise_and_delete "$C" &&
|
|
|
|
promise_and_delete "$T" &&
|
|
|
|
promise_and_delete "$B" &&
|
|
|
|
promise_and_delete "$AT" &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo fsck
|
|
|
|
'
|
|
|
|
|
2017-12-06 00:58:47 +08:00
|
|
|
test_expect_success 'missing CLI object, but promised, passes fsck' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo my_commit &&
|
|
|
|
|
|
|
|
A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
|
|
|
|
promise_and_delete "$A" &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo fsck "$A"
|
|
|
|
'
|
|
|
|
|
2017-12-08 23:27:14 +08:00
|
|
|
test_expect_success 'fetching of missing objects' '
|
2020-09-03 05:05:39 +08:00
|
|
|
rm -rf repo err &&
|
2017-12-08 23:27:14 +08:00
|
|
|
test_create_repo server &&
|
|
|
|
test_commit -C server foo &&
|
|
|
|
git -C server repack -a -d --write-bitmap-index &&
|
|
|
|
|
|
|
|
git clone "file://$(pwd)/server" repo &&
|
|
|
|
HASH=$(git -C repo rev-parse foo) &&
|
|
|
|
rm -rf repo/.git/objects/* &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "origin" &&
|
2020-09-03 05:05:39 +08:00
|
|
|
git -C repo cat-file -p "$HASH" 2>err &&
|
|
|
|
|
|
|
|
# Ensure that no spurious FETCH_HEAD messages are written
|
|
|
|
! grep FETCH_HEAD err &&
|
2017-12-08 23:27:14 +08:00
|
|
|
|
|
|
|
# Ensure that the .promisor file is written, and check that its
|
|
|
|
# associated packfile contains the object
|
|
|
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
|
|
|
test_line_count = 1 promisorlist &&
|
2019-06-25 21:40:25 +08:00
|
|
|
IDX=$(sed "s/promisor$/idx/" promisorlist) &&
|
|
|
|
git verify-pack --verbose "$IDX" >out &&
|
|
|
|
grep "$HASH" out
|
2017-12-08 23:27:14 +08:00
|
|
|
'
|
|
|
|
|
promisor-remote: die upon failing fetch
In a partial clone, an attempt to read a missing object results in an
attempt to fetch that single object. In order to avoid multiple
sequential fetches, which would occur when multiple objects are missing
(which is the typical case), some commands have been taught to prefetch
in a batch: such a command would, in a partial clone, notice that
several objects that it will eventually need are missing, and call
promisor_remote_get_direct() with all such objects at once.
When this batch prefetch fails, these commands fall back to the
sequential fetches. But at $DAYJOB we have noticed that this results in
a bad user experience: a command would take unexpectedly long to finish
(and possibly use up a lot of bandwidth) if the batch prefetch would
fail for some intermittent reason, but all subsequent fetches would
work. It would be a better user experience for such a command would
just fail.
Therefore, make it a fatal error if the prefetch fails and at least one
object being fetched is known to be a promisor object. (The latter
criterion is to make sure that we are not misleading the user that such
an object would be present from the promisor remote. For example, a
missing object may be a result of repository corruption and not because
it is expectedly missing due to the repository being a partial clone.)
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-10-05 05:13:41 +08:00
|
|
|
test_expect_success 'fetching of a promised object that promisor remote no longer has' '
|
|
|
|
rm -f err &&
|
|
|
|
test_create_repo unreliable-server &&
|
|
|
|
git -C unreliable-server config uploadpack.allowanysha1inwant 1 &&
|
|
|
|
git -C unreliable-server config uploadpack.allowfilter 1 &&
|
|
|
|
test_commit -C unreliable-server foo &&
|
|
|
|
|
|
|
|
git clone --filter=blob:none --no-checkout "file://$(pwd)/unreliable-server" unreliable-client &&
|
|
|
|
|
|
|
|
rm -rf unreliable-server/.git/objects/* &&
|
|
|
|
test_must_fail git -C unreliable-client checkout HEAD 2>err &&
|
|
|
|
grep "could not fetch.*from promisor remote" err
|
|
|
|
'
|
|
|
|
|
2018-09-12 23:47:38 +08:00
|
|
|
test_expect_success 'fetching of missing objects works with ref-in-want enabled' '
|
|
|
|
# ref-in-want requires protocol version 2
|
|
|
|
git -C server config protocol.version 2 &&
|
|
|
|
git -C server config uploadpack.allowrefinwant 1 &&
|
|
|
|
git -C repo config protocol.version 2 &&
|
|
|
|
|
|
|
|
rm -rf repo/.git/objects/* &&
|
|
|
|
rm -f trace &&
|
|
|
|
GIT_TRACE_PACKET="$(pwd)/trace" git -C repo cat-file -p "$HASH" &&
|
2020-08-18 12:01:36 +08:00
|
|
|
grep "fetch< fetch=.*ref-in-want" trace
|
2018-09-12 23:47:38 +08:00
|
|
|
'
|
|
|
|
|
2019-06-25 21:40:34 +08:00
|
|
|
test_expect_success 'fetching of missing objects from another promisor remote' '
|
|
|
|
git clone "file://$(pwd)/server" server2 &&
|
|
|
|
test_commit -C server2 bar &&
|
|
|
|
git -C server2 repack -a -d --write-bitmap-index &&
|
|
|
|
HASH2=$(git -C server2 rev-parse bar) &&
|
|
|
|
|
|
|
|
git -C repo remote add server2 "file://$(pwd)/server2" &&
|
|
|
|
git -C repo config remote.server2.promisor true &&
|
|
|
|
git -C repo cat-file -p "$HASH2" &&
|
|
|
|
|
|
|
|
git -C repo fetch server2 &&
|
|
|
|
rm -rf repo/.git/objects/* &&
|
|
|
|
git -C repo cat-file -p "$HASH2" &&
|
|
|
|
|
|
|
|
# Ensure that the .promisor file is written, and check that its
|
|
|
|
# associated packfile contains the object
|
|
|
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
|
|
|
test_line_count = 1 promisorlist &&
|
|
|
|
IDX=$(sed "s/promisor$/idx/" promisorlist) &&
|
|
|
|
git verify-pack --verbose "$IDX" >out &&
|
|
|
|
grep "$HASH2" out
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'fetching of missing objects configures a promisor remote' '
|
|
|
|
git clone "file://$(pwd)/server" server3 &&
|
|
|
|
test_commit -C server3 baz &&
|
|
|
|
git -C server3 repack -a -d --write-bitmap-index &&
|
|
|
|
HASH3=$(git -C server3 rev-parse baz) &&
|
|
|
|
git -C server3 config uploadpack.allowfilter 1 &&
|
|
|
|
|
|
|
|
rm repo/.git/objects/pack/pack-*.promisor &&
|
|
|
|
|
|
|
|
git -C repo remote add server3 "file://$(pwd)/server3" &&
|
|
|
|
git -C repo fetch --filter="blob:none" server3 $HASH3 &&
|
|
|
|
|
|
|
|
test_cmp_config -C repo true remote.server3.promisor &&
|
|
|
|
|
|
|
|
# Ensure that the .promisor file is written, and check that its
|
|
|
|
# associated packfile contains the object
|
|
|
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
|
|
|
test_line_count = 1 promisorlist &&
|
|
|
|
IDX=$(sed "s/promisor$/idx/" promisorlist) &&
|
|
|
|
git verify-pack --verbose "$IDX" >out &&
|
|
|
|
grep "$HASH3" out
|
|
|
|
'
|
|
|
|
|
fetch-pack: exclude blobs when lazy-fetching trees
A partial clone with missing trees can be obtained using "git clone
--filter=tree:none <repo>". In such a repository, when a tree needs to
be lazily fetched, any tree or blob it directly or indirectly references
is fetched as well, regardless of whether the original command required
those objects, or if the local repository already had some of them.
This is because the fetch protocol, which the lazy fetch uses, does not
allow clients to request that only the wanted objects be sent, which
would be the ideal solution. This patch implements a partial solution:
specify the "blob:none" filter, somewhat reducing the fetch payload.
This change has no effect when lazily fetching blobs (due to how filters
work). And if lazily fetching a commit (such repositories are difficult
to construct and is not a use case we support very well, but it is
possible), referenced commits and trees are still fetched - only the
blobs are not fetched.
The necessary code change is done in fetch_pack() instead of somewhere
closer to where the "filter" instruction is written to the wire so that
only one part of the code needs to be changed in order for users of all
protocol versions to benefit from this optimization.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-10-04 07:04:53 +08:00
|
|
|
test_expect_success 'fetching of missing blobs works' '
|
2019-06-25 21:40:34 +08:00
|
|
|
rm -rf server server2 repo &&
|
|
|
|
rm -rf server server3 repo &&
|
fetch-pack: exclude blobs when lazy-fetching trees
A partial clone with missing trees can be obtained using "git clone
--filter=tree:none <repo>". In such a repository, when a tree needs to
be lazily fetched, any tree or blob it directly or indirectly references
is fetched as well, regardless of whether the original command required
those objects, or if the local repository already had some of them.
This is because the fetch protocol, which the lazy fetch uses, does not
allow clients to request that only the wanted objects be sent, which
would be the ideal solution. This patch implements a partial solution:
specify the "blob:none" filter, somewhat reducing the fetch payload.
This change has no effect when lazily fetching blobs (due to how filters
work). And if lazily fetching a commit (such repositories are difficult
to construct and is not a use case we support very well, but it is
possible), referenced commits and trees are still fetched - only the
blobs are not fetched.
The necessary code change is done in fetch_pack() instead of somewhere
closer to where the "filter" instruction is written to the wire so that
only one part of the code needs to be changed in order for users of all
protocol versions to benefit from this optimization.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-10-04 07:04:53 +08:00
|
|
|
test_create_repo server &&
|
|
|
|
test_commit -C server foo &&
|
|
|
|
git -C server repack -a -d --write-bitmap-index &&
|
|
|
|
|
|
|
|
git clone "file://$(pwd)/server" repo &&
|
|
|
|
git hash-object repo/foo.t >blobhash &&
|
|
|
|
rm -rf repo/.git/objects/* &&
|
|
|
|
|
|
|
|
git -C server config uploadpack.allowanysha1inwant 1 &&
|
|
|
|
git -C server config uploadpack.allowfilter 1 &&
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "origin" &&
|
|
|
|
|
|
|
|
git -C repo cat-file -p $(cat blobhash)
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'fetching of missing trees does not fetch blobs' '
|
|
|
|
rm -rf server repo &&
|
|
|
|
test_create_repo server &&
|
|
|
|
test_commit -C server foo &&
|
|
|
|
git -C server repack -a -d --write-bitmap-index &&
|
|
|
|
|
|
|
|
git clone "file://$(pwd)/server" repo &&
|
|
|
|
git -C repo rev-parse foo^{tree} >treehash &&
|
|
|
|
git hash-object repo/foo.t >blobhash &&
|
|
|
|
rm -rf repo/.git/objects/* &&
|
|
|
|
|
|
|
|
git -C server config uploadpack.allowanysha1inwant 1 &&
|
|
|
|
git -C server config uploadpack.allowfilter 1 &&
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "origin" &&
|
|
|
|
git -C repo cat-file -p $(cat treehash) &&
|
|
|
|
|
|
|
|
# Ensure that the tree, but not the blob, is fetched
|
|
|
|
git -C repo rev-list --objects --missing=print $(cat treehash) >objects &&
|
|
|
|
grep "^$(cat treehash)" objects &&
|
|
|
|
grep "^[?]$(cat blobhash)" objects
|
|
|
|
'
|
|
|
|
|
2017-12-08 23:27:15 +08:00
|
|
|
test_expect_success 'rev-list stops traversal at missing and promised commit' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo foo &&
|
|
|
|
test_commit -C repo bar &&
|
|
|
|
|
|
|
|
FOO=$(git -C repo rev-parse foo) &&
|
|
|
|
promise_and_delete "$FOO" &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
2021-10-16 04:16:29 +08:00
|
|
|
git -C repo rev-list --exclude-promisor-objects --objects bar >out &&
|
2017-12-08 23:27:15 +08:00
|
|
|
grep $(git -C repo rev-parse bar) out &&
|
|
|
|
! grep $FOO out
|
|
|
|
'
|
|
|
|
|
2018-10-06 05:31:23 +08:00
|
|
|
test_expect_success 'missing tree objects with --missing=allow-promisor and --exclude-promisor-objects' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo foo &&
|
|
|
|
test_commit -C repo bar &&
|
|
|
|
test_commit -C repo baz &&
|
|
|
|
|
|
|
|
promise_and_delete $(git -C repo rev-parse bar^{tree}) &&
|
|
|
|
promise_and_delete $(git -C repo rev-parse foo^{tree}) &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
|
|
|
|
git -C repo rev-list --missing=allow-promisor --objects HEAD >objs 2>rev_list_err &&
|
|
|
|
test_must_be_empty rev_list_err &&
|
|
|
|
# 3 commits, 3 blobs, and 1 tree
|
|
|
|
test_line_count = 7 objs &&
|
|
|
|
|
|
|
|
# Do the same for --exclude-promisor-objects, but with all trees gone.
|
|
|
|
promise_and_delete $(git -C repo rev-parse baz^{tree}) &&
|
|
|
|
git -C repo rev-list --exclude-promisor-objects --objects HEAD >objs 2>rev_list_err &&
|
|
|
|
test_must_be_empty rev_list_err &&
|
|
|
|
# 3 commits, no blobs or trees
|
|
|
|
test_line_count = 3 objs
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'missing non-root tree object and rev-list' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
mkdir repo/dir &&
|
|
|
|
echo foo >repo/dir/foo &&
|
|
|
|
git -C repo add dir/foo &&
|
|
|
|
git -C repo commit -m "commit dir/foo" &&
|
|
|
|
|
|
|
|
promise_and_delete $(git -C repo rev-parse HEAD:dir) &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
|
|
|
|
git -C repo rev-list --missing=allow-any --objects HEAD >objs 2>rev_list_err &&
|
|
|
|
test_must_be_empty rev_list_err &&
|
|
|
|
# 1 commit and 1 tree
|
|
|
|
test_line_count = 2 objs
|
|
|
|
'
|
|
|
|
|
2017-12-08 23:27:15 +08:00
|
|
|
test_expect_success 'rev-list stops traversal at missing and promised tree' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo foo &&
|
|
|
|
mkdir repo/a_dir &&
|
|
|
|
echo something >repo/a_dir/something &&
|
|
|
|
git -C repo add a_dir/something &&
|
|
|
|
git -C repo commit -m bar &&
|
|
|
|
|
|
|
|
# foo^{tree} (tree referenced from commit)
|
|
|
|
TREE=$(git -C repo rev-parse foo^{tree}) &&
|
|
|
|
|
|
|
|
# a tree referenced by HEAD^{tree} (tree referenced from tree)
|
|
|
|
TREE2=$(git -C repo ls-tree HEAD^{tree} | grep " tree " | head -1 | cut -b13-52) &&
|
|
|
|
|
|
|
|
promise_and_delete "$TREE" &&
|
|
|
|
promise_and_delete "$TREE2" &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&
|
|
|
|
grep $(git -C repo rev-parse foo) out &&
|
|
|
|
! grep $TREE out &&
|
|
|
|
grep $(git -C repo rev-parse HEAD) out &&
|
|
|
|
! grep $TREE2 out
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'rev-list stops traversal at missing and promised blob' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
echo something >repo/something &&
|
|
|
|
git -C repo add something &&
|
|
|
|
git -C repo commit -m foo &&
|
|
|
|
|
|
|
|
BLOB=$(git -C repo hash-object -w something) &&
|
|
|
|
promise_and_delete "$BLOB" &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&
|
|
|
|
grep $(git -C repo rev-parse HEAD) out &&
|
|
|
|
! grep $BLOB out
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'rev-list stops traversal at promisor commit, tree, and blob' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo foo &&
|
|
|
|
test_commit -C repo bar &&
|
|
|
|
test_commit -C repo baz &&
|
|
|
|
|
|
|
|
COMMIT=$(git -C repo rev-parse foo) &&
|
|
|
|
TREE=$(git -C repo rev-parse bar^{tree}) &&
|
|
|
|
BLOB=$(git hash-object repo/baz.t) &&
|
|
|
|
printf "%s\n%s\n%s\n" $COMMIT $TREE $BLOB | pack_as_from_promisor &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&
|
|
|
|
! grep $COMMIT out &&
|
|
|
|
! grep $TREE out &&
|
|
|
|
! grep $BLOB out &&
|
|
|
|
grep $(git -C repo rev-parse bar) out # sanity check that some walking was done
|
|
|
|
'
|
|
|
|
|
2018-12-06 05:43:46 +08:00
|
|
|
test_expect_success 'rev-list dies for missing objects on cmd line' '
|
2017-12-08 23:27:15 +08:00
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo foo &&
|
|
|
|
test_commit -C repo bar &&
|
|
|
|
test_commit -C repo baz &&
|
|
|
|
|
|
|
|
COMMIT=$(git -C repo rev-parse foo) &&
|
|
|
|
TREE=$(git -C repo rev-parse bar^{tree}) &&
|
|
|
|
BLOB=$(git hash-object repo/baz.t) &&
|
|
|
|
|
|
|
|
promise_and_delete $COMMIT &&
|
|
|
|
promise_and_delete $TREE &&
|
|
|
|
promise_and_delete $BLOB &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
2018-12-06 05:43:46 +08:00
|
|
|
|
|
|
|
for OBJ in "$COMMIT" "$TREE" "$BLOB"; do
|
|
|
|
test_must_fail git -C repo rev-list --objects \
|
|
|
|
--exclude-promisor-objects "$OBJ" &&
|
|
|
|
test_must_fail git -C repo rev-list --objects-edge-aggressive \
|
|
|
|
--exclude-promisor-objects "$OBJ" &&
|
|
|
|
|
|
|
|
# Do not die or crash when --ignore-missing is passed.
|
|
|
|
git -C repo rev-list --ignore-missing --objects \
|
|
|
|
--exclude-promisor-objects "$OBJ" &&
|
|
|
|
git -C repo rev-list --ignore-missing --objects-edge-aggressive \
|
2021-12-09 13:11:12 +08:00
|
|
|
--exclude-promisor-objects "$OBJ" || return 1
|
2018-12-06 05:43:46 +08:00
|
|
|
done
|
2017-12-08 23:27:15 +08:00
|
|
|
'
|
|
|
|
|
2019-10-01 06:03:55 +08:00
|
|
|
test_expect_success 'single promisor remote can be re-initialized gracefully' '
|
|
|
|
# ensure one promisor is in the promisors list
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_create_repo other &&
|
|
|
|
git -C repo remote add foo "file://$(pwd)/other" &&
|
|
|
|
git -C repo config remote.foo.promisor true &&
|
|
|
|
git -C repo config extensions.partialclone foo &&
|
|
|
|
|
|
|
|
# reinitialize the promisors list
|
|
|
|
git -C repo fetch --filter=blob:none foo
|
|
|
|
'
|
|
|
|
|
2018-08-09 06:34:06 +08:00
|
|
|
test_expect_success 'gc repacks promisor objects separately from non-promisor objects' '
|
2017-12-08 23:27:16 +08:00
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
2018-08-09 06:34:06 +08:00
|
|
|
test_commit -C repo one &&
|
|
|
|
test_commit -C repo two &&
|
2017-12-08 23:27:16 +08:00
|
|
|
|
2018-08-09 06:34:06 +08:00
|
|
|
TREE_ONE=$(git -C repo rev-parse one^{tree}) &&
|
|
|
|
printf "$TREE_ONE\n" | pack_as_from_promisor &&
|
|
|
|
TREE_TWO=$(git -C repo rev-parse two^{tree}) &&
|
|
|
|
printf "$TREE_TWO\n" | pack_as_from_promisor &&
|
2017-12-08 23:27:16 +08:00
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo gc &&
|
|
|
|
|
2018-08-09 06:34:06 +08:00
|
|
|
# Ensure that exactly one promisor packfile exists, and that it
|
|
|
|
# contains the trees but not the commits
|
|
|
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
|
|
|
test_line_count = 1 promisorlist &&
|
|
|
|
PROMISOR_PACKFILE=$(sed "s/.promisor/.pack/" <promisorlist) &&
|
|
|
|
git verify-pack $PROMISOR_PACKFILE -v >out &&
|
|
|
|
grep "$TREE_ONE" out &&
|
|
|
|
grep "$TREE_TWO" out &&
|
|
|
|
! grep "$(git -C repo rev-parse one)" out &&
|
|
|
|
! grep "$(git -C repo rev-parse two)" out &&
|
|
|
|
|
|
|
|
# Remove the promisor packfile and associated files
|
|
|
|
rm $(sed "s/.promisor//" <promisorlist).* &&
|
|
|
|
|
|
|
|
# Ensure that the single other pack contains the commits, but not the
|
|
|
|
# trees
|
2017-12-08 23:27:16 +08:00
|
|
|
ls repo/.git/objects/pack/pack-*.pack >packlist &&
|
|
|
|
test_line_count = 1 packlist &&
|
|
|
|
git verify-pack repo/.git/objects/pack/pack-*.pack -v >out &&
|
2018-08-09 06:34:06 +08:00
|
|
|
grep "$(git -C repo rev-parse one)" out &&
|
|
|
|
grep "$(git -C repo rev-parse two)" out &&
|
|
|
|
! grep "$TREE_ONE" out &&
|
|
|
|
! grep "$TREE_TWO" out
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'gc does not repack promisor objects if there are none' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo one &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo gc &&
|
|
|
|
|
|
|
|
# Ensure that only one pack exists
|
|
|
|
ls repo/.git/objects/pack/pack-*.pack >packlist &&
|
|
|
|
test_line_count = 1 packlist
|
|
|
|
'
|
|
|
|
|
|
|
|
repack_and_check () {
|
|
|
|
rm -rf repo2 &&
|
|
|
|
cp -r repo repo2 &&
|
2021-08-25 00:15:54 +08:00
|
|
|
if test x"$1" = "x--must-fail"
|
|
|
|
then
|
|
|
|
shift
|
|
|
|
test_must_fail git -C repo2 repack $1 -d
|
|
|
|
else
|
|
|
|
git -C repo2 repack $1 -d
|
|
|
|
fi &&
|
2018-08-09 06:34:06 +08:00
|
|
|
git -C repo2 fsck &&
|
|
|
|
|
|
|
|
git -C repo2 cat-file -e $2 &&
|
|
|
|
git -C repo2 cat-file -e $3
|
|
|
|
}
|
|
|
|
|
|
|
|
test_expect_success 'repack -d does not irreversibly delete promisor objects' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
|
|
|
|
git -C repo commit --allow-empty -m one &&
|
|
|
|
git -C repo commit --allow-empty -m two &&
|
|
|
|
git -C repo commit --allow-empty -m three &&
|
|
|
|
git -C repo commit --allow-empty -m four &&
|
|
|
|
ONE=$(git -C repo rev-parse HEAD^^^) &&
|
|
|
|
TWO=$(git -C repo rev-parse HEAD^^) &&
|
|
|
|
THREE=$(git -C repo rev-parse HEAD^) &&
|
|
|
|
|
|
|
|
printf "$TWO\n" | pack_as_from_promisor &&
|
|
|
|
printf "$THREE\n" | pack_as_from_promisor &&
|
|
|
|
delete_object repo "$ONE" &&
|
|
|
|
|
2021-08-25 00:15:54 +08:00
|
|
|
repack_and_check --must-fail -ab "$TWO" "$THREE" &&
|
2018-08-09 06:34:06 +08:00
|
|
|
repack_and_check -a "$TWO" "$THREE" &&
|
|
|
|
repack_and_check -A "$TWO" "$THREE" &&
|
|
|
|
repack_and_check -l "$TWO" "$THREE"
|
2017-12-08 23:27:16 +08:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'gc stops traversal when a missing but promised object is reached' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo my_commit &&
|
|
|
|
|
|
|
|
TREE_HASH=$(git -C repo rev-parse HEAD^{tree}) &&
|
|
|
|
HASH=$(promise_and_delete $TREE_HASH) &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
git -C repo gc &&
|
|
|
|
|
|
|
|
# Ensure that the promisor packfile still exists, and remove it
|
|
|
|
test -e repo/.git/objects/pack/pack-$HASH.pack &&
|
|
|
|
rm repo/.git/objects/pack/pack-$HASH.* &&
|
|
|
|
|
|
|
|
# Ensure that the single other pack contains the commit, but not the tree
|
|
|
|
ls repo/.git/objects/pack/pack-*.pack >packlist &&
|
|
|
|
test_line_count = 1 packlist &&
|
|
|
|
git verify-pack repo/.git/objects/pack/pack-*.pack -v >out &&
|
|
|
|
grep "$(git -C repo rev-parse HEAD)" out &&
|
|
|
|
! grep "$TREE_HASH" out
|
|
|
|
'
|
|
|
|
|
2019-09-04 03:42:47 +08:00
|
|
|
test_expect_success 'do not fetch when checking existence of tree we construct ourselves' '
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_commit -C repo base &&
|
|
|
|
test_commit -C repo side1 &&
|
|
|
|
git -C repo checkout base &&
|
|
|
|
test_commit -C repo side2 &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "arbitrary string" &&
|
|
|
|
|
|
|
|
git -C repo cherry-pick side1
|
|
|
|
'
|
|
|
|
|
2022-03-16 17:46:09 +08:00
|
|
|
test_expect_success 'exact rename does not need to fetch the blob lazily' '
|
|
|
|
rm -rf repo partial.git &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
content="some dummy content" &&
|
|
|
|
test_commit -C repo create-a-file file.txt "$content" &&
|
|
|
|
git -C repo mv file.txt new-file.txt &&
|
|
|
|
git -C repo commit -m rename-the-file &&
|
|
|
|
FILE_HASH=$(git -C repo rev-parse HEAD:new-file.txt) &&
|
|
|
|
test_config -C repo uploadpack.allowfilter 1 &&
|
|
|
|
test_config -C repo uploadpack.allowanysha1inwant 1 &&
|
|
|
|
|
|
|
|
git clone --filter=blob:none --bare "file://$(pwd)/repo" partial.git &&
|
|
|
|
git -C partial.git rev-list --objects --missing=print HEAD >out &&
|
|
|
|
grep "[?]$FILE_HASH" out &&
|
|
|
|
git -C partial.git log --follow -- new-file.txt &&
|
|
|
|
git -C partial.git rev-list --objects --missing=print HEAD >out &&
|
|
|
|
grep "[?]$FILE_HASH" out
|
|
|
|
'
|
|
|
|
|
2021-06-18 01:13:26 +08:00
|
|
|
test_expect_success 'lazy-fetch when accessing object not in the_repository' '
|
|
|
|
rm -rf full partial.git &&
|
|
|
|
test_create_repo full &&
|
|
|
|
test_commit -C full create-a-file file.txt &&
|
|
|
|
|
|
|
|
test_config -C full uploadpack.allowfilter 1 &&
|
|
|
|
test_config -C full uploadpack.allowanysha1inwant 1 &&
|
|
|
|
git clone --filter=blob:none --bare "file://$(pwd)/full" partial.git &&
|
|
|
|
FILE_HASH=$(git -C full rev-parse HEAD:file.txt) &&
|
|
|
|
|
|
|
|
# Sanity check that the file is missing
|
|
|
|
git -C partial.git rev-list --objects --missing=print HEAD >out &&
|
|
|
|
grep "[?]$FILE_HASH" out &&
|
|
|
|
|
2024-02-28 00:48:29 +08:00
|
|
|
# The no-lazy-fetch mechanism prevents Git from fetching
|
|
|
|
test_must_fail env GIT_NO_LAZY_FETCH=1 \
|
|
|
|
git -C partial.git cat-file -e "$FILE_HASH" &&
|
|
|
|
|
|
|
|
# The same with command line option to "git"
|
|
|
|
test_must_fail git --no-lazy-fetch -C partial.git cat-file -e "$FILE_HASH" &&
|
|
|
|
|
|
|
|
# The same, forcing a subprocess via an alias
|
|
|
|
test_must_fail git --no-lazy-fetch -C partial.git \
|
|
|
|
-c alias.foo="!git cat-file" foo -e "$FILE_HASH" &&
|
|
|
|
|
|
|
|
# Sanity check that the file is still missing
|
|
|
|
git -C partial.git rev-list --objects --missing=print HEAD >out &&
|
|
|
|
grep "[?]$FILE_HASH" out &&
|
|
|
|
|
2021-06-18 01:13:26 +08:00
|
|
|
git -C full cat-file -s "$FILE_HASH" >expect &&
|
|
|
|
test-tool partial-clone object-info partial.git "$FILE_HASH" >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
# Sanity check that the file is now present
|
|
|
|
git -C partial.git rev-list --objects --missing=print HEAD >out &&
|
|
|
|
! grep "[?]$FILE_HASH" out
|
|
|
|
'
|
|
|
|
|
2024-05-23 04:15:40 +08:00
|
|
|
test_expect_success 'push should not fetch new commit objects' '
|
|
|
|
rm -rf server client &&
|
|
|
|
test_create_repo server &&
|
|
|
|
test_config -C server uploadpack.allowfilter 1 &&
|
|
|
|
test_config -C server uploadpack.allowanysha1inwant 1 &&
|
|
|
|
test_commit -C server server1 &&
|
|
|
|
|
|
|
|
git clone --filter=blob:none "file://$(pwd)/server" client &&
|
|
|
|
test_commit -C client client1 &&
|
|
|
|
|
|
|
|
test_commit -C server server2 &&
|
|
|
|
COMMIT=$(git -C server rev-parse server2) &&
|
|
|
|
|
|
|
|
test_must_fail git -C client push 2>err &&
|
|
|
|
grep "fetch first" err &&
|
|
|
|
git -C client rev-list --objects --missing=print "$COMMIT" >objects &&
|
|
|
|
grep "^[?]$COMMIT" objects
|
|
|
|
'
|
|
|
|
|
2024-05-25 18:09:27 +08:00
|
|
|
test_expect_success 'setup for promisor.quiet tests' '
|
|
|
|
rm -rf server &&
|
|
|
|
test_create_repo server &&
|
|
|
|
test_commit -C server foo &&
|
|
|
|
git -C server rm foo.t &&
|
|
|
|
git -C server commit -m remove &&
|
|
|
|
git -C server config uploadpack.allowanysha1inwant 1 &&
|
|
|
|
git -C server config uploadpack.allowfilter 1
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success TTY 'promisor.quiet=false shows progress messages' '
|
|
|
|
rm -rf repo &&
|
|
|
|
git clone --filter=blob:none "file://$(pwd)/server" repo &&
|
|
|
|
git -C repo config promisor.quiet "false" &&
|
|
|
|
|
|
|
|
test_terminal git -C repo cat-file -p foo:foo.t 2>err &&
|
|
|
|
|
|
|
|
# Ensure that progress messages are written
|
|
|
|
grep "Receiving objects" err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success TTY 'promisor.quiet=true does not show progress messages' '
|
|
|
|
rm -rf repo &&
|
|
|
|
git clone --filter=blob:none "file://$(pwd)/server" repo &&
|
|
|
|
git -C repo config promisor.quiet "true" &&
|
|
|
|
|
|
|
|
test_terminal git -C repo cat-file -p foo:foo.t 2>err &&
|
|
|
|
|
|
|
|
# Ensure that no progress messages are written
|
|
|
|
! grep "Receiving objects" err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success TTY 'promisor.quiet=unconfigured shows progress messages' '
|
|
|
|
rm -rf repo &&
|
|
|
|
git clone --filter=blob:none "file://$(pwd)/server" repo &&
|
|
|
|
|
|
|
|
test_terminal git -C repo cat-file -p foo:foo.t 2>err &&
|
|
|
|
|
|
|
|
# Ensure that progress messages are written
|
|
|
|
grep "Receiving objects" err
|
|
|
|
'
|
|
|
|
|
2017-12-08 23:27:14 +08:00
|
|
|
. "$TEST_DIRECTORY"/lib-httpd.sh
|
|
|
|
start_httpd
|
|
|
|
|
|
|
|
test_expect_success 'fetching of missing objects from an HTTP server' '
|
|
|
|
rm -rf repo &&
|
|
|
|
SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
|
|
|
|
test_create_repo "$SERVER" &&
|
|
|
|
test_commit -C "$SERVER" foo &&
|
|
|
|
git -C "$SERVER" repack -a -d --write-bitmap-index &&
|
|
|
|
|
|
|
|
git clone $HTTPD_URL/smart/server repo &&
|
|
|
|
HASH=$(git -C repo rev-parse foo) &&
|
|
|
|
rm -rf repo/.git/objects/* &&
|
|
|
|
|
|
|
|
git -C repo config core.repositoryformatversion 1 &&
|
|
|
|
git -C repo config extensions.partialclone "origin" &&
|
|
|
|
git -C repo cat-file -p "$HASH" &&
|
|
|
|
|
|
|
|
# Ensure that the .promisor file is written, and check that its
|
|
|
|
# associated packfile contains the object
|
|
|
|
ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
|
|
|
|
test_line_count = 1 promisorlist &&
|
2019-06-25 21:40:25 +08:00
|
|
|
IDX=$(sed "s/promisor$/idx/" promisorlist) &&
|
|
|
|
git verify-pack --verbose "$IDX" >out &&
|
|
|
|
grep "$HASH" out
|
2017-12-08 23:27:14 +08:00
|
|
|
'
|
|
|
|
|
2019-08-01 23:53:09 +08:00
|
|
|
# DO NOT add non-httpd-specific tests here, because the last part of this
|
|
|
|
# test script is only executed when httpd is available and enabled.
|
|
|
|
|
2017-12-06 00:58:44 +08:00
|
|
|
test_done
|