-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Fix git clone failing when default branch is not master #29004
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
Open
chrisnojima
wants to merge
10
commits into
master
Choose a base branch
from
nojima/HOTPOT-kbfs-git-master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+235
−10
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
8d9bc47
Fix git clone failing when default branch is not master
chrisnojima 7b02d4d
Merge branch 'master' into nojima/HOTPOT-kbfs-git-master
chrisnojima 5c78925
Fix PR #29004 feedback: deterministic HEAD repair, journal flush, and…
chrisnojima 79ee8db
Address PR #29004 feedback: extract helper, fix flush ordering, and h…
chrisnojima 3655536
Use all repo branches (not just pushed refs) for HEAD fixup in handle…
chrisnojima 2ef1c19
Fix doc comment placement, close reference iterators
chrisnojima 99d9973
Scope symref rewrite to HEAD only, update NewBrowser doc comment
chrisnojima 86719f8
Fix NewBrowser doc comment to match fallback behavior
chrisnojima d3eb416
Fall back to master when HEAD points to a stale ref in NewBrowser
chrisnojima 6f10d3d
Emit non-HEAD symrefs unchanged when their targets are unknown
chrisnojima File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -682,6 +682,21 @@ func (r *runner) waitForJournal(ctx context.Context) error { | |
| r.printStageEndIfNeeded) | ||
| } | ||
|
|
||
| // bestBranchFromCandidates selects the best branch for HEAD from a set of | ||
| // candidate branch names (prefer main > master > alphabetically first). | ||
| func bestBranchFromCandidates(best plumbing.ReferenceName, candidate plumbing.ReferenceName) plumbing.ReferenceName { | ||
| switch { | ||
| case candidate == "refs/heads/main": | ||
| return candidate | ||
| case candidate == "refs/heads/master" && best != "refs/heads/main": | ||
| return candidate | ||
| case best == "" || (best != "refs/heads/main" && best != "refs/heads/master" && candidate < best): | ||
| return candidate | ||
| default: | ||
| return best | ||
| } | ||
| } | ||
|
|
||
| // handleList: From https://git-scm.com/docs/git-remote-helpers | ||
| // | ||
| // Lists the refs, one per line, in the format "<value> <name> [<attr> | ||
|
|
@@ -708,9 +723,18 @@ func (r *runner) handleList(ctx context.Context, args []string) (err error) { | |
| if err != nil { | ||
| return err | ||
| } | ||
| defer refs.Close() | ||
|
|
||
| var symRefs []string | ||
| type symRefInfo struct { | ||
| name plumbing.ReferenceName | ||
| target plumbing.ReferenceName | ||
| } | ||
| var symRefs []symRefInfo | ||
| hashRefNames := make(map[plumbing.ReferenceName]bool) | ||
| hashesSeen := false | ||
| // Track the best fallback branch for HEAD in case its target | ||
| // doesn't exist (prefer main > master > alphabetically first). | ||
| var bestBranch plumbing.ReferenceName | ||
| for { | ||
| ref, err := refs.Next() | ||
| if errors.Cause(err) == io.EOF { | ||
|
|
@@ -725,6 +749,11 @@ func (r *runner) handleList(ctx context.Context, args []string) (err error) { | |
| case plumbing.HashReference: | ||
| value = ref.Hash().String() | ||
| hashesSeen = true | ||
| hashRefNames[ref.Name()] = true | ||
| // Track best branch for fallback HEAD. | ||
| if strings.HasPrefix(ref.Name().String(), "refs/heads/") { | ||
| bestBranch = bestBranchFromCandidates(bestBranch, ref.Name()) | ||
| } | ||
| case plumbing.SymbolicReference: | ||
| value = "@" + ref.Target().String() | ||
| default: | ||
|
|
@@ -737,7 +766,10 @@ func (r *runner) handleList(ctx context.Context, args []string) (err error) { | |
| // cloning an empty repo will result in an error because | ||
| // the HEAD symbolic ref points to a ref that doesn't | ||
| // exist. | ||
| symRefs = append(symRefs, refStr) | ||
| symRefs = append(symRefs, symRefInfo{ | ||
| name: ref.Name(), | ||
| target: ref.Target(), | ||
| }) | ||
| continue | ||
| } | ||
| r.log.CDebugf(ctx, "Listing ref %s", refStr) | ||
|
|
@@ -748,7 +780,30 @@ func (r *runner) handleList(ctx context.Context, args []string) (err error) { | |
| } | ||
|
|
||
| if hashesSeen && !forPush { | ||
| for _, refStr := range symRefs { | ||
| for _, sr := range symRefs { | ||
| target := sr.target | ||
| // If the symref target doesn't exist among hash refs, | ||
| // rewrite it to point to the best available branch, | ||
| // but only for HEAD. Other symrefs are emitted as-is. | ||
| if !hashRefNames[target] { | ||
| if sr.name == plumbing.HEAD { | ||
| if bestBranch == "" { | ||
| r.log.CDebugf(ctx, | ||
| "Skipping HEAD symref %s -> %s (no branches available)", | ||
| sr.name, target) | ||
| continue | ||
| } | ||
| r.log.CDebugf(ctx, | ||
| "Rewriting HEAD symref from %s to %s", | ||
| target, bestBranch) | ||
| target = bestBranch | ||
| } else { | ||
| r.log.CDebugf(ctx, | ||
| "Emitting non-HEAD symref %s -> %s with unknown target", | ||
| sr.name, target) | ||
| } | ||
| } | ||
| refStr := "@" + target.String() + " " + sr.name.String() + "\n" | ||
| r.log.CDebugf(ctx, "Listing symbolic ref %s", refStr) | ||
| _, err = r.output.Write([]byte(refStr)) | ||
| if err != nil { | ||
|
|
@@ -1830,6 +1885,53 @@ func (r *runner) handlePushBatch(ctx context.Context, args [][]string) ( | |
| return nil, err | ||
| } | ||
|
|
||
| // If HEAD points to a nonexistent ref, update it to point to the | ||
| // best available branch in the repo (prefer main > master > alphabetical). | ||
| // We intentionally repair HEAD even when the target was explicitly | ||
| // deleted in this batch, because a broken HEAD causes clone failures. | ||
| // This must happen before waitForJournal so the HEAD update is | ||
| // included in the same flush. | ||
| head, headErr := repo.Storer.Reference(plumbing.HEAD) | ||
| if headErr == nil && head.Type() == plumbing.SymbolicReference { | ||
| _, targetErr := repo.Storer.Reference(head.Target()) | ||
| if targetErr == plumbing.ErrReferenceNotFound { | ||
chrisnojima marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| var bestBranch plumbing.ReferenceName | ||
| allRefs, refsErr := repo.References() | ||
| if refsErr == nil { | ||
chrisnojima marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| defer allRefs.Close() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move to before the error check? |
||
| for { | ||
| ref, nextErr := allRefs.Next() | ||
| if errors.Cause(nextErr) == io.EOF { | ||
| break | ||
| } | ||
| if nextErr != nil { | ||
| break | ||
| } | ||
| if ref.Type() != plumbing.HashReference { | ||
| continue | ||
| } | ||
| if !strings.HasPrefix(ref.Name().String(), "refs/heads/") { | ||
| continue | ||
| } | ||
| bestBranch = bestBranchFromCandidates(bestBranch, ref.Name()) | ||
| } | ||
| } | ||
| if bestBranch != "" { | ||
| newHead := plumbing.NewSymbolicReference( | ||
| plumbing.HEAD, bestBranch) | ||
| if setErr := repo.Storer.SetReference( | ||
| newHead); setErr != nil { | ||
| r.log.CDebugf(ctx, | ||
| "Error updating HEAD to %s: %+v", | ||
| bestBranch, setErr) | ||
| } else { | ||
| r.log.CDebugf(ctx, | ||
| "Updated HEAD to point to %s", bestBranch) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| err = r.waitForJournal(ctx) | ||
| if err != nil { | ||
| return nil, err | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.