Merge branch 'ensure-clean-env' into develop
diff --git a/gitflow-feature b/gitflow-feature
index 6551b99..adad481 100755
--- a/gitflow-feature
+++ b/gitflow-feature
@@ -32,17 +32,32 @@
 }
 
 start() {
-	# TODO
 	parse_args "$@"
+
+	# Checks
 	gitflow_check_clean_working_tree
+	gitflow_require_branch_absent "$FEATURE"
+	if [ "$BASE" = "develop" ]; then
+		gitflow_require_branches_equal 'develop' 'origin/develop'
+	fi
+
+	# All checks passed, ready to roll
 	echo "git checkout -b $FEATURE $BASE"
 }
 
 finish() {
-	# TODO
 	parse_args "$@"
+
+	# Checks
 	gitflow_check_clean_working_tree
+	gitflow_require_branch "$FEATURE"
+	if [ "$BASE" = "develop" ]; then
+		gitflow_require_branches_equal 'develop' 'origin/develop'
+	fi
+
+	# All checks passed, ready to roll
 	echo "git checkout $BASE"
 	echo "git merge --no-ff $FEATURE"
+	echo "git branch -d $FEATURE"
 }
 
diff --git a/gitflow-hotfix b/gitflow-hotfix
index 6e339a7..7ee8459 100755
--- a/gitflow-hotfix
+++ b/gitflow-hotfix
@@ -24,25 +24,39 @@
 		usage
 		exit 1
 	fi
+	HOTFIX_BRANCH="hotfix-$RELEASE"
 }
 
 start() {
-	# TODO
 	parse_args "$@"
+
+	# Checks
 	gitflow_check_clean_working_tree
-	echo "git checkout -b hotfix-$RELEASE master"
-	echo "Bump version number"
-	echo "Fix bug"
+	gitflow_require_branches_equal 'master' 'origin/master'
+	gitflow_require_branch_absent "$HOTFIX_BRANCH"
+
+	# All checks passed, ready to roll
+	echo "git checkout -b \"$HOTFIX_BRANCH\" master"
+	echo "Don't forget to bump the version number now."
 }
 
 finish() {
-	# TODO
 	parse_args "$@"
+
+	# Checks
 	gitflow_check_clean_working_tree
+
+	echo "git fetch origin"
+	git fetch origin
+	gitflow_require_branches_equal 'master' 'origin/master'
+	gitflow_require_branches_equal 'develop' 'origin/develop'
+
+	# All checks passed, ready to roll
 	echo "git checkout master"
-	echo "git merge --no-ff hotfix-$RELEASE"
+	echo "git merge --no-ff \"$HOTFIX_BRANCH\""
+	echo "git tag \"$RELEASE\""
 	echo "git checkout develop"
-	echo "git merge --no-ff hotfix-$RELEASE"
-	echo "git branch -d hotfix-$RELEASE"
+	echo "git merge --no-ff \"$HOTFIX_BRANCH\""
+	echo "git branch -d \"$HOTFIX_BRANCH\""
 }
 
diff --git a/gitflow-release b/gitflow-release
index b8e4810..8790405 100755
--- a/gitflow-release
+++ b/gitflow-release
@@ -24,26 +24,39 @@
 		usage
 		exit 1
 	fi
+	RELEASE_BRANCH="release-$RELEASE"
 }
 
 start() {
-	# TODO
 	parse_args "$@"
+
+	# Checks
 	gitflow_check_clean_working_tree
-	echo "git checkout -b release-$RELEASE develop"
-	echo "Bump version number"
-	echo "Fix bug"
+	gitflow_require_branches_equal 'develop' 'origin/develop'
+	gitflow_require_branch_absent "$RELEASE_BRANCH"
+
+	# All checks passed, ready to roll
+	echo "git checkout -b \"$RELEASE_BRANCH\" develop"
+	echo "Don't forget to bump the version number now."
 }
 
 finish() {
-	# TODO
 	parse_args "$@"
+
+	# Checks
 	gitflow_check_clean_working_tree
+
+	echo "git fetch origin"
+	git fetch origin
+	gitflow_require_branches_equal 'master' 'origin/master'
+	gitflow_require_branches_equal 'develop' 'origin/develop'
+
+	# All checks passed, ready to roll
 	echo "git checkout master"
-	echo "git merge --no-ff release-$RELEASE"
-	echo "git tag $RELEASE"
+	echo "git merge --no-ff \"$RELEASE_BRANCH\""
+	echo "git tag \"$RELEASE\""
 	echo "git checkout develop"
-	echo "git merge --no-ff release-$RELEASE"
-	echo "git branch -d release-$RELEASE"
+	echo "git merge --no-ff \"$RELEASE_BRANCH\""
+	echo "git branch -d \"$RELEASE_BRANCH\""
 }
 
