Merge branch 'jc/commit'

* jc/commit:
  commit: detect misspelled pathspec while making a partial commit.
  combine-diff: diff-files fix (#2)
  combine-diff: diff-files fix.
diff --git a/combine-diff.c b/combine-diff.c
index a38f01b..d812600 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -630,9 +630,10 @@
 	int i, show_hunks, shown_header = 0;
 	char ourtmp_buf[TMPPATHLEN];
 	char *ourtmp = ourtmp_buf;
+	int working_tree_file = !memcmp(elem->sha1, null_sha1, 20);
 
 	/* Read the result of merge first */
-	if (memcmp(elem->sha1, null_sha1, 20)) {
+	if (!working_tree_file) {
 		result = grab_blob(elem->sha1, &size);
 		write_to_temp_file(ourtmp, result, size);
 	}
@@ -646,6 +647,7 @@
 			int len = st.st_size;
 			int cnt = 0;
 
+			elem->mode = DIFF_FILE_CANON_MODE(st.st_mode);
 			size = len;
 			result = xmalloc(len + 1);
 			while (cnt < len) {
@@ -661,6 +663,7 @@
 		else {
 			/* deleted file */
 			size = 0;
+			elem->mode = 0;
 			result = xmalloc(1);
 			result[0] = 0;
 			ourtmp = "/dev/null";
@@ -716,7 +719,7 @@
 
 	show_hunks = make_hunks(sline, cnt, num_parent, dense);
 
-	if (show_hunks || mode_differs) {
+	if (show_hunks || mode_differs || working_tree_file) {
 		const char *abb;
 
 		if (header) {
@@ -731,8 +734,6 @@
 		putchar('\n');
 		printf("index ");
 		for (i = 0; i < num_parent; i++) {
-			if (elem->parent[i].mode != elem->mode)
-				mode_differs = 1;
 			abb = find_unique_abbrev(elem->parent[i].sha1,
 						 DEFAULT_ABBREV);
 			printf("%s%s", i ? "," : "", abb);
diff --git a/diff-files.c b/diff-files.c
index 7db5ce6..0c3f800 100644
--- a/diff-files.c
+++ b/diff-files.c
@@ -150,6 +150,8 @@
 					       nce->sha1, 20);
 					combine.p.parent[stage-2].mode =
 						DIFF_FILE_CANON_MODE(mode);
+					combine.p.parent[stage-2].status =
+						DIFF_STATUS_MODIFIED;
 				}
 
 				/* diff against the proper unmerged stage */
diff --git a/git-commit.sh b/git-commit.sh
index ab5e6bc..f7ee1aa 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -180,6 +180,7 @@
 verbose=
 signoff=
 force_author=
+only_include_assumed=
 while case "$#" in 0) break;; esac
 do
   case "$1" in
@@ -340,12 +341,8 @@
 0,)
   ;;
 *,)
-  echo >&2 "assuming --only paths..."
+  only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
   also=
-
-  # If we are going to launch an editor, the message won't be
-  # shown without this...
-  test -z "$log_given$status_only" && sleep 1
   ;;
 esac
 unset only
@@ -380,6 +377,8 @@
 	;;
 ,t)
 	save_index &&
+	git-ls-files --error-unmatch -- "$@" >/dev/null || exit
+
 	git-diff-files --name-only -z -- "$@"  |
 	(
 		cd "$TOP"
@@ -408,7 +407,7 @@
 		refuse_partial "Different in index and the last commit:
 $dirty_in_index"
 	    fi
-	    commit_only=`git-ls-files -- "$@"`
+	    commit_only=`git-ls-files --error-unmatch -- "$@"` || exit
 
 	    # Build the temporary index and update the real index
 	    # the same way.
@@ -569,7 +568,10 @@
 	PARENTS=""
 fi
 
-run_status >>"$GIT_DIR"/COMMIT_EDITMSG
+{
+	test -z "$only_include_assumed" || echo "$only_include_assumed"
+	run_status
+} >>"$GIT_DIR"/COMMIT_EDITMSG
 if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
 then
 	rm -f "$GIT_DIR/COMMIT_EDITMSG"
diff --git a/ls-files.c b/ls-files.c
index 7024cf1..a716e5f 100644
--- a/ls-files.c
+++ b/ls-files.c
@@ -25,6 +25,8 @@
 static int prefix_len = 0, prefix_offset = 0;
 static const char *prefix = NULL;
 static const char **pathspec = NULL;
+static int error_unmatch = 0;
+static char *ps_matched = NULL;
 
 static const char *tag_cached = "";
 static const char *tag_unmerged = "";
@@ -325,7 +327,8 @@
  * Match a pathspec against a filename. The first "len" characters
  * are the common prefix
  */
-static int match(const char **spec, const char *filename, int len)
+static int match(const char **spec, char *ps_matched,
+		 const char *filename, int len)
 {
 	const char *m;
 
@@ -333,17 +336,24 @@
 		int matchlen = strlen(m + len);
 
 		if (!matchlen)
-			return 1;
+			goto matched;
 		if (!strncmp(m + len, filename + len, matchlen)) {
 			if (m[len + matchlen - 1] == '/')
-				return 1;
+				goto matched;
 			switch (filename[len + matchlen]) {
 			case '/': case '\0':
-				return 1;
+				goto matched;
 			}
 		}
 		if (!fnmatch(m + len, filename + len, 0))
-			return 1;
+			goto matched;
+		if (ps_matched)
+			ps_matched++;
+		continue;
+	matched:
+		if (ps_matched)
+			*ps_matched = 1;
+		return 1;
 	}
 	return 0;
 }
@@ -356,7 +366,7 @@
 	if (len >= ent->len)
 		die("git-ls-files: internal error - directory entry not superset of prefix");
 
-	if (pathspec && !match(pathspec, ent->name, len))
+	if (pathspec && !match(pathspec, ps_matched, ent->name, len))
 		return;
 
 	fputs(tag, stdout);
@@ -444,7 +454,7 @@
 	if (len >= ce_namelen(ce))
 		die("git-ls-files: internal error - cache entry not superset of prefix");
 
-	if (pathspec && !match(pathspec, ce->name, len))
+	if (pathspec && !match(pathspec, ps_matched, ce->name, len))
 		return;
 
 	if (!show_stage) {
@@ -699,6 +709,10 @@
 			prefix_offset = 0;
 			continue;
 		}
+		if (!strcmp(arg, "--error-unmatch")) {
+			error_unmatch = 1;
+			continue;
+		}
 		if (*arg == '-')
 			usage(ls_files_usage);
 		break;
@@ -710,6 +724,14 @@
 	if (pathspec)
 		verify_pathspec();
 
+	/* Treat unmatching pathspec elements as errors */
+	if (pathspec && error_unmatch) {
+		int num;
+		for (num = 0; pathspec[num]; num++)
+			;
+		ps_matched = xcalloc(1, num);
+	}
+
 	if (show_ignored && !exc_given) {
 		fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
 			argv[0]);
@@ -725,5 +747,20 @@
 	if (prefix)
 		prune_cache();
 	show_files();
+
+	if (ps_matched) {
+		/* We need to make sure all pathspec matched otherwise
+		 * it is an error.
+		 */
+		int num, errors = 0;
+		for (num = 0; pathspec[num]; num++) {
+			if (ps_matched[num])
+				continue;
+			error("pathspec '%s' did not match any.",
+			      pathspec[num] + prefix_len);
+		}
+		return errors ? 1 : 0;
+	}
+
 	return 0;
 }