diff options
| -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 { |
