diff options
| author | Shawn O. Pearce <spearce@spearce.org> | 2008-09-29 11:04:20 -0700 | 
|---|---|---|
| committer | Shawn O. Pearce <spearce@spearce.org> | 2008-09-29 11:04:20 -0700 | 
| commit | 9800c0df412869c7949935b61581b9361fc49bd1 (patch) | |
| tree | 837cb43f80452126e46ff5de641f14b7b349484f | |
| parent | 9ba929ed652f5ed7707f1c684999af4ad02c4925 (diff) | |
| parent | 5a139ba483efea47e103fef47afe87157e3bba77 (diff) | |
| download | git-9800c0df412869c7949935b61581b9361fc49bd1.tar.gz | |
Merge branch 'bc/master-diff-hunk-header-fix'
* bc/master-diff-hunk-header-fix:
  Clarify commit error message for unmerged files
  Use strchrnul() instead of strchr() plus manual workaround
  Use remove_path from dir.c instead of own implementation
  Add remove_path: a function to remove as much as possible of a path
  git-submodule: Fix "Unable to checkout" for the initial 'update'
  Clarify how the user can satisfy stash's 'dirty state' check.
  t4018-diff-funcname: test syntax of builtin xfuncname patterns
  t4018-diff-funcname: test syntax of builtin xfuncname patterns
  make "git remote" report multiple URLs
  diff hunk pattern: fix misconverted "\{" tex macro introducers
  diff: fix "multiple regexp" semantics to find hunk header comment
  diff: use extended regexp to find hunk headers
  diff: use extended regexp to find hunk headers
  diff.*.xfuncname which uses "extended" regex's for hunk header selection
  diff.c: associate a flag with each pattern and use it for compiling regex
  diff.c: return pattern entry pointer rather than just the hunk header pattern
Conflicts:
	builtin-merge-recursive.c
	t/t7201-co.sh
	xdiff-interface.h
