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

stg branch --create sets up remote tracking information incorrectly #522

Closed
fbenkstein opened this issue Jan 9, 2025 · 3 comments
Closed

Comments

@fbenkstein
Copy link
Contributor

fbenkstein commented Jan 9, 2025

stg version
Stacked Git 2.5.0
Copyright (C) 2005-2024 StGit authors
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
SPDX-License-Identifier: GPL-2.0-only
git version 2.47.1

When creating a new branch from a remote reference stg branch --create sets up the remote differently from git:

Creating the branch with git

> git checkout -b git-branch origin/master
branch 'git-branch' set up to track 'origin/master'.
Switched to a new branch 'git-branch'
> git config get --show-names --all --regexp 'branch\\.git-branch'
branch.git-branch.remote origin
branch.git-branch.merge refs/heads/master

Creating branch with stg

> stg branch -c stg-branch origin/master
info: Recording `origin/master` as parent branch
info: Using remote `origin/master` to pull parent from
> git config get --show-names --all --regexp 'branch\\.stg-branch'
branch.stg-branch.stgit.parentbranch origin/master
branch.stg-branch.remote origin
branch.stg-branch.merge master

Note that the remote tracking ref is unqualified: master vs refs/heads/master. It is also unresolved because technically the fetch refspec of the remote could rename the branch and the remote to something else.

Actual bug

Unfortunately, this means that stg rebase and git rebase both fail when called without an argument on such a branch:

> git checkout stg-branch
Switched to branch 'stg-branch'
> git reset --hard HEAD~1
HEAD is now at 2bc36869 chore: update windows-sys to 0.59.0
> git rebase
There is no tracking information for the current branch.
Please specify which branch you want to rebase against.
See git-rebase(1) for details.

    git rebase '<branch>'

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> stg-branch
> stg rebase
error: Could not get the remote reference to translate into the local tracking branch: The configured name of the remote ref to merge wasn't valid: Standalone references must be all uppercased, like 'HEAD'

Git behaves correctly

They do work correctly on the branches set up with git:

> git checkout git-branch
Switched to branch 'git-branch'
Your branch is up to date with 'origin/master'.
> stg init
> git reset --hard HEAD~1
HEAD is now at a0f39085 chore: update transitive deps
> git rebase
Successfully rebased and updated refs/heads/git-branch.
> git reset --hard HEAD~1
HEAD is now at a0f39085 chore: update transitive deps
> stg rebase
info: Rebasing to `10db7b5131d11b6bd27fb516fa13ecd2967b50cf` (git-branch2 pristine rebase-fixes-2 stg-branch2 test test2 origin/HEAD origin/master yet-another-origin/main)
HEAD is now at 10db7b51 chore: update changelog for 2.5.0

Weird remote branch example

> git remote add another-origin https://github.com/stacked-git/stgit.git
> git config remote.another-origin.fetch '+refs/heads/master:refs/remotes/yet-another-origin/main'
> git fetch another-origin
From https://github.com/stacked-git/stgit
 * [new branch]        master     -> yet-another-origin/main

Even though remote branches like refs/heads/<branch name> are conventionally fetched to refs/remotes/<remote name>/<branch name> this isn't a requirement. What git actually does internally is resoling yet-another-origin/main to refs/remotes/yet-another-origin/main and then walking through the remote.<name>.fetch refspecs of all remotes until it finds exactly one match by reverse applying the refspec which results in refs/heads/master of the another-origin remote:

> git checkout -b git-branch2 yet-another-origin/main
branch 'git-branch2' set up to track 'another-origin/master'.
Switched to a new branch 'git-branch2'
> git config get --show-names --all --regexp 'branch\\.git-branch2'
branch.git-branch2.remote another-origin
branch.git-branch2.merge refs/heads/master

stg doesn't do this and simply splits the shortened input ref by / and treats the first part as the remote name and the second part as the branch name:

> stg branch -c stg-branch2 yet-another-origin/main
info: Recording `yet-another-origin/main` as parent branch
info: Using remote `yet-another-origin/main` to pull parent from
> git config get --show-names --all --regexp 'branch\\.stg-branch2'
branch.stg-branch2.stgit.parentbranch yet-another-origin/main
branch.stg-branch2.remote yet-another-origin
branch.stg-branch2.merge main

This means git rebase and stg rebase still work on the branch set up by git:

> git checkout git-branch2
Switched to branch 'git-branch2'
Your branch is up to date with 'yet-another-origin/main'.
> git reset --hard HEAD~1
HEAD is now at a0f39085 chore: update transitive deps
> git rebase
Successfully rebased and updated refs/heads/git-branch2.
> git reset --hard HEAD~1
HEAD is now at a0f39085 chore: update transitive deps
> stg init
> stg rebase
info: Rebasing to `10db7b5131d11b6bd27fb516fa13ecd2967b50cf` (git-branch pristine rebase-fixes-2 stg-branch2 test test2 origin/HEAD origin/master yet-another-origin/main)
HEAD is now at 10db7b51 chore: update changelog for 2.5.0

