From 9b56d030c42176eeb17bbbbac10710e3723df958 Mon Sep 17 00:00:00 2001 From: Jegor Gorbunov Date: Fri, 27 Mar 2026 12:49:54 +0200 Subject: [PATCH] util/gitutil: Full/ShortCommit(): replace git show with git rev-parse The FullCommit and ShortCommit methods are expected to simply get the hash of HEAD. Using `git show` for this purpose is overkill because `git show` can have side effects that are annoying when `docker build` runs in a CI environment: 1) CI environments (e.g. CircleCI) may use blobless clones, where the target repository is checked out using `git clone --filter=blob:none {url}`. 2) `git show` does more than just discover the hash of a specified revision: in general, it needs parent commits and blobs to compute the diff. When a blobless clone is used, `git show` may try to download these additional blobs from the remote. From my experiments, this happens even when `--quiet` or `--no-patch` is specified. 3) If the `docker build` step runs in an environment where Git is not configured properly to download from the remote, the step may hang indefinitely, as it did in my case with the following prompt: The authenticity of host 'github.com (140.82.112.3)' can't be established. ED25519 key fingerprint is SHA256:+.... This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])? Notes on test fixes: git rev-parse HEAD doesn't need any `--`, however, when it is called on an empty repo git returns an error: ``` fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git [...] -- [...]' ``` So, it is both IsUnknownRevision and IsAmbiguousArgument. Lets simply fix the test by flipping the check: I don't see any dependency on this behavior in non-test code. Moreover, `git rev-parse --short HEAD` fails with another error: ``` fatal: Needed a single revision ``` Lets handle it as IsUnknownRevision Signed-off-by: Jegor Gorbunov --- util/gitutil/gitutil.go | 9 ++++++--- util/gitutil/gitutil_test.go | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/util/gitutil/gitutil.go b/util/gitutil/gitutil.go index cca79f9001f4..97615be61b41 100644 --- a/util/gitutil/gitutil.go +++ b/util/gitutil/gitutil.go @@ -101,11 +101,11 @@ func (c *Git) RemoteURL() (string, error) { } func (c *Git) FullCommit() (string, error) { - return c.clean(c.run("show", "--format=%H", "HEAD", "--quiet", "--")) + return c.clean(c.run("rev-parse", "HEAD")) } func (c *Git) ShortCommit() (string, error) { - return c.clean(c.run("show", "--format=%h", "HEAD", "--quiet", "--")) + return c.clean(c.run("rev-parse", "--short", "HEAD")) } func (c *Git) Tag() (string, error) { @@ -185,8 +185,11 @@ func IsUnknownRevision(err error) bool { return false } // https://github.com/git/git/blob/a6a323b31e2bcbac2518bddec71ea7ad558870eb/setup.c#L204 + // https://github.com/git/git/blob/1adf5bca8c3cf778103548b9355777cf2d12efdd/builtin/rev-parse.c#L585 errMsg := strings.ToLower(err.Error()) - return strings.Contains(errMsg, "unknown revision or path not in the working tree") || strings.Contains(errMsg, "bad revision") + return strings.Contains(errMsg, "unknown revision or path not in the working tree") || + strings.Contains(errMsg, "bad revision") || + strings.Contains(errMsg, "needed a single revision") } // stripCredentials takes a URL and strips username and password from it. diff --git a/util/gitutil/gitutil_test.go b/util/gitutil/gitutil_test.go index 8a21b25ef1e7..56ad50f621d3 100644 --- a/util/gitutil/gitutil_test.go +++ b/util/gitutil/gitutil_test.go @@ -62,7 +62,7 @@ func TestGitFullCommitErr(t *testing.T) { _, err = c.FullCommit() require.Error(t, err) require.True(t, gitutil.IsUnknownRevision(err)) - require.False(t, gittestutil.IsAmbiguousArgument(err)) + require.True(t, gittestutil.IsAmbiguousArgument(err)) } func TestGitShortCommitErr(t *testing.T) {