Skip to content

Commit 9800c0d

Browse files
committed
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
2 parents 9ba929e + 5a139ba commit 9800c0d

15 files changed

+139
-120
lines changed

Documentation/gitattributes.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,13 +288,13 @@ for paths.
288288
*.tex diff=tex
289289
------------------------
290290

291-
Then, you would define a "diff.tex.funcname" configuration to
291+
Then, you would define a "diff.tex.xfuncname" configuration to
292292
specify a regular expression that matches a line that you would
293293
want to appear as the hunk header "TEXT", like this:
294294

295295
------------------------
296296
[diff "tex"]
297-
funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$"
297+
xfuncname = "^(\\\\(sub)*section\\{.*)$"
298298
------------------------
299299

300300
Note. A single level of backslashes are eaten by the

builtin-apply.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "delta.h"
1414
#include "builtin.h"
1515
#include "string-list.h"
16+
#include "dir.h"
1617

1718
/*
1819
* --check turns on checking that the working tree matches the
@@ -2735,15 +2736,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
27352736
warning("unable to remove submodule %s",
27362737
patch->old_name);
27372738
} else if (!unlink(patch->old_name) && rmdir_empty) {
2738-
char *name = xstrdup(patch->old_name);
2739-
char *end = strrchr(name, '/');
2740-
while (end) {
2741-
*end = 0;
2742-
if (rmdir(name))
2743-
break;
2744-
end = strrchr(name, '/');
2745-
}
2746-
free(name);
2739+
remove_path(patch->old_name);
27472740
}
27482741
}
27492742
}

builtin-commit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
639639
active_cache_tree = cache_tree();
640640
if (cache_tree_update(active_cache_tree,
641641
active_cache, active_nr, 0, 0) < 0) {
642-
error("Error building trees");
642+
error("Error building trees; the index is unmerged?");
643643
return 0;
644644
}
645645

builtin-for-each-ref.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,9 +320,7 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un
320320

321321
static const char *copy_line(const char *buf)
322322
{
323-
const char *eol = strchr(buf, '\n');
324-
if (!eol) // simulate strchrnul()
325-
eol = buf + strlen(buf);
323+
const char *eol = strchrnul(buf, '\n');
326324
return xmemdupz(buf, eol - buf);
327325
}
328326

builtin-remote.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -650,10 +650,13 @@ static int get_one_entry(struct remote *remote, void *priv)
650650
{
651651
struct string_list *list = priv;
652652

653-
string_list_append(remote->name, list)->util = remote->url_nr ?
654-
(void *)remote->url[0] : NULL;
655-
if (remote->url_nr > 1)
656-
warning("Remote %s has more than one URL", remote->name);
653+
if (remote->url_nr > 0) {
654+
int i;
655+
656+
for (i = 0; i < remote->url_nr; i++)
657+
string_list_append(remote->name, list)->util = (void *)remote->url[i];
658+
} else
659+
string_list_append(remote->name, list)->util = NULL;
657660

658661
return 0;
659662
}
@@ -669,10 +672,14 @@ static int show_all(void)
669672
sort_string_list(&list);
670673
for (i = 0; i < list.nr; i++) {
671674
struct string_list_item *item = list.items + i;
672-
printf("%s%s%s\n", item->string,
673-
verbose ? "\t" : "",
674-
verbose && item->util ?
675-
(const char *)item->util : "");
675+
if (verbose)
676+
printf("%s\t%s\n", item->string,
677+
item->util ? (const char *)item->util : "");
678+
else {
679+
if (i && !strcmp((item - 1)->string, item->string))
680+
continue;
681+
printf("%s\n", item->string);
682+
}
676683
}
677684
}
678685
return result;

builtin-rm.c

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,6 @@ static void add_list(const char *name)
2929
list.name[list.nr++] = name;
3030
}
3131

32-
static int remove_file(const char *name)
33-
{
34-
int ret;
35-
char *slash;
36-
37-
ret = unlink(name);
38-
if (ret && errno == ENOENT)
39-
/* The user has removed it from the filesystem by hand */
40-
ret = errno = 0;
41-
42-
if (!ret && (slash = strrchr(name, '/'))) {
43-
char *n = xstrdup(name);
44-
do {
45-
n[slash - name] = 0;
46-
name = n;
47-
} while (!rmdir(name) && (slash = strrchr(name, '/')));
48-
}
49-
return ret;
50-
}
51-
5232
static int check_local_mod(unsigned char *head, int index_only)
5333
{
5434
/* 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)
239219
int removed = 0;
240220
for (i = 0; i < list.nr; i++) {
241221
const char *path = list.name[i];
242-
if (!remove_file(path)) {
222+
if (!remove_path(path)) {
243223
removed = 1;
244224
continue;
245225
}

diff.c

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -96,32 +96,37 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
9696
* to define a customized regexp to find the beginning of a function to
9797
* be used for hunk header lines of "diff -p" style output.
9898
*/
99-
static struct funcname_pattern {
99+
struct funcname_pattern_entry {
100100
char *name;
101101
char *pattern;
102-
struct funcname_pattern *next;
102+
int cflags;
103+
};
104+
static struct funcname_pattern_list {
105+
struct funcname_pattern_list *next;
106+
struct funcname_pattern_entry e;
103107
} *funcname_pattern_list;
104108

105-
static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
109+
static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)
106110
{
107111
const char *name;
108112
int namelen;
109-
struct funcname_pattern *pp;
113+
struct funcname_pattern_list *pp;
110114

111115
name = var + 5; /* "diff." */
112116
namelen = ep - name;
113117

114118
for (pp = funcname_pattern_list; pp; pp = pp->next)
115-
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
119+
if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen])
116120
break;
117121
if (!pp) {
118122
pp = xcalloc(1, sizeof(*pp));
119-
pp->name = xmemdupz(name, namelen);
123+
pp->e.name = xmemdupz(name, namelen);
120124
pp->next = funcname_pattern_list;
121125
funcname_pattern_list = pp;
122126
}
123-
free(pp->pattern);
124-
pp->pattern = xstrdup(value);
127+
free(pp->e.pattern);
128+
pp->e.pattern = xstrdup(value);
129+
pp->e.cflags = cflags;
125130
return 0;
126131
}
127132

