Set HEAD = first pushed branch

229 views
Skip to first unread message

Nick

unread,
Feb 11, 2021, 9:11:00 AM2/11/21
to gito...@googlegroups.com
Hi there!

I've run into a problem with the new `init.defaultBranch` setting [1]. Teams that think 'master' is rude will now want to set

```
$ git config --global init.defaultBranch trunk
```

But with this set, users can't make usable gitolite repos because it respects the *server's* `init.defaultBranch` setting:

```
$ mkdir test
$ cd test/
$ git init
Initialized empty Git repository in /home/kousu/src/neuropoly/datalad/test/.git/
$ touch README.md
$ git add README.md
$ git commit -m "Initial Commit"
[trunk (root-commit) df0039d] Initial Commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
$ git remote add gitt@localhost:d/test
usage: git remote add [<options>] <name> <url>

-f, --fetch fetch the remote branches
--tags import all tags and associated objects when fetching
or do not fetch any tag at all (--no-tags)
-t, --track <branch> branch(es) to track
-m, --master <branch>
master branch
--mirror[=(push|fetch)]
set up remote as a mirror to push to or fetch from

$ git remote add origin gitt@localhost:d/test
$ git push -u origin trunk
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /home/gitt/repositories/d/test.git/
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 206 bytes | 206.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To localhost:d/test
* [new branch] trunk -> trunk
Branch 'trunk' set up to track remote branch 'trunk' from 'origin'.
```


See, the upload works but if I try to retreive it:

```
$ git clone gitt@localhost:d/test test-2
Cloning into 'test-2'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.
```

You have to do this:


```
$ git clone -b trunk gitt@localhost:d/test test-3
Cloning into 'test-3'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
```


To be clear, this is because serverside, HEAD is pointing at refs/heads/master even though that branch doesn't exist:

```
[gitt@requiem d]$ cd test.git/
[gitt@requiem test.git]$ pwd
/home/gitt/repositories/d/test.git
[gitt@requiem test.git]$ cat HEAD
ref: refs/heads/master
[gitt@requiem test.git]$ ls -l refs/heads/
total 4
-rw------- 1 gitt gitt 41 Feb 9 12:12 trunk
```

This problem isn't specific to init.defaultBranch, it's just going to be a lot more common with that setting. On Github.com and Gitlab.com, the behaviour is that the first pushed branch becomes HEAD, and in their GUIs there's a way to change it [2]. Could this behaviour be added to gitolite? I'm happy to do it if there's support for it. I think I would:

- make gitolite set the default branch to the first pushed branch
- add a command to change the default branch

Thank you for the software and defintely thank you for the time you take managing your mailing list.


[1]: https://sfconservancy.org/news/2020/jun/23/gitbranchname/
[2]: https://docs.github.com/en/github/administering-a-repository/changing-the-default-branch.

Sitaram Chamarty

