Skip to content

Conversation

@EdmondFrank
Copy link
Contributor

Because the default branch of some recently new repository is main now, but when you create a new repository and do the first push, the HEAD is still points to to refs/head/master.

So when you access the repository on the page that was just pushed with the default branch of main, it will trigger an error that the refs/heads/master was not found.

This PR tries to fix the problem by setting the first branch in the branch list to HEAD if the current HEAD does not exist.

@redrabbit
Copy link
Owner

Hi @EdmondFrank and thank for the help.

Can you further explain when/how this does happen?

As long as I know, the HEAD is not hardcoded anywhere in the code. If I remember correctly the repository HEAD symbolic reference is assigned on the first push (when the server receives the first PACK) and is specified by the client.

What we could do is let the repository owner/admin change the default branch (HEAD) in the repository settings (like GitHub and GitLab do).

{:ok, stream} ->
with %GitRef{name: name} =
ref <- Enum.at(Stream.map(stream, &resolve_reference_peel!(&1, :undefined, handle)), 0),
:ok <- Git.repository_set_head(handle, "refs/heads/#{name}") do
Copy link
Owner

Choose a reason for hiding this comment

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

Not sure this is a good idea ☺️.

I'd prefer to fix the issue upfront over implicitly updating the HEAD here.

case Git.reference_resolve(handle, "HEAD") do
{:ok, name, shorthand, oid} ->
{:ok, resolve_reference({name, shorthand, :oid, oid})}
{:error, reason} ->
Copy link
Owner

Choose a reason for hiding this comment

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

What kind of error are you getting here? And how doe it happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What kind of error are you getting here? And how doe it happen?

Refer to the third paragraph of this comment: #87 (comment)

Reproduction steps:

  1. Create a new repository Test on git.limo.
  2. Create a local repository Test with only one branch main as default branch.
  3. Add git.limo Test repository as local repository's remote and git push -u origin main.
  4. Access Test repository at git.limo on web.

eg: https://git.limo/edmondfrank/Test

}

ERL_NIF_TERM
geef_repository_set_head(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
Copy link
Owner

Choose a reason for hiding this comment

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

👍

We could use that for letting the repository owner/admin change the default branch in the repository settings.

@EdmondFrank
Copy link
Contributor Author

Hi @EdmondFrank and thank for the help.

Can you further explain when/how this does happen?

As long as I know, the HEAD is not hardcoded anywhere in the code. If I remember correctly the repository HEAD symbolic reference is assigned on the first push (when the server receives the first PACK) and is specified by the client.

What we could do is let the repository owner/admin change the default branch (HEAD) in the repository settings (like GitHub and GitLab do).

Hi @redrabbit Thank you for your reply.

https://github.com/libgit2/libgit2/blob/a3841af5eecc6301e87f8302c7fdce6555e39247/include/git2/repository.h#L342

According to the source code of libgit2, the initial_head It is set during the initialization of the repository and does not change with the first push of the branch.

Although we can provide the user with a global setting for the default branch of the initialized repository, there are still two problems: one, the setting cannot directly affect the existing repository, it can only take effect when the repository is initialized, and two, this global default branch is not always the same as the branch the user pushed for the first time.

And when the branch pointed to by HEAD does not exist in the repository, we cannot access the repository through the front-end page and update default branch settings.
image

redrabbit added a commit that referenced this pull request Nov 28, 2022
This commit adds support for setting the default branch on a repository.

* Add :default_branch to GitGud.Repo schema.
* Add <form> field to templates/repo/{edit.html.eex, new.html.eex}.
* Refactor GitRekt.RepoStorage.init/2 to set initial_head accordingly.
* Ensure that HEAD is updated when :default_branch field changes.
* Add workaround for views relying on @Head (which can be nil).

See #87 for more details.
@redrabbit
Copy link
Owner

Hey @EdmondFrank.

I've pushed a few changes for fixing the issue:

  • GitGud.Repo has a new :default_branch field (default to "main").
  • Git.repository_init/3 takes a third initial_head argument for initializing a Git repo with a custom HEAD.

This allows for setting a custom default branch when creating/updating a repository.

one, the setting cannot directly affect the existing repository, it can only take effect when the repository is initialized,

GitGud.Repo.update/2 now takes care of this by updating the Git symbolic reference accordingly.

and two, this global default branch is not always the same as the branch the user pushed for the first time.

This is still true but now the user can customize the default branch when creating the repository or update it later on.
GitHub seems to override the default branch on initial push. We could technically do that too but I'm ok with letting the repository owner change the default branch in the settings.

My preferred approach would be showing an alert in GitGud.Web.TreeBrowserLive for the repository admin/owner if the repository has been pushed already but HEAD is pointing to an invalid reference.

when the branch pointed to by HEAD does not exist in the repository, we cannot access the repository through the front-end page and update default branch settings.

I've fixed that (and a few other things). All views should be able to work even when @head is nil.
Accessing a repository through GitGud.Web.TreeBrowserLive will render the "Quick Setup" if @head is nil.

@redrabbit
Copy link
Owner

I deployed the code to https://git.limo.

@EdmondFrank
Copy link
Contributor Author

EdmondFrank commented Nov 30, 2022

Hey @EdmondFrank.

I've pushed a few changes for fixing the issue:

  • GitGud.Repo has a new :default_branch field (default to "main").
  • Git.repository_init/3 takes a third initial_head argument for initializing a Git repo with a custom HEAD.

This allows for setting a custom default branch when creating/updating a repository.

one, the setting cannot directly affect the existing repository, it can only take effect when the repository is initialized,

GitGud.Repo.update/2 now takes care of this by updating the Git symbolic reference accordingly.

and two, this global default branch is not always the same as the branch the user pushed for the first time.

This is still true but now the user can customize the default branch when creating the repository or update it later on. GitHub seems to override the default branch on initial push. We could technically do that too but I'm ok with letting the repository owner change the default branch in the settings.

My preferred approach would be showing an alert in GitGud.Web.TreeBrowserLive for the repository admin/owner if the repository has been pushed already but HEAD is pointing to an invalid reference.

when the branch pointed to by HEAD does not exist in the repository, we cannot access the repository through the front-end page and update default branch settings.

I've fixed that (and a few other things). All views should be able to work even when @head is nil. Accessing a repository through GitGud.Web.TreeBrowserLive will render the "Quick Setup" if @head is nil.

Thanks @redrabbit .
This solution does seem to make more reasonable. If you still want to keep the geef_repository_set_head related code in this PR, please let me know and I will create a new PR with the related code individually
, otherwise, I will just turn off the PR, thanks again for your reply and contribution.

@redrabbit
Copy link
Owner

If you still want to keep the geef_repository_set_head related code in this PR, please let me know...

I think we're good, GitRekt.Git.reference_create/5 can be used to do the same thing:

target = "refs/heads/" <> branch
case GitAgent.reference_create(repo, "HEAD", :symbolic, target, force: true) do
:ok ->
{:ok, target}
{:error, reason} ->
{:error, reason}
end

@redrabbit
Copy link
Owner

Closing this PR. Support for custom default branch has been added to master branch.

@redrabbit redrabbit closed this Nov 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants