Repository: remotemobprogramming/mob
Pull request #157 (2021-03-29 19:48:23)

issue #156 - prevent mob session with outstanding local commits
Let me know if this makes sense as a first start to fixing this issue.

TrentonAdams: @simonharrer Oh, i see what you mean.  I think this would work, yes?

```bash
echo hello > blah; git add blah; git commit -m 'blah'
git rev-list --count HEAD...refs/remotes/origin/main
1
```

Then if non zero, there's a local commit that wasn't pushed.
simonharrer: Yeah, let's try that. Can you introduce a new method that basically only checks that?
TrentonAdams: I sure can.  I'll see if I can get to that today.
TrentonAdams: I'm not sure what you wanted to see for line wrapping if any.  Let me know if you want anything changed.
simonharrer: Can you add a changelog entry, please?
simonharrer: Otherwise looks really great. I already want to say thanks for contributing and helping out making the tool better! :-)

Looking forward to see this enhancement in the next version. 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ad8f905..8451b47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 1.5.0
+- added support for preventing `mob start` if there are unpushed commits
+
 # 1.4.0
 - The list of commits included in a mob branch is now truncated to a maximum of 5 entries to prevent the need for scrolling up in order to see the latest included changes.
 - Show more informative error message when `mob <cmd>` is run outside of a git repository.
diff --git a/mob.go b/mob.go
index f2cd0d8..fd2125b 100644
--- a/mob.go
+++ b/mob.go
@@ -540,6 +540,11 @@ func start(configuration Configuration) {
 		stash := findLatestMobStash(stashes)
 		git("stash", "pop", stash)
 	}
+
+	if hasUnpushedCommits(currentBaseBranch, configuration) {
+		sayError("cannot start; unpushed changes on current branch must be pushed upstream")
+		return
+	}
 }
 
 func sayUntrackedFilesInfo() {
@@ -746,6 +751,18 @@ func hasUncommittedChanges() bool {
 	return !isNothingToCommit()
 }
 
+func hasUnpushedCommits(branch string, configuration Configuration) bool {
+	countOutput := silentgit(
+		"rev-list", "--count", "refs/heads/"+branch+"..."+"refs/remotes/"+configuration.RemoteName+"/"+branch,
+	)
+	unpushedCount, err := strconv.Atoi(countOutput)
+	if err != nil {
+		panic(err)
+	}
+	sayInfo(fmt.Sprintf("there are %d unpushed commits", unpushedCount))
+	return unpushedCount != 0
+}
+
 func isMobProgramming(configuration Configuration) bool {
 	currentBranch := gitCurrentBranch()
 	_, currentWipBranch := determineBranches(currentBranch, gitBranches(), configuration)


Test patch:
diff --git a/mob_test.go b/mob_test.go
index aa7056b..17674cd 100644
--- a/mob_test.go
+++ b/mob_test.go
@@ -479,6 +479,16 @@ func TestStartIncludeUnstagedChanges(t *testing.T) {
 	assertMobSessionBranches(t, "mob-session")
 }
 
+func TestStartHasUnpushedCommits(t *testing.T) {
+	output := setup(t)
+	createFileAndCommitIt(t, "test.txt", "content", "unpushed change")
+
+	start(configuration)
+
+	assertOutputContains(t, output, "cannot start; unpushed changes")
+	assertOutputContains(t, output, "unpushed commits")
+}
+
 func TestStartIncludeUntrackedFiles(t *testing.T) {
 	setup(t)
 	configuration.MobStartIncludeUncommittedChanges = true