unread,
Feb 11, 2021, 10:27:49 AM2/11/21
to Nick, gito...@googlegroups.com
On Thu, Feb 11, 2021 at 02:10:56PM +0000, Nick wrote:
> Hi there!
>
> I've run into a problem with the new `init.defaultBranch` setting [1]. Teams that think 'master' is rude will now want to set
>
> ```
> $ git config --global init.defaultBranch trunk

I may need some time to figure this out but meanwhile I have a
quick question for you: would this problem appear if the server
*also* had the same git config setting, either globally or at
least for the gitolite repositories?

Sitaram Chamarty

unread,
Feb 12, 2021, 10:46:05 AM2/12/21
to Nick, gito...@googlegroups.com
On Thu, Feb 11, 2021 at 04:04:05PM +0000, Nick wrote:
> February 11, 2021 10:27 AM, "Sitaram Chamarty" <sita...@gmail.com> wrote:

> > quick question for you: would this problem appear if the server
> > *also* had the same git config setting, either globally or at
> > least for the gitolite repositories?

[snip]

> That's a great question. And no, it doesn't:

Great; that is what I was hoping to hear.

[snip]

> But then I cause a different problem for the majority of users, the ones with

I think the issue is this:

- github and gitlab are *public* servers -- Alice and Bob have
repos but they have nothing to do with each other. As such,
github has to accommodate that Alice wants "master" and Bob
wants "trunk".

- gitolite is usually in a much more closed user group of
people with some connection to each other, and more
importantly, to the *admin*. Alice and Bob are now
colleagues, and Carol the admin sits (modulo Covid!) across
the hall.

I would not expect the same level of "everyone do your
thing" in this scenario,

That said, I do solutions for you which do *not* involve me
changing anything in gitolite.

First, the command to set the HEAD for any repo already exists;
it's called `symbolic-ref` and takes the same arguments as git's
own symbolic-ref program, except you have to insert the repo
name as the first argument:

ssh git@server symbolic-ref my/repo HEAD refs/heads/trunk

For this to work, you have to enable [1] it in ~/.gitolite.rc.

[1]: https://gitolite.com/gitolite/cookbook.html#making-commands-available-to-remote-users

Second, as far as changing the HEAD on the first push... well
the "first push" part is tricky. I know of no way to make
something happen *only* on the first push.

However, following, installed as a POST_GIT trigger [2], seems
to do the job. I have only smoke tested it; please test it in
your environment over a bit more of an extended use if possible!

#!/bin/bash

[[ $4 == W ]] || exit 0

cd $GL_REPO_BASE/$2.git

head=`git symbolic-ref HEAD`
[[ -f $head ]] || {
set -- refs/heads/*
git symbolic-ref HEAD $1
# if you have more than one branch AND your HEAD is not one of them, well
# you've got bigger problems than I can help with
}

[2]: https://gitolite.com/gitolite/cookbook.html#adding-your-own-triggers

You could, conceivably, do this in a post-receive hook also, but
even there, I have no idea how to detect if the repo was empty
prior to this push.

Hope this helps.

sitaram

Nick

unread,
Feb 12, 2021, 1:03:59 PM2/12/21
to Sitaram Chamarty, gito...@googlegroups.com
February 11, 2021 10:27 AM, "Sitaram Chamarty" <sita...@gmail.com> wrote:

> I may need some time to figure this out but meanwhile I have a
> quick question for you: would this problem appear if the server
> *also* had the same git config setting, either globally or at
> least for the gitolite repositories?

Hi!

That's a great question. And no, it doesn't:

```
[gitt@localhost ~]$ git config --global init.defaultBranch trunk
```

```
$ git remote set-url origin gitt@localhost:d/best
$ git push
Initialized empty Git repository in /home/gitt/repositories/d/best.git/


Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 206 bytes | 206.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0

To localhost:d/best


* [new branch] trunk -> trunk

$ cd ..
$ git clone gitt@localhost:d/best best-2
Cloning into 'best-2'...


remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.

```

But then I cause a different problem for the majority of users, the ones with

```
$ git config --global --unset init.defaultBranch
```

or the smaller set who saw the warning from git and chose this for backwards compatibility

```
$ git config --global init.defaultBranch master
```

They cause the same problem the other way around:

```
$ git init


hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>

Initialized empty Git repository in /home/kousu/src/neuropoly/datalad/cest/.git/
$ touch README
$ git add README
$ git commit -m "initial commit"
[master (root-commit) 93a47f0] initial commit


1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README

$ git remote add origin gitt@localhost:d/cest
$ git push --set-upstream origin master
Initialized empty Git repository in /home/gitt/repositories/d/cest.git/


Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.

Writing objects: 100% (3/3), 199 bytes | 199.00 KiB/s, done.


Total 3 (delta 0), reused 0 (delta 0), pack-reused 0

To localhost:d/cest
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
```

```
$ git clone gitt@localhost:d/cest cest-2
Cloning into 'cest-2'...


remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.
```

I don't want to try to enforce settings on my users. They've got lots of Github repos to deal with
too.

It's only an issue with the creation push, and I could fix it manually for each repo. But I'm using
wildrepos to avoid having to manually intervene in my user's work (which is, of course, just the
best feature).

Thanks for taking a look, Sitaram!
-Nick

Reply all
Reply to author
Forward
0 new messages