-
Notifications
You must be signed in to change notification settings - Fork 7.4k
gh pr create: Support Git's @{push} revision syntax for determining head ref
#10513
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
gh pr create: Support Git's @{push} revision syntax for determining head ref
#10513
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Overview
This PR adds support for Git's @{push} revision syntax for determining the head reference when creating pull requests. Key changes include updating the push destination logic in create.go, modifying test stubs in create_test.go to support the new git commands, and updating documentation in finder.go regarding PR reference order.
Reviewed Changes
| File | Description |
|---|---|
| pkg/cmd/pr/create/create.go | Refactored push destination prompting and remote branch determination logic |
| pkg/cmd/pr/create/create_test.go | Updated test stubs to simulate the new @{push} revision syntax command responses |
| pkg/cmd/pr/shared/finder.go | Updated comment to reflect the correct PR ref direction for head and base repositories |
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
pkg/cmd/pr/create/create_test.go:1678
- The removal of Test_tryDetermineTrackingRef may reduce test coverage for tracking reference resolution. Consider adding tests that specifically validate the new behavior for push revision resolution.
func Test_tryDetermineTrackingRef(t *testing.T) {
Tip: Turn on automatic Copilot reviews for this repository to get quick feedback on every pull request. Learn more
acceptance/testdata/pr/pr-create-respects-branch-pushremote.txtar
Outdated
Show resolved
Hide resolved
jtmcg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good start! Looks like you've managed to parse the complexity of how the context is using refs. I was sort of imaging this leaned a bit more into PRRefs, though, and had less duplication of its internal primitives (BranchName, HeadRepo, BaseRepo) floating around.
That's definitely a bigger refactor, but I think you've taken the right partial step there to follow through with it. Happy to pair on that if you'd like.
And, of course, if it isn't possible, let me know! I'd love to try to update PRRefs to make it possible, though, and I'm happy to help with that as well!
acceptance/testdata/pr/pr-create-respects-branch-pushremote.txtar
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Overview
This PR implements support for Git’s @{push} revision syntax in the pull request creation flow. It updates the internal representation of PR references by replacing separate base and head branch fields with a unified PullRequestRefs struct, updates the forking and remote handling logic accordingly, and adjusts tests to accommodate changes in the push destination resolution process.
Reviewed Changes
| File | Description |
|---|---|
| pkg/cmd/pr/create/create.go | Refactored how head ref is determined using the PullRequestRefs struct and updated push logic. |
| pkg/cmd/pr/create/create_test.go | Updated command stubs and test expectations to reflect new push destination and branch parsing. |
| pkg/cmd/pr/shared/finder.go | Updated comments to reflect the new representation of PR references. |
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Comments suppressed due to low confidence (2)
pkg/cmd/pr/create/create.go:914
- The change in the forking condition now checks only ctx.forkHeadRepo and not whether a head repository was already determined. Please verify that this behavior is intended and that it correctly reflects the desired logic for automating forks.
if ctx.forkHeadRepo && ctx.isPushEnabled {
pkg/cmd/pr/shared/finder.go:102
- [nitpick] The updated comment changes the direction of the PR representation. Please confirm that the new comment correctly describes the intended relationship between the head and base branches.
// headRef -----PR-----> baseRef
Tip: Copilot code review supports C#, Go, Java, JavaScript, Markdown, Python, Ruby and TypeScript, with more languages coming soon. Learn more
|
On it! 🫡 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for delayed follow up on this 🙇
This is a pretty extensive set of changes to tricky logic and think it would benefit from 1) me making more time to really reason out the changes and 2) getting a 2nd set of eyes (@williammartin) that hasn't paired on developing the changes. Or maybe a synchronous code review 🤔
All of that said, I did have a handful of questions and commentary but will try to make time to dig deeper in the core of the refactor.
jtmcg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Loving how this is shaping up! Good work propagating PRRefs through to the command 🙌 I've added some thoughts for your consideration and some questions.
jtmcg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hell yeah, nice work on this! I've run all the acceptance tests myself as well and have verified they are working as expected ![]()
andyfeller
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for having more questions in digging into the stickier parts of the PR here. 😞 I fear the complexity of the code involved and repercussions in replacing out the logic involved and whether it has greater impacts beyond the original AC in #575 (comment).
andyfeller
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Final round of suggestions and thoughts pairing with @BagToad ✨
We've resolved a number of conversations for now and so a few other little suggestions and will give this a ship! 💪
| setup: func(opts *CreateOptions, t *testing.T) func() { | ||
| opts.TitleProvided = true | ||
| opts.BodyProvided = true | ||
| opts.Title = "my title" | ||
| opts.Body = "my body" | ||
| opts.HeadBranch = "otherowner:feature" | ||
| return func() {} | ||
| }, | ||
| customPushDestination: true, | ||
| cmdStubs: func(cs *run.CommandStubber) { | ||
| cs.Register("git rev-parse --abbrev-ref feature@{push}", 0, "origin/feature") | ||
| cs.Register("git config remote.pushDefault", 0, "") | ||
| cs.Register("git config push.default", 0, "") | ||
| }, | ||
| expectedOut: "https://github.com/OWNER/REPO/pull/12\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: is there something else we can do in this test to communicate the upstream/origin nature of the test to help the next person understand?
In the other tests, opts.Remotes is missing here and acts as context in the others. Unsure what to do here but took me a hot minute to connect some of the dots. 🤷
pkg/cmd/pr/create/create.go
Outdated
| if prRefs.HeadRepo == nil && isPushEnabled && !opts.IO.CanPrompt() { | ||
| fmt.Fprintf(opts.IO.ErrOut, "aborted: you must first push the current branch to a remote, or use the --head flag") | ||
| return nil, cmdutil.SilentError | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm concerned about this conditional being impossible because prRefs.HeadRepo will likely never be nil 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it won't be because of this line in ParsePRRefs. That means we're assuming that the headRepo is the same as the baseRepo when it isn't specified in the config. I think that means we'll always push to the baseRepo unless you tell us otherwise. That is different behavior, but is it undesirable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm yeah 🤔 I don't know if it's undesirable or not.
If isPushEnabled is true here, it means that we prompted the user for a head repo and they selected an option. That means in this case, again, the HeadRepo is also never nil.
Previously prRefs.HeadRepo == nil && isPushEnabled would indicate to downstream in handlePush to fork... I don't see why we'd care about prompting because it looks like no prompting is happening later around where we fork.
With these proposed changes, we check forkHeadRepo instead:
cli/pkg/cmd/pr/create/create.go
Lines 919 to 928 in d29db2d
| if ctx.forkHeadRepo && ctx.isPushEnabled { | |
| opts.IO.StartProgressIndicator() | |
| headRepo, err = api.ForkRepo(client, ctx.PrRefs.BaseRepo, "", "", false) | |
| opts.IO.StopProgressIndicator() | |
| if err != nil { | |
| return fmt.Errorf("error forking repo: %w", err) | |
| } | |
| didForkRepo = true | |
| } | |
All this rambling is to say, I don't really understand what we were previously guarding against in the old code. I guess there was a case where we didn't have a HeadRepo but still had isPushEnabled set to true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW this is uncovered in tests (maybe indicating it is impossible).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In past this would happen if:
- The user did not provide
-H - No tracking branch could be determined
- Prompting wasn't possible
Like you point out, this guard prevents forking. Perhaps the idea is that forks shouldn't be created without user interaction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a new field to track forking is far clearer than relying on tracking the state through, thanks. I sort of think forkBaseRepo might be clearer though? That's the one we are forking, in order to create a headRepo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, if previously the idea here was that we would prevent forking the repo under the following conditions:
- The user did not provide -H
- No tracking branch could be determined
- Prompting wasn't possible
And now prRefs.HeadRepo is always set, as Tyler mentions originally, that means in this case we will be pushing to the base repo. Maybe that's ok? I really don't know.
williammartin
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed everything except create.go and create_test.go, just getting some questions out ahead of time.
acceptance/testdata/pr/pr-create-respects-branch-pushremote.txtar
Outdated
Show resolved
Hide resolved
acceptance/testdata/pr/pr-create-respects-remote-colon-branch-syntax.txtar
Outdated
Show resolved
Hide resolved
acceptance/testdata/pr/pr-create-respects-branch-pushremote.txtar
Outdated
Show resolved
Hide resolved
pkg/cmd/pr/create/create.go
Outdated
| if prRefs.HeadRepo == nil && isPushEnabled && !opts.IO.CanPrompt() { | ||
| fmt.Fprintf(opts.IO.ErrOut, "aborted: you must first push the current branch to a remote, or use the --head flag") | ||
| return nil, cmdutil.SilentError | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW this is uncovered in tests (maybe indicating it is impossible).
Co-authored-by: Tyler McGoffin <[email protected]>
Co-authored-by: Andy Feller <[email protected]>
Standardize <user>:<branch> syntax wherever it is described in comments.
Co-authored-by: Andy Feller <[email protected]>
Document the user:branch syntax for the `--head`` flag in `gh pr create`.
Co-authored-by: Andy Feller <[email protected]>
This test was setting `remote.pushDefault` which likely caused the `user:branch` syntax to be ignored. Update the test to not set this config value.
8b67d4e to
a9dbda6
Compare
|
I tested this out locally, and it seems to work great! Before I would always push and then have the ❯ git ppr
Enumerating objects: 35, done.
Counting objects: 100% (35/35), done.
Delta compression using up to 12 threads
Compressing objects: 100% (18/18), done.
Writing objects: 100% (18/18), 3.41 KiB | 3.41 MiB/s, done.
Total 18 (delta 17), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (17/17), completed with 17 local objects.
remote:
remote: Create a pull request for 'update' on GitHub by visiting:
remote: https://github.com/gibfahn/myrepo/pull/new/update
remote:
To https://github.com/gibfahn/myrepo.git
* [new branch] update -> update
❯ gh pr create ...
? Where should we push the 'update' branch? [Use arrows to move, type to filter]
upstream-org/myrepo
gibfahn/myrepo
Skip pushing the branch
> CancelNow it just works directly 🎉 . Looking forward to this shipping in a release. |
|
We love to hear that @gibfahn! Thank you for trying it and writing your feedback ❤️ ✨ |
|
@gibfahn just curious (you may have described this elsewhere), what is your workflow / what are your git settings? Just nice to know which one of the settings we now respect solved this for you. |
|
I always have I'll have some PRs that go to GitHub Enterprise, and some that go to github.com. So having the detection understand that makes things much simpler. (in case it's useful I wrote up my full config at https://fahn.co/posts/a-better-pull-request-workflow-with-git-push-branches.html) |
Fixes #575
Description
This adds support Git's
@{push}revision syntax for determining head ref.Acceptance Criteria
Acceptance Tests
Notes
A lot of review for this PR happened on #10621