| -rw-r--r-- | Documentation/gitattributes.txt | 4 | ||||
| -rw-r--r-- | builtin-apply.c | 11 | ||||
| -rw-r--r-- | builtin-commit.c | 2 | ||||
| -rw-r--r-- | builtin-for-each-ref.c | 4 | ||||
| -rw-r--r-- | builtin-remote.c | 23 | ||||
| -rw-r--r-- | builtin-rm.c | 22 | ||||
| -rw-r--r-- | diff.c | 106 | ||||
| -rw-r--r-- | dir.c | 20 | ||||
| -rw-r--r-- | dir.h | 3 | ||||
| -rwxr-xr-x | git-stash.sh | 2 | ||||
| -rwxr-xr-x | git-submodule.sh | 9 | ||||
| -rw-r--r-- | merge-recursive.c | 17 | ||||
| -rwxr-xr-x | t/t4018-diff-funcname.sh | 13 | ||||
| -rw-r--r-- | xdiff-interface.c | 21 | ||||
| -rw-r--r-- | xdiff-interface.h | 2 | 
15 files changed, 139 insertions, 120 deletions
| diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index e848c94397..2ae771f2fb 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -288,13 +288,13 @@ for paths.  *.tex	diff=tex  ------------------------ -Then, you would define a "diff.tex.funcname" configuration to +Then, you would define a "diff.tex.xfuncname" configuration to  specify a regular expression that matches a line that you would  want to appear as the hunk header "TEXT", like this:  ------------------------  [diff "tex"] -	funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$" +	xfuncname = "^(\\\\(sub)*section\\{.*)$"  ------------------------  Note.  A single level of backslashes are eaten by the diff --git a/builtin-apply.c b/builtin-apply.c index 2ab4aba5a0..e2c611bf96 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -13,6 +13,7 @@  #include "delta.h"  #include "builtin.h"  #include "string-list.h" +#include "dir.h"  /*   *  --check turns on checking that the working tree matches the @@ -2735,15 +2736,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)  				warning("unable to remove submodule %s",  					patch->old_name);  		} else if (!unlink(patch->old_name) && rmdir_empty) { -			char *name = xstrdup(patch->old_name); -			char *end = strrchr(name, '/'); -			while (end) { -				*end = 0; -				if (rmdir(name)) -					break; -				end = strrchr(name, '/'); -			} -			free(name); +			remove_path(patch->old_name);  		}  	}  } diff --git a/builtin-commit.c b/builtin-commit.c index 55e1087d27..b920257524 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -639,7 +639,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)  		active_cache_tree = cache_tree();  	if (cache_tree_update(active_cache_tree,  			      active_cache, active_nr, 0, 0) < 0) { -		error("Error building trees"); +		error("Error building trees; the index is unmerged?");  		return 0;  	} diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index e59bd8075e..fa6c1ed752 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -320,9 +320,7 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un  static const char *copy_line(const char *buf)  { -	const char *eol = strchr(buf, '\n'); -	if (!eol) // simulate strchrnul() -		eol = buf + strlen(buf); +	const char *eol = strchrnul(buf, '\n');  	return xmemdupz(buf, eol - buf);  } diff --git a/builtin-remote.c b/builtin-remote.c index 4cb763f989..90a4e35828 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -650,10 +650,13 @@ static int get_one_entry(struct remote *remote, void *priv)  {  	struct string_list *list = priv; -	string_list_append(remote->name, list)->util = remote->url_nr ? -		(void *)remote->url[0] : NULL; -	if (remote->url_nr > 1) -		warning("Remote %s has more than one URL", remote->name); +	if (remote->url_nr > 0) { +		int i; + +		for (i = 0; i < remote->url_nr; i++) +			string_list_append(remote->name, list)->util = (void *)remote->url[i]; +	} else +		string_list_append(remote->name, list)->util = NULL;  	return 0;  } @@ -669,10 +672,14 @@ static int show_all(void)  		sort_string_list(&list);  		for (i = 0; i < list.nr; i++) {  			struct string_list_item *item = list.items + i; -			printf("%s%s%s\n", item->string, -				verbose ? "\t" : "", -				verbose && item->util ? -					(const char *)item->util : ""); +			if (verbose) +				printf("%s\t%s\n", item->string, +					item->util ? (const char *)item->util : ""); +			else { +				if (i && !strcmp((item - 1)->string, item->string)) +					continue; +				printf("%s\n", item->string); +			}  		}  	}  	return result; diff --git a/builtin-rm.c b/builtin-rm.c index fdac34f242..50ae6d5401 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -29,26 +29,6 @@ static void add_list(const char *name)  	list.name[list.nr++] = name;  } -static int remove_file(const char *name) -{ -	int ret; -	char *slash; - -	ret = unlink(name); -	if (ret && errno == ENOENT) -		/* The user has removed it from the filesystem by hand */ -		ret = errno = 0; - -	if (!ret && (slash = strrchr(name, '/'))) { -		char *n = xstrdup(name); -		do { -			n[slash - name] = 0; -			name = n; -		} while (!rmdir(name) && (slash = strrchr(name, '/'))); -	} -	return ret; -} -  static int check_local_mod(unsigned char *head, int index_only)  {  	/* items in list are already sorted in the cache order, @@ -239,7 +219,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)  		int removed = 0;  		for (i = 0; i < list.nr; i++) {  			const char *path = list.name[i]; -			if (!remove_file(path)) { +			if (!remove_path(path)) {  				removed = 1;  				continue;  			} @@ -96,32 +96,37 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val   * to define a customized regexp to find the beginning of a function to   * be used for hunk header lines of "diff -p" style output.   */ -static struct funcname_pattern { +struct funcname_pattern_entry {  	char *name;  	char *pattern; -	struct funcname_pattern *next; +	int cflags; +}; +static struct funcname_pattern_list { +	struct funcname_pattern_list *next; +	struct funcname_pattern_entry e;  } *funcname_pattern_list; -static int parse_funcname_pattern(const char *var, const char *ep, const char *value) +static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)  {  	const char *name;  	int namelen; -	struct funcname_pattern *pp; +	struct funcname_pattern_list *pp;  	name = var + 5; /* "diff." */  	namelen = ep - name;  	for (pp = funcname_pattern_list; pp; pp = pp->next) -		if (!strncmp(pp->name, name, namelen) && !pp->name[namelen]) +		if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen])  			break;  	if (!pp) {  		pp = xcalloc(1, sizeof(*pp)); -		pp->name = xmemdupz(name, namelen); +		pp->e.name = xmemdupz(name, namelen);  		pp->next = funcname_pattern_list;  		funcname_pattern_list = pp;  	} -	free(pp->pattern); -	pp->pattern = xstrdup(value); +	free(pp->e.pattern); +	pp->e.pattern = xstrdup(value); +	pp->e.cflags = cflags;  	return 0;  } @@ -194,7 +199,13 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)  			if (!strcmp(ep, ".funcname")) {  				if (!value)  					return config_error_nonbool(var); -				return parse_funcname_pattern(var, ep, value); +				return parse_funcname_pattern(var, ep, value, +					0); +			} else if (!strcmp(ep, ".xfuncname")) { +				if (!value) +					return config_error_nonbool(var); +				return parse_funcname_pattern(var, ep, value, +					REG_EXTENDED);  			}  		}  	} @@ -1400,42 +1411,45 @@ int diff_filespec_is_binary(struct diff_filespec *one)  	return one->is_binary;  } -static const char *funcname_pattern(const char *ident) +static const struct funcname_pattern_entry *funcname_pattern(const char *ident)  { -	struct funcname_pattern *pp; +	struct funcname_pattern_list *pp;  	for (pp = funcname_pattern_list; pp; pp = pp->next) -		if (!strcmp(ident, pp->name)) -			return pp->pattern; +		if (!strcmp(ident, pp->e.name)) +			return &pp->e;  	return NULL;  } -static struct builtin_funcname_pattern { -	const char *name; -	const char *pattern; -} builtin_funcname_pattern[] = { -	{ "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, -	{ "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$" }, -	{ "java", "!^[ 	]*\\(catch\\|do\\|for\\|if\\|instanceof\\|" -			"new\\|return\\|switch\\|throw\\|while\\)\n" -			"^[ 	]*\\(\\([ 	]*" -			"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}" -			"[ 	]*([^;]*\\)$" }, -	{ "pascal", "^\\(\\(procedure\\|function\\|constructor\\|" -			"destructor\\|interface\\|implementation\\|" -			"initialization\\|finalization\\)[ \t]*.*\\)$" -			"\\|" -			"^\\(.*=[ \t]*\\(class\\|record\\).*\\)$" -			}, -	{ "php", "^[\t ]*\\(\\(function\\|class\\).*\\)" }, -	{ "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" }, -	{ "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, -	{ "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, +static const struct funcname_pattern_entry builtin_funcname_pattern[] = { +	{ "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", +	  REG_EXTENDED }, +	{ "html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", REG_EXTENDED }, +	{ "java", +	  "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" +	  "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$", +	  REG_EXTENDED }, +	{ "pascal", +	  "^((procedure|function|constructor|destructor|interface|" +		"implementation|initialization|finalization)[ \t]*.*)$" +	  "\n" +	  "^(.*=[ \t]*(class|record).*)$", +	  REG_EXTENDED }, +	{ "php", "^[\t ]*((function|class).*)", REG_EXTENDED }, +	{ "python", "^[ \t]*((class|def)[ \t].*)$", REG_EXTENDED }, +	{ "ruby", "^[ \t]*((class|module|def)[ \t].*)$", +	  REG_EXTENDED }, +	{ "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", +	  REG_EXTENDED }, +	{ "tex", +	  "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", +	  REG_EXTENDED },  }; -static const char *diff_funcname_pattern(struct diff_filespec *one) +static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)  { -	const char *ident, *pattern; +	const char *ident; +	const struct funcname_pattern_entry *pe;  	int i;  	diff_filespec_check_attr(one); @@ -1450,9 +1464,9 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)  		return funcname_pattern("default");  	/* Look up custom "funcname.$ident" regexp from config. */ -	pattern = funcname_pattern(ident); -	if (pattern) -		return pattern; +	pe = funcname_pattern(ident); +	if (pe) +		return pe;  	/*  	 * And define built-in fallback patterns here.  Note that @@ -1460,7 +1474,7 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)  	 */  	for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)  		if (!strcmp(ident, builtin_funcname_pattern[i].name)) -			return builtin_funcname_pattern[i].pattern; +			return &builtin_funcname_pattern[i];  	return NULL;  } @@ -1556,11 +1570,11 @@ static void builtin_diff(const char *name_a,  		xdemitconf_t xecfg;  		xdemitcb_t ecb;  		struct emit_callback ecbdata; -		const char *funcname_pattern; +		const struct funcname_pattern_entry *pe; -		funcname_pattern = diff_funcname_pattern(one); -		if (!funcname_pattern) -			funcname_pattern = diff_funcname_pattern(two); +		pe = diff_funcname_pattern(one); +		if (!pe) +			pe = diff_funcname_pattern(two);  		memset(&xecfg, 0, sizeof(xecfg));  		memset(&ecbdata, 0, sizeof(ecbdata)); @@ -1572,8 +1586,8 @@ static void builtin_diff(const char *name_a,  		xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;  		xecfg.ctxlen = o->context;  		xecfg.flags = XDL_EMIT_FUNCNAMES; -		if (funcname_pattern) -			xdiff_set_find_func(&xecfg, funcname_pattern); +		if (pe) +			xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);  		if (!diffopts)  			;  		else if (!prefixcmp(diffopts, "--unified=")) @@ -831,3 +831,23 @@ void setup_standard_excludes(struct dir_struct *dir)  	if (excludes_file && !access(excludes_file, R_OK))  		add_excludes_from_file(dir, excludes_file);  } + +int remove_path(const char *name) +{ +	char *slash; + +	if (unlink(name) && errno != ENOENT) +		return -1; + +	slash = strrchr(name, '/'); +	if (slash) { +		char *dirs = xstrdup(name); +		slash = dirs + (slash - name); +		do { +			*slash = '\0'; +		} while (rmdir(dirs) && (slash = strrchr(dirs, '/'))); +		free(dirs); +	} +	return 0; +} + @@ -81,4 +81,7 @@ extern int is_inside_dir(const char *dir);  extern void setup_standard_excludes(struct dir_struct *dir);  extern int remove_dir_recursively(struct strbuf *path, int only_empty); +/* tries to remove the path with empty directories along it, ignores ENOENT */ +extern int remove_path(const char *path); +  #endif diff --git a/git-stash.sh b/git-stash.sh index 6bd2572f77..42f626f9d5 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -161,7 +161,7 @@ show_stash () {  apply_stash () {  	git update-index -q --refresh &&  	git diff-files --quiet --ignore-submodules || -		die 'Cannot restore on top of a dirty state' +		die 'Cannot apply to a dirty working tree, please stage your changes'  	unstash_index=  	case "$1" in diff --git a/git-submodule.sh b/git-submodule.sh index 92be0feb58..65178ae8e3 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -194,7 +194,7 @@ cmd_add()  	else  		module_clone "$path" "$realrepo" || exit -		(unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) || +		(unset GIT_DIR; cd "$path" && git checkout -f -q ${branch:+-b "$branch" "origin/$branch"}) ||  		die "Unable to checkout submodule '$path'"  	fi @@ -340,8 +340,13 @@ cmd_update()  		if test "$subsha1" != "$sha1"  		then +			force= +			if test -z "$subsha1" +			then +				force="-f" +			fi  			(unset GIT_DIR; cd "$path" && git-fetch && -				git-checkout -q "$sha1") || +				git-checkout $force -q "$sha1") ||  			die "Unable to checkout '$sha1' in submodule path '$path'"  			say "Submodule path '$path': checked out '$sha1'" diff --git a/merge-recursive.c b/merge-recursive.c index 08917314fb..6bc3eac85c 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -19,6 +19,7 @@  #include "interpolate.h"  #include "attr.h"  #include "merge-recursive.h" +#include "dir.h"  static struct tree *shift_tree_object(struct tree *one, struct tree *two)  { @@ -392,22 +393,6 @@ static int update_stages(const char *path, struct diff_filespec *o,  	return 0;  } -static int remove_path(const char *name) -{ -	char *slash, *dirs; - -	if (unlink(name)) -		return -1; -	dirs = xstrdup(name); -	while ((slash = strrchr(name, '/'))) { -		*slash = '\0'; -		if (rmdir(name) != 0) -			break; -	} -	free(dirs); -	return 0; -} -  static int remove_file(struct merge_options *o, int clean,  		       const char *path, int no_wd)  { diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 18bcd9713d..520e095c59 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -32,7 +32,18 @@ EOF  sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java +builtin_patterns="bibtex html java pascal php python ruby tex" +for p in $builtin_patterns +do +	test_expect_success "builtin $p pattern compiles" ' +		echo "*.java diff=$p" > .gitattributes && +		! ( git diff --no-index Beer.java Beer-correct.java 2>&1 | +			grep "fatal" > /dev/null ) +	' +done +  test_expect_success 'default behaviour' ' +	rm -f .gitattributes &&  	git diff --no-index Beer.java Beer-correct.java |  	grep "^@@.*@@ public class Beer"  ' @@ -58,7 +69,7 @@ test_expect_success 'last regexp must not be negated' '  '  test_expect_success 'alternation in pattern' ' -	git config diff.java.funcname "^[ 	]*\\(\\(public\\|static\\).*\\)$" +	git config diff.java.xfuncname "^[ 	]*((public|static).*)$" &&  	git diff --no-index Beer.java Beer-correct.java |  	grep "^@@.*@@ public static void main("  ' diff --git a/xdiff-interface.c b/xdiff-interface.c index 8457601bc4..8bab82ed7f 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -194,31 +194,34 @@ static long ff_regexp(const char *line, long len,  	char *line_buffer = xstrndup(line, len); /* make NUL terminated */  	struct ff_regs *regs = priv;  	regmatch_t pmatch[2]; -	int result = 0, i; +	int i; +	int result = -1;  	for (i = 0; i < regs->nr; i++) {  		struct ff_reg *reg = regs->array + i; -		if (reg->negate ^ !!regexec(®->re, -					line_buffer, 2, pmatch, 0)) { -			free(line_buffer); -			return -1; +		if (!regexec(®->re, line_buffer, 2, pmatch, 0)) { +			if (reg->negate) +				goto fail; +			break;  		}  	} +	if (regs->nr <= i) +		goto fail;  	i = pmatch[1].rm_so >= 0 ? 1 : 0;  	line += pmatch[i].rm_so;  	result = pmatch[i].rm_eo - pmatch[i].rm_so;  	if (result > buffer_size)  		result = buffer_size;  	else -		while (result > 0 && (isspace(line[result - 1]) || -					line[result - 1] == '\n')) +		while (result > 0 && (isspace(line[result - 1])))  			result--;  	memcpy(buffer, line, result); + fail:  	free(line_buffer);  	return result;  } -void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value) +void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)  {  	int i;  	struct ff_regs *regs; @@ -243,7 +246,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)  			expression = buffer = xstrndup(value, ep - value);  		else  			expression = value; -		if (regcomp(®->re, expression, 0)) +		if (regcomp(®->re, expression, cflags))  			die("Invalid regexp to look for hunk header: %s", expression);  		free(buffer);  		value = ep + 1; diff --git a/xdiff-interface.h b/xdiff-interface.h index b3b5c933bf..eaf9cd3498 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -16,7 +16,7 @@ int parse_hunk_header(char *line, int len,  int read_mmfile(mmfile_t *ptr, const char *filename);  int buffer_is_binary(const char *ptr, unsigned long size); -extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line); +extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);  extern int git_xmerge_config(const char *var, const char *value, void *cb);  extern int git_xmerge_style; | 
