Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git: allow cloning commit shas not referenced by branch/tag #5441

Merged
merged 2 commits into from
Oct 23, 2024

Conversation

jedevc
Copy link
Member

@jedevc jedevc commented Oct 21, 2024

#5072 is only half the fix - it's still possible for a commit to not be tagged or part of a branch.

For a practical example, see refs/pull/.../merge - the commit referenced by this ref is not tagged or part of any branch, and so isn't advertised by upload-pack, and so won't be part of clone.

Modern git servers should support this though - https://git-scm.com/docs/protocol-capabilities#_allow_reachable_sha1_in_want - we should be able to specify a specific commit when fetching. We can include a fallback for if the server doesn't support this capability (not 100% sure about the logic here though 🤔 - can we assume everyone is using upload-pack?)

This might feel a little edge-casey - but they're still important! The main reason is - git fetch supports this, so we should do as well. Another is that it's possible to break cache consistency without this fix, e.g.:

  • Running these in order:
  • Snapshot(<commit at refs/pull/.../merge>) - fails
  • Snapshot(refs/pull/.../merge) - succeeds
  • Snapshot(<commit at refs/pull/.../merge>) - succeeds, since this commit is now in the cloned repo
    This doesn't really make much sense, and can break reproducibility.

(Originally reported in dagger/dagger#8584)

@jedevc jedevc force-pushed the git-clone-hidden-sha branch from 648caff to 57b4c9a Compare October 21, 2024 13:43
@jedevc jedevc changed the title git: export gitutil helper for identifying commit shas git: allow cloning commit shas not referenced by branch/tag Oct 21, 2024
Copy link
Member

@tonistiigi tonistiigi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iiuc correctly then this is breaking for servers that don't support fetch by commit. The old behavior is that in case of commit, all refs are pulled and commit needs to exist somewhere in the commit-tree. In the case of pull/nr/merge shouldn't the pull always be by ref anyway as Github can change the merge base on unrelated changes and old commit would either start giving errors or pull wrong content.

util/gitutil/git_commit.go Outdated Show resolved Hide resolved
@jedevc jedevc force-pushed the git-clone-hidden-sha branch 3 times, most recently from 8a0f32d to 7476ffc Compare October 22, 2024 10:37
@jedevc
Copy link
Member Author

jedevc commented Oct 22, 2024

Iiuc correctly then this is breaking for servers that don't support fetch by commit

The latest changes should fix this - we detect specific error messages in the output to detect this scenario:

Specifically, the error in fetch-pack occurs when REF_UNADVERTISED_NOT_ALLOWED is set - which happens when an unmatched ref appears and neither allow-tip-sha1-in-want or allow-reachable-sha1-in-want capabilities are exposed by the server.

In this case, we can detect these specific errors, and retry without the guilty specific commit in the fetch, which is a fallback to the previous behavior.

In the case of pull/nr/merge shouldn't the pull always be by ref anyway

Sure. But IMO, we should be aiming for compatibility with the git fetch command. It's not just for pull/nr/merge ofc, this applies in any case.

@jedevc jedevc force-pushed the git-clone-hidden-sha branch from 7476ffc to 90d2d8b Compare October 22, 2024 10:38
// testFetchUnreferencedTagSha tests fetching a SHA that points to a tag that is not reachable from any branch.
func testFetchUnreferencedTagSha(t *testing.T, keepGitDir bool) {
func TestFetchUnreferencedRefSha(t *testing.T) {
testFetchUnreferencedRefSha(t, "refs/special", false)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really not sure why this test actually passes 🤔 The config uploadpack.allowReachableSHA1InWant doesn't seem to be set anywhere.

@tonistiigi
Copy link
Member

The latest changes should fix this - we detect specific error messages in the output to detect this scenario:

Where's this error detection code?

@jedevc
Copy link
Member Author

jedevc commented Oct 23, 2024

The latest changes should fix this - we detect specific error messages in the output to detect this scenario:

Where's this error detection code?

https://github.com/moby/buildkit/pull/5441/files#diff-a30e20e46441cc408bd8e5a6f487c6e5a0fb7057b71dfe7ffd74170f96f7a765R221-R228

Exactly the same as how we fallback when we try and set --depth and fail.

@tonistiigi tonistiigi merged commit ff0cedd into moby:master Oct 23, 2024
91 checks passed
@crazy-max crazy-max added this to the v0.17.0 milestone Oct 25, 2024
package gitutil

func IsCommitSHA(str string) bool {
if len(str) != 40 {
Copy link
Member

@tianon tianon Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relevant to https://git-scm.com/docs/hash-function-transition, this should probably also accept 64, right?

Edit: sent a PR at #5471

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants