Make 'review sync' handle the case where the change has been rebased on submission.
Change-Id: I7f6ae2045a00ff1578cc3afe352abb1f976bd585
diff --git a/review.go b/review.go
index 0806ca7..10f3e8b 100644
--- a/review.go
+++ b/review.go
@@ -95,7 +95,7 @@
if !hasStagedChanges() {
dief("No staged changes. Did you forget to \"git add\" your files?\n")
}
- if !isOnMaster() {
+ if currentBranch() != "master" {
dief("You must run create from the master branch.\n" +
"(Try \"review sync\" or \"git checkout master\" first.)\n")
}
@@ -105,13 +105,14 @@
run("git", "checkout", "-q", "master")
run("git", "branch", "-q", "-d", name)
}
+ // TODO(adg): check style of commit message
}
func commit() {
if !hasStagedChanges() {
dief("No staged changes. Did you forget to \"git add\" your files?\n")
}
- if isOnMaster() {
+ if currentBranch() == "master" {
dief("Can't commit to master branch.\n")
}
run("git", "commit", "-q", "--amend", "-C", "HEAD")
@@ -122,7 +123,7 @@
}
func upload() {
- if isOnMaster() {
+ if currentBranch() == "master" {
dief("Can't upload from master branch.\n")
}
run("git", "push", "-q", "origin", "HEAD:refs/for/master")
@@ -130,21 +131,46 @@
func sync() {
run("git", "fetch", "-q")
- if isOnMaster() {
+
+ // If we're on master, just fast-forward.
+ branch := currentBranch()
+ if branch == "master" {
run("git", "merge", "-q", "--ff-only", "origin/master")
return
}
+
+ // Check that exactly this commit was submitted to master. If so,
+ // switch back to master, fast-forward, delete the feature branch.
if branchContains("origin/master", "HEAD") {
- b := currentBranch()
run("git", "checkout", "-q", "master")
run("git", "merge", "-q", "--ff-only", "origin/master")
- run("git", "branch", "-q", "-d", b)
+ run("git", "branch", "-q", "-d", branch)
return
}
+
+ // Check whether a rebased version of this commit was submitted to
+ // master. If so, switch back to master, fast-forward, and
+ // provide instructions for deleting the feature branch.
+ // (We're not 100% sure that the feature branch HEAD was submitted,
+ // so be cautious.)
+ if headSubmitted() {
+ run("git", "checkout", "-q", "master")
+ run("git", "merge", "-q", "--ff-only", "origin/master")
+ fmt.Fprintf(os.Stderr, "Switched back to master from %q, "+
+ "which I think has been submitted.\n"+
+ "If you agree, and no longer need branch %q, run:\n"+
+ "\tgit branch -D %v\n",
+ branch, branch, branch)
+ return
+ }
+
+ // Bump master HEAD to that of origin/master, just in case the user
+ // switches back to master with "git checkout master" later.
if !branchContains("origin/master", "master") {
- // Bump master HEAD to that of origin/master.
run("git", "branch", "-f", "master", "origin/master")
}
+
+ // We have un-submitted changes on this feature branch; rebase.
run("git", "rebase", "-q", "origin/master")
}
@@ -152,8 +178,6 @@
dief("not implemented\n")
}
-var stagedRe = regexp.MustCompile(`^[ACDMR] `)
-
func branchContains(branch, rev string) bool {
b, err := exec.Command("git", "branch", "-r", "--contains", rev).CombinedOutput()
if err != nil {
@@ -167,6 +191,8 @@
return false
}
+var stagedRe = regexp.MustCompile(`^[ACDMR] `)
+
func hasStagedChanges() bool {
for _, s := range gitStatus() {
if stagedRe.MatchString(s) {
@@ -195,17 +221,28 @@
return strings.Split(string(b), "\n")
}
-func isOnMaster() bool {
- branch, err := exec.Command("git", "branch").CombinedOutput()
+func headSubmitted() bool {
+ s := "Change-Id: " + headChangeId()
+ b, err := exec.Command("git", "log", "--grep", s).CombinedOutput()
if err != nil {
- dief("%s\nchecking current branch: %v\n", branch, err)
+ dief("%s\ngit log failed: %v\n", b, err)
}
- for _, s := range strings.Split(string(branch), "\n") {
- if strings.HasPrefix(s, "* ") {
- return s == "* master"
+ return len(b) > 0
+}
+
+func headChangeId() string {
+ b, err := exec.Command("git", "log", "-n", "1", "--format=format:%b").CombinedOutput()
+ if err != nil {
+ dief("%s\ngit log failed: %v\n", b, err)
+ }
+ const p = "Change-Id: "
+ for _, s := range strings.Split(string(b), "\n") {
+ if strings.HasPrefix(s, p) {
+ return strings.TrimSpace(strings.TrimPrefix(s, p))
}
}
- return false
+ dief("No Change-Id line found in HEAD commit.\n")
+ panic("unreachable")
}
func goToRepoRoot() {