[PATCH] Channels defaulting to HEAD instead of ‘master’

  • Open
  • quality assurance status badge
Details
3 participants
  • Kyle Meyer
  • Ludovic Courtès
  • Ricardo Wurmus
Owner
unassigned
Submitted by
Ludovic Courtès
Severity
normal
L
L
Ludovic Courtès wrote on 28 Jun 2021 14:56
[PATCH] Channels defaulting to HEAD instead of ‘mas ter’
(address . guix-patches@gnu.org)
87y2auw3jo.fsf@inria.fr
Hi,

With an eye on allowing channel authors, and Guix in particular, to
eventually be able to choose a default branch name other than ‘master’,
what about changing defaults like this:
Toggle diff (48 lines)
diff --git a/guix/channels.scm b/guix/channels.scm
index 476d62e1f4..a5283b4bf4 100644
--- a/guix/channels.scm
+++ b/guix/channels.scm
@@ -122,7 +122,7 @@
channel?
(name channel-name)
(url channel-url)
- (branch channel-branch (default "master"))
+ (branch channel-branch (default #f))
(commit channel-commit (default #f))
(introduction channel-introduction (default #f))
(location channel-location
@@ -179,7 +179,6 @@ to the corresponding bytevector."
(define %default-guix-channel
(channel
(name 'guix)
- (branch "master")
(url %default-channel-url)
(introduction %guix-channel-introduction)))
@@ -225,7 +224,9 @@ introduction, add it."
"Return the \"reference\" for CHANNEL, an sexp suitable for
'latest-repository-commit'."
(match (channel-commit channel)
- (#f `(branch . ,(channel-branch channel)))
+ (#f (if (channel-branch channel)
+ `(branch . ,(channel-branch channel))
+ '())) ;remote HEAD
(commit `(commit . ,(channel-commit channel)))))
(define sexp->channel-introduction
diff --git a/guix/inferior.scm b/guix/inferior.scm
index 7c8e478f2a..3db63167fd 100644
--- a/guix/inferior.scm
+++ b/guix/inferior.scm
@@ -732,7 +732,10 @@ prefix, resolve it; and if 'commit' is unset, fetch CHANNEL's branch tip."
(branch (channel-branch channel)))
(if (and commit (= (string-length commit) 40))
commit
- (let* ((ref (if commit `(commit . ,commit) `(branch . ,branch)))
+ (let* ((ref (cond
+ (commit `(commit . ,commit))
+ (branch `(branch . ,branch))
+ (else '()))) ;remote HEAD
(cache commit relation
(update-cached-checkout (channel-url channel)
#:ref ref
For the record, commit cb41c15827a2e910aa56fb5d1917ba8a085c95c7 by Kyle
(Cc’d) gives the ability to use the remote HEAD by default, which is
exactly what we need here.

Unfortunately, for the Guix repo at Savannah, I get:

Toggle snippet (4 lines)
$ ./pre-inst-env guix time-machine -- describe
guix time-machine: error: Git error: reference 'refs/remotes/origin/HEAD' not found


Presumably we have a server-side setup issue at Savannah?

Are there downsides, or cases where it might pick the wrong branch?

Thoughts?

Ludo’.
K
K
Kyle Meyer wrote on 9 Jul 2021 02:38
Re: [bug#49252] [PATCH] Channels defaulting to HEAD instead of ‘master’
(name . Ludovic Courtès)(address . ludo@gnu.org)
87fswo8goa.fsf@kyleam.com
Ludovic Courtès writes:

Toggle quote (15 lines)
> For the record, commit cb41c15827a2e910aa56fb5d1917ba8a085c95c7 by Kyle
> (Cc’d) gives the ability to use the remote HEAD by default, which is
> exactly what we need here.
>
> Unfortunately, for the Guix repo at Savannah, I get:
>
> --8<---------------cut here---------------start------------->8---
> $ ./pre-inst-env guix time-machine -- describe
> guix time-machine: error: Git error: reference 'refs/remotes/origin/HEAD' not found
> --8<---------------cut here---------------end--------------->8---
>
> … but it works for <https://github.com/guix-mirror/guix>.
>
> Presumably we have a server-side setup issue at Savannah?

Hmm, it looks like it's there:

$ git ls-remote https://git.savannah.gnu.org/git/guix.git| grep HEAD
e499500730de23fd54ae63696a725d4b90a406d7 HEAD

$ git for-each-ref refs/remotes/origin | grep HEAD
e499500730de23fd54ae63696a725d4b90a406d7 commit refs/remotes/origin/HEAD
$ git name-rev refs/remotes/origin/HEAD
refs/remotes/origin/HEAD master

This might be a long shot, but if you cloned the repo with magit-clone,
it has some custom logic that deletes refs/remotes/<remote>/HEAD unless
magit-clone-set-remote-head is non-nil (and it's nil by default).

Toggle quote (2 lines)
> Are there downsides, or cases where it might pick the wrong branch?

The main downside I can think of is what I mentioned in bug#45187
(87v9d8dk0r.fsf@kyleam.com):

[The remote HEAD symref] probably the best indicator of what the
primary branch is. In a clone, it doesn't necessarily match HEAD on
the remote, because users may change it to another branch they're
interested in, but that isn't really relevant to these
behind-the-scenes checkouts.

So, if it's a user-facing clone, refs/remotes/origin/HEAD isn't a
reliable indicator because users are free to redirect the remote HEAD
symref to another branch of interest [*] or to delete it altogether.

I think channel clones would fall into the "behind the scenes" category,
though, right?


[*] This is discussed here:
L
L
Ludovic Courtès wrote on 4 Aug 2021 17:04
(name . Kyle Meyer)(address . kyle@kyleam.com)
87h7g5p7yi.fsf@gnu.org
Hi Kyle,

Kyle Meyer <kyle@kyleam.com> skribis:

Toggle quote (28 lines)
> Ludovic Courtès writes:
>
>> For the record, commit cb41c15827a2e910aa56fb5d1917ba8a085c95c7 by Kyle
>> (Cc’d) gives the ability to use the remote HEAD by default, which is
>> exactly what we need here.
>>
>> Unfortunately, for the Guix repo at Savannah, I get:
>>
>> --8<---------------cut here---------------start------------->8---
>> $ ./pre-inst-env guix time-machine -- describe
>> guix time-machine: error: Git error: reference 'refs/remotes/origin/HEAD' not found
>> --8<---------------cut here---------------end--------------->8---
>>
>> … but it works for <https://github.com/guix-mirror/guix>.
>>
>> Presumably we have a server-side setup issue at Savannah?
>
> Hmm, it looks like it's there:
>
> $ git ls-remote https://git.savannah.gnu.org/git/guix.git | grep HEAD
> e499500730de23fd54ae63696a725d4b90a406d7 HEAD
>
> $ git clone https://git.savannah.gnu.org/git/guix.git && cd guix
> $ git for-each-ref refs/remotes/origin | grep HEAD
> e499500730de23fd54ae63696a725d4b90a406d7 commit refs/remotes/origin/HEAD
> $ git name-rev refs/remotes/origin/HEAD
> refs/remotes/origin/HEAD master

OK, so something else must be at fault.

Ideas?

Toggle quote (4 lines)
> This might be a long shot, but if you cloned the repo with magit-clone,
> it has some custom logic that deletes refs/remotes/<remote>/HEAD unless
> magit-clone-set-remote-head is non-nil (and it's nil by default).

No, these are clones managed via (guix git) only.

Toggle quote (18 lines)
>> Are there downsides, or cases where it might pick the wrong branch?
>
> The main downside I can think of is what I mentioned in bug#45187
> (87v9d8dk0r.fsf@kyleam.com):
>
> [The remote HEAD symref] probably the best indicator of what the
> primary branch is. In a clone, it doesn't necessarily match HEAD on
> the remote, because users may change it to another branch they're
> interested in, but that isn't really relevant to these
> behind-the-scenes checkouts.
>
> So, if it's a user-facing clone, refs/remotes/origin/HEAD isn't a
> reliable indicator because users are free to redirect the remote HEAD
> symref to another branch of interest [*] or to delete it altogether.
>
> I think channel clones would fall into the "behind the scenes" category,
> though, right?

Right, those cached clones managed by (guix git) are behind the scenes;
we can assume only (guix git) will only ever touch them.

Thanks,
Ludo’.
R
R
Ricardo Wurmus wrote on 8 Aug 2021 15:53
(name . Ludovic Courtès)(address . ludo@gnu.org)
87tuk0kpoz.fsf@elephly.net
Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (18 lines)
> For the record, commit cb41c15827a2e910aa56fb5d1917ba8a085c95c7
> by Kyle
> (Cc’d) gives the ability to use the remote HEAD by default,
> which is
> exactly what we need here.
>
> Unfortunately, for the Guix repo at Savannah, I get:
>
> --8<---------------cut
> here---------------start------------->8---
> $ ./pre-inst-env guix time-machine -- describe
> guix time-machine: error: Git error: reference
> 'refs/remotes/origin/HEAD' not found
> --8<---------------cut
> here---------------end--------------->8---
>
> … but it works for <https://github.com/guix-mirror/guix>.

For what it’s worth I found the same kind of problem when
importing an R package from Github:

./pre-inst-env guix import cran -a git

Here’s the error backtrace:

Toggle snippet (56 lines)
Backtrace:
In ice-9/boot-9.scm:
724:2 19 (call-with-prompt _ _ #<procedure
default-prompt-handler (k proc)>)
In ice-9/eval.scm:
619:8 18 (_ #(#(#<directory (guile-user) 7f95f8626c80>)))
In guix/ui.scm:
2185:7 17 (run-guix . _)
2148:10 16 (run-guix-command _ . _)
In guix/scripts/import.scm:
120:11 15 (guix-import . _)
In guix/scripts/import/cran.scm:
110:25 14 (guix-import-cran . _)
In guix/memoization.scm:
98:0 13 (mproc "https://github.com/ImmuneDynamics/Spectre"
#:repo git)
In unknown file:
12 (_ #<procedure 7f95f4ce5e60 at
guix/memoization.scm:179:32 ()> #<procedure list _>
(this is nothing))
In guix/import/cran.scm:
594:24 11 (_ "https://github.com/ImmuneDynamics/Spectre" #:repo
_ #:version _)
279:25 10 (fetch-description _
"https://github.com/ImmuneDynamics/Spectre")
In guix/memoization.scm:
98:0 9 (mproc "https://github.com/ImmuneDynamics/Spectre"
#:method git)
In unknown file:
8 (_ #<procedure 7f95f4ce5e00 at
guix/memoization.scm:179:32 ()> #<procedure list _>
(this is nothing))
In ice-9/boot-9.scm:
1752:10 7 (with-exception-handler _ _ #:unwind? _
#:unwind-for-type _)
In guix/store.scm:
658:37 6 (thunk)
In guix/git.scm:
481:8 5 (latest-repository-commit #<store-connection 256.99
7f95f4c18320> "https://github.com/ImmuneDynamics/Spectre"
#:recursive? _ #:log-port _ #:cache-directory _ #:ref _)
247:4 4 (update-cached-checkout _ #:ref _ #:recursive? _
#:check-out? _ #:starting-commit _ #:log-port _
#:cache-directory _)
214:18 3 (resolve _)
In git/reference.scm:
60:8 2 (_ _ _)
In git/bindings.scm:
77:2 1 (raise-git-error _)
In ice-9/boot-9.scm:
1685:16 0 (raise-exception _ #:continuable? _)

ice-9/boot-9.scm:1685:16: In procedure raise-exception:
Git error: reference 'refs/remotes/origin/HEAD' not found

Toggle quote (2 lines)
> Presumably we have a server-side setup issue at Savannah?

I think it might be a repository setting rather than a server
setting as other Github repositories work, yet this one repo on
Github does not.

--
Ricardo
K
K
Kyle Meyer wrote on 9 Aug 2021 01:08
(name . Ricardo Wurmus)(address . rekado@elephly.net)
87mtpr8rhl.fsf@kyleam.com
Ricardo Wurmus writes:

Toggle quote (7 lines)
> For what it’s worth I found the same kind of problem when
> importing an R package from Github:
>
> ./pre-inst-env guix import cran -a git
> https://github.com/ImmuneDynamics/Spectre
>
> Here’s the error backtrace:
[...]
Toggle quote (11 lines)
>
> ice-9/boot-9.scm:1685:16: In procedure raise-exception:
> Git error: reference 'refs/remotes/origin/HEAD' not found
> --8<---------------cut here---------------end--------------->8---
>
>> Presumably we have a server-side setup issue at Savannah?
>
> I think it might be a repository setting rather than a server
> setting as other Github repositories work, yet this one repo on
> Github does not.

Hmm, I'm not sure what's going on here, but, as with
via `git clone', refs/remotes/origin/HEAD is there:

$ git ls-remote https://github.com/ImmuneDynamics/Spectre| grep HEAD
742ebc4bc09ce69b970eceb78291bdbf5229d20d HEAD

$ git for-each-ref refs/remotes/origin | grep HEAD
742ebc4bc09ce69b970eceb78291bdbf5229d20d commit refs/remotes/origin/HEAD
K
K
Kyle Meyer wrote on 9 Aug 2021 01:28
(name . Ludovic Courtès)(address . ludo@gnu.org)
87k0kv8qka.fsf@kyleam.com
Ludovic Courtès writes:

Toggle quote (1 lines)
> Kyle Meyer <kyle@kyleam.com> skribis:
[...]
Toggle quote (16 lines)
>>
>> Hmm, it looks like it's there:
>>
>> $ git ls-remote https://git.savannah.gnu.org/git/guix.git | grep HEAD
>> e499500730de23fd54ae63696a725d4b90a406d7 HEAD
>>
>> $ git clone https://git.savannah.gnu.org/git/guix.git && cd guix
>> $ git for-each-ref refs/remotes/origin | grep HEAD
>> e499500730de23fd54ae63696a725d4b90a406d7 commit refs/remotes/origin/HEAD
>> $ git name-rev refs/remotes/origin/HEAD
>> refs/remotes/origin/HEAD master
>
> OK, so something else must be at fault.
>
> Ideas?

My understanding is that the clone is happening through guile-git, which
uses libgit2. In libgit2's v1.1.0 release notes, I see "[t]he
refs/remotes/origin/HEAD file will be created at clone time to point to
the origin's default branch". So my current guess is that this clone
was made before guix's libgit2 was 1.1.0.

Does that sound possible (i.e. this clone is from before 2020-12-ish)?
Do you still see the "reference 'refs/remotes/origin/HEAD' not found"
failure if you force a fresh clone?
L
L
Ludovic Courtès wrote on 9 Aug 2021 11:12
(name . Kyle Meyer)(address . kyle@kyleam.com)
87wnovyobb.fsf@gnu.org
Hello Kyle,

Kyle Meyer <kyle@kyleam.com> skribis:

Toggle quote (30 lines)
> Ludovic Courtès writes:
>
>> Kyle Meyer <kyle@kyleam.com> skribis:
> [...]
>>>
>>> Hmm, it looks like it's there:
>>>
>>> $ git ls-remote https://git.savannah.gnu.org/git/guix.git | grep HEAD
>>> e499500730de23fd54ae63696a725d4b90a406d7 HEAD
>>>
>>> $ git clone https://git.savannah.gnu.org/git/guix.git && cd guix
>>> $ git for-each-ref refs/remotes/origin | grep HEAD
>>> e499500730de23fd54ae63696a725d4b90a406d7 commit refs/remotes/origin/HEAD
>>> $ git name-rev refs/remotes/origin/HEAD
>>> refs/remotes/origin/HEAD master
>>
>> OK, so something else must be at fault.
>>
>> Ideas?
>
> My understanding is that the clone is happening through guile-git, which
> uses libgit2. In libgit2's v1.1.0 release notes, I see "[t]he
> refs/remotes/origin/HEAD file will be created at clone time to point to
> the origin's default branch". So my current guess is that this clone
> was made before guix's libgit2 was 1.1.0.
>
> Does that sound possible (i.e. this clone is from before 2020-12-ish)?
> Do you still see the "reference 'refs/remotes/origin/HEAD' not found"
> failure if you force a fresh clone?

Oh, this must be the reason. If I remove the cached clone:

rm -rf ~/.cache/guix/checkouts/pjmkglp4t7znuugeurpurzikxq3tnlaywmisyr27shj7apsnalwq

and then clone again, it works:

Toggle snippet (7 lines)
scheme@(guile-user)> ,use(guix git)
scheme@(guile-user)> (update-cached-checkout "https://git.savannah.gnu.org/git/guix.git")
$2 = "/home/ludo/.cache/guix/checkouts/pjmkglp4t7znuugeurpurzikxq3tnlaywmisyr27shj7apsnalwq"
$3 = "30289f4d4638452520f52c1a36240220d0d940ff"
$4 = #f

Likewise with the other repo Ricardo mentions:

Toggle snippet (6 lines)
scheme@(guile-user)> (update-cached-checkout "https://github.com/ImmuneDynamics/Spectre")
$5 = "/home/ludo/.cache/guix/checkouts/lpz4iyuu3pztx73ks74bfiymewyzn24rm565l6cgiutvjow5joka"
$6 = "742ebc4bc09ce69b970eceb78291bdbf5229d20d"
$7 = #f

I suppose we need to add a call to fetch remote heads when they’re
missing? It seems that calling ‘remote-fetch’ is not enough. If I
explicitly remove ‘HEAD’ from the clone, then I get:

Toggle snippet (18 lines)
scheme@(guile-user)> (define r (repository-open "/home/ludo/.cache/guix/checkouts/lpz4iyuu3pztx73ks74bfiymewyzn24rm565l6cgiutvjow5joka"))
scheme@(guile-user)> (reference-name->oid r "refs/remotes/origin/HEAD")
ice-9/boot-9.scm:1685:16: In procedure raise-exception:
Git error: reference 'refs/remotes/origin/HEAD' not found


Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]> ,q
scheme@(guile-user)> (remote-fetch (remote-lookup r "origin"))
scheme@(guile-user)> (reference-name->oid r "refs/remotes/origin/HEAD")
ice-9/boot-9.scm:1685:16: In procedure raise-exception:
Git error: reference 'refs/remotes/origin/HEAD' not found


Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]> ,q

Calling ‘remote-ls’ doesn’t populate that file either:

Toggle snippet (6 lines)
scheme@(guile-user)> (define o (remote-lookup r "origin"))
scheme@(guile-user)> (remote-connect o)
scheme@(guile-user)> (remote-ls o)
$13 = (#<<remote-head> local: 0 oid: #<oid 00000000742ebc4bc09ce69b970eceb78291bdbf> loid: #<oid 00000000742ebc4bc09ce69b970eceb78291bdbf> name: "HEAD" symref-target: 73408368> #<<remote-head> local: 0 oid: #<oid 00000000c9d6e28e5d48c056ee6ad36cc4ab0861> loid: #<oid 00000000c9d6e28e5d48c056ee6ad36cc4ab0861> name: "refs/heads/development" symref-target: 0> #<<remote-head> local: 0 oid: #<oid 00000000742ebc4bc09ce69b970eceb78291bdbf> loid: #<oid 00000000742ebc4bc09ce69b970eceb78291bdbf> name: "refs/heads/master" symref-target: 0> #<<remote-head> local: 0 oid: #<oid 00000000e6985cce0e75b63dab3032ae875f5592> loid: #<oid 00000000e6985cce0e75b63dab3032ae875f5592> name: "refs/heads/pre-release" symref-target: 0> […])

So I’m not sure what the best approach is. Thoughts?

Ludo’.
K
K
Kyle Meyer wrote on 10 Aug 2021 04:10
(name . Ludovic Courtès)(address . ludo@gnu.org)
87h7fyhwwj.fsf@kyleam.com
Ludovic Courtès writes:

Toggle quote (6 lines)
> Oh, this must be the reason. If I remove the cached clone:
>
> rm -rf ~/.cache/guix/checkouts/pjmkglp4t7znuugeurpurzikxq3tnlaywmisyr27shj7apsnalwq
>
> and then clone again, it works:

Great, glad that that mystery is solved.

Toggle quote (3 lines)
> I suppose we need to add a call to fetch remote heads when they’re
> missing? It seems that calling ‘remote-fetch’ is not enough.

Right, a fetch won't do it [1]. Users are free to delete or redirect
refs/remotes/<remote>/HEAD, and a fetch won't repopulate it.

On the command line, you can query the remote and recreate the symref
with `remote set-head <remote> -a':

$ git symbolic-ref -d refs/remotes/origin/HEAD
$ git symbolic-ref refs/remotes/origin/HEAD
fatal: ref refs/remotes/origin/HEAD is not a symbolic ref
$ git remote set-head origin -a
origin/HEAD set to master
$ git symbolic-ref refs/remotes/origin/HEAD
refs/remotes/origin/master

In the libgit2 world, I think the most direct path might be something
along the lines of "get remote ref via git_remote_default_branch()"
followed by "create refs/remotes/<remote>/HEAD via
git_reference_symbolic_create()". I'm not spotting either of those
functions in guile-git, though.

I haven't confirmed but based on the "symref-target" in the remote-ls
output you showed...

Toggle quote (6 lines)
> --8<---------------cut here---------------start------------->8---
> scheme@(guile-user)> (define o (remote-lookup r "origin"))
> scheme@(guile-user)> (remote-connect o)
> scheme@(guile-user)> (remote-ls o)
> $13 = (#<<remote-head> local: 0 oid: #<oid 00000000742ebc4bc09ce69b970eceb78291bdbf> loid: #<oid 00000000742ebc4bc09ce69b970eceb78291bdbf> name: "HEAD" symref-target: 73408368> [...]

... I guess it might be possible to determine the ref target with
remote-ls. In that case, it'd just be the
git_reference_symbolic_create() wrapper that was missing.


[1] In addition to the link I gave upthread, see
for some discussion about whether fetch should populate it.
L
L
Ludovic Courtès wrote on 10 Aug 2021 10:04
(name . Kyle Meyer)(address . kyle@kyleam.com)
87r1f1sp2x.fsf@gnu.org
Kyle Meyer <kyle@kyleam.com> skribis:

Toggle quote (46 lines)
> Ludovic Courtès writes:
>
>> Oh, this must be the reason. If I remove the cached clone:
>>
>> rm -rf ~/.cache/guix/checkouts/pjmkglp4t7znuugeurpurzikxq3tnlaywmisyr27shj7apsnalwq
>>
>> and then clone again, it works:
>
> Great, glad that that mystery is solved.
>
>> I suppose we need to add a call to fetch remote heads when they’re
>> missing? It seems that calling ‘remote-fetch’ is not enough.
>
> Right, a fetch won't do it [1]. Users are free to delete or redirect
> refs/remotes/<remote>/HEAD, and a fetch won't repopulate it.
>
> On the command line, you can query the remote and recreate the symref
> with `remote set-head <remote> -a':
>
> $ git symbolic-ref -d refs/remotes/origin/HEAD
> $ git symbolic-ref refs/remotes/origin/HEAD
> fatal: ref refs/remotes/origin/HEAD is not a symbolic ref
> $ git remote set-head origin -a
> origin/HEAD set to master
> $ git symbolic-ref refs/remotes/origin/HEAD
> refs/remotes/origin/master
>
> In the libgit2 world, I think the most direct path might be something
> along the lines of "get remote ref via git_remote_default_branch()"
> followed by "create refs/remotes/<remote>/HEAD via
> git_reference_symbolic_create()". I'm not spotting either of those
> functions in guile-git, though.
>
> I haven't confirmed but based on the "symref-target" in the remote-ls
> output you showed...
>
>> --8<---------------cut here---------------start------------->8---
>> scheme@(guile-user)> (define o (remote-lookup r "origin"))
>> scheme@(guile-user)> (remote-connect o)
>> scheme@(guile-user)> (remote-ls o)
>> $13 = (#<<remote-head> local: 0 oid: #<oid 00000000742ebc4bc09ce69b970eceb78291bdbf> loid: #<oid 00000000742ebc4bc09ce69b970eceb78291bdbf> name: "HEAD" symref-target: 73408368> [...]
>
> ... I guess it might be possible to determine the ref target with
> remote-ls. In that case, it'd just be the
> git_reference_symbolic_create() wrapper that was missing.

Right. We can add the missing procedures in Guile-Git, but in the
meantime, maybe we could create .git/refs/origin/HEAD “by hand”? The
advantage is that we wouldn’t have to wait for the new Guile-Git
release; but OTOH, we’re the ones making the Guile-Git release, too…

Thanks,
Ludo’.
K
K
Kyle Meyer wrote on 11 Aug 2021 02:34
(name . Ludovic Courtès)(address . ludo@gnu.org)
87czqkizt9.fsf@kyleam.com
Ludovic Courtès writes:

Toggle quote (3 lines)
> Right. We can add the missing procedures in Guile-Git, but in the
> meantime, maybe we could create .git/refs/origin/HEAD “by hand”?

Yep, for the default branch $NAME, "ref: refs/remotes/origin/$NAME\n"
can be written to .git/refs/origin/HEAD.

With respect to getting the default branch, I said in my last message
that I thought it'd be possible to glean the target from the remote-ls
output. To flesh that out a bit:

Toggle snippet (18 lines)
(use-modules
(git)
(system foreign))

(define origin (remote-lookup (repository-open ".") "origin"))
(remote-connect origin)

(define head (car (remote-ls origin)))

(define target-pt
(make-pointer
((record-accessor (record-type-descriptor head) 'symref-target)
head)))

(if (not (null-pointer? target-pt))
(display (pointer->string target-pt))) ;; => refs/heads/master

And that looks like it matches what libgit2's
git_remote_default_branch() does for the non-guessing case (see below),
so stopping there may be sufficient for a compatibility kludge.

Toggle snippet (23 lines)
if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
goto done;

if (heads_len == 0 || strcmp(heads[0]->name, GIT_HEAD_FILE)) {
error = GIT_ENOTFOUND;
goto done;
}

if ((error = git_buf_sanitize(out)) < 0)
return error;

/* the first one must be HEAD so if that has the symref info, we're done */
if (heads[0]->symref_target) {
error = git_buf_puts(out, heads[0]->symref_target);
goto done;
}

/*
* If there's no symref information, we have to look over them
* and guess. We return the first match unless the default
* branch is a candidate. Then we return the default branch.
*/--8<---------------cut here---------------end--------------->8---
?