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

fetchGit: allow fetching revs which are not ancestors of HEAD without specifying a ref #3408

Closed

Conversation

basvandijk
Copy link
Member

@basvandijk basvandijk commented Mar 13, 2020

Note that builtins.fetchGit defaults ref to HEAD when not specified. This is problematic when fetching a rev which is not an ancestor of HEAD when no ref is available:

nix-instantiate -v --eval -E \
'builtins.fetchGit { 
  url = "https://github.com/.../..."; 
  rev = "9ec3a6973f6a17dc4b2566520253fc6203f75ac6"; 
}'
evaluating file '/nix/store/lrnvapsqmf0ja6zfyx4cpxr7ahdr7f9b-nix-2.3.3/share/nix/corepkgs/derivation.nix'
fetching Git repository 'https://github.com/.../...'...
using revision 9ec3a6973f6a17dc4b2566520253fc6203f75ac6 of repo 'https://github.com/.../...'
fatal: not a tree object: 9ec3a6973f6a17dc4b2566520253fc6203f75ac6
error: program 'git' failed with exit code 128

This error occurs because rev is never fetched since it's not an ancestor of the ref HEAD which is fetched.

This commit introduces the fetchRevInsteadOfRef argument to builtins.fetchGit which when true fetches the rev directly instead of fetching HEAD.

fetchRevInsteadOfRef defaults to false to keep backwards compatibility and since git servers by default don't allow fetching revisions directly (Note that GitHub does allow this).

This commit now also checks whether rev is an ancestor of ref when the latter is specified.

basvandijk added a commit to nix-community/naersk that referenced this pull request Mar 13, 2020
This is to work around a bug in `builtins.fetchGit` where
specifying a `rev` which is not an ancestor of HEAD
results in a git error. When setting `ref` to `rev` we
force Nix to fetch the `rev`.

TODO: This hack can be removed once the following is
merged and released:
NixOS/nix#3408
@edolstra
Copy link
Member

In the past we've decided that fetchGit should require a ref if you're pulling from a non-master branch. I don't really want to change that since it will requiring cloning an entire repository rather than a single branch.

@basvandijk
Copy link
Member Author

basvandijk commented Mar 13, 2020

... it will requiring cloning an entire repository rather than a single branch.

Why does it require cloning an entire repository?

Only fetching rev like I do here should be enough no?

@basvandijk
Copy link
Member Author

Also when both specifying a rev and a ref I now check if rev is an ancestor of ref. I'm careful to only fetch ref when rev is not an ancestor of the already cached ref.

@basvandijk
Copy link
Member Author

BTW the reason I need this is that in naersk we need to fetch crates with a git source. However since crates only specify a rev we don't have a ref available.

I currently work around this by setting ref = rev but that results in ugly git warnings like:

warning: refname '9ec3a6973f6a17dc4b2566520253fc6203f75ac6' is ambiguous.
Git normally never creates a ref that ends with 40 hex characters
because it will be ignored when you just specify 40-hex. These refs
may be created by mistake. For example,

  git switch -c $br $(git rev-parse ...)

where "$br" is somehow empty and a 40-hex ref is created. Please
examine these refs and maybe delete them. Turn this message off by
running "git config advice.objectNameWarning false"

@edolstra
Copy link
Member

Git in general does not allow fetching an arbitrary revision from a remote for security reasons. (IIRC there is a server setting to disable this check.) You have to specify a ref that contains the revision.

@basvandijk basvandijk force-pushed the fetchGit-fetch-rev-instead-of-ref branch from abb4ffe to 9eb6dff Compare March 13, 2020 22:49
@basvandijk
Copy link
Member Author

TIL that git servers indeed don't allow fetching revisions directly by default (GitHub however does).

So if this is parameterizable on the server, what about making it parameterizable on the client as well?

I forced-pushed a proposal for this where I introduce the fetchRevInsteadOfRef argument to builtins.fetchGit (I'm open for other names). It defaults to false to keep backwards compatibility and to mimic the default on the server. When fetchRevInsteadOfRef == true builtins.fetchGit fetches the specified rev directly instead of fetching ref.

This keeps the old semantics, although with the additional ancestor checks, but allows fetching revisions directly.

@edolstra WDYT?

@basvandijk basvandijk force-pushed the fetchGit-fetch-rev-instead-of-ref branch 4 times, most recently from 5f26a2b to fa43782 Compare March 14, 2020 00:19
… specifying a ref

Note that `builtins.fetchGit` defaults `ref` to `HEAD` when not
specified. This is problematic when fetching a `rev` which is not
an ancestor of `HEAD` when no `ref` is available:

```
nix-instantiate -v --eval -E 'builtins.fetchGit { url = "https://github.com/.../..."; rev = "9ec3a6973f6a17dc4b2566520253fc6203f75ac6"; }'
evaluating file '/nix/store/lrnvapsqmf0ja6zfyx4cpxr7ahdr7f9b-nix-2.3.3/share/nix/corepkgs/derivation.nix'
fetching Git repository 'https://github.com/.../...'...
using revision 9ec3a6973f6a17dc4b2566520253fc6203f75ac6 of repo 'https://github.com/.../...'
fatal: not a tree object: 9ec3a6973f6a17dc4b2566520253fc6203f75ac6
error: program 'git' failed with exit code 128
```

This error occurs because `rev` is never fetched since it's not an
ancestor of the ref `HEAD` which is fetched.

This commit introduces the `fetchRevInsteadOfRef` argument to
`builtins.fetchGit` which when `true` fetches the `rev` directly
instead of fetching `HEAD`.

`fetchRevInsteadOfRef` defaults to `false` to keep backwards
compatibility and since git servers by default
[don't allow fetching revisions directly](https://www.git-scm.com/docs/git-config/2.25.1#Documentation/git-config.txt-uploadpackallowAnySHA1InWant)
(Note that GitHub does allow this).

This commit now also checks whether `rev` is an ancestor of `ref` when
the latter is specified.
@basvandijk basvandijk force-pushed the fetchGit-fetch-rev-instead-of-ref branch from fa43782 to 2f849a4 Compare March 14, 2020 00:19
@yorickvP
Copy link
Contributor

@basvandijk GitHub does not allow fetching 'unadvertised refs' (one of the heads or tags, basically), which is the git default. We work around this by specifying ref = "*"; where needed and setting rev to the revision, does that work for you? Alternatively, fetchTarball will work on non-private github repos and usually download less data.

@nmattia
Copy link
Contributor

nmattia commented Aug 13, 2020

@yorickvP what's the ref="*" about? Is that an instruction to nix to perform a full clone first? Or is that a git thing?

$ git fetch origin '*'
fatal: invalid refspec '*'

@yorickvP
Copy link
Contributor

It's a git thing, git fetch origin 'refs/heads/*'. Also see #2409

Ekleog added a commit to Ekleog/naersk that referenced this pull request Jan 14, 2021
This is required so that fetching dependencies from a feature branch is
possible.

See also NixOS/nix#3408
Ekleog added a commit to Ekleog/naersk that referenced this pull request Jan 26, 2021
This is required so that fetching dependencies from a feature branch is
possible.

See also NixOS/nix#3408
nmattia pushed a commit to nix-community/naersk that referenced this pull request Jan 26, 2021
This is required so that fetching dependencies from a feature branch is
possible.

See also NixOS/nix#3408
@stale
Copy link

stale bot commented Jun 28, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added the stale label Jun 28, 2021
@stale
Copy link

stale bot commented Jul 10, 2022

I closed this issue due to inactivity. → More info

@stale stale bot closed this Jul 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants