[Buildroot] [PATCH v2 2/4] support/download/git: optimized download of sha1

Ricardo Martincoski ricardo.martincoski at datacom.ind.br
Fri Dec 2 15:21:21 UTC 2016


Shallow fetch don't work for downloading SHAs. However it's common to
track a tag or branch by the commit SHA so that a branch or tag doesn't
unexpectedly change.

We can take advantage of this scenario by searching the remote for a ref
that it equivalent to our sha, then shallow fetching that ref instead.

Regarding the case the remote changes between the git ls-remote and the
git fetch, once the script creates the equivalent of a shallow clone,
the fetch and the checkout do what is expected:
- for a sha1 of a removed ref (branch, tag or special ref), the fetch
  fails, falling back to the equivalent of a full clone;
- for a sha1 of a changed ref (branch, tag or special ref), the checkout
  fails (because the desired sha1 is not fetched), falling back to the
  equivalent of a full clone;
In both cases, the checkout after the equivalent of a full clone or
mirror clone is successful if the sha1 is still reachable from any ref.

Similar patch was submitted in [1] using git clone.
[1] http://patchwork.ozlabs.org/patch/681841/

Reported-by: Brandon Maier <brandon.maier at rockwellcollins.com>
Reported-by: Bryce Ferguson <bryce.ferguson at rockwellcollins.com>
Signed-off-by: Ricardo Martincoski <ricardo.martincoski at datacom.ind.br>
---
Changes v1 -> v2:
  - moved the optimized download of sha1 to this separate patch
    (Arnout);
  - part of commit message copied from Brandon's patch;
  - only full sha1 are optimized because the output of git ls-remote is
    a subset of all sha1 and so cannot be used to validate a sha1 is
    unambiguous in the full set of sha1s from the repo (that also
    include tree-ish sha1s);
  - save the output of grep to a temporary file and then get the ref
    name using cut instead of using awk (Arnout);
  - any reference that points to the sha1 can be used, we just want to
    avoid HEAD because it is the most volatile one. So use tail -1 to
    get the last match instead of doing many 'if's to accomplish the
    same goal (Arnout);
  - added more comments, especially this: ref for sha1 pointed by
    annotated tags shows a ^{} at the end in the output of ls-remote;
  - use 'Pattern substitution' from bash to remove ^{}.
---
 support/download/git | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/support/download/git b/support/download/git
index 0780c6a9e..42048ad48 100755
--- a/support/download/git
+++ b/support/download/git
@@ -69,6 +69,18 @@ if grep -F "${cset}" ${a_r} >${c_r} 2>/dev/null; then
         # clone and git checkout. To accomplish this we use the first match
         # because output of git ls-remote is already sorted by ref.
         ref="$(cut -f 2 ${m_r} | head -1)"
+    elif grep "^${cset}\>" ${c_r} >${m_r} 2>/dev/null; then
+        # Support sha1 of branch head and commit pointed by tag (annotated or
+        # not) and sha1 of special refs head.
+        # Do not support partial sha1 because it is possible it is unambiguous
+        # in the subset of ls-remote but ambiguous in the full set of all sha1.
+        # A sha1 can be referenced by many names. Any reference can be used but
+        # avoid using HEAD if possible because it is the most volatile one.
+        # HEAD appears at the begin of ls-remote, so use the last match.
+        ref="$(cut -f 2 ${m_r} | tail -1)"
+        # The ref of the sha1 pointed by an annotated tag ends with tag^{} in
+        # the output of git ls-remote but we want the name of the tag to fetch.
+        ref=${ref/%"^{}"}
     fi
 fi
 git_done=0
@@ -82,6 +94,8 @@ if [ "${ref}" ]; then
         if _git checkout -q "'${cset}'" 2>&1; then
             git_done=1
         else
+            # It catches the case we want a sha1 but the remote changed the ref
+            # after git ls-remote.
             printf "Checkout failed, falling back to doing a full fetch\n"
         fi
     else
-- 
2.11.0




More information about the buildroot mailing list