diff options
| author | Shulhan <m.shulhan@gmail.com> | 2024-07-21 03:48:32 +0700 |
|---|---|---|
| committer | Shulhan <m.shulhan@gmail.com> | 2026-04-09 22:20:06 +0700 |
| commit | 31f678e5a420fecf567c30bc66e40b43ad85fd17 (patch) | |
| tree | e3b1a4b83fb4db9e2dde3d3846966240e3b5e618 | |
| parent | 99962d5770bded6aa8fac22d4c74103b5f832d6d (diff) | |
| download | go-x-review-31f678e5a420fecf567c30bc66e40b43ad85fd17.tar.xz | |
For the git-codereview commands to works on any Go's repositories, the
remote name for "origin" must be pointed to the Go original repository URL
(in most cases the one with go.googlesource.com domain).
The problem is when the "origin" is from the fork, all of the
git-codereview commands then will not works.
For example, in computer X, I clone the this repository from
"https://go.googlesource.com/review" (the origin) and then push my
changes on "git@git.sr.ht:~shulhan/go-x-review" (the fork).
In another computer Y, I then clone from the fork to continue my works.
The fork become origin.
One of the solution is to rename the remote names manually each time we
clone the fork.
The only cons using this solution is every time new branch created we need
to remember to pass "--set-upstream" during git push.
This changes introduce "remote" configuration in codereview.cfg.
When one first working on fork of Go repository, they set the "remote"
key, commit it, and push it.
When they cloned the fork, they did not needs to changes anything except
adding new remote using the pre-defined name.
Change-Id: I335d08fd8b7efe17ba07b3c0a3794f9ccf59b339
| -rw-r--r-- | git-codereview/api.go | 8 | ||||
| -rw-r--r-- | git-codereview/branch.go | 17 | ||||
| -rw-r--r-- | git-codereview/change.go | 11 | ||||
| -rw-r--r-- | git-codereview/config.go | 25 | ||||
| -rw-r--r-- | git-codereview/doc.go | 11 | ||||
| -rw-r--r-- | git-codereview/gofmt.go | 4 | ||||
| -rw-r--r-- | git-codereview/hook.go | 6 | ||||
| -rw-r--r-- | git-codereview/mail.go | 4 | ||||
| -rw-r--r-- | git-codereview/pending.go | 6 | ||||
| -rw-r--r-- | git-codereview/submit.go | 2 | ||||
| -rw-r--r-- | git-codereview/sync.go | 40 |
11 files changed, 85 insertions, 49 deletions
diff --git a/git-codereview/api.go b/git-codereview/api.go index da3fa76..9fc1b67 100644 --- a/git-codereview/api.go +++ b/git-codereview/api.go @@ -57,8 +57,10 @@ func loadGerritOrigin() { // Gerrit must be set, either explicitly via the code review config or // implicitly as Git's origin remote. - origin := config()["gerrit"] - originUrl := trim(cmdOutput("git", "config", "remote.origin.url")) + cfg := config() + cfgRemote := cfg["remote"] + origin := cfg["gerrit"] + originUrl := trim(cmdOutput("git", "config", "remote."+cfgRemote+".url")) err := loadGerritOriginInternal(origin, originUrl) if err != nil { @@ -73,7 +75,7 @@ func loadGerritOrigin() { func loadGerritOriginInternal(origin, remoteOrigin string) error { originUrl, err := url.Parse(remoteOrigin) if err != nil { - return fmt.Errorf("failed to parse git's remote.origin.url %q as a URL: %v", remoteOrigin, err) + return fmt.Errorf("failed to parse git's remote.%s.url %q as a URL: %v", cachedConfig["remote"], remoteOrigin, err) } else { originUrl.User = nil remoteOrigin = originUrl.String() diff --git a/git-codereview/branch.go b/git-codereview/branch.go index b22ac39..329109f 100644 --- a/git-codereview/branch.go +++ b/git-codereview/branch.go @@ -81,6 +81,9 @@ func (b *Branch) Config() map[string]string { verbosef("failed to load config for branch %v: %v", b.Name, err) cfg = make(map[string]string) } + if cfg["remote"] == "" { + cfg["remote"] = "origin" + } b.config = cfg return b.config } @@ -121,10 +124,12 @@ func (b *Branch) OriginBranch() string { return b.originBranch } - cfg := b.Config()["branch"] + cfg := b.Config() + cfgRemote := cfg["remote"] + branch := cfg["branch"] upstream := "" - if cfg != "" { - upstream = "origin/" + cfg + if branch != "" { + upstream = cfgRemote + "/" + branch } // Consult and possibly update git, @@ -139,13 +144,13 @@ func (b *Branch) OriginBranch() string { // Assume branch was created before we set upstream correctly. // See if origin/main exists; if so, use it. // Otherwise, fall back to origin/master. - argv := []string{"git", "rev-parse", "--abbrev-ref", "origin/main"} + argv := []string{"git", "rev-parse", "--abbrev-ref", cfgRemote + "/main"} cmd := exec.Command(argv[0], argv[1:]...) setEnglishLocale(cmd) if err := cmd.Run(); err == nil { - upstream = "origin/main" + upstream = cfgRemote + "/main" } else { - upstream = "origin/master" + upstream = cfgRemote + "/master" } } if gitUpstream != upstream && b.Current { diff --git a/git-codereview/change.go b/git-codereview/change.go index 06b658f..ea0cf3e 100644 --- a/git-codereview/change.go +++ b/git-codereview/change.go @@ -156,9 +156,12 @@ func checkoutOrCreate(target string) { } } + cfg := config() + cfgRemote := cfg["remote"] + // If origin branch exists, create local branch tracking it. for _, name := range OriginBranches() { - if name == "origin/"+target { + if name == cfgRemote+"/"+target { run("git", "checkout", "-q", "-t", "-b", target, name) printf("created branch %v tracking %s.", target, name) return @@ -226,7 +229,11 @@ func checkoutCL(what, cl, ps string) { } else { ref = fmt.Sprintf("pull/%s/head", cl) } - err := runErr("git", "fetch", "-q", "origin", ref) + + cfg := config() + cfgRemote := cfg["remote"] + + err := runErr("git", "fetch", "-q", cfgRemote, ref) if err != nil { dief("cannot change to %v %s: %v", what, cl, err) } diff --git a/git-codereview/config.go b/git-codereview/config.go index cc9286c..8c86abf 100644 --- a/git-codereview/config.go +++ b/git-codereview/config.go @@ -17,26 +17,29 @@ var ( cachedConfig map[string]string ) -// Config returns the code review config. +// config returns the code review config. // Configs consist of lines of the form "key: value". // Lines beginning with # are comments. // If there is no config, it returns an empty map. // If the config is malformed, it dies. func config() map[string]string { - if cachedConfig != nil { - return cachedConfig - } configPath = filepath.Join(repoRoot(), "codereview.cfg") b, err := os.ReadFile(configPath) raw := string(b) if err != nil { verbosef("%sfailed to load config from %q: %v", raw, configPath, err) cachedConfig = make(map[string]string) - return cachedConfig + } else { + cachedConfig, err = parseConfig(raw) + if err != nil { + dief("%v", err) + } } - cachedConfig, err = parseConfig(raw) - if err != nil { - dief("%v", err) + if cachedConfig["remote"] == "" { + cachedConfig["remote"] = "origin" + } + if cachedConfig["branch"] == "" { + cachedConfig["branch"] = "main" } return cachedConfig } @@ -46,8 +49,10 @@ func config() map[string]string { // the gerrit https URL or the git origin must be to // "https://<project>.googlesource.com/<repo>". func haveGerrit() bool { - gerrit := config()["gerrit"] - origin := trim(cmdOutput("git", "config", "remote.origin.url")) + cfg := config() + cfgRemote := cfg["remote"] + gerrit := cfg["gerrit"] + origin := trim(cmdOutput("git", "config", "remote."+cfgRemote+".url")) return haveGerritInternal(gerrit, origin) } diff --git a/git-codereview/doc.go b/git-codereview/doc.go index 012e5ef..ca1b4b2 100644 --- a/git-codereview/doc.go +++ b/git-codereview/doc.go @@ -8,8 +8,9 @@ server. The git-codereview tool manages “change branches” in the local git repository. Each such branch tracks a single commit, or “pending change”, -that is reviewed using a Gerrit server; the Gerrit remote must be -named “origin” in the local git repo. +that is reviewed using a Gerrit server. +The Gerrit remote must be named “origin” in the local git repo, unless +set in configuration under "remote" key. Modifications to the pending change are applied by amending the commit. This process implements the “single-commit feature branch” model. @@ -425,6 +426,12 @@ would typically be “main”, in which case it would have this codereview.cfg: branch: dev.feature parent-branch: main +The "remote" key specifies the name of git remote. +If this setting is missing its default to "origin". +This setting can be useful if you works on fork of the repository. +Your fork can be still the named "origin" and the "upstream" (or other +remote name) can be configured using this key. + In a more complex configuration, one feature branch might depend upon another, like “dev.feature2” containing follow-on work for “dev.feature”, neither of which has merged yet. In this case, the dev.feature2 branch diff --git a/git-codereview/gofmt.go b/git-codereview/gofmt.go index 1df3e43..de99487 100644 --- a/git-codereview/gofmt.go +++ b/git-codereview/gofmt.go @@ -125,7 +125,9 @@ func runGofmt(flags int) (files []string, stderrText string) { // then check all the pending commits. branchpt := "HEAD" if b.OriginBranch() != "" { - isBranchTagMove := strings.Contains(cmdOutput("git", "branch", "-r", "--contains", b.FullName()), "origin/") + cfg := config() + cfgRemote := cfg["remote"] + isBranchTagMove := strings.Contains(cmdOutput("git", "branch", "-r", "--contains", b.FullName()), cfgRemote+"/") if !isBranchTagMove { branchpt = b.Branchpoint() } diff --git a/git-codereview/hook.go b/git-codereview/hook.go index be2b699..0634687 100644 --- a/git-codereview/hook.go +++ b/git-codereview/hook.go @@ -227,7 +227,8 @@ func fixCommitMessage(msg []byte) []byte { data[eol+1] = '\n' } - issueRepo := config()["issuerepo"] + cfg := config() + issueRepo := cfg["issuerepo"] // Update issue references to point to issue repo, if set. if issueRepo != "" { data = issueRefRE.ReplaceAll(data, []byte("${space}"+issueRepo+"${ref}")) @@ -259,7 +260,8 @@ func fixCommitMessage(msg []byte) []byte { // dev or release branch and not a special Git fixup! or // squash! commit message. b := CurrentBranch() - branch := strings.TrimPrefix(b.OriginBranch(), "origin/") + cfgRemote := cfg["remote"] + branch := strings.TrimPrefix(b.OriginBranch(), cfgRemote+"/") if strings.HasPrefix(branch, "dev.") || strings.HasPrefix(branch, "release-branch.") { prefix := "[" + branch + "] " if !bytes.HasPrefix(data, []byte(prefix)) && !isFixup(data) { diff --git a/git-codereview/mail.go b/git-codereview/mail.go index c0592bf..98de7fa 100644 --- a/git-codereview/mail.go +++ b/git-codereview/mail.go @@ -175,7 +175,7 @@ func cmdMail(args []string) { if *noverify { args = append(args, "--no-verify") } - args = append(args, "origin", refSpec) + args = append(args, config()["remote"], refSpec) run("git", args...) // Create local tag for mailed change. @@ -199,7 +199,7 @@ func (b *Branch) PushSpec(c *Commit) string { if c != nil && (len(b.Pending()) == 0 || b.Pending()[0].Hash != c.Hash) { local = c.ShortHash } - return local + ":refs/for/" + strings.TrimPrefix(b.OriginBranch(), "origin/") + return local + ":refs/for/" + strings.TrimPrefix(b.OriginBranch(), config()["remote"]+"/") } // mailAddressRE matches the mail addresses we admit. It's restrictive but admits diff --git a/git-codereview/pending.go b/git-codereview/pending.go index 8a74e09..d03b003 100644 --- a/git-codereview/pending.go +++ b/git-codereview/pending.go @@ -240,6 +240,8 @@ func printPendingStandard(branches []*pendingBranch) { } } + cfgRemote := config()["remote"] + for _, b := range branches { if !b.current && b.commitsAhead == 0 { // Hide branches with no work on them. @@ -268,8 +270,8 @@ func printPendingStandard(branches []*pendingBranch) { } if br := b.OriginBranch(); br == "" { tags = append(tags, "remote branch unknown") - } else if br != "origin/master" && br != "origin/main" { - tags = append(tags, "tracking "+strings.TrimPrefix(b.OriginBranch(), "origin/")) + } else if br != cfgRemote+"/master" && br != cfgRemote+"/main" { + tags = append(tags, "tracking "+strings.TrimPrefix(b.OriginBranch(), cfgRemote+"/")) } if len(tags) > 0 { fmt.Fprintf(&buf, " (%s)", strings.Join(tags, ", ")) diff --git a/git-codereview/submit.go b/git-codereview/submit.go index 4bbbf32..5577dac 100644 --- a/git-codereview/submit.go +++ b/git-codereview/submit.go @@ -96,7 +96,7 @@ func submit(b *Branch, c *Commit) *GerritChange { // Upload most recent revision if not already on server. if c.Hash != g.CurrentRevision { - run("git", "push", "-q", "origin", b.PushSpec(c)) + run("git", "push", "-q", config()["remote"], b.PushSpec(c)) // Refetch change information. g, err = b.GerritChange(c, "LABELS", "CURRENT_REVISION") diff --git a/git-codereview/sync.go b/git-codereview/sync.go index 71fc312..6ff36a3 100644 --- a/git-codereview/sync.go +++ b/git-codereview/sync.go @@ -60,10 +60,11 @@ func cmdSync(args []string) { // hint: use --reapply-cherry-picks to include skipped commits // hint: Disable this message with "git config advice.skippedCherryPicks false" // + cfgRemote := config()["remote"] if *verbose > 1 { - run("git", "-c", "advice.skippedCherryPicks=false", "pull", "-q", "-r", "-v", "origin", strings.TrimPrefix(b.OriginBranch(), "origin/")) + run("git", "-c", "advice.skippedCherryPicks=false", "pull", "-q", "-r", "-v", cfgRemote, strings.TrimPrefix(b.OriginBranch(), cfgRemote+"/")) } else { - run("git", "-c", "advice.skippedCherryPicks=false", "pull", "-q", "-r", "origin", strings.TrimPrefix(b.OriginBranch(), "origin/")) + run("git", "-c", "advice.skippedCherryPicks=false", "pull", "-q", "-r", cfgRemote, strings.TrimPrefix(b.OriginBranch(), cfgRemote+"/")) } b = CurrentBranch() // discard any cached information @@ -188,30 +189,32 @@ func cmdSyncBranch(args []string) { // Note that this does a remote fetch of b.OriginBranch() (aka branch). cmdSync(nil) + cfgRemote := config()["remote"] + // Pull down parent commits too. quiet := "-q" if *verbose > 0 { quiet = "-v" } - run("git", "fetch", quiet, "origin", "refs/heads/"+parent+":refs/remotes/origin/"+parent) + run("git", "fetch", quiet, cfgRemote, "refs/heads/"+parent+":refs/remotes/"+cfgRemote+"/"+parent) // Write the status file to make sure we can, before starting a merge. status := &syncBranchStatus{ Local: b.Name, Parent: parent, - ParentHash: gitHash("origin/" + parent), + ParentHash: gitHash(cfgRemote + "/" + parent), Branch: branch, - BranchHash: gitHash("origin/" + branch), + BranchHash: gitHash(cfgRemote + "/" + branch), } writeSyncBranchStatus(status) - parentHash, err := cmdOutputErr("git", "rev-parse", "origin/"+parent) + parentHash, err := cmdOutputErr("git", "rev-parse", cfgRemote+"/"+parent) if err != nil { - dief("cannot sync-branch: cannot resolve origin/%s: %v\n%s", parent, err, parentHash) + dief("cannot sync-branch: cannot resolve %s/%s: %v\n%s", cfgRemote, parent, err, parentHash) } - branchHash, err := cmdOutputErr("git", "rev-parse", "origin/"+branch) + branchHash, err := cmdOutputErr("git", "rev-parse", cfgRemote+"/"+branch) if err != nil { - dief("cannot sync-branch: cannot resolve origin/%s: %v\n%s", branch, err, branchHash) + dief("cannot sync-branch: cannot resolve %s/%s: %v\n%s", cfgRemote, branch, err, branchHash) } parentHash = trim(parentHash) branchHash = trim(branchHash) @@ -221,7 +224,7 @@ func cmdSyncBranch(args []string) { // to be done, it should be done first on the dev branch, // not the parent branch. if mergeBackToParent { - other := cmdOutput("git", "log", "--format=format:+ %cd %h %s", "--date=short", "origin/"+branch+"..origin/"+parent) + other := cmdOutput("git", "log", "--format=format:+ %cd %h %s", "--date=short", cfgRemote+"/"+branch+".."+cfgRemote+"/"+parent) if other != "" { dief("cannot sync-branch --merge-back-to-parent: parent has new commits.\n"+ "\trun 'git codereview sync-branch' to bring them into this branch first:\n%s", @@ -237,10 +240,10 @@ func cmdSyncBranch(args []string) { // of the merge, the same as it would when we are doing it by hand // with a plain "git merge". This may help the display of the // merge graph in some tools more closely reflect what we did. - run("git", "reset", "--hard", "origin/"+parent) - _, err = cmdOutputErr("git", "merge", "--no-ff", "origin/"+branch) + run("git", "reset", "--hard", cfgRemote+"/"+parent) + _, err = cmdOutputErr("git", "merge", "--no-ff", cfgRemote+"/"+branch) } else { - _, err = cmdOutputErr("git", "merge", "--no-ff", "origin/"+parent) + _, err = cmdOutputErr("git", "merge", "--no-ff", cfgRemote+"/"+parent) } // Resolve codereview.cfg the right way - never take it from the merge. @@ -322,10 +325,11 @@ const ( ) func syncBranchContinue(flag string, b *Branch, status *syncBranchStatus) { - if h := gitHash("origin/" + status.Parent); h != status.ParentHash { + cfgRemote := config()["remote"] + if h := gitHash(cfgRemote + "/" + status.Parent); h != status.ParentHash { dief("cannot sync-branch%s: parent hash changed: %.7s -> %.7s", flag, status.ParentHash, h) } - if h := gitHash("origin/" + status.Branch); h != status.BranchHash { + if h := gitHash(cfgRemote + "/" + status.Branch); h != status.BranchHash { dief("cannot sync-branch%s: branch hash changed: %.7s -> %.7s", flag, status.BranchHash, h) } if b.Name != status.Local { @@ -364,11 +368,11 @@ func syncBranchContinue(flag string, b *Branch, status *syncBranchStatus) { } mergeHead = trim(mergeHead) if mergeHead != srcHash { - dief("cannot sync-branch%s: MERGE_HEAD is %.7s, but origin/%s is %.7s", flag, mergeHead, src, srcHash) + dief("cannot sync-branch%s: MERGE_HEAD is %.7s, but %s/%s is %.7s", flag, mergeHead, cfgRemote, src, srcHash) } head := gitHash("HEAD") if head != dstHash { - dief("cannot sync-branch%s: HEAD is %.7s, but origin/%s is %.7s", flag, head, dst, dstHash) + dief("cannot sync-branch%s: HEAD is %.7s, but %s/%s is %.7s", flag, head, cfgRemote, dst, dstHash) } if HasUnstagedChanges() { @@ -387,7 +391,7 @@ func syncBranchContinue(flag string, b *Branch, status *syncBranchStatus) { // Merge must never sync codereview.cfg, // because it contains the src and dst config. // Force the on-dst copy back while amending the commit. - cmdOutputDir(repoRoot(), "git", "checkout", "origin/"+dst, "--", "codereview.cfg") + cmdOutputDir(repoRoot(), "git", "checkout", cfgRemote+"/"+dst, "--", "codereview.cfg") conflictMsg := "" if len(status.Conflicts) > 0 { |