They break on stg-branch2 with an error similar to the one already shown above:

> stg rebase
error: Could not get the remote reference to translate into the local tracking branch: The configured name of the remote ref to merge wasn't valid: Standalone references must be all uppercased, like 'HEAD'
> git rebase
There is no tracking information for the current branch.
Please specify which branch you want to rebase against.
See git-rebase(1) for details.

    git rebase '<branch>'

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=yet-another-origin/<branch> stg-branch2

git pull / stg pull

git pull and stg pull don't have a problem with the unqualified remote branch at least when the remote name matches. They interpret branch.<name>.merge as a refspec and then merge or rebase from FETCH_HEAD. git rebase / stg rebase on the other hand, need to forward translate the branch.<name>.merge name back to the remote tracking branch name, i.e. by convention something like refs/remotes/<remote name>/<branch name> so they can find the ref to rebase to.

Running git pull on the stg-branch created like above works but it fails on the stg-branch2 because the remote name is incorrect:

fatal: 'yet-another-origin' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Conclusion

I tried fixing this myself by looking at what git does. The logic is actually quite complicated and there doesn't appear to be an simple API in Gitoxide. Correctly implementing it would mean duplicating the git logic in stg. (IIUC it would involve building a gix_refspec::MatchGroup for each remote and then calling match_remotes on each of them, handling the case where there is no match or multiple matches as errors.) I think this is better implemented upstream in Gitoxide itself instead. The easy way out is likely just creating the branch without tracking and then calling git branch --set-upstream on it. I've run out of time working on this for now but wanted to record my findings in case someone else might pick it up. Otherwise, I'll try to have a go at it at some point.

Finally, I think the setting branch.<name>.stgit.parentbranch should also be resolved to a fully qualified ref (and maybe only set if the source branch actually has an StackedGit stack). I haven't run into a case where this is an issue yet, though.

@fbenkstein fbenkstein changed the title stg branch --create sets up remote tracking branch incorrectly stg branch --create sets up remote tracking information incorrectly Jan 9, 2025
@jpgrayson
Copy link
Collaborator

This is amazing analysis @fbenkstein! Thank you for working through all these differences between StGit and Git. I learned some things about git's behavior from this.

Tagging @Byron since he may be interested in these details in the context of gitoxide.

For StGit, agreed that punting to git branch --set-upstream seems like the most straightforward and safe way to correct the issue.

@Byron
Copy link
Contributor

Byron commented Jan 10, 2025

Thanks so much for digging into this and sharing your analysis, it's will be very helpful in fixing this upstream and it's now on my list to fix with priority, hoping to get it done this weekend.

Meanwhile, I wouldn't mind if this was fixed by shelling this out to git so I can submit a revert once it's fixed in gitoxide and a new release is available - it's scheduled for the 22nd of January.

Byron added a commit to Byron/stgit that referenced this issue Jan 13, 2025
Byron added a commit to Byron/stgit that referenced this issue Jan 13, 2025
…-git#522)

Previously assumptions were made about how shortened tracking branches
would relate to remote names, and partial names would be set as `merge` field
of local branch configuration. The latter could lead to Git being unable
to perform certain operations.

Now the correct full reference name is set.
@Byron Byron mentioned this issue Jan 13, 2025
2 tasks
Byron added a commit to Byron/stgit that referenced this issue Jan 13, 2025
…-git#522)

Previously assumptions were made about how shortened tracking branches
would relate to remote names, and partial names would be set as `merge` field
of local branch configuration. The latter could lead to Git being unable
to perform certain operations.

Now the correct full reference name is set.
Byron added a commit to Byron/stgit that referenced this issue Jan 18, 2025
Byron added a commit to Byron/stgit that referenced this issue Jan 18, 2025
…-git#522)

Previously assumptions were made about how shortened tracking branches
would relate to remote names, and partial names would be set as `merge` field
of local branch configuration. The latter could lead to Git being unable
to perform certain operations.

Now the correct full reference name is set.
Byron added a commit to Byron/stgit that referenced this issue Jan 18, 2025
Byron added a commit to Byron/stgit that referenced this issue Jan 18, 2025
…-git#522)

Previously assumptions were made about how shortened tracking branches
would relate to remote names, and partial names would be set as `merge` field
of local branch configuration. The latter could lead to Git being unable
to perform certain operations.

Now the correct full reference name is set.
jpgrayson pushed a commit that referenced this issue Jan 18, 2025
Previously assumptions were made about how shortened tracking branches
would relate to remote names, and partial names would be set as `merge` field
of local branch configuration. The latter could lead to Git being unable
to perform certain operations.

Now the correct full reference name is set.
@jpgrayson
Copy link
Collaborator

This is fixed as of 20fbdcc.

Thank you @fbenkstein for the great issue report and @Byron for the quick and effective fix.

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 a pull request may close this issue.

3 participants