-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Fetch with ref if specified first for fetchGit #13440
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
base: master
Are you sure you want to change the base?
Conversation
Users for `builtins.fetchGit` may specified: * nothing (will use default branch) * rev * ref * rev & ref * all of the above with `allRefs` Previously if `rev` was ever specified, the `ref` attribute was completely ignored which to some felt like a bug. The bug is if the commit is valid but the ref was wrong, the `git fetch` works and people think they are on the matching `ref`. This commit changes the behavior such that the `ref` if specified is always fetched and then the commit is searched using that ref. This will help catch cases where the rev may be not matched with the specified ref. If no ref is specified then the behavior continues as normal by trying to fetch the commit. fixes NixOS#12974
} else if (originalRef) { | ||
// FIXME: We should just use input.getRef() but it's modified above | ||
// If ref is specified try that next to fetch the latest ref | ||
// we will then check that the commit is part of it if given. | ||
if (ref.compare(0, 5, "refs/")) { | ||
fetchRef = fmt("%1%:%1%", ref); | ||
} else { | ||
fetchRef = *originalRef; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this just ignores rev
when ref
is specified, which is the original issue. So I don't understand how this is meant to fix #12974, unless rev
is checked elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see #13440 (comment)
@l0b0 it's a bit difficult to see what's going on in the change however here is an example. Let's use 5a4aa7adeb087067cdb8539f6b6f486014c3b213 from my blog fzakaria/fzakaria.com if we specify an invalid ref even with a valid commit, it fails. > nix eval --expr 'builtins.fetchGit {url = "https://github.com/fzakaria/fzakaria.com"; rev = "5a4aa7adeb087067cdb8539f6b6f486014c3b213"; ref = "no-such-ref";}'
error: Cannot find Git revision '5a4aa7adeb087067cdb8539f6b6f486014c3b213' in ref 'no-such-ref' of repository 'https://github.com/fzakaria/fzakaria.com'! Please make sure that the rev exists on the ref you've specified or add allRefs = true; to fetchGit. if we specify a valid commit without a ref, it will fetch the commit and that will work if any of the advertised refs by the remote have that commit reachable. > nix eval --expr 'builtins.fetchGit {url = "https://github.com/fzakaria/fzakaria.com"; rev = "5a4aa7adeb087067cdb8539f6b6f486014c3b213";}'
{ lastModified = 1751929943; lastModifiedDate = "20250707231223"; narHash = "sha256-rYwNDGotROs5vafWKXtBjFQhI6KbL0lIlYCH5Ui14pI="; outPath = "/nix/store/plcpv7vcvmppa2f33gik0d8amhjixn3l-source"; rev = "5a4aa7adeb087067cdb8539f6b6f486014c3b213"; revCount = 264; shortRev = "5a4aa7a"; submodules = false; } I'll now use ref gh-pages which is just the compiled blog posts and is a ref with only ever 1 commit. This is what I believe your bug is about, the ref and rev don't match. > nix eval --expr 'builtins.fetchGit {url = "https://github.com/fzakaria/fzakaria.com"; rev = "5a4aa7adeb087067cdb8539f6b6f486014c3b213"; ref = "gh-pages";}'
error: Cannot find Git revision '5a4aa7adeb087067cdb8539f6b6f486014c3b213' in ref 'gh-pages' of repository 'https://github.com/fzakaria/fzakaria.com'! Please make sure that the rev exists on the ref you've specified or add allRefs = true; to fetchGit. If I specify a ref that does have the commit reachable everything works. > nix eval --expr 'builtins.fetchGit {url = "https://github.com/fzakaria/fzakaria.com"; rev = "5a4aa7adeb087067cdb8539f6b6f486014c3b213"; ref = "master";}'
{ lastModified = 1751929943; lastModifiedDate = "20250707231223"; narHash = "sha256-rYwNDGotROs5vafWKXtBjFQhI6KbL0lIlYCH5Ui14pI="; outPath = "/nix/store/plcpv7vcvmppa2f33gik0d8amhjixn3l-source"; rev = "5a4aa7adeb087067cdb8539f6b6f486014c3b213"; revCount = 264; shortRev = "5a4aa7a"; submodules = false; } |
Feature branches may disappear on the remote, but it's useful to be able to fetch it even after a merge+delete. |
Thanks for the thorough examples!
That's as expected.
Also as expected.
In Git, a ref corresponds to a single commit (although for practical purposes it's often used to also refer to every ancestor of that commit), so this seems fishy. I guess some users would not consider that a bug. I'd rather it was an error, at least by default. |
I'm not clear from your answer if you are saying you agree or not.... Basically, a commit has to be reachable from a ref. If you don't include the So if you have specify a commit, you are kind of hoping that it's advertised or that setting is set. By adding a ref & a rev, you are being more explicit "Hey, I expect this commit to be an ancestor of this ref". This can be useful for tying a commit to a release branch. The nice thing is, if you put a commit but a faulty ref, this should catch some cases of that (unless the faulty ref also has that as an ancestor). @roberth thanks for taking the time to look at it. |
Sorry 😁. I consider the last case, where the |
I agree that that's a useful feature. My worry is that people will use it excessively for two reasons
So I believe it will be overused, and we need an escape hatch for the case when inevitable feature branches are merged and deleted. Doing the archaeology to figure out your chain of transitive reverse deps and making PRs for all of them is a bunch of work that shouldn't block your deployment.
For tags I agree, but for pinning a branch it would be unusable. |
@roberth it's funny to worry it'll be over-used -- based on my research when providing a @l0b0 I consider the case where rev == ref (not just an ancestor) the most brittle. That means any committed flake to a branch, let's say so... where did we land on where we should take this change? |
For me, brittle doesn't come into it. I would never use a |
@l0b0 super popular is to reference nixpkgs by branch name though:
These branches get security updates and change at any time. |
Is that applicable? When used without a lock file, it's also used without a commit ID, so there's no issue (TOFU). When used with a lock file, whatever reads the lock file and performs the download surely just uses the commit ID without the (at that point) pointless ref. |
Motivation
Users for
builtins.fetchGit
may specified:allRefs
Previously if
rev
was ever specified, theref
attribute was completely ignored which to some felt like a bug. The bug is if the commit is valid but the ref was wrong, thegit fetch
works and people think they are on the matchingref
.This commit changes the behavior such that the
ref
if specified is always fetched and then the commit is searched using that ref.This will help catch cases where the rev may be not matched with the specified ref.
If no ref is specified then the behavior continues as normal by trying to fetch the commit.
fixes #12974
Add 👍 to pull requests you find important.
The Nix maintainer team uses a GitHub project board to schedule and track reviews.