@@ -194,7 +199,13 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
194199
if (!strcmp(ep, ".funcname")) {
195200
if (!value)
196201
return config_error_nonbool(var);
197-
return parse_funcname_pattern(var, ep, value);
202+
return parse_funcname_pattern(var, ep, value,
203+
0);
204+
} else if (!strcmp(ep, ".xfuncname")) {
205+
if (!value)
206+
return config_error_nonbool(var);
207+
return parse_funcname_pattern(var, ep, value,
208+
REG_EXTENDED);
198209
}
199210
}
200211
}
@@ -1400,42 +1411,45 @@ int diff_filespec_is_binary(struct diff_filespec *one)
14001411
return one->is_binary;
14011412
}
14021413

1403-
static const char *funcname_pattern(const char *ident)
1414+
static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
14041415
{
1405-
struct funcname_pattern *pp;
1416+
struct funcname_pattern_list *pp;
14061417

14071418
for (pp = funcname_pattern_list; pp; pp = pp->next)
1408-
if (!strcmp(ident, pp->name))
1409-
return pp->pattern;
1419+
if (!strcmp(ident, pp->e.name))
1420+
return &pp->e;
14101421
return NULL;
14111422
}
14121423

1413-
static struct builtin_funcname_pattern {
1414-
const char *name;
1415-
const char *pattern;
1416-
} builtin_funcname_pattern[] = {
1417-
{ "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" },
1418-
{ "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$" },
1419-
{ "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
1420-
"new\\|return\\|switch\\|throw\\|while\\)\n"
1421-
"^[ ]*\\(\\([ ]*"
1422-
"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
1423-
"[ ]*([^;]*\\)$" },
1424-
{ "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
1425-
"destructor\\|interface\\|implementation\\|"
1426-
"initialization\\|finalization\\)[ \t]*.*\\)$"
1427-
"\\|"
1428-
"^\\(.*=[ \t]*\\(class\\|record\\).*\\)$"
1429-
},
1430-
{ "php", "^[\t ]*\\(\\(function\\|class\\).*\\)" },
1431-
{ "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" },
1432-
{ "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" },
1433-
{ "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" },
1424+
static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
1425+
{ "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
1426+
REG_EXTENDED },
1427+
{ "html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", REG_EXTENDED },
1428+
{ "java",
1429+
"!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
1430+
"^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
1431+
REG_EXTENDED },
1432+
{ "pascal",
1433+
"^((procedure|function|constructor|destructor|interface|"
1434+
"implementation|initialization|finalization)[ \t]*.*)$"
1435+
"\n"
1436+
"^(.*=[ \t]*(class|record).*)$",
1437+
REG_EXTENDED },
1438+
{ "php", "^[\t ]*((function|class).*)", REG_EXTENDED },
1439+
{ "python", "^[ \t]*((class|def)[ \t].*)$", REG_EXTENDED },
1440+
{ "ruby", "^[ \t]*((class|module|def)[ \t].*)$",
1441+
REG_EXTENDED },
1442+
{ "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
1443+
REG_EXTENDED },
1444+
{ "tex",
1445+
"^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
1446+
REG_EXTENDED },
14341447
};
14351448

