aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bpkg/fetch-git.cxx67
-rw-r--r--tests/remote-git.testscript10
-rw-r--r--tests/rep-fetch-git-commit.testscript3
-rw-r--r--tests/rep-fetch-git-refname.testscript1
4 files changed, 64 insertions, 17 deletions
diff --git a/bpkg/fetch-git.cxx b/bpkg/fetch-git.cxx
index 20bad96..2cf526d 100644
--- a/bpkg/fetch-git.cxx
+++ b/bpkg/fetch-git.cxx
@@ -74,14 +74,11 @@ namespace bpkg
static string
git_line (const common_options&, const char* what, A&&... args);
- // Start git process. On the first call check that git version is 2.14.0 or
- // above, and fail if that's not the case.
- //
- // Note that prior to 2.14.0 the git-fetch command doesn't accept commit id
- // as a refspec:
- //
- // $ git fetch --no-recurse-submodules --depth 1 origin 5e8245ee3526530a3467f59b0601bbffb614f45b
- // error: Server does not allow request for unadvertised object 5e8245ee3526530a3467f59b0601bbffb614f45b
+ // Start git process. On the first call check that git version is 2.11.0 or
+ // above, and fail if that's not the case. Note that the full functionality
+ // (such as being able to fetch unadvertised commits) requires 2.14.0. And
+ // supporting versions prior to 2.11.0 doesn't seem worth it (plus other
+ // parts of the toolchain also requires 2.11.0).
//
// Also note that git is executed in the "sanitized" environment, having the
// environment variables that are local to the repository being unset (all
@@ -89,6 +86,7 @@ namespace bpkg
// does for commands executed for submodules. Though we do it for all
// commands (including the ones related to the top repository).
//
+ static semantic_version git_ver;
static optional<strings> unset_vars;
template <typename O, typename E, typename... A>
@@ -124,9 +122,11 @@ namespace bpkg
info << "produced by '" << co.git () << "'; "
<< "use --git to override" << endg;
- if (*v < semantic_version {2, 14, 0})
+ if (*v < semantic_version {2, 11, 0})
fail << "unsupported git version " << *v <<
- info << "minimum supported version is 2.14.0" << endf;
+ info << "minimum supported version is 2.11.0" << endf;
+
+ git_ver = move (*v);
// Sanitize the environment.
//
@@ -910,8 +910,9 @@ namespace bpkg
// Collect the list of commits together with the refspecs that should be
// used to fetch them. If refspecs are absent then the commit is already
- // fetched (and must not be re-fetched). Otherwise, it it is empty, then
- // the whole repository history must be fetched.
+ // fetched (and must not be re-fetched). Otherwise, if it is empty, then
+ // the whole repository history must be fetched. And otherwise, it is a
+ // list of commit ids.
//
// Note that the <refname>@<commit> filter may result in multiple refspecs
// for a single commit.
@@ -1174,6 +1175,40 @@ namespace bpkg
//
assert (!refspecs.empty () || !shallow);
+ // Prior to 2.14.0 the git-fetch command didn't accept commit id as a
+ // refspec:
+ //
+ // $ git fetch --no-recurse-submodules --depth 1 origin 5e8245ee3526530a3467f59b0601bbffb614f45b
+ // error: Server does not allow request for unadvertised object 5e8245ee3526530a3467f59b0601bbffb614f45b
+ //
+ // We will try to remap commits back to git refs (tags, branches, etc)
+ // based on git-ls-remote output and fail if unable to do so (which
+ // should only happen for unadvertised commits).
+ //
+ // Note that in this case we will fail only for servers supporting
+ // unadvertised refs fetch. For other protocols we have already fallen
+ // back to fetching some history, passing to fetch() either advertised
+ // commit ids (of branches, tags, etc) or an empty refspecs list (the
+ // whole repository history). So we could just reduce the server
+ // capabilities from 'unadv' to 'smart' for such old clients.
+ //
+ optional<strings> remapped_refspecs;
+ if (!refspecs.empty () && git_ver < semantic_version {2, 14, 0})
+ {
+ remapped_refspecs = strings ();
+
+ for (const string& c: refspecs)
+ {
+ const ref* r (load_refs (co, url ()).find_commit (c));
+
+ if (r == nullptr)
+ fail << "git version is too old for specified location" <<
+ info << "consider upgrading git to 2.14.0 or above";
+
+ remapped_refspecs->push_back (r->name);
+ }
+ }
+
// Note that we suppress the (too detailed) fetch command output if the
// verbosity level is 1. However, we still want to see the progress in
// this case, unless stderr is not directed to a terminal.
@@ -1192,7 +1227,7 @@ namespace bpkg
verb == 1 && fdterm (2) ? opt ("--progress") : nullopt,
verb < 2 ? opt ("-q") : verb > 3 ? opt ("-v") : nullopt,
"origin",
- refspecs))
+ remapped_refspecs ? *remapped_refspecs : refspecs))
fail << "unable to fetch " << dir << endg;
};
@@ -1318,7 +1353,11 @@ namespace bpkg
co.git_option (),
"-C", dir,
- !prefix.empty ()
+ // Note that older git versions don't recognize the --super-prefix
+ // option but seem to behave correctly without any additional
+ // efforts when it is omitted.
+ //
+ !prefix.empty () && git_ver >= semantic_version {2, 14, 0}
? strings ({"--super-prefix", prefix.posix_representation ()})
: strings (),
diff --git a/tests/remote-git.testscript b/tests/remote-git.testscript
index 2ce0fa0..595220d 100644
--- a/tests/remote-git.testscript
+++ b/tests/remote-git.testscript
@@ -26,11 +26,15 @@ end
+echo "$git_version" | sed -e 's/(\d+).*/\1/' | set git_version_major
+echo "$git_version" | sed -e 's/\d+\.(\d+).*/\1/' | set git_version_minor
-# This flag must be used by testscripts to decide if they should skip git
-# repository-related tests.
+# These flags must be used by testscripts to decide if they should skip git
+# repository-related tests. See bpkg/fetch-git.cxx for the functionality
+# reduction details for partially supported git versions.
#
git_supported = ($git_version_major > 2 || \
- $git_version_major == 2 && $git_version_minor >= 14)
+ $git_version_major == 2 && $git_version_minor >= 11)
+
+git_fully_supported = ($git_version_major > 2 || \
+ $git_version_major == 2 && $git_version_minor >= 14)
# Output directory path that testscripts must use to prepare repositories
# required by tests they contain.
diff --git a/tests/rep-fetch-git-commit.testscript b/tests/rep-fetch-git-commit.testscript
index ff6c7a3..f5aa685 100644
--- a/tests/rep-fetch-git-commit.testscript
+++ b/tests/rep-fetch-git-commit.testscript
@@ -6,6 +6,7 @@
: unadvertised
:
+if ($git_fully_supported || $git_protocol != 'https-smart-unadv')
{
+git -C ../style-basic log '--pretty=format:%H' --all --grep='README' | \
set commit
@@ -72,6 +73,7 @@
%fetching git:.+style-basic#@$commit%
%querying .+style-basic\.git%?
%fetching from .+style-basic.\git%
+ %querying .+style-basic\.git%?
$warn
1 package\(s\) in 1 repository\(s\)
EOE
@@ -86,6 +88,7 @@
%fetching git:.+style-basic#stable@$commit%
%querying .+style-basic\.git%?
%fetching from .+style-basic\.git%
+ %querying .+style-basic\.git%?
$warn
1 package\(s\) in 1 repository\(s\)
EOE
diff --git a/tests/rep-fetch-git-refname.testscript b/tests/rep-fetch-git-refname.testscript
index fe5b330..88f1e2a 100644
--- a/tests/rep-fetch-git-refname.testscript
+++ b/tests/rep-fetch-git-refname.testscript
@@ -39,6 +39,7 @@
: changed
:
+ if ($git_fully_supported || $git_protocol != 'https-smart-unadv')
{
g = git -C
u = "$rep_git/state1"