зеркало из https://github.com/microsoft/git.git
Merge branch 'jc/maint-log-grep'
* jc/maint-log-grep: log --author/--committer: really match only with name part diff --cumulative is a sub-option of --dirstat bash completion: Hide more plumbing commands
This commit is contained in:
Коммит
80d12c23de
|
@ -386,7 +386,9 @@ __git_porcelain_commands ()
|
|||
cat-file) : plumbing;;
|
||||
check-attr) : plumbing;;
|
||||
check-ref-format) : plumbing;;
|
||||
checkout-index) : plumbing;;
|
||||
commit-tree) : plumbing;;
|
||||
count-objects) : infrequent;;
|
||||
cvsexportcommit) : export;;
|
||||
cvsimport) : import;;
|
||||
cvsserver) : daemon;;
|
||||
|
@ -395,6 +397,7 @@ __git_porcelain_commands ()
|
|||
diff-index) : plumbing;;
|
||||
diff-tree) : plumbing;;
|
||||
fast-import) : import;;
|
||||
fast-export) : export;;
|
||||
fsck-objects) : plumbing;;
|
||||
fetch-pack) : plumbing;;
|
||||
fmt-merge-msg) : plumbing;;
|
||||
|
@ -404,6 +407,10 @@ __git_porcelain_commands ()
|
|||
index-pack) : plumbing;;
|
||||
init-db) : deprecated;;
|
||||
local-fetch) : plumbing;;
|
||||
lost-found) : infrequent;;
|
||||
ls-files) : plumbing;;
|
||||
ls-remote) : plumbing;;
|
||||
ls-tree) : plumbing;;
|
||||
mailinfo) : plumbing;;
|
||||
mailsplit) : plumbing;;
|
||||
merge-*) : plumbing;;
|
||||
|
@ -428,6 +435,7 @@ __git_porcelain_commands ()
|
|||
runstatus) : plumbing;;
|
||||
sh-setup) : internal;;
|
||||
shell) : daemon;;
|
||||
show-ref) : plumbing;;
|
||||
send-pack) : plumbing;;
|
||||
show-index) : plumbing;;
|
||||
ssh-*) : transport;;
|
||||
|
@ -442,6 +450,8 @@ __git_porcelain_commands ()
|
|||
upload-archive) : plumbing;;
|
||||
upload-pack) : plumbing;;
|
||||
write-tree) : plumbing;;
|
||||
var) : infrequent;;
|
||||
verify-pack) : infrequent;;
|
||||
verify-tag) : plumbing;;
|
||||
*) echo $i;;
|
||||
esac
|
||||
|
|
9
diff.c
9
diff.c
|
@ -1078,7 +1078,7 @@ static void show_dirstat(struct diff_options *options)
|
|||
dir.alloc = 0;
|
||||
dir.nr = 0;
|
||||
dir.percent = options->dirstat_percent;
|
||||
dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE;
|
||||
dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE);
|
||||
|
||||
changed = 0;
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
|
@ -2300,6 +2300,7 @@ void diff_setup(struct diff_options *options)
|
|||
options->break_opt = -1;
|
||||
options->rename_limit = -1;
|
||||
options->dirstat_percent = 3;
|
||||
DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
|
||||
options->context = 3;
|
||||
|
||||
options->change = diff_change;
|
||||
|
@ -2472,8 +2473,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
|
|||
options->output_format |= DIFF_FORMAT_SHORTSTAT;
|
||||
else if (opt_arg(arg, 'X', "dirstat", &options->dirstat_percent))
|
||||
options->output_format |= DIFF_FORMAT_DIRSTAT;
|
||||
else if (!strcmp(arg, "--cumulative"))
|
||||
options->output_format |= DIFF_FORMAT_CUMULATIVE;
|
||||
else if (!strcmp(arg, "--cumulative")) {
|
||||
options->output_format |= DIFF_FORMAT_DIRSTAT;
|
||||
DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
|
||||
}
|
||||
else if (!strcmp(arg, "--check"))
|
||||
options->output_format |= DIFF_FORMAT_CHECKDIFF;
|
||||
else if (!strcmp(arg, "--summary"))
|
||||
|
|
2
diff.h
2
diff.h
|
@ -31,7 +31,6 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
|
|||
#define DIFF_FORMAT_PATCH 0x0010
|
||||
#define DIFF_FORMAT_SHORTSTAT 0x0020
|
||||
#define DIFF_FORMAT_DIRSTAT 0x0040
|
||||
#define DIFF_FORMAT_CUMULATIVE 0x0080
|
||||
|
||||
/* These override all above */
|
||||
#define DIFF_FORMAT_NAME 0x0100
|
||||
|
@ -64,6 +63,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
|
|||
#define DIFF_OPT_CHECK_FAILED (1 << 16)
|
||||
#define DIFF_OPT_RELATIVE_NAME (1 << 17)
|
||||
#define DIFF_OPT_IGNORE_SUBMODULES (1 << 18)
|
||||
#define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19)
|
||||
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
|
||||
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
|
||||
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)
|
||||
|
|
52
grep.c
52
grep.c
|
@ -2,6 +2,19 @@
|
|||
#include "grep.h"
|
||||
#include "xdiff-interface.h"
|
||||
|
||||
void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat)
|
||||
{
|
||||
struct grep_pat *p = xcalloc(1, sizeof(*p));
|
||||
p->pattern = pat;
|
||||
p->origin = "header";
|
||||
p->no = 0;
|
||||
p->token = GREP_PATTERN_HEAD;
|
||||
p->field = field;
|
||||
*opt->pattern_tail = p;
|
||||
opt->pattern_tail = &p->next;
|
||||
p->next = NULL;
|
||||
}
|
||||
|
||||
void append_grep_pattern(struct grep_opt *opt, const char *pat,
|
||||
const char *origin, int no, enum grep_pat_token t)
|
||||
{
|
||||
|
@ -247,16 +260,53 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match)
|
|||
}
|
||||
}
|
||||
|
||||
static int strip_timestamp(char *bol, char **eol_p)
|
||||
{
|
||||
char *eol = *eol_p;
|
||||
int ch;
|
||||
|
||||
while (bol < --eol) {
|
||||
if (*eol != '>')
|
||||
continue;
|
||||
*eol_p = ++eol;
|
||||
ch = *eol;
|
||||
*eol = '\0';
|
||||
return ch;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *field;
|
||||
size_t len;
|
||||
} header_field[] = {
|
||||
{ "author ", 7 },
|
||||
{ "committer ", 10 },
|
||||
};
|
||||
|
||||
static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx)
|
||||
{
|
||||
int hit = 0;
|
||||
int at_true_bol = 1;
|
||||
int saved_ch = 0;
|
||||
regmatch_t pmatch[10];
|
||||
|
||||
if ((p->token != GREP_PATTERN) &&
|
||||
((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
|
||||
return 0;
|
||||
|
||||
if (p->token == GREP_PATTERN_HEAD) {
|
||||
const char *field;
|
||||
size_t len;
|
||||
assert(p->field < ARRAY_SIZE(header_field));
|
||||
field = header_field[p->field].field;
|
||||
len = header_field[p->field].len;
|
||||
if (strncmp(bol, field, len))
|
||||
return 0;
|
||||
bol += len;
|
||||
saved_ch = strip_timestamp(bol, &eol);
|
||||
}
|
||||
|
||||
again:
|
||||
if (!opt->fixed) {
|
||||
regex_t *exp = &p->regexp;
|
||||
|
@ -298,6 +348,8 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
|
|||
goto again;
|
||||
}
|
||||
}
|
||||
if (p->token == GREP_PATTERN_HEAD && saved_ch)
|
||||
*eol = saved_ch;
|
||||
return hit;
|
||||
}
|
||||
|
||||
|
|
7
grep.h
7
grep.h
|
@ -17,12 +17,18 @@ enum grep_context {
|
|||
GREP_CONTEXT_BODY,
|
||||
};
|
||||
|
||||
enum grep_header_field {
|
||||
GREP_HEADER_AUTHOR = 0,
|
||||
GREP_HEADER_COMMITTER,
|
||||
};
|
||||
|
||||
struct grep_pat {
|
||||
struct grep_pat *next;
|
||||
const char *origin;
|
||||
int no;
|
||||
enum grep_pat_token token;
|
||||
const char *pattern;
|
||||
enum grep_header_field field;
|
||||
regex_t regexp;
|
||||
};
|
||||
|
||||
|
@ -74,6 +80,7 @@ struct grep_opt {
|
|||
};
|
||||
|
||||
extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
|
||||
extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
|
||||
extern void compile_grep_patterns(struct grep_opt *opt);
|
||||
extern void free_grep_patterns(struct grep_opt *opt);
|
||||
extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size);
|
||||
|
|
21
revision.c
21
revision.c
|
@ -953,22 +953,9 @@ static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token
|
|||
append_grep_pattern(&revs->grep_filter, ptn, "command line", 0, what);
|
||||
}
|
||||
|
||||
static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern)
|
||||
static void add_header_grep(struct rev_info *revs, enum grep_header_field field, const char *pattern)
|
||||
{
|
||||
char *pat;
|
||||
const char *prefix;
|
||||
int patlen, fldlen;
|
||||
|
||||
fldlen = strlen(field);
|
||||
patlen = strlen(pattern);
|
||||
pat = xmalloc(patlen + fldlen + 10);
|
||||
prefix = ".*";
|
||||
if (*pattern == '^') {
|
||||
prefix = "";
|
||||
pattern++;
|
||||
}
|
||||
sprintf(pat, "^%s %s%s", field, prefix, pattern);
|
||||
add_grep(revs, pat, GREP_PATTERN_HEAD);
|
||||
append_header_grep_pattern(&revs->grep_filter, field, pattern);
|
||||
}
|
||||
|
||||
static void add_message_grep(struct rev_info *revs, const char *pattern)
|
||||
|
@ -1159,9 +1146,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
|||
* Grepping the commit log
|
||||
*/
|
||||
else if (!prefixcmp(arg, "--author=")) {
|
||||
add_header_grep(revs, "author", arg+9);
|
||||
add_header_grep(revs, GREP_HEADER_AUTHOR, arg+9);
|
||||
} else if (!prefixcmp(arg, "--committer=")) {
|
||||
add_header_grep(revs, "committer", arg+12);
|
||||
add_header_grep(revs, GREP_HEADER_COMMITTER, arg+12);
|
||||
} else if (!prefixcmp(arg, "--grep=")) {
|
||||
add_message_grep(revs, arg+7);
|
||||
} else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
|
||||
|
|
|
@ -22,6 +22,7 @@ test_expect_success setup '
|
|||
mkdir t &&
|
||||
echo test >t/t &&
|
||||
git add file x y z t/t &&
|
||||
test_tick &&
|
||||
git commit -m initial
|
||||
'
|
||||
|
||||
|
@ -113,4 +114,54 @@ do
|
|||
|
||||
done
|
||||
|
||||
test_expect_success 'log grep setup' '
|
||||
echo a >>file &&
|
||||
test_tick &&
|
||||
GIT_AUTHOR_NAME="With * Asterisk" \
|
||||
GIT_AUTHOR_EMAIL="xyzzy@frotz.com" \
|
||||
git commit -a -m "second" &&
|
||||
|
||||
echo a >>file &&
|
||||
test_tick &&
|
||||
git commit -a -m "third"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'log grep (1)' '
|
||||
git log --author=author --pretty=tformat:%s >actual &&
|
||||
( echo third ; echo initial ) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log grep (2)' '
|
||||
git log --author=" * " -F --pretty=tformat:%s >actual &&
|
||||
( echo second ) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log grep (3)' '
|
||||
git log --author="^A U" --pretty=tformat:%s >actual &&
|
||||
( echo third ; echo initial ) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log grep (4)' '
|
||||
git log --author="frotz\.com>$" --pretty=tformat:%s >actual &&
|
||||
( echo second ) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log grep (5)' '
|
||||
git log --author=Thor -F --grep=Thu --pretty=tformat:%s >actual &&
|
||||
( echo third ; echo initial ) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log grep (6)' '
|
||||
git log --author=-0700 --pretty=tformat:%s >actual &&
|
||||
>expect &&
|
||||
test_cmp expect actual
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Загрузка…
Ссылка в новой задаче