1436-
static const char *diff_funcname_pattern(struct diff_filespec *one)
1449+
static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
14371450
{
1438-
const char *ident, *pattern;
1451+
const char *ident;
1452+
const struct funcname_pattern_entry *pe;
14391453
int i;
14401454

14411455
diff_filespec_check_attr(one);
@@ -1450,17 +1464,17 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
14501464
return funcname_pattern("default");
14511465

14521466
/* Look up custom "funcname.$ident" regexp from config. */
1453-
pattern = funcname_pattern(ident);
1454-
if (pattern)
1455-
return pattern;
1467+
pe = funcname_pattern(ident);
1468+
if (pe)
1469+
return pe;
14561470

14571471
/*
14581472
* And define built-in fallback patterns here. Note that
14591473
* these can be overridden by the user's config settings.
14601474
*/
14611475
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
14621476
if (!strcmp(ident, builtin_funcname_pattern[i].name))
1463-
return builtin_funcname_pattern[i].pattern;
1477+
return &builtin_funcname_pattern[i];
14641478

14651479
return NULL;
14661480
}
@@ -1556,11 +1570,11 @@ static void builtin_diff(const char *name_a,
15561570
xdemitconf_t xecfg;
15571571
xdemitcb_t ecb;
15581572
struct emit_callback ecbdata;
1559-
const char *funcname_pattern;
1573+
const struct funcname_pattern_entry *pe;
15601574

1561-
funcname_pattern = diff_funcname_pattern(one);
1562-
if (!funcname_pattern)
1563-
funcname_pattern = diff_funcname_pattern(two);
1575+
pe = diff_funcname_pattern(one);
1576+
if (!pe)
1577+
pe = diff_funcname_pattern(two);
15641578

15651579
memset(&xecfg, 0, sizeof(xecfg));
15661580
memset(&ecbdata, 0, sizeof(ecbdata));
@@ -1572,8 +1586,8 @@ static void builtin_diff(const char *name_a,
15721586
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
15731587
xecfg.ctxlen = o->context;
15741588
xecfg.flags = XDL_EMIT_FUNCNAMES;
1575-
if (funcname_pattern)
1576-
xdiff_set_find_func(&xecfg, funcname_pattern);
1589+
if (pe)
1590+
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
15771591
if (!diffopts)
15781592
;
15791593
else if (!prefixcmp(diffopts, "--unified="))

dir.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,3 +831,23 @@ void setup_standard_excludes(struct dir_struct *dir)
831831
if (excludes_file && !access(excludes_file, R_OK))
832832
add_excludes_from_file(dir, excludes_file);
833833
}
834+
835+
int remove_path(const char *name)
836+
{
837+
char *slash;
838+
839+
if (unlink(name) && errno != ENOENT)
840+
return -1;
841+
842+
slash = strrchr(name, '/');
843+
if (slash) {
844+
char *dirs = xstrdup(name);
845+
slash = dirs + (slash - name);
846+
do {
847+
*slash = '\0';
848+
} while (rmdir(dirs) && (slash = strrchr(dirs, '/')));
849+
free(dirs);
850+
}
851+
return 0;
852+
}
853+

dir.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,7 @@ extern int is_inside_dir(const char *dir);
8181
extern void setup_standard_excludes(struct dir_struct *dir);
8282
extern int remove_dir_recursively(struct strbuf *path, int only_empty);
8383

84+
/* tries to remove the path with empty directories along it, ignores ENOENT */
85+
extern int remove_path(const char *path);
86+
8487
#endif

git-stash.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ show_stash () {
161161
apply_stash () {
162162
git update-index -q --refresh &&
163163
git diff-files --quiet --ignore-submodules ||
164-
die 'Cannot restore on top of a dirty state'
164+
die 'Cannot apply to a dirty working tree, please stage your changes'
165165

166166
unstash_index=
167167
case "$1" in

0 commit comments

Comments
 (0)