git-codereview: make change fail with multiple pending changes

When using 'git change' to amend the current change, it will fail
if there are multiple pending changes. The previous behavior (amending
the latest) wasn't always what the user intended.

    $ git change
    git-codereview: cannot amend change: multiple changes pending:
    	fc60fd5 test: dummy change
    	6440cdc git-codereview: make change fail with multiple pending changes
    $

Unlike mail and submit, change doesn't support explicitly telling
which commit to work on. Either 'git commit --amend' (for updating
the topmost change) or a combination of 'git commit' and 'git rebase'
must be used.

Fixes golang/go#10443.

Change-Id: I2f6ea1b0e302b66b627761d72d031a3b6aa0fba2
Reviewed-on: https://go-review.googlesource.com/20049
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Andrew Gerrand <adg@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/git-codereview/branch.go b/git-codereview/branch.go
index 8cf1566..c96bce0 100644
--- a/git-codereview/branch.go
+++ b/git-codereview/branch.go
@@ -335,8 +335,9 @@
 
 // DefaultCommit returns the default pending commit for this branch.
 // It dies if there is not exactly one pending commit,
-// using the action ("mail", "submit") in the failure message.
-func (b *Branch) DefaultCommit(action string) *Commit {
+// using the action (e.g. "mail", "submit") and optional extra instructions
+// in the failure message.
+func (b *Branch) DefaultCommit(action, extra string) *Commit {
 	work := b.Pending()
 	if len(work) == 0 {
 		dief("cannot %s: no changes pending", action)
@@ -346,11 +347,10 @@
 		for _, c := range work {
 			fmt.Fprintf(&buf, "\n\t%s %s", c.ShortHash, c.Subject)
 		}
-		extra := ""
-		if action == "submit" {
-			extra = " or use submit -i"
+		if extra != "" {
+			extra = "; " + extra
 		}
-		dief("cannot %s: multiple changes pending; must specify commit on command line%s:%s", action, extra, buf.String())
+		dief("cannot %s: multiple changes pending%s:%s", action, extra, buf.String())
 	}
 	return work[0]
 }
diff --git a/git-codereview/change.go b/git-codereview/change.go
index 4c0e252..0d47857 100644
--- a/git-codereview/change.go
+++ b/git-codereview/change.go
@@ -43,6 +43,10 @@
 	}
 
 	amend := b.HasPendingCommit()
+	if amend {
+		// Dies if there is not exactly one commit.
+		b.DefaultCommit("amend change", "")
+	}
 	commitChanges(amend)
 	b.loadedPending = false // force reload after commitChanges
 	b.check()
diff --git a/git-codereview/change_test.go b/git-codereview/change_test.go
index 524c021..05e5c82 100644
--- a/git-codereview/change_test.go
+++ b/git-codereview/change_test.go
@@ -76,3 +76,29 @@
 		}
 	}
 }
+
+func TestChangeAmendCommit(t *testing.T) {
+	gt := newGitTest(t)
+	defer gt.done()
+
+	testCommitMsg = "foo: amended commit message"
+	gt.work(t)
+
+	write(t, gt.client+"/file", "new content in work to be amend")
+	trun(t, gt.client, "git", "add", "file")
+	testMain(t, "change")
+}
+
+func TestChangeFailAmendWithMultiplePending(t *testing.T) {
+	gt := newGitTest(t)
+	defer gt.done()
+
+	testCommitMsg = "foo: amended commit message"
+	gt.work(t)
+	gt.work(t)
+
+	write(t, gt.client+"/file", "new content in work to be amend")
+	trun(t, gt.client, "git", "add", "file")
+	testMainDied(t, "change")
+	testPrintedStderr(t, "multiple changes pending")
+}
diff --git a/git-codereview/mail.go b/git-codereview/mail.go
index 4c40968..040ef19 100644
--- a/git-codereview/mail.go
+++ b/git-codereview/mail.go
@@ -39,7 +39,7 @@
 	if len(flags.Args()) == 1 {
 		c = b.CommitByRev("mail", flags.Arg(0))
 	} else {
-		c = b.DefaultCommit("mail")
+		c = b.DefaultCommit("mail", "must specify commit on command line")
 	}
 
 	if *diff {
diff --git a/git-codereview/submit.go b/git-codereview/submit.go
index d163914..78c6339 100644
--- a/git-codereview/submit.go
+++ b/git-codereview/submit.go
@@ -42,7 +42,7 @@
 			cs = append(cs, b.CommitByRev("submit", arg))
 		}
 	} else {
-		cs = append(cs, b.DefaultCommit("submit"))
+		cs = append(cs, b.DefaultCommit("submit", "must specify commit on command line or use submit -i"))
 	}
 
 	// No staged changes.