mirror of
https://github.com/git/git.git
synced 2026-03-12 09:59:45 +01:00
Merge branch 'by/line-log' into next
* by/line-log: Document line history browser Add tests for line history browser Add --full-line-diff option Add --graph prefix before line history output Add parent rewriting to line history browser Make graph_next_line external to other part of git Make rewrite_parents public to other part of git Hook line history into cmd_log, ensuring a topo-ordered walk Print the line log map/take range to the parent of commits Add range clone functions Export three functions from diff.c Parse the -L options Refactor parse_loc Add the basic data structure for line level history parse-options: add two helper functions parse-options: enhance STOP_AT_NON_OPTION Conflicts: builtin/log.c
This commit is contained in:
@@ -13,24 +13,7 @@
|
||||
Annotate only the given line range. <start> and <end> can take
|
||||
one of these forms:
|
||||
|
||||
- number
|
||||
+
|
||||
If <start> or <end> is a number, it specifies an
|
||||
absolute line number (lines count from 1).
|
||||
+
|
||||
|
||||
- /regex/
|
||||
+
|
||||
This form will use the first line matching the given
|
||||
POSIX regex. If <end> is a regex, it will search
|
||||
starting at the line given by <start>.
|
||||
+
|
||||
|
||||
- +offset or -offset
|
||||
+
|
||||
This is only valid for <end> and will specify a number
|
||||
of lines before or after the line given by <start>.
|
||||
+
|
||||
include::line-range-format.txt[]
|
||||
|
||||
-l::
|
||||
Show long rev (Default: off).
|
||||
|
||||
@@ -9,6 +9,7 @@ git-log - Show commit logs
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git log' [<options>] [<since>..<until>] [[\--] <path>...]
|
||||
'git log' [<options>] -L n,m <path>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -19,6 +20,9 @@ command to control what is shown and how, and options applicable to
|
||||
the 'git diff-*' commands to control how the changes
|
||||
each commit introduces are shown.
|
||||
|
||||
With '-L' option, the command will help to trace the history of user specified
|
||||
line ranges. It can trace multiple ranges coming from multiple files.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@@ -66,6 +70,17 @@ produced by --stat etc.
|
||||
Note that only message is considered, if also a diff is shown
|
||||
its size is not included.
|
||||
|
||||
-L <start>,<end>::
|
||||
The line range. <start> and <end> can take one of these forms:
|
||||
|
||||
include::line-range-format.txt[]
|
||||
You can also specify this option more than once before each path.
|
||||
|
||||
|
||||
--full-line-diff::
|
||||
Always print the interesting range even if the current commit
|
||||
does not change any line of the range.
|
||||
|
||||
[\--] <path>...::
|
||||
Show only commits that affect any of the specified paths. To
|
||||
prevent confusion with options and branch names, paths may need
|
||||
|
||||
18
Documentation/line-range-format.txt
Normal file
18
Documentation/line-range-format.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
- number
|
||||
+
|
||||
If <start> or <end> is a number, it specifies an
|
||||
absolute line number (lines count from 1).
|
||||
+
|
||||
|
||||
- /regex/
|
||||
+
|
||||
This form will use the first line matching the given
|
||||
POSIX regex. If <end> is a regex, it will search
|
||||
starting at the line given by <start>.
|
||||
+
|
||||
|
||||
- +offset or -offset
|
||||
+
|
||||
This is only valid for <end> and will specify a number
|
||||
of lines before or after the line given by <start>.
|
||||
+
|
||||
2
Makefile
2
Makefile
@@ -518,6 +518,7 @@ LIB_H += grep.h
|
||||
LIB_H += hash.h
|
||||
LIB_H += help.h
|
||||
LIB_H += levenshtein.h
|
||||
LIB_H += line.h
|
||||
LIB_H += list-objects.h
|
||||
LIB_H += ll-merge.h
|
||||
LIB_H += log-tree.h
|
||||
@@ -608,6 +609,7 @@ LIB_OBJS += help.o
|
||||
LIB_OBJS += hex.o
|
||||
LIB_OBJS += ident.o
|
||||
LIB_OBJS += levenshtein.o
|
||||
LIB_OBJS += line.o
|
||||
LIB_OBJS += list-objects.o
|
||||
LIB_OBJS += ll-merge.o
|
||||
LIB_OBJS += lockfile.o
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "parse-options.h"
|
||||
#include "utf8.h"
|
||||
#include "userdiff.h"
|
||||
#include "line.h"
|
||||
|
||||
static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file";
|
||||
|
||||
@@ -541,11 +542,16 @@ static void dup_entry(struct blame_entry *dst, struct blame_entry *src)
|
||||
dst->score = 0;
|
||||
}
|
||||
|
||||
static const char *nth_line(struct scoreboard *sb, int lno)
|
||||
static const char *nth_line(struct scoreboard *sb, long lno)
|
||||
{
|
||||
return sb->final_buf + sb->lineno[lno];
|
||||
}
|
||||
|
||||
static const char *nth_line_cb(void *data, long lno)
|
||||
{
|
||||
return nth_line((struct scoreboard *)data, lno);
|
||||
}
|
||||
|
||||
/*
|
||||
* It is known that lines between tlno to same came from parent, and e
|
||||
* has an overlap with that range. it also is known that parent's
|
||||
@@ -1898,83 +1904,6 @@ static const char *add_prefix(const char *prefix, const char *path)
|
||||
return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing of (comma separated) one item in the -L option
|
||||
*/
|
||||
static const char *parse_loc(const char *spec,
|
||||
struct scoreboard *sb, long lno,
|
||||
long begin, long *ret)
|
||||
{
|
||||
char *term;
|
||||
const char *line;
|
||||
long num;
|
||||
int reg_error;
|
||||
regex_t regexp;
|
||||
regmatch_t match[1];
|
||||
|
||||
/* Allow "-L <something>,+20" to mean starting at <something>
|
||||
* for 20 lines, or "-L <something>,-5" for 5 lines ending at
|
||||
* <something>.
|
||||
*/
|
||||
if (1 < begin && (spec[0] == '+' || spec[0] == '-')) {
|
||||
num = strtol(spec + 1, &term, 10);
|
||||
if (term != spec + 1) {
|
||||
if (spec[0] == '-')
|
||||
num = 0 - num;
|
||||
if (0 < num)
|
||||
*ret = begin + num - 2;
|
||||
else if (!num)
|
||||
*ret = begin;
|
||||
else
|
||||
*ret = begin + num;
|
||||
return term;
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
num = strtol(spec, &term, 10);
|
||||
if (term != spec) {
|
||||
*ret = num;
|
||||
return term;
|
||||
}
|
||||
if (spec[0] != '/')
|
||||
return spec;
|
||||
|
||||
/* it could be a regexp of form /.../ */
|
||||
for (term = (char *) spec + 1; *term && *term != '/'; term++) {
|
||||
if (*term == '\\')
|
||||
term++;
|
||||
}
|
||||
if (*term != '/')
|
||||
return spec;
|
||||
|
||||
/* try [spec+1 .. term-1] as regexp */
|
||||
*term = 0;
|
||||
begin--; /* input is in human terms */
|
||||
line = nth_line(sb, begin);
|
||||
|
||||
if (!(reg_error = regcomp(®exp, spec + 1, REG_NEWLINE)) &&
|
||||
!(reg_error = regexec(®exp, line, 1, match, 0))) {
|
||||
const char *cp = line + match[0].rm_so;
|
||||
const char *nline;
|
||||
|
||||
while (begin++ < lno) {
|
||||
nline = nth_line(sb, begin);
|
||||
if (line <= cp && cp < nline)
|
||||
break;
|
||||
line = nline;
|
||||
}
|
||||
*ret = begin;
|
||||
regfree(®exp);
|
||||
*term++ = '/';
|
||||
return term;
|
||||
}
|
||||
else {
|
||||
char errbuf[1024];
|
||||
regerror(reg_error, ®exp, errbuf, 1024);
|
||||
die("-L parameter '%s': %s", spec + 1, errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing of -L option
|
||||
*/
|
||||
@@ -1985,9 +1914,9 @@ static void prepare_blame_range(struct scoreboard *sb,
|
||||
{
|
||||
const char *term;
|
||||
|
||||
term = parse_loc(bottomtop, sb, lno, 1, bottom);
|
||||
term = parse_loc(bottomtop, nth_line_cb, sb, lno, 1, bottom);
|
||||
if (*term == ',') {
|
||||
term = parse_loc(term + 1, sb, lno, *bottom + 1, top);
|
||||
term = parse_loc(term + 1, nth_line_cb, sb, lno, *bottom + 1, top);
|
||||
if (*term)
|
||||
usage(blame_usage);
|
||||
}
|
||||
|
||||
113
builtin/log.c
113
builtin/log.c
@@ -19,6 +19,7 @@
|
||||
#include "remote.h"
|
||||
#include "string-list.h"
|
||||
#include "parse-options.h"
|
||||
#include "line.h"
|
||||
|
||||
/* Set a default date-time format for git log ("log.date" config variable) */
|
||||
static const char *default_date_mode = NULL;
|
||||
@@ -27,11 +28,24 @@ static int default_show_root = 1;
|
||||
static int decoration_style;
|
||||
static const char *fmt_patch_subject_prefix = "PATCH";
|
||||
static const char *fmt_pretty;
|
||||
static const char *dashdash = "--";
|
||||
|
||||
static const char * const builtin_log_usage =
|
||||
static char builtin_log_usage[] =
|
||||
"git log [<options>] [<since>..<until>] [[--] <path>...]\n"
|
||||
"git log [<options>] -L n,m <path>\n"
|
||||
" or: git show [options] <object>...";
|
||||
|
||||
static const char *log_opt_usage[] = {
|
||||
builtin_log_usage,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct line_opt_callback_data {
|
||||
struct diff_line_range **range;
|
||||
struct parse_opt_ctx_t *ctx;
|
||||
struct rev_info *rev;
|
||||
};
|
||||
|
||||
static int parse_decoration_style(const char *var, const char *value)
|
||||
{
|
||||
switch (git_config_maybe_bool(var, value)) {
|
||||
@@ -49,12 +63,48 @@ static int parse_decoration_style(const char *var, const char *value)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int log_line_range_callback(const struct option *option, const char *arg, int unset)
|
||||
{
|
||||
struct line_opt_callback_data *data = option->value;
|
||||
struct diff_line_range *r = *data->range;
|
||||
struct parse_opt_ctx_t *ctx = data->ctx;
|
||||
|
||||
if (!arg)
|
||||
return -1;
|
||||
|
||||
if (r->nr == 0 && r->next == NULL)
|
||||
ctx->out[ctx->cpidx++] = dashdash;
|
||||
|
||||
diff_line_range_append(r, arg);
|
||||
data->rev->line_level_traverse = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
struct rev_info *rev, struct setup_revision_opt *opt)
|
||||
{
|
||||
int i;
|
||||
int decoration_given = 0;
|
||||
static int full_line_diff;
|
||||
struct userformat_want w;
|
||||
const char *path = NULL, *fullpath = NULL;
|
||||
static struct diff_line_range *range;
|
||||
struct diff_line_range *r = NULL;
|
||||
static struct parse_opt_ctx_t ctx;
|
||||
static struct line_opt_callback_data line_cb = {&range, &ctx, NULL};
|
||||
static const struct option options[] = {
|
||||
OPT_CALLBACK('L', NULL, &line_cb, "n,m",
|
||||
"Process only line range n,m, counting from 1",
|
||||
log_line_range_callback),
|
||||
OPT_BOOLEAN(0, "full-line-diff", &full_line_diff,
|
||||
"Always print the interesting range even if the \
|
||||
current commit does not change any line of it"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
line_cb.rev = rev;
|
||||
range = xmalloc(sizeof(*range));
|
||||
DIFF_LINE_RANGE_INIT(range);
|
||||
|
||||
rev->abbrev = DEFAULT_ABBREV;
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
@@ -75,6 +125,56 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
*/
|
||||
if (argc == 2 && !strcmp(argv[1], "-h"))
|
||||
usage(builtin_log_usage);
|
||||
|
||||
parse_options_start(&ctx, argc, argv, prefix, PARSE_OPT_KEEP_DASHDASH |
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
for (;;) {
|
||||
switch (parse_options_step(&ctx, options, log_opt_usage)) {
|
||||
case PARSE_OPT_HELP:
|
||||
exit(129);
|
||||
case PARSE_OPT_DONE:
|
||||
goto parse_done;
|
||||
case PARSE_OPT_NON_OPTION:
|
||||
path = parse_options_current(&ctx);
|
||||
fullpath = prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
|
||||
range->spec = alloc_filespec(fullpath);
|
||||
free((void *)fullpath);
|
||||
if (range->nr == 0) {
|
||||
if (range->next) {
|
||||
die("Path %s need a -L <range> option\n"
|
||||
"If you want follow the history of the whole file "
|
||||
"use 'git log -L 1,$ <path>'", range->spec->path);
|
||||
} else {
|
||||
parse_options_next(&ctx, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
r = xmalloc(sizeof(*r));
|
||||
DIFF_LINE_RANGE_INIT(r);
|
||||
r->next = range;
|
||||
range = r;
|
||||
parse_options_next(&ctx, 1);
|
||||
continue;
|
||||
case PARSE_OPT_UNKNOWN:
|
||||
parse_options_next(&ctx, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
parse_revision_opt(rev, &ctx, options, log_opt_usage);
|
||||
}
|
||||
parse_done:
|
||||
argc = parse_options_end(&ctx);
|
||||
|
||||
/* die if '-L <range>' with no pathspec follow */
|
||||
if (range->nr > 0 && range->spec == NULL)
|
||||
die("Each -L should follow a path");
|
||||
/* clear up the last range */
|
||||
if (range->nr == 0) {
|
||||
struct diff_line_range *r = range->next;
|
||||
DIFF_LINE_RANGE_CLEAR(range);
|
||||
range = r;
|
||||
}
|
||||
|
||||
argc = setup_revisions(argc, argv, rev, opt);
|
||||
|
||||
memset(&w, 0, sizeof(w));
|
||||
@@ -125,6 +225,12 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
rev->show_decorations = 1;
|
||||
load_ref_decorations(decoration_style);
|
||||
}
|
||||
|
||||
/* Test whether line level history is asked for */
|
||||
if (range && range->nr > 0) {
|
||||
setup_line(rev, range);
|
||||
rev->full_line_diff = full_line_diff;
|
||||
}
|
||||
setup_pager();
|
||||
}
|
||||
|
||||
@@ -510,7 +616,10 @@ int cmd_log(int argc, const char **argv, const char *prefix)
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
opt.def = "HEAD";
|
||||
cmd_log_init(argc, argv, prefix, &rev, &opt);
|
||||
return cmd_log_walk(&rev);
|
||||
if (rev.line_level_traverse)
|
||||
return cmd_line_log_walk(&rev);
|
||||
else
|
||||
return cmd_log_walk(&rev);
|
||||
}
|
||||
|
||||
/* format-patch */
|
||||
|
||||
6
diff.c
6
diff.c
@@ -151,7 +151,7 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
|
||||
return git_color_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
static char *quote_two(const char *one, const char *two)
|
||||
char *quote_two(const char *one, const char *two)
|
||||
{
|
||||
int need_one = quote_c_style(one, NULL, NULL, 1);
|
||||
int need_two = quote_c_style(two, NULL, NULL, 1);
|
||||
@@ -332,7 +332,7 @@ static void emit_line_0(struct diff_options *o, const char *set, const char *res
|
||||
fputc('\n', file);
|
||||
}
|
||||
|
||||
static void emit_line(struct diff_options *o, const char *set, const char *reset,
|
||||
void emit_line(struct diff_options *o, const char *set, const char *reset,
|
||||
const char *line, int len)
|
||||
{
|
||||
emit_line_0(o, set, reset, line[0], line+1, len-1);
|
||||
@@ -2571,7 +2571,7 @@ static int similarity_index(struct diff_filepair *p)
|
||||
return p->score * 100 / MAX_SCORE;
|
||||
}
|
||||
|
||||
static void fill_metainfo(struct strbuf *msg,
|
||||
void fill_metainfo(struct strbuf *msg,
|
||||
const char *name,
|
||||
const char *other,
|
||||
struct diff_filespec *one,
|
||||
|
||||
17
diff.h
17
diff.h
@@ -12,6 +12,7 @@ struct diff_queue_struct;
|
||||
struct strbuf;
|
||||
struct diff_filespec;
|
||||
struct userdiff_driver;
|
||||
struct diff_filepair;
|
||||
|
||||
typedef void (*change_fn_t)(struct diff_options *options,
|
||||
unsigned old_mode, unsigned new_mode,
|
||||
@@ -312,4 +313,20 @@ extern size_t fill_textconv(struct userdiff_driver *driver,
|
||||
|
||||
extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
|
||||
|
||||
/* some output functions line.c need */
|
||||
extern void fill_metainfo(struct strbuf *msg,
|
||||
const char *name,
|
||||
const char *other,
|
||||
struct diff_filespec *one,
|
||||
struct diff_filespec *two,
|
||||
struct diff_options *o,
|
||||
struct diff_filepair *p,
|
||||
int *must_show_header,
|
||||
int use_color);
|
||||
|
||||
extern void emit_line(struct diff_options *o, const char *set, const char *reset,
|
||||
const char *line, int len);
|
||||
|
||||
extern char *quote_two(const char *one, const char *two);
|
||||
|
||||
#endif /* DIFF_H */
|
||||
|
||||
141
line.h
Normal file
141
line.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifndef LINE_H
|
||||
#define LINE_H
|
||||
|
||||
#include "diffcore.h"
|
||||
|
||||
struct rev_info;
|
||||
struct commit;
|
||||
struct diff_line_range;
|
||||
struct diff_options;
|
||||
|
||||
typedef const char *(*nth_line_fn_t)(void *data, long lno);
|
||||
|
||||
struct print_range {
|
||||
int start, end; /* Line range of post-image */
|
||||
int pstart, pend; /* Line range of pre-image */
|
||||
int line_added : 1; /* whether this range is added */
|
||||
};
|
||||
|
||||
struct print_pair {
|
||||
int alloc, nr;
|
||||
struct print_range *ranges;
|
||||
};
|
||||
|
||||
#define PRINT_RANGE_INIT(r) \
|
||||
do { \
|
||||
(r)->start = (r)->end = 0; \
|
||||
(r)->pstart = (r)->pend = 0; \
|
||||
(r)->line_added = 0; \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_PAIR_INIT(p) \
|
||||
do { \
|
||||
(p)->alloc = (p)->nr = 0; \
|
||||
(p)->ranges = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_PAIR_GROW(p) \
|
||||
do { \
|
||||
(p)->nr++; \
|
||||
ALLOC_GROW((p)->ranges, (p)->nr, (p)->alloc); \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_PAIR_CLEAR(p) \
|
||||
do { \
|
||||
(p)->alloc = (p)->nr = 0; \
|
||||
if ((p)->ranges) \
|
||||
free((p)->ranges); \
|
||||
(p)->ranges = NULL; \
|
||||
} while (0)
|
||||
|
||||
struct line_range {
|
||||
const char *arg; /* The argument to specify this line range */
|
||||
long start, end; /* The interesting line range of current commit */
|
||||
long pstart, pend; /* The corresponding range of parent commit */
|
||||
struct print_pair pair;
|
||||
/* The changed lines inside this range */
|
||||
unsigned int diff:1;
|
||||
};
|
||||
|
||||
struct diff_line_range {
|
||||
struct diff_filespec *prev;
|
||||
struct diff_filespec *spec;
|
||||
char status;
|
||||
int alloc;
|
||||
int nr;
|
||||
struct line_range *ranges;
|
||||
unsigned int touch:1,
|
||||
diff:1;
|
||||
struct diff_line_range *next;
|
||||
};
|
||||
|
||||
#define RANGE_INIT(r) \
|
||||
do { \
|
||||
(r)->arg = NULL; \
|
||||
(r)->start = (r)->end = 0; \
|
||||
(r)->pstart = (r)->pend = 0; \
|
||||
PRINT_PAIR_INIT(&((r)->pair)); \
|
||||
(r)->diff = 0; \
|
||||
} while (0)
|
||||
|
||||
#define RANGE_CLEAR(r) \
|
||||
do { \
|
||||
(r)->arg = NULL; \
|
||||
(r)->start = (r)->end = 0; \
|
||||
(r)->pstart = (r)->pend = 0; \
|
||||
PRINT_PAIR_CLEAR(&r->pair); \
|
||||
(r)->diff = 0; \
|
||||
} while (0)
|
||||
|
||||
#define DIFF_LINE_RANGE_INIT(r) \
|
||||
do { \
|
||||
(r)->prev = (r)->spec = NULL; \
|
||||
(r)->status = '\0'; \
|
||||
(r)->alloc = (r)->nr = 0; \
|
||||
(r)->ranges = NULL; \
|
||||
(r)->next = NULL; \
|
||||
(r)->touch = 0; \
|
||||
(r)->diff = 0; \
|
||||
} while (0)
|
||||
|
||||
#define DIFF_LINE_RANGE_GROW(r) \
|
||||
do { \
|
||||
(r)->nr++; \
|
||||
ALLOC_GROW((r)->ranges, (r)->nr, (r)->alloc); \
|
||||
RANGE_INIT(((r)->ranges + (r)->nr - 1)); \
|
||||
} while (0)
|
||||
|
||||
#define DIFF_LINE_RANGE_CLEAR(r) \
|
||||
diff_line_range_clear((r));
|
||||
|
||||
extern struct line_range *diff_line_range_insert(struct diff_line_range *r,
|
||||
const char *arg, int start, int end);
|
||||
|
||||
extern void diff_line_range_append(struct diff_line_range *r, const char *arg);
|
||||
|
||||
extern void diff_line_range_clear(struct diff_line_range *r);
|
||||
|
||||
extern struct diff_line_range *diff_line_range_merge(
|
||||
struct diff_line_range *out,
|
||||
struct diff_line_range *other);
|
||||
|
||||
extern struct diff_line_range *diff_line_range_clone(struct diff_line_range *r);
|
||||
|
||||
extern struct diff_line_range *diff_line_range_clone_deeply(struct diff_line_range *r);
|
||||
|
||||
extern void setup_line(struct rev_info *rev, struct diff_line_range *r);
|
||||
|
||||
extern void add_line_range(struct rev_info *revs, struct commit *commit,
|
||||
struct diff_line_range *r);
|
||||
|
||||
extern struct diff_line_range *lookup_line_range(struct rev_info *revs,
|
||||
struct commit *commit);
|
||||
|
||||
const char *parse_loc(const char *spec, nth_line_fn_t nth_line,
|
||||
void *data, long lines, long begin, long *ret);
|
||||
|
||||
extern int cmd_line_log_walk(struct rev_info *rev);
|
||||
|
||||
extern void limit_list_line(struct rev_info *rev);
|
||||
|
||||
#endif
|
||||
@@ -374,7 +374,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
|
||||
if (parse_nodash_opt(ctx, arg, options) == 0)
|
||||
continue;
|
||||
if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
|
||||
break;
|
||||
return PARSE_OPT_NON_OPTION;
|
||||
ctx->out[ctx->cpidx++] = ctx->argv[0];
|
||||
continue;
|
||||
}
|
||||
@@ -439,6 +439,25 @@ unknown:
|
||||
return PARSE_OPT_DONE;
|
||||
}
|
||||
|
||||
const char *parse_options_current(struct parse_opt_ctx_t *ctx)
|
||||
{
|
||||
return ctx->argv[0];
|
||||
}
|
||||
|
||||
int parse_options_next(struct parse_opt_ctx_t *ctx, int keep)
|
||||
{
|
||||
if (ctx->argc <= 0)
|
||||
return -1;
|
||||
|
||||
if (keep)
|
||||
ctx->out[ctx->cpidx++] = ctx->argv[0];
|
||||
|
||||
ctx->argc--;
|
||||
ctx->argv++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_options_end(struct parse_opt_ctx_t *ctx)
|
||||
{
|
||||
memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
|
||||
@@ -456,6 +475,7 @@ int parse_options(int argc, const char **argv, const char *prefix,
|
||||
switch (parse_options_step(&ctx, options, usagestr)) {
|
||||
case PARSE_OPT_HELP:
|
||||
exit(129);
|
||||
case PARSE_OPT_NON_OPTION:
|
||||
case PARSE_OPT_DONE:
|
||||
break;
|
||||
default: /* PARSE_OPT_UNKNOWN */
|
||||
|
||||
@@ -161,7 +161,8 @@ extern NORETURN void usage_msg_opt(const char *msg,
|
||||
enum {
|
||||
PARSE_OPT_HELP = -1,
|
||||
PARSE_OPT_DONE,
|
||||
PARSE_OPT_UNKNOWN
|
||||
PARSE_OPT_NON_OPTION,
|
||||
PARSE_OPT_UNKNOWN,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -186,6 +187,10 @@ extern int parse_options_step(struct parse_opt_ctx_t *ctx,
|
||||
const struct option *options,
|
||||
const char * const usagestr[]);
|
||||
|
||||
extern const char *parse_options_current(struct parse_opt_ctx_t *ctx);
|
||||
|
||||
extern int parse_options_next(struct parse_opt_ctx_t *ctx, int keep);
|
||||
|
||||
extern int parse_options_end(struct parse_opt_ctx_t *ctx);
|
||||
|
||||
extern int parse_options_concat(struct option *dst, size_t, struct option *src);
|
||||
|
||||
25
revision.c
25
revision.c
@@ -13,6 +13,7 @@
|
||||
#include "decorate.h"
|
||||
#include "log-tree.h"
|
||||
#include "string-list.h"
|
||||
#include "line.h"
|
||||
|
||||
volatile show_early_output_fn_t show_early_output;
|
||||
|
||||
@@ -1662,6 +1663,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
|
||||
if (revs->combine_merges)
|
||||
revs->ignore_merges = 0;
|
||||
revs->diffopt.abbrev = revs->abbrev;
|
||||
|
||||
if (revs->line_level_traverse) {
|
||||
revs->limited = 1;
|
||||
revs->topo_order = 1;
|
||||
}
|
||||
|
||||
if (diff_setup_done(&revs->diffopt) < 0)
|
||||
die("diff_setup_done failed");
|
||||
|
||||
@@ -1905,6 +1912,11 @@ int prepare_revision_walk(struct rev_info *revs)
|
||||
return -1;
|
||||
if (revs->topo_order)
|
||||
sort_in_topological_order(&revs->commits, revs->lifo);
|
||||
if (revs->full_line_diff)
|
||||
revs->dense = 0;
|
||||
if (revs->rewrite_parents && revs->line_level_traverse
|
||||
&& !revs->full_line_diff)
|
||||
limit_list_line(revs);
|
||||
if (revs->simplify_merges)
|
||||
simplify_merges(revs);
|
||||
if (revs->children.name)
|
||||
@@ -1912,12 +1924,6 @@ int prepare_revision_walk(struct rev_info *revs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum rewrite_result {
|
||||
rewrite_one_ok,
|
||||
rewrite_one_noparents,
|
||||
rewrite_one_error
|
||||
};
|
||||
|
||||
static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
|
||||
{
|
||||
struct commit_list *cache = NULL;
|
||||
@@ -1939,12 +1945,13 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
|
||||
}
|
||||
}
|
||||
|
||||
static int rewrite_parents(struct rev_info *revs, struct commit *commit)
|
||||
int rewrite_parents(struct rev_info *revs, struct commit *commit,
|
||||
rewrite_parent_fn_t rewrite_parent)
|
||||
{
|
||||
struct commit_list **pp = &commit->parents;
|
||||
while (*pp) {
|
||||
struct commit_list *parent = *pp;
|
||||
switch (rewrite_one(revs, &parent->item)) {
|
||||
switch (rewrite_parent(revs, &parent->item)) {
|
||||
case rewrite_one_ok:
|
||||
break;
|
||||
case rewrite_one_noparents:
|
||||
@@ -2012,7 +2019,7 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
|
||||
if (action == commit_show &&
|
||||
!revs->show_all &&
|
||||
revs->prune && revs->dense && want_ancestry(revs)) {
|
||||
if (rewrite_parents(revs, commit) < 0)
|
||||
if (rewrite_parents(revs, commit, rewrite_one) < 0)
|
||||
return commit_error;
|
||||
}
|
||||
return action;
|
||||
|
||||
23
revision.h
23
revision.h
@@ -14,7 +14,11 @@
|
||||
#define CHILD_SHOWN (1u<<6)
|
||||
#define ADDED (1u<<7) /* Parents already parsed and added? */
|
||||
#define SYMMETRIC_LEFT (1u<<8)
|
||||
#define ALL_REV_FLAGS ((1u<<9)-1)
|
||||
#define RANGE_UPDATE (1u<<9) /* for line level traverse */
|
||||
#define NEED_PRINT (1u<<10)
|
||||
#define NONTRIVIAL_MERGE (1u<<11)
|
||||
#define EVIL_MERGE (1u<<12)
|
||||
#define ALL_REV_FLAGS ((1u<<13)-1)
|
||||
|
||||
#define DECORATE_SHORT_REFS 1
|
||||
#define DECORATE_FULL_REFS 2
|
||||
@@ -68,7 +72,9 @@ struct rev_info {
|
||||
cherry_pick:1,
|
||||
bisect:1,
|
||||
ancestry_path:1,
|
||||
first_parent_only:1;
|
||||
first_parent_only:1,
|
||||
line_level_traverse:1,
|
||||
full_line_diff:1;
|
||||
|
||||
/* Diff flags */
|
||||
unsigned int diff:1,
|
||||
@@ -137,6 +143,9 @@ struct rev_info {
|
||||
/* commit counts */
|
||||
int count_left;
|
||||
int count_right;
|
||||
/* line level range that we are chasing */
|
||||
struct decoration line_range;
|
||||
struct decoration nontrivial_merge;
|
||||
};
|
||||
|
||||
#define REV_TREE_SAME 0
|
||||
@@ -193,4 +202,14 @@ enum commit_action {
|
||||
extern enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit);
|
||||
extern enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit);
|
||||
|
||||
enum rewrite_result {
|
||||
rewrite_one_ok,
|
||||
rewrite_one_noparents,
|
||||
rewrite_one_error
|
||||
};
|
||||
|
||||
typedef enum rewrite_result (*rewrite_parent_fn_t)(struct rev_info *revs, struct commit **pp);
|
||||
|
||||
extern int rewrite_parents(struct rev_info *revs, struct commit *commit,
|
||||
rewrite_parent_fn_t rewrite_parent);
|
||||
#endif
|
||||
|
||||
685
t/t4301-log-line-single-history.sh
Executable file
685
t/t4301-log-line-single-history.sh
Executable file
@@ -0,0 +1,685 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2010 Bo Yang
|
||||
#
|
||||
|
||||
test_description='Test git log -L with single line of history'
|
||||
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/diff-lib.sh
|
||||
|
||||
cat >path0 <<\EOF
|
||||
void func()
|
||||
{
|
||||
int a = 0;
|
||||
int b = 1;
|
||||
int c;
|
||||
c = a + b;
|
||||
}
|
||||
EOF
|
||||
|
||||
cat >path1 <<\EOF
|
||||
void output()
|
||||
{
|
||||
printf("hello world");
|
||||
}
|
||||
EOF
|
||||
|
||||
test_expect_success 'add path0/path1 and commit.' '
|
||||
git add path0 path1 &&
|
||||
git commit -m "Base commit"
|
||||
'
|
||||
|
||||
cat >path0 <<\EOF
|
||||
void func()
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
int c;
|
||||
c = a + b;
|
||||
}
|
||||
EOF
|
||||
|
||||
cat >path1 <<\EOF
|
||||
void output()
|
||||
{
|
||||
const char *str = "hello world!";
|
||||
printf("%s", str);
|
||||
}
|
||||
EOF
|
||||
|
||||
test_expect_success 'Change the 2,3 lines of path0 and path1.' '
|
||||
git add path0 path1 &&
|
||||
git commit -m "Change 2,3 lines of path0 and path1"
|
||||
'
|
||||
|
||||
cat >path0 <<\EOF
|
||||
void func()
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
int c;
|
||||
c = 10 * (a + b);
|
||||
}
|
||||
EOF
|
||||
|
||||
test_expect_success 'Change the 5th line of path0.' '
|
||||
git add path0 &&
|
||||
git commit -m "Change the 5th line of path0"
|
||||
'
|
||||
|
||||
cat >path0 <<\EOF
|
||||
void func()
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
printf("%d", a - b);
|
||||
}
|
||||
EOF
|
||||
|
||||
test_expect_success 'Final change of path0.' '
|
||||
git add path0 &&
|
||||
git commit -m "Final change of path0"
|
||||
'
|
||||
|
||||
cat >expected-path0 <<\EOF
|
||||
Final change of path0
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index ccdf243..ccf8bcf 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -1,7 +1,6 @@
|
||||
void func()
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
- int c;
|
||||
- c = 10 * (a + b);
|
||||
+ printf("%d", a - b);
|
||||
}
|
||||
|
||||
Change the 5th line of path0
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index b0eb888..ccdf243 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -1,7 +1,7 @@
|
||||
void func()
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
int c;
|
||||
- c = a + b;
|
||||
+ c = 10 * (a + b);
|
||||
}
|
||||
|
||||
Change 2,3 lines of path0 and path1
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index fb33939..b0eb888 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -1,7 +1,7 @@
|
||||
void func()
|
||||
{
|
||||
- int a = 0;
|
||||
- int b = 1;
|
||||
+ int a = 10;
|
||||
+ int b = 11;
|
||||
int c;
|
||||
c = a + b;
|
||||
}
|
||||
|
||||
Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..fb33939
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +1,7 @@
|
||||
+void func()
|
||||
+{
|
||||
+ int a = 0;
|
||||
+ int b = 1;
|
||||
+ int c;
|
||||
+ c = a + b;
|
||||
+}
|
||||
EOF
|
||||
|
||||
cat >expected-path1 <<\EOF
|
||||
Change 2,3 lines of path0 and path1
|
||||
|
||||
diff --git a/path1 b/path1
|
||||
index 52be2a5..cc54b12 100644
|
||||
--- a/path1
|
||||
+++ b/path1
|
||||
@@ -1,4 +1,5 @@
|
||||
void output()
|
||||
{
|
||||
- printf("hello world");
|
||||
+ const char *str = "hello world!";
|
||||
+ printf("%s", str);
|
||||
}
|
||||
|
||||
Base commit
|
||||
|
||||
diff --git a/path1 b/path1
|
||||
new file mode 100644
|
||||
index 0000000..52be2a5
|
||||
--- /dev/null
|
||||
+++ b/path1
|
||||
@@ -0,0 +1,4 @@
|
||||
+void output()
|
||||
+{
|
||||
+ printf("hello world");
|
||||
+}
|
||||
EOF
|
||||
|
||||
cat >expected-pathall <<\EOF
|
||||
Final change of path0
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index ccdf243..ccf8bcf 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -1,7 +1,6 @@
|
||||
void func()
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
- int c;
|
||||
- c = 10 * (a + b);
|
||||
+ printf("%d", a - b);
|
||||
}
|
||||
|
||||
Change the 5th line of path0
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index b0eb888..ccdf243 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -1,7 +1,7 @@
|
||||
void func()
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
int c;
|
||||
- c = a + b;
|
||||
+ c = 10 * (a + b);
|
||||
}
|
||||
|
||||
Change 2,3 lines of path0 and path1
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index fb33939..b0eb888 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -1,7 +1,7 @@
|
||||
void func()
|
||||
{
|
||||
- int a = 0;
|
||||
- int b = 1;
|
||||
+ int a = 10;
|
||||
+ int b = 11;
|
||||
int c;
|
||||
c = a + b;
|
||||
}
|
||||
diff --git a/path1 b/path1
|
||||
index 52be2a5..cc54b12 100644
|
||||
--- a/path1
|
||||
+++ b/path1
|
||||
@@ -1,4 +1,5 @@
|
||||
void output()
|
||||
{
|
||||
- printf("hello world");
|
||||
+ const char *str = "hello world!";
|
||||
+ printf("%s", str);
|
||||
}
|
||||
|
||||
Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..fb33939
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +1,7 @@
|
||||
+void func()
|
||||
+{
|
||||
+ int a = 0;
|
||||
+ int b = 1;
|
||||
+ int c;
|
||||
+ c = a + b;
|
||||
+}
|
||||
diff --git a/path1 b/path1
|
||||
new file mode 100644
|
||||
index 0000000..52be2a5
|
||||
--- /dev/null
|
||||
+++ b/path1
|
||||
@@ -0,0 +1,4 @@
|
||||
+void output()
|
||||
+{
|
||||
+ printf("hello world");
|
||||
+}
|
||||
EOF
|
||||
|
||||
cat >expected-linenum <<\EOF
|
||||
Change 2,3 lines of path0 and path1
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index fb33939..b0eb888 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -2,3 +2,3 @@
|
||||
{
|
||||
- int a = 0;
|
||||
- int b = 1;
|
||||
+ int a = 10;
|
||||
+ int b = 11;
|
||||
|
||||
Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..fb33939
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +2,3 @@
|
||||
+{
|
||||
+ int a = 0;
|
||||
+ int b = 1;
|
||||
EOF
|
||||
|
||||
cat >expected-always <<\EOF
|
||||
Final change of path0
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index ccdf243..ccf8bcf 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -2,3 +2,3 @@
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
|
||||
Change the 5th line of path0
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index b0eb888..ccdf243 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -2,3 +2,3 @@
|
||||
{
|
||||
int a = 10;
|
||||
int b = 11;
|
||||
|
||||
Change 2,3 lines of path0 and path1
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index fb33939..b0eb888 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -2,3 +2,3 @@
|
||||
{
|
||||
- int a = 0;
|
||||
- int b = 1;
|
||||
+ int a = 10;
|
||||
+ int b = 11;
|
||||
|
||||
Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..fb33939
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +2,3 @@
|
||||
+{
|
||||
+ int a = 0;
|
||||
+ int b = 1;
|
||||
EOF
|
||||
|
||||
test_expect_success 'Show the line level log of path0' '
|
||||
git log --pretty=format:%s%n%b -L /func/,/^}/ path0 > current-path0
|
||||
'
|
||||
|
||||
test_expect_success 'validate the path0 output.' '
|
||||
test_cmp current-path0 expected-path0
|
||||
'
|
||||
|
||||
test_expect_success 'Show the line level log of path1' '
|
||||
git log --pretty=format:%s%n%b -L /output/,/^}/ path1 > current-path1
|
||||
'
|
||||
|
||||
test_expect_success 'validate the path1 output.' '
|
||||
test_cmp current-path1 expected-path1
|
||||
'
|
||||
|
||||
test_expect_success 'Show the line level log of two files' '
|
||||
git log --pretty=format:%s%n%b -L /func/,/^}/ path0 -L /output/,/^}/ path1 > current-pathall
|
||||
'
|
||||
|
||||
test_expect_success 'validate the all path output.' '
|
||||
test_cmp current-pathall expected-pathall
|
||||
'
|
||||
|
||||
test_expect_success 'Test the line number argument' '
|
||||
git log --pretty=format:%s%n%b -L 2,4 path0 > current-linenum
|
||||
'
|
||||
|
||||
test_expect_success 'validate the line number output.' '
|
||||
test_cmp current-linenum expected-linenum
|
||||
'
|
||||
test_expect_success 'Test the --full-line-diff option' '
|
||||
git log --pretty=format:%s%n%b --full-line-diff -L 2,4 path0 > current-always
|
||||
'
|
||||
|
||||
test_expect_success 'validate the --full-line-diff output.' '
|
||||
test_cmp current-always expected-always
|
||||
'
|
||||
|
||||
# Rerun all log with graph
|
||||
test_expect_success 'Show the line level log of path0 with --graph' '
|
||||
git log --pretty=format:%s%n%b --graph -L /func/,/^}/ path0 > current-path0-graph
|
||||
'
|
||||
|
||||
test_expect_success 'Show the line level log of path1 with --graph' '
|
||||
git log --pretty=format:%s%n%b --graph -L /output/,/^}/ path1 > current-path1-graph
|
||||
'
|
||||
|
||||
test_expect_success 'Show the line level log of two files with --graph' '
|
||||
git log --pretty=format:%s%n%b --graph -L /func/,/^}/ path0 --graph -L /output/,/^}/ path1 > current-pathall-graph
|
||||
'
|
||||
|
||||
test_expect_success 'Test the line number argument with --graph' '
|
||||
git log --pretty=format:%s%n%b --graph -L 2,4 path0 > current-linenum-graph
|
||||
'
|
||||
|
||||
test_expect_success 'Test the --full-line-diff option with --graph option' '
|
||||
git log --pretty=format:%s%n%b --full-line-diff --graph -L 2,4 path0 > current-always-graph
|
||||
'
|
||||
|
||||
cat > expected-path0-graph <<\EOF
|
||||
* Final change of path0
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index ccdf243..ccf8bcf 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -1,7 +1,6 @@
|
||||
| void func()
|
||||
| {
|
||||
| int a = 10;
|
||||
| int b = 11;
|
||||
| - int c;
|
||||
| - c = 10 * (a + b);
|
||||
| + printf("%d", a - b);
|
||||
| }
|
||||
|
|
||||
* Change the 5th line of path0
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index b0eb888..ccdf243 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -1,7 +1,7 @@
|
||||
| void func()
|
||||
| {
|
||||
| int a = 10;
|
||||
| int b = 11;
|
||||
| int c;
|
||||
| - c = a + b;
|
||||
| + c = 10 * (a + b);
|
||||
| }
|
||||
|
|
||||
* Change 2,3 lines of path0 and path1
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index fb33939..b0eb888 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -1,7 +1,7 @@
|
||||
| void func()
|
||||
| {
|
||||
| - int a = 0;
|
||||
| - int b = 1;
|
||||
| + int a = 10;
|
||||
| + int b = 11;
|
||||
| int c;
|
||||
| c = a + b;
|
||||
| }
|
||||
|
|
||||
* Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..fb33939
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +1,7 @@
|
||||
+void func()
|
||||
+{
|
||||
+ int a = 0;
|
||||
+ int b = 1;
|
||||
+ int c;
|
||||
+ c = a + b;
|
||||
+}
|
||||
EOF
|
||||
|
||||
cat > expected-path1-graph <<\EOF
|
||||
* Change 2,3 lines of path0 and path1
|
||||
|
|
||||
| diff --git a/path1 b/path1
|
||||
| index 52be2a5..cc54b12 100644
|
||||
| --- a/path1
|
||||
| +++ b/path1
|
||||
| @@ -1,4 +1,5 @@
|
||||
| void output()
|
||||
| {
|
||||
| - printf("hello world");
|
||||
| + const char *str = "hello world!";
|
||||
| + printf("%s", str);
|
||||
| }
|
||||
|
|
||||
* Base commit
|
||||
|
||||
diff --git a/path1 b/path1
|
||||
new file mode 100644
|
||||
index 0000000..52be2a5
|
||||
--- /dev/null
|
||||
+++ b/path1
|
||||
@@ -0,0 +1,4 @@
|
||||
+void output()
|
||||
+{
|
||||
+ printf("hello world");
|
||||
+}
|
||||
EOF
|
||||
|
||||
cat > expected-pathall-graph <<\EOF
|
||||
* Final change of path0
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index ccdf243..ccf8bcf 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -1,7 +1,6 @@
|
||||
| void func()
|
||||
| {
|
||||
| int a = 10;
|
||||
| int b = 11;
|
||||
| - int c;
|
||||
| - c = 10 * (a + b);
|
||||
| + printf("%d", a - b);
|
||||
| }
|
||||
|
|
||||
* Change the 5th line of path0
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index b0eb888..ccdf243 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -1,7 +1,7 @@
|
||||
| void func()
|
||||
| {
|
||||
| int a = 10;
|
||||
| int b = 11;
|
||||
| int c;
|
||||
| - c = a + b;
|
||||
| + c = 10 * (a + b);
|
||||
| }
|
||||
|
|
||||
* Change 2,3 lines of path0 and path1
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index fb33939..b0eb888 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -1,7 +1,7 @@
|
||||
| void func()
|
||||
| {
|
||||
| - int a = 0;
|
||||
| - int b = 1;
|
||||
| + int a = 10;
|
||||
| + int b = 11;
|
||||
| int c;
|
||||
| c = a + b;
|
||||
| }
|
||||
| diff --git a/path1 b/path1
|
||||
| index 52be2a5..cc54b12 100644
|
||||
| --- a/path1
|
||||
| +++ b/path1
|
||||
| @@ -1,4 +1,5 @@
|
||||
| void output()
|
||||
| {
|
||||
| - printf("hello world");
|
||||
| + const char *str = "hello world!";
|
||||
| + printf("%s", str);
|
||||
| }
|
||||
|
|
||||
* Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..fb33939
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +1,7 @@
|
||||
+void func()
|
||||
+{
|
||||
+ int a = 0;
|
||||
+ int b = 1;
|
||||
+ int c;
|
||||
+ c = a + b;
|
||||
+}
|
||||
diff --git a/path1 b/path1
|
||||
new file mode 100644
|
||||
index 0000000..52be2a5
|
||||
--- /dev/null
|
||||
+++ b/path1
|
||||
@@ -0,0 +1,4 @@
|
||||
+void output()
|
||||
+{
|
||||
+ printf("hello world");
|
||||
+}
|
||||
EOF
|
||||
|
||||
cat > expected-linenum-graph <<\EOF
|
||||
* Change 2,3 lines of path0 and path1
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index fb33939..b0eb888 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -2,3 +2,3 @@
|
||||
| {
|
||||
| - int a = 0;
|
||||
| - int b = 1;
|
||||
| + int a = 10;
|
||||
| + int b = 11;
|
||||
|
|
||||
* Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..fb33939
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +2,3 @@
|
||||
+{
|
||||
+ int a = 0;
|
||||
+ int b = 1;
|
||||
EOF
|
||||
|
||||
cat > expected-always-graph <<\EOF
|
||||
* Final change of path0
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index ccdf243..ccf8bcf 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -2,3 +2,3 @@
|
||||
| {
|
||||
| int a = 10;
|
||||
| int b = 11;
|
||||
|
|
||||
* Change the 5th line of path0
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index b0eb888..ccdf243 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -2,3 +2,3 @@
|
||||
| {
|
||||
| int a = 10;
|
||||
| int b = 11;
|
||||
|
|
||||
* Change 2,3 lines of path0 and path1
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index fb33939..b0eb888 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -2,3 +2,3 @@
|
||||
| {
|
||||
| - int a = 0;
|
||||
| - int b = 1;
|
||||
| + int a = 10;
|
||||
| + int b = 11;
|
||||
|
|
||||
* Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..fb33939
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +2,3 @@
|
||||
+{
|
||||
+ int a = 0;
|
||||
+ int b = 1;
|
||||
EOF
|
||||
|
||||
test_expect_success 'validate the path0 output.' '
|
||||
test_cmp current-path0-graph expected-path0-graph
|
||||
'
|
||||
|
||||
test_expect_success 'validate the path1 output.' '
|
||||
test_cmp current-path1-graph expected-path1-graph
|
||||
'
|
||||
|
||||
test_expect_success 'validate the all path output.' '
|
||||
test_cmp current-pathall-graph expected-pathall-graph
|
||||
'
|
||||
|
||||
test_expect_success 'validate graph output' '
|
||||
test_cmp current-linenum-graph expected-linenum-graph
|
||||
'
|
||||
|
||||
test_expect_success 'validate --full-line-diff output' '
|
||||
test_cmp current-always-graph expected-always-graph
|
||||
'
|
||||
|
||||
test_done
|
||||
174
t/t4302-log-line-merge-history.sh
Executable file
174
t/t4302-log-line-merge-history.sh
Executable file
@@ -0,0 +1,174 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2010 Bo Yang
|
||||
#
|
||||
|
||||
test_description='Test git log -L with merge commit'
|
||||
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/diff-lib.sh
|
||||
|
||||
cat >path0 <<\EOF
|
||||
void func()
|
||||
{
|
||||
printf("hello");
|
||||
}
|
||||
EOF
|
||||
|
||||
test_expect_success 'Add path0 and commit.' '
|
||||
git add path0 &&
|
||||
git commit -m "Base commit"
|
||||
'
|
||||
|
||||
cat >path0 <<\EOF
|
||||
void func()
|
||||
{
|
||||
printf("hello earth");
|
||||
}
|
||||
EOF
|
||||
|
||||
test_expect_success 'Change path0 in master.' '
|
||||
git add path0 &&
|
||||
git commit -m "Change path0 in master"
|
||||
'
|
||||
|
||||
test_expect_success 'Make a new branch from the base commit' '
|
||||
git checkout -b feature master^
|
||||
'
|
||||
|
||||
cat >path0 <<\EOF
|
||||
void func()
|
||||
{
|
||||
print("hello moon");
|
||||
}
|
||||
EOF
|
||||
|
||||
test_expect_success 'Change path0 in feature.' '
|
||||
git add path0 &&
|
||||
git commit -m "Change path0 in feature"
|
||||
'
|
||||
|
||||
test_expect_success 'Merge the master to feature' '
|
||||
! git merge master
|
||||
'
|
||||
|
||||
cat >path0 <<\EOF
|
||||
void func()
|
||||
{
|
||||
printf("hello earth and moon");
|
||||
}
|
||||
EOF
|
||||
|
||||
test_expect_success 'Resolve the conflict' '
|
||||
git add path0 &&
|
||||
git commit -m "Merge two branches"
|
||||
'
|
||||
|
||||
test_expect_success 'Show the line level log of path0' '
|
||||
git log --pretty=format:%s%n%b -L /func/,/^}/ path0 > current
|
||||
'
|
||||
|
||||
cat >expected <<\EOF
|
||||
Merge two branches
|
||||
|
||||
nontrivial merge found
|
||||
path0
|
||||
@@ 3,1 @@
|
||||
printf("hello earth and moon");
|
||||
|
||||
|
||||
Change path0 in master
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index 56aeee5..11e66c5 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -1,4 +1,4 @@
|
||||
void func()
|
||||
{
|
||||
- printf("hello");
|
||||
+ printf("hello earth");
|
||||
}
|
||||
|
||||
Change path0 in feature
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
index 56aeee5..258fced 100644
|
||||
--- a/path0
|
||||
+++ b/path0
|
||||
@@ -1,4 +1,4 @@
|
||||
void func()
|
||||
{
|
||||
- printf("hello");
|
||||
+ print("hello moon");
|
||||
}
|
||||
|
||||
Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..56aeee5
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +1,4 @@
|
||||
+void func()
|
||||
+{
|
||||
+ printf("hello");
|
||||
+}
|
||||
EOF
|
||||
|
||||
cat > expected-graph <<\EOF
|
||||
* Merge two branches
|
||||
|\
|
||||
| |
|
||||
| | nontrivial merge found
|
||||
| | path0
|
||||
| | @@ 3,1 @@
|
||||
| | printf("hello earth and moon");
|
||||
| |
|
||||
| |
|
||||
| * Change path0 in master
|
||||
| |
|
||||
| | diff --git a/path0 b/path0
|
||||
| | index 56aeee5..11e66c5 100644
|
||||
| | --- a/path0
|
||||
| | +++ b/path0
|
||||
| | @@ -3,1 +3,1 @@
|
||||
| | - printf("hello");
|
||||
| | + printf("hello earth");
|
||||
| |
|
||||
* | Change path0 in feature
|
||||
|/
|
||||
|
|
||||
| diff --git a/path0 b/path0
|
||||
| index 56aeee5..258fced 100644
|
||||
| --- a/path0
|
||||
| +++ b/path0
|
||||
| @@ -3,1 +3,1 @@
|
||||
| - printf("hello");
|
||||
| + print("hello moon");
|
||||
|
|
||||
* Base commit
|
||||
|
||||
diff --git a/path0 b/path0
|
||||
new file mode 100644
|
||||
index 0000000..56aeee5
|
||||
--- /dev/null
|
||||
+++ b/path0
|
||||
@@ -0,0 +3,1 @@
|
||||
+ printf("hello");
|
||||
EOF
|
||||
|
||||
test_expect_success 'Show the line log of the 2 line of path0 with graph' '
|
||||
git log --pretty=format:%s%n%b --graph -L 3,+1 path0 > current-graph
|
||||
'
|
||||
|
||||
test_expect_success 'validate the output.' '
|
||||
test_cmp current expected
|
||||
'
|
||||
|
||||
test_expect_success 'validate the graph output.' '
|
||||
test_cmp current-graph expected-graph
|
||||
'
|
||||
|
||||
test_done
|
||||
Reference in New Issue
Block a user