diff --git a/gitflow-sh-setup b/gitflow-sh-setup
index f78bf5c..f24025d 100755
--- a/gitflow-sh-setup
+++ b/gitflow-sh-setup
@@ -12,7 +12,96 @@
 # Copyright (c) 2010 by Vincent Driessen
 #
 
+# Get the git dir
+GIT_DIR=$(git rev-parse --git-dir)
+
+# Get all available branches
+LOCAL_BRANCHES=$(cd "$GIT_DIR/refs/heads"; find * -type f)
+REMOTE_BRANCHES=$(cd "$GIT_DIR/refs/remotes"; find * -type f)
+ALL_BRANCHES="$LOCAL_BRANCHES\n$REMOTE_BRANCHES"
+
+warn() { echo "$@" >&2; }
+die() { warn "$@"; exit 1; }
+
 gitflow_check_clean_working_tree() {
-	echo "Working tree $(pwd) clean."
+	if [ "$(git status 2> /dev/null | tail -n1)" != "nothing to commit (working directory clean)" ]; then
+		die "Working directory is dirty. Only use gitflow in clean working directories for your own safety."
+	fi
+}
+
+gitflow_require_local_branch() {
+	echo "$LOCAL_BRANCHES" | grep "^$1\$" 2>/dev/null >/dev/null
+	if [ $? -ne 0 ]; then
+		die "Local branch '$1' does not exist and is required."
+	fi
+}
+
+gitflow_require_remote_branch() {
+	echo "$REMOTE_BRANCHES" | grep "^$1\$" 2>/dev/null >/dev/null
+	if [ $? -ne 0 ]; then
+		die "Remote branch '$1' does not exist and is required."
+	fi
+}
+
+gitflow_require_branch() {
+	echo "$ALL_BRANCHES" | grep "^$1\$" 2>/dev/null >/dev/null
+	if [ $? -ne 0 ]; then
+		die "Branch '$1' does not exist and is required."
+	fi
+}
+
+gitflow_require_branch_absent() {
+	echo "$ALL_BRANCHES" | grep "^$1\$" 2>/dev/null >/dev/null
+	if [ $? -eq 0 ]; then
+		die "Branch '$1' already exists."
+	fi
+}
+
+#
+# gitflow_test_branches_equal()
+# 
+# Tests whether branches and their "origin" counterparts have diverged and need
+# merging first. It returns error codes to provide more detail, like so:
+# 
+# 0		Branch heads point to the same commit
+# 1		First given branch needs fast-forwarding
+# 2		Second given branch needs fast-forwarding
+# 3		Branch needs a real merge
+#
+gitflow_test_branches_equal() {
+	commit1=$(git rev-parse "$1")
+	commit2=$(git rev-parse "$2")
+	if [ "$commit1" != "$commit2" ]; then
+		base=$(git merge-base "$commit1" "$commit2")
+		short_base=$(git rev-parse --short "$base")
+
+		if [ "$commit1" = "$base" ]; then
+			return 1
+		elif [ "$commit2" = "$base" ]; then
+			return 2
+		else
+			return 3
+		fi
+	else
+		return 0
+	fi
+}
+
+gitflow_require_branches_equal() {
+	gitflow_require_local_branch "$1"
+	gitflow_require_remote_branch "$2"
+	gitflow_test_branches_equal "$1" "$2"
+	status=$?
+	if [ $status -gt 0 ]; then
+		warn "Branches '$1' and '$2' have diverged."
+
+		if [ $status -eq 1 ]; then
+			die "And branch '$1' may be fast-forwarded."
+		elif [ $status -eq 2 ]; then
+			die "And local branch '$1' is ahead of '$2'."
+		else
+			die "Branches need merging first."
+		fi
+	fi
 }
 
diff --git a/test-sh-setup b/test-sh-setup
new file mode 100755
index 0000000..1c69056
--- /dev/null
+++ b/test-sh-setup
@@ -0,0 +1,13 @@
+#!/bin/sh
+. gitflow-sh-setup
+
+gitflow_require_branch 'master'
+gitflow_require_branch 'develop'
+gitflow_require_branch 'origin/develop'
+gitflow_require_branch 'origin/master'
+
+gitflow_require_branches_equal 'master' 'origin/master'
+gitflow_require_branches_equal 'develop' 'origin/develop'
+gitflow_require_branches_equal 'rebase-not-merge' 'truemped/rebase-not-merge'
+
+echo "All OK."