Skip to content

Commit

Permalink
commit: detect misspelled pathspec while making a partial commit.
Browse files Browse the repository at this point in the history
When you say "git commit Documentaiton" to make partial commit
for the files only in that directory, we did not detect that as
a misspelled pathname and attempted to commit index without
change.  If nothing matched, there is no harm done, but if the
index gets modified otherwise by having another valid pathspec
or after an explicit update-index, a user will not notice
without paying attention to the "git status" preview.

This introduces --error-unmatch option to ls-files, and uses it
to detect this common user error.

Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Junio C Hamano committed Feb 14, 2006
1 parent 9ece716 commit bba319b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 17 deletions.
19 changes: 9 additions & 10 deletions git-commit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ verify=t
verbose=
signoff=
force_author=
only_include_assumed=
while case "$#" in 0) break;; esac
do
case "$1" in
Expand Down Expand Up @@ -340,15 +341,8 @@ case "$#,$also$only" in
0,)
;;
*,)
echo >&2 "assuming --include paths..."
only_include_assumed="# Explicit paths specified without -i nor -o; assuming --include paths..."
also=t
# Later when switch the defaults, we will replace them with these:
# echo >&2 "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
Expand Down Expand Up @@ -383,6 +377,8 @@ t,)
;;
,t)
save_index &&
git-ls-files --error-unmatch -- "$@" >/dev/null || exit

git-diff-files --name-only -z -- "$@" |
(
cd "$TOP"
Expand Down Expand Up @@ -411,7 +407,7 @@ t,)
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.
Expand Down Expand Up @@ -572,7 +568,10 @@ else
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"
Expand Down
51 changes: 44 additions & 7 deletions ls-files.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ static int line_terminator = '\n';
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 = "";
Expand Down Expand Up @@ -325,25 +327,33 @@ static int cmp_name(const void *p1, const void *p2)
* 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;

while ((m = *spec++) != NULL) {
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;
}
Expand All @@ -356,7 +366,7 @@ static void show_dir_entry(const char *tag, struct nond_on_fs *ent)
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);
Expand Down Expand Up @@ -444,7 +454,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
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) {
Expand Down Expand Up @@ -699,6 +709,10 @@ int main(int argc, const char **argv)
prefix_offset = 0;
continue;
}
if (!strcmp(arg, "--error-unmatch")) {
error_unmatch = 1;
continue;
}
if (*arg == '-')
usage(ls_files_usage);
break;
Expand All @@ -710,6 +724,14 @@ int main(int argc, const char **argv)
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]);
Expand All @@ -725,5 +747,20 @@ int main(int argc, const char **argv)
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;
}

0 comments on commit bba319b

Please sign in to comment.