Merge branch 'lt/logopt'

* lt/logopt:
  Fix "git log --stat": make sure to set recursive with --stat.
  combine-diff: show diffstat with the first parent.
  git.c: LOGSIZE is unused after log printing cleanup.
  Log message printout cleanups (#3): fix --pretty=oneline
  Log message printout cleanups (#2)
  Log message printout cleanups
  rev-list --header: output format fix
  Fixes for option parsing
  log/whatchanged/show - log formatting cleanup.
  Simplify common default options setup for built-in log family.
  Tentative built-in "git show"
  Built-in git-whatchanged.
  rev-list option parser fix.
  Split init_revisions() out of setup_revisions()
  Fix up rev-list option parsing.
  Fix up default abbrev in setup_revisions() argument parser.
  Common option parsing for "git log --diff" and friends
This commit is contained in:
Junio C Hamano 2006-04-18 13:56:36 -07:00
commit 34e98ea564
14 changed files with 479 additions and 444 deletions

View File

@ -5,6 +5,7 @@
#include "diffcore.h"
#include "quote.h"
#include "xdiff-interface.h"
#include "log-tree.h"
static int uninteresting(struct diff_filepair *p)
{
@ -584,10 +585,20 @@ static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
sline->p_lno[i] = sline->p_lno[j];
}
static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
int dense, const char *header,
struct diff_options *opt)
static void dump_quoted_path(const char *prefix, const char *path)
{
fputs(prefix, stdout);
if (quote_c_style(path, NULL, NULL, 0))
quote_c_style(path, NULL, stdout, 0);
else
printf("%s", path);
putchar('\n');
}
static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
int dense, struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
unsigned long result_size, cnt, lno;
char *result, *cp;
struct sline *sline; /* survived lines */
@ -688,16 +699,9 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
if (show_hunks || mode_differs || working_tree_file) {
const char *abb;
if (header) {
shown_header++;
printf("%s%c", header, opt->line_termination);
}
printf("diff --%s ", dense ? "cc" : "combined");
if (quote_c_style(elem->path, NULL, NULL, 0))
quote_c_style(elem->path, NULL, stdout, 0);
else
printf("%s", elem->path);
putchar('\n');
if (rev->loginfo)
show_log(rev, rev->loginfo, "\n");
dump_quoted_path(dense ? "diff --cc " : "diff --combined ", elem->path);
printf("index ");
for (i = 0; i < num_parent; i++) {
abb = find_unique_abbrev(elem->parent[i].sha1,
@ -728,6 +732,8 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
}
putchar('\n');
}
dump_quoted_path("--- a/", elem->path);
dump_quoted_path("+++ b/", elem->path);
dump_sline(sline, cnt, num_parent);
}
free(result);
@ -749,8 +755,9 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
#define COLONS "::::::::::::::::::::::::::::::::"
static void show_raw_diff(struct combine_diff_path *p, int num_parent, const char *header, struct diff_options *opt)
static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
int i, offset;
const char *prefix;
int line_termination, inter_name_termination;
@ -760,8 +767,8 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, const cha
if (!line_termination)
inter_name_termination = 0;
if (header)
printf("%s%c", header, line_termination);
if (rev->loginfo)
show_log(rev, rev->loginfo, "\n");
if (opt->output_format == DIFF_FORMAT_RAW) {
offset = strlen(COLONS) - num_parent;
@ -802,40 +809,44 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, const cha
}
}
int show_combined_diff(struct combine_diff_path *p,
void show_combined_diff(struct combine_diff_path *p,
int num_parent,
int dense,
const char *header,
struct diff_options *opt)
struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
if (!p->len)
return 0;
return;
switch (opt->output_format) {
case DIFF_FORMAT_RAW:
case DIFF_FORMAT_NAME_STATUS:
case DIFF_FORMAT_NAME:
show_raw_diff(p, num_parent, header, opt);
return 1;
default:
show_raw_diff(p, num_parent, rev);
return;
case DIFF_FORMAT_PATCH:
return show_patch_diff(p, num_parent, dense, header, opt);
show_patch_diff(p, num_parent, dense, rev);
return;
default:
return;
}
}
const char *diff_tree_combined_merge(const unsigned char *sha1,
const char *header, int dense,
struct diff_options *opt)
void diff_tree_combined_merge(const unsigned char *sha1,
int dense, struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
struct commit *commit = lookup_commit(sha1);
struct diff_options diffopts;
struct commit_list *parents;
struct combine_diff_path *p, *paths = NULL;
int num_parent, i, num_paths;
int do_diffstat;
do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT ||
opt->with_stat);
diffopts = *opt;
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
diffopts.with_raw = 0;
diffopts.with_stat = 0;
diffopts.recursive = 1;
/* count parents */
@ -849,11 +860,24 @@ const char *diff_tree_combined_merge(const unsigned char *sha1,
parents;
parents = parents->next, i++) {
struct commit *parent = parents->item;
/* show stat against the first parent even
* when doing combined diff.
*/
if (i == 0 && do_diffstat)
diffopts.output_format = DIFF_FORMAT_DIFFSTAT;
else
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_tree_sha1(parent->object.sha1, commit->object.sha1, "",
&diffopts);
diffcore_std(&diffopts);
paths = intersect_paths(paths, i, num_parent);
if (do_diffstat && rev->loginfo)
show_log(rev, rev->loginfo,
opt->with_stat ? "---\n" : "\n");
diff_flush(&diffopts);
if (opt->with_stat)
putchar('\n');
}
/* find out surviving paths */
@ -866,17 +890,13 @@ const char *diff_tree_combined_merge(const unsigned char *sha1,
int saved_format = opt->output_format;
opt->output_format = DIFF_FORMAT_RAW;
for (p = paths; p; p = p->next) {
if (show_combined_diff(p, num_parent, dense,
header, opt))
header = NULL;
show_combined_diff(p, num_parent, dense, rev);
}
opt->output_format = saved_format;
putchar(opt->line_termination);
}
for (p = paths; p; p = p->next) {
if (show_combined_diff(p, num_parent, dense,
header, opt))
header = NULL;
show_combined_diff(p, num_parent, dense, rev);
}
}
@ -886,5 +906,4 @@ const char *diff_tree_combined_merge(const unsigned char *sha1,
paths = paths->next;
free(tmp);
}
return header;
}

View File

@ -45,6 +45,8 @@ enum cmit_fmt {
CMIT_FMT_FULL,
CMIT_FMT_FULLER,
CMIT_FMT_ONELINE,
CMIT_FMT_UNSPECIFIED,
};
extern enum cmit_fmt get_commit_format(const char *arg);

View File

@ -5,12 +5,14 @@
*/
#include "cache.h"
#include "diff.h"
#include "commit.h"
#include "revision.h"
static const char diff_files_usage[] =
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
static struct diff_options diff_options;
static struct rev_info rev;
static int silent = 0;
static int diff_unmerged_stage = 2;
static int combine_merges = 0;
@ -18,12 +20,12 @@ static int dense_combined_merges = 0;
static void show_unmerge(const char *path)
{
diff_unmerge(&diff_options, path);
diff_unmerge(&rev.diffopt, path);
}
static void show_file(int pfx, struct cache_entry *ce)
{
diff_addremove(&diff_options, pfx, ntohl(ce->ce_mode),
diff_addremove(&rev.diffopt, pfx, ntohl(ce->ce_mode),
ce->sha1, ce->name, NULL);
}
@ -31,7 +33,7 @@ static void show_modified(int oldmode, int mode,
const unsigned char *old_sha1, const unsigned char *sha1,
char *path)
{
diff_change(&diff_options, oldmode, mode, old_sha1, sha1, path, NULL);
diff_change(&rev.diffopt, oldmode, mode, old_sha1, sha1, path, NULL);
}
int main(int argc, const char **argv)
@ -41,7 +43,7 @@ int main(int argc, const char **argv)
int entries, i;
git_config(git_diff_config);
diff_setup(&diff_options);
diff_setup(&rev.diffopt);
while (1 < argc && argv[1][0] == '-') {
if (!strcmp(argv[1], "--")) {
argv++;
@ -74,7 +76,7 @@ int main(int argc, const char **argv)
dense_combined_merges = combine_merges = 1;
else {
int diff_opt_cnt;
diff_opt_cnt = diff_opt_parse(&diff_options,
diff_opt_cnt = diff_opt_parse(&rev.diffopt,
argv+1, argc-1);
if (diff_opt_cnt < 0)
usage(diff_files_usage);
@ -89,13 +91,13 @@ int main(int argc, const char **argv)
argv++; argc--;
}
if (dense_combined_merges)
diff_options.output_format = DIFF_FORMAT_PATCH;
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
/* Find the directory, and set up the pathspec */
pathspec = get_pathspec(prefix, argv + 1);
entries = read_cache();
if (diff_setup_done(&diff_options) < 0)
if (diff_setup_done(&rev.diffopt) < 0)
usage(diff_files_usage);
/* At this point, if argc == 1, then we are doing everything.
@ -167,8 +169,7 @@ int main(int argc, const char **argv)
if (combine_merges && num_compare_stages == 2) {
show_combined_diff(&combine.p, 2,
dense_combined_merges,
NULL,
&diff_options);
&rev);
free(combine.p.path);
continue;
}
@ -194,7 +195,7 @@ int main(int argc, const char **argv)
continue;
}
changed = ce_match_stat(ce, &st, 0);
if (!changed && !diff_options.find_copies_harder)
if (!changed && !rev.diffopt.find_copies_harder)
continue;
oldmode = ntohl(ce->ce_mode);
@ -207,7 +208,7 @@ int main(int argc, const char **argv)
ce->sha1, (changed ? null_sha1 : ce->sha1),
ce->name);
}
diffcore_std(&diff_options);
diff_flush(&diff_options);
diffcore_std(&rev.diffopt);
diff_flush(&rev.diffopt);
return 0;
}

View File

@ -3,7 +3,7 @@
#include "commit.h"
#include "log-tree.h"
static struct log_tree_opt log_tree_opt;
static struct rev_info log_tree_opt;
static int diff_tree_commit_sha1(const unsigned char *sha1)
{
@ -62,47 +62,21 @@ int main(int argc, const char **argv)
{
int nr_sha1;
char line[1000];
unsigned char sha1[2][20];
const char *prefix = setup_git_directory();
static struct log_tree_opt *opt = &log_tree_opt;
struct object *tree1, *tree2;
static struct rev_info *opt = &log_tree_opt;
struct object_list *list;
int read_stdin = 0;
git_config(git_diff_config);
nr_sha1 = 0;
init_log_tree_opt(opt);
init_revisions(opt);
opt->abbrev = 0;
opt->diff = 1;
argc = setup_revisions(argc, argv, opt, NULL);
for (;;) {
int opt_cnt;
const char *arg;
while (--argc > 0) {
const char *arg = *++argv;
argv++;
argc--;
arg = *argv;
if (!arg)
break;
if (*arg != '-') {
if (nr_sha1 < 2 && !get_sha1(arg, sha1[nr_sha1])) {
nr_sha1++;
continue;
}
break;
}
opt_cnt = log_tree_opt_parse(opt, argv, argc);
if (opt_cnt < 0)
usage(diff_tree_usage);
else if (opt_cnt) {
argv += opt_cnt - 1;
argc -= opt_cnt - 1;
continue;
}
if (!strcmp(arg, "--")) {
argv++;
argc--;
break;
}
if (!strcmp(arg, "--stdin")) {
read_stdin = 1;
continue;
@ -110,15 +84,36 @@ int main(int argc, const char **argv)
usage(diff_tree_usage);
}
if (opt->combine_merges)
opt->ignore_merges = 0;
/* We can only do dense combined merges with diff output */
if (opt->dense_combined_merges)
opt->diffopt.output_format = DIFF_FORMAT_PATCH;
diff_tree_setup_paths(get_pathspec(prefix, argv), &opt->diffopt);
diff_setup_done(&opt->diffopt);
/*
* NOTE! "setup_revisions()" will have inserted the revisions
* it parsed in reverse order. So if you do
*
* git-diff-tree a b
*
* the commit list will be "b" -> "a" -> NULL, so we reverse
* the order of the objects if the first one is not marked
* UNINTERESTING.
*/
nr_sha1 = 0;
list = opt->pending_objects;
if (list) {
nr_sha1++;
tree1 = list->item;
list = list->next;
if (list) {
nr_sha1++;
tree2 = tree1;
tree1 = list->item;
if (list->next)
usage(diff_tree_usage);
/* Switch them around if the second one was uninteresting.. */
if (tree2->flags & UNINTERESTING) {
struct object *tmp = tree2;
tree2 = tree1;
tree1 = tmp;
}
}
}
switch (nr_sha1) {
case 0:
@ -126,10 +121,12 @@ int main(int argc, const char **argv)
usage(diff_tree_usage);
break;
case 1:
diff_tree_commit_sha1(sha1[0]);
diff_tree_commit_sha1(tree1->sha1);
break;
case 2:
diff_tree_sha1(sha1[0], sha1[1], "", &opt->diffopt);
diff_tree_sha1(tree1->sha1,
tree2->sha1,
"", &opt->diffopt);
log_tree_diff_flush(opt);
break;
}

3
diff.c
View File

@ -1035,8 +1035,7 @@ int diff_setup_done(struct diff_options *options)
* recursive bits for other formats here.
*/
if ((options->output_format == DIFF_FORMAT_PATCH) ||
(options->output_format == DIFF_FORMAT_DIFFSTAT) ||
(options->with_stat))
(options->output_format == DIFF_FORMAT_DIFFSTAT))
options->recursive = 1;
if (options->detect_rename && options->rename_limit < 0)

8
diff.h
View File

@ -6,6 +6,7 @@
#include "tree-walk.h"
struct rev_info;
struct diff_options;
typedef void (*change_fn_t)(struct diff_options *options,
@ -70,11 +71,10 @@ struct combine_diff_path {
(sizeof(struct combine_diff_path) + \
sizeof(struct combine_diff_parent) * (n) + (l) + 1)
extern int show_combined_diff(struct combine_diff_path *elem, int num_parent,
int dense, const char *header,
struct diff_options *);
extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
int dense, struct rev_info *);
extern const char *diff_tree_combined_merge(const unsigned char *sha1, const char *, int, struct diff_options *opt);
extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *);
extern void diff_addremove(struct diff_options *,
int addremove,

170
git.c
View File

@ -276,126 +276,64 @@ static int cmd_help(int argc, const char **argv, char **envp)
return 0;
}
#define LOGSIZE (65536)
static int cmd_log_wc(int argc, const char **argv, char **envp,
struct rev_info *rev)
{
struct commit *commit;
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
rev->verbose_header = 1;
argc = setup_revisions(argc, argv, rev, "HEAD");
if (argc > 1)
die("unrecognized argument: %s", argv[1]);
prepare_revision_walk(rev);
setup_pager();
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
return 0;
}
static int cmd_wc(int argc, const char **argv, char **envp)
{
struct rev_info rev;
init_revisions(&rev);
rev.diff = 1;
rev.diffopt.recursive = 1;
return cmd_log_wc(argc, argv, envp, &rev);
}
static int cmd_show(int argc, const char **argv, char **envp)
{
struct rev_info rev;
init_revisions(&rev);
rev.diff = 1;
rev.diffopt.recursive = 1;
rev.combine_merges = 1;
rev.dense_combined_merges = 1;
rev.always_show_header = 1;
rev.ignore_merges = 0;
rev.no_walk = 1;
return cmd_log_wc(argc, argv, envp, &rev);
}
static int cmd_log(int argc, const char **argv, char **envp)
{
struct rev_info rev;
struct commit *commit;
char *buf = xmalloc(LOGSIZE);
static enum cmit_fmt commit_format = CMIT_FMT_DEFAULT;
int abbrev = DEFAULT_ABBREV;
int abbrev_commit = 0;
const char *commit_prefix = "commit ";
struct log_tree_opt opt;
int shown = 0;
int do_diff = 0;
int full_diff = 0;
init_log_tree_opt(&opt);
argc = setup_revisions(argc, argv, &rev, "HEAD");
while (1 < argc) {
const char *arg = argv[1];
if (!strncmp(arg, "--pretty", 8)) {
commit_format = get_commit_format(arg + 8);
if (commit_format == CMIT_FMT_ONELINE)
commit_prefix = "";
}
else if (!strcmp(arg, "--no-abbrev")) {
abbrev = 0;
}
else if (!strcmp(arg, "--abbrev")) {
abbrev = DEFAULT_ABBREV;
}
else if (!strcmp(arg, "--abbrev-commit")) {
abbrev_commit = 1;
}
else if (!strncmp(arg, "--abbrev=", 9)) {
abbrev = strtoul(arg + 9, NULL, 10);
if (abbrev && abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
else if (40 < abbrev)
abbrev = 40;
}
else if (!strcmp(arg, "--full-diff")) {
do_diff = 1;
full_diff = 1;
}
else {
int cnt = log_tree_opt_parse(&opt, argv+1, argc-1);
if (0 < cnt) {
do_diff = 1;
argv += cnt;
argc -= cnt;
continue;
}
die("unrecognized argument: %s", arg);
}
argc--; argv++;
}
if (do_diff) {
opt.diffopt.abbrev = abbrev;
opt.verbose_header = 0;
opt.always_show_header = 0;
opt.no_commit_id = 1;
if (opt.combine_merges)
opt.ignore_merges = 0;
if (opt.dense_combined_merges)
opt.diffopt.output_format = DIFF_FORMAT_PATCH;
if (!full_diff && rev.prune_data)
diff_tree_setup_paths(rev.prune_data, &opt.diffopt);
diff_setup_done(&opt.diffopt);
}
prepare_revision_walk(&rev);
setup_pager();
while ((commit = get_revision(&rev)) != NULL) {
if (shown && do_diff && commit_format != CMIT_FMT_ONELINE)
putchar('\n');
fputs(commit_prefix, stdout);
if (abbrev_commit && abbrev)
fputs(find_unique_abbrev(commit->object.sha1, abbrev),
stdout);
else
fputs(sha1_to_hex(commit->object.sha1), stdout);
if (rev.parents) {
struct commit_list *parents = commit->parents;
while (parents) {
struct object *o = &(parents->item->object);
parents = parents->next;
if (o->flags & TMP_MARK)
continue;
printf(" %s", sha1_to_hex(o->sha1));
o->flags |= TMP_MARK;
}
/* TMP_MARK is a general purpose flag that can
* be used locally, but the user should clean
* things up after it is done with them.
*/
for (parents = commit->parents;
parents;
parents = parents->next)
parents->item->object.flags &= ~TMP_MARK;
}
if (commit_format == CMIT_FMT_ONELINE)
putchar(' ');
else
putchar('\n');
pretty_print_commit(commit_format, commit, ~0, buf,
LOGSIZE, abbrev);
printf("%s\n", buf);
if (do_diff) {
printf("---\n");
log_tree_commit(&opt, commit);
}
shown = 1;
free(commit->buffer);
commit->buffer = NULL;
}
free(buf);
return 0;
init_revisions(&rev);
rev.always_show_header = 1;
rev.diffopt.recursive = 1;
rev.combine_merges = 1;
rev.ignore_merges = 0;
return cmd_log_wc(argc, argv, envp, &rev);
}
static void handle_internal_command(int argc, const char **argv, char **envp)
@ -408,6 +346,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "version", cmd_version },
{ "help", cmd_help },
{ "log", cmd_log },
{ "whatchanged", cmd_wc },
{ "show", cmd_show },
};
int i;

View File

@ -2498,6 +2498,7 @@ int main(int argc, char **argv)
commit_argv[3] = old_sha1_hex;
commit_argc++;
}
init_revisions(&revs);
setup_revisions(commit_argc, commit_argv, &revs, NULL);
free(new_sha1_hex);
if (old_sha1_hex) {

View File

@ -3,59 +3,58 @@
#include "commit.h"
#include "log-tree.h"
void init_log_tree_opt(struct log_tree_opt *opt)
void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
{
memset(opt, 0, sizeof *opt);
opt->ignore_merges = 1;
opt->header_prefix = "";
opt->commit_format = CMIT_FMT_RAW;
diff_setup(&opt->diffopt);
static char this_header[16384];
struct commit *commit = log->commit, *parent = log->parent;
int abbrev = opt->diffopt.abbrev;
int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
const char *extra;
int len;
opt->loginfo = NULL;
if (!opt->verbose_header) {
puts(sha1_to_hex(commit->object.sha1));
return;
}
int log_tree_opt_parse(struct log_tree_opt *opt, const char **av, int ac)
{
const char *arg;
int cnt = diff_opt_parse(&opt->diffopt, av, ac);
if (0 < cnt)
return cnt;
arg = *av;
if (!strcmp(arg, "-r"))
opt->diffopt.recursive = 1;
else if (!strcmp(arg, "-t")) {
opt->diffopt.recursive = 1;
opt->diffopt.tree_in_recursive = 1;
}
else if (!strcmp(arg, "-m"))
opt->ignore_merges = 0;
else if (!strcmp(arg, "-c"))
opt->combine_merges = 1;
else if (!strcmp(arg, "--cc")) {
opt->dense_combined_merges = 1;
opt->combine_merges = 1;
}
else if (!strcmp(arg, "-v")) {
opt->verbose_header = 1;
opt->header_prefix = "diff-tree ";
}
else if (!strncmp(arg, "--pretty", 8)) {
opt->verbose_header = 1;
opt->header_prefix = "diff-tree ";
opt->commit_format = get_commit_format(arg+8);
}
else if (!strcmp(arg, "--root"))
opt->show_root_diff = 1;
else if (!strcmp(arg, "--no-commit-id"))
opt->no_commit_id = 1;
else if (!strcmp(arg, "--always"))
opt->always_show_header = 1;
else
return 0;
return 1;
/*
* The "oneline" format has several special cases:
* - The pretty-printed commit lacks a newline at the end
* of the buffer, but we do want to make sure that we
* have a newline there. If the separator isn't already
* a newline, add an extra one.
* - unlike other log messages, the one-line format does
* not have an empty line between entries.
*/
extra = "";
if (*sep != '\n' && opt->commit_format == CMIT_FMT_ONELINE)
extra = "\n";
if (opt->shown_one && opt->commit_format != CMIT_FMT_ONELINE)
putchar('\n');
opt->shown_one = 1;
/*
* Print header line of header..
*/
printf("%s%s",
opt->commit_format == CMIT_FMT_ONELINE ? "" : "commit ",
diff_unique_abbrev(commit->object.sha1, abbrev_commit));
if (parent)
printf(" (from %s)", diff_unique_abbrev(parent->object.sha1, abbrev_commit));
putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
/*
* And then the pretty-printed message itself
*/
len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev);
printf("%s%s%s", this_header, extra, sep);
}
int log_tree_diff_flush(struct log_tree_opt *opt)
int log_tree_diff_flush(struct rev_info *opt)
{
diffcore_std(&opt->diffopt);
if (diff_queue_is_empty()) {
int saved_fmt = opt->diffopt.output_format;
opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
@ -63,17 +62,14 @@ int log_tree_diff_flush(struct log_tree_opt *opt)
opt->diffopt.output_format = saved_fmt;
return 0;
}
if (opt->header) {
if (!opt->no_commit_id)
printf("%s%c", opt->header,
opt->diffopt.line_termination);
opt->header = NULL;
}
if (opt->loginfo && !opt->no_commit_id)
show_log(opt, opt->loginfo, opt->diffopt.with_stat ? "---\n" : "\n");
diff_flush(&opt->diffopt);
return 1;
}
static int diff_root_tree(struct log_tree_opt *opt,
static int diff_root_tree(struct rev_info *opt,
const unsigned char *new, const char *base)
{
int retval;
@ -93,83 +89,78 @@ static int diff_root_tree(struct log_tree_opt *opt,
return retval;
}
static const char *generate_header(struct log_tree_opt *opt,
const unsigned char *commit_sha1,
const unsigned char *parent_sha1,
const struct commit *commit)
{
static char this_header[16384];
int offset;
unsigned long len;
int abbrev = opt->diffopt.abbrev;
const char *msg = commit->buffer;
if (!opt->verbose_header)
return sha1_to_hex(commit_sha1);
len = strlen(msg);
offset = sprintf(this_header, "%s%s ",
opt->header_prefix,
diff_unique_abbrev(commit_sha1, abbrev));
if (commit_sha1 != parent_sha1)
offset += sprintf(this_header + offset, "(from %s)\n",
parent_sha1
? diff_unique_abbrev(parent_sha1, abbrev)
: "root");
else
offset += sprintf(this_header + offset, "(from parents)\n");
offset += pretty_print_commit(opt->commit_format, commit, len,
this_header + offset,
sizeof(this_header) - offset, abbrev);
if (opt->always_show_header) {
puts(this_header);
return NULL;
}
return this_header;
}
static int do_diff_combined(struct log_tree_opt *opt, struct commit *commit)
static int do_diff_combined(struct rev_info *opt, struct commit *commit)
{
unsigned const char *sha1 = commit->object.sha1;
opt->header = generate_header(opt, sha1, sha1, commit);
opt->header = diff_tree_combined_merge(sha1, opt->header,
opt->dense_combined_merges,
&opt->diffopt);
if (!opt->header && opt->verbose_header)
opt->header_prefix = "\ndiff-tree ";
return 0;
diff_tree_combined_merge(sha1, opt->dense_combined_merges, opt);
return !opt->loginfo;
}
int log_tree_commit(struct log_tree_opt *opt, struct commit *commit)
/*
* Show the diff of a commit.
*
* Return true if we printed any log info messages
*/
static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log_info *log)
{
int showed_log;
struct commit_list *parents;
unsigned const char *sha1 = commit->object.sha1;
if (!opt->diff)
return 0;
/* Root commit? */
if (opt->show_root_diff && !commit->parents) {
opt->header = generate_header(opt, sha1, NULL, commit);
parents = commit->parents;
if (!parents) {
if (opt->show_root_diff)
diff_root_tree(opt, sha1, "");
return !opt->loginfo;
}
/* More than one parent? */
if (commit->parents && commit->parents->next) {
if (parents && parents->next) {
if (opt->ignore_merges)
return 0;
else if (opt->combine_merges)
return do_diff_combined(opt, commit);
/* If we show individual diffs, show the parent info */
log->parent = parents->item;
}
for (parents = commit->parents; parents; parents = parents->next) {
showed_log = 0;
for (;;) {
struct commit *parent = parents->item;
unsigned const char *psha1 = parent->object.sha1;
opt->header = generate_header(opt, sha1, psha1, commit);
diff_tree_sha1(psha1, sha1, "", &opt->diffopt);
diff_tree_sha1(parent->object.sha1, sha1, "", &opt->diffopt);
log_tree_diff_flush(opt);
if (!opt->header && opt->verbose_header)
opt->header_prefix = "\ndiff-tree ";
showed_log |= !opt->loginfo;
/* Set up the log info for the next parent, if any.. */
parents = parents->next;
if (!parents)
break;
log->parent = parents->item;
opt->loginfo = log;
}
return showed_log;
}
int log_tree_commit(struct rev_info *opt, struct commit *commit)
{
struct log_info log;
log.commit = commit;
log.parent = NULL;
opt->loginfo = &log;
if (!log_tree_diff(opt, commit, &log) && opt->loginfo && opt->always_show_header) {
log.parent = NULL;
show_log(opt, opt->loginfo, "");
}
opt->loginfo = NULL;
return 0;
}

View File

@ -1,23 +1,16 @@
#ifndef LOG_TREE_H
#define LOG_TREE_H
struct log_tree_opt {
struct diff_options diffopt;
int show_root_diff;
int no_commit_id;
int verbose_header;
int ignore_merges;
int combine_merges;
int dense_combined_merges;
int always_show_header;
const char *header_prefix;
const char *header;
enum cmit_fmt commit_format;
#include "revision.h"
struct log_info {
struct commit *commit, *parent;
};
void init_log_tree_opt(struct log_tree_opt *);
int log_tree_diff_flush(struct log_tree_opt *);
int log_tree_commit(struct log_tree_opt *, struct commit *);
int log_tree_opt_parse(struct log_tree_opt *, const char **, int);
void init_log_tree_opt(struct rev_info *);
int log_tree_diff_flush(struct rev_info *);
int log_tree_commit(struct rev_info *, struct commit *);
int log_tree_opt_parse(struct rev_info *, const char **, int);
void show_log(struct rev_info *opt, struct log_info *log, const char *sep);
#endif

View File

@ -39,24 +39,21 @@ static const char rev_list_usage[] =
struct rev_info revs;
static int bisect_list = 0;
static int verbose_header = 0;
static int abbrev = DEFAULT_ABBREV;
static int abbrev_commit = 0;
static int show_timestamp = 0;
static int hdr_termination = 0;
static const char *commit_prefix = "";
static enum cmit_fmt commit_format = CMIT_FMT_RAW;
static const char *header_prefix;
static void show_commit(struct commit *commit)
{
if (show_timestamp)
printf("%lu ", commit->date);
if (commit_prefix[0])
fputs(commit_prefix, stdout);
if (header_prefix)
fputs(header_prefix, stdout);
if (commit->object.flags & BOUNDARY)
putchar('-');
if (abbrev_commit && abbrev)
fputs(find_unique_abbrev(commit->object.sha1, abbrev), stdout);
if (revs.abbrev_commit && revs.abbrev)
fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
stdout);
else
fputs(sha1_to_hex(commit->object.sha1), stdout);
if (revs.parents) {
@ -78,14 +75,16 @@ static void show_commit(struct commit *commit)
parents = parents->next)
parents->item->object.flags &= ~TMP_MARK;
}
if (commit_format == CMIT_FMT_ONELINE)
if (revs.commit_format == CMIT_FMT_ONELINE)
putchar(' ');
else
putchar('\n');
if (verbose_header) {
if (revs.verbose_header) {
static char pretty_header[16384];
pretty_print_commit(commit_format, commit, ~0, pretty_header, sizeof(pretty_header), abbrev);
pretty_print_commit(revs.commit_format, commit, ~0,
pretty_header, sizeof(pretty_header),
revs.abbrev);
printf("%s%c", pretty_header, hdr_termination);
}
fflush(stdout);
@ -297,58 +296,16 @@ int main(int argc, const char **argv)
struct commit_list *list;
int i;
init_revisions(&revs);
revs.abbrev = 0;
revs.commit_format = CMIT_FMT_UNSPECIFIED;
argc = setup_revisions(argc, argv, &revs, NULL);
for (i = 1 ; i < argc; i++) {
const char *arg = argv[i];
/* accept -<digit>, like traditilnal "head" */
if ((*arg == '-') && isdigit(arg[1])) {
revs.max_count = atoi(arg + 1);
continue;
}
if (!strcmp(arg, "-n")) {
if (++i >= argc)
die("-n requires an argument");
revs.max_count = atoi(argv[i]);
continue;
}
if (!strncmp(arg,"-n",2)) {
revs.max_count = atoi(arg + 2);
continue;
}
if (!strcmp(arg, "--header")) {
verbose_header = 1;
continue;
}
if (!strcmp(arg, "--no-abbrev")) {
abbrev = 0;
continue;
}
if (!strcmp(arg, "--abbrev")) {
abbrev = DEFAULT_ABBREV;
continue;
}
if (!strcmp(arg, "--abbrev-commit")) {
abbrev_commit = 1;
continue;
}
if (!strncmp(arg, "--abbrev=", 9)) {
abbrev = strtoul(arg + 9, NULL, 10);
if (abbrev && abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
else if (40 < abbrev)
abbrev = 40;
continue;
}
if (!strncmp(arg, "--pretty", 8)) {
commit_format = get_commit_format(arg+8);
verbose_header = 1;
hdr_termination = '\n';
if (commit_format == CMIT_FMT_ONELINE)
commit_prefix = "";
else
commit_prefix = "commit ";
revs.verbose_header = 1;
continue;
}
if (!strcmp(arg, "--timestamp")) {
@ -362,14 +319,27 @@ int main(int argc, const char **argv)
usage(rev_list_usage);
}
if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
/* The command line has a --pretty */
hdr_termination = '\n';
if (revs.commit_format == CMIT_FMT_ONELINE)
header_prefix = "";
else
header_prefix = "commit ";
}
else if (revs.verbose_header)
/* Only --header was specified */
revs.commit_format = CMIT_FMT_RAW;
list = revs.commits;
if (!list &&
(!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending_objects))
if ((!list &&
(!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
!revs.pending_objects)) ||
revs.diff)
usage(rev_list_usage);
save_commit_buffer = verbose_header;
save_commit_buffer = revs.verbose_header;
track_object_refs = 0;
if (bisect_list)
revs.limited = 1;

View File

@ -116,21 +116,27 @@ static void add_pending_object(struct rev_info *revs, struct object *obj, const
add_object(obj, &revs->pending_objects, NULL, name);
}
static struct commit *get_commit_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
{
struct object *object;
object = parse_object(sha1);
if (!object)
die("bad object %s", name);
object->flags |= flags;
return object;
}
static struct commit *handle_commit(struct rev_info *revs, struct object *object, const char *name)
{
unsigned long flags = object->flags;
/*
* Tag object? Look what it points to..
*/
while (object->type == tag_type) {
struct tag *tag = (struct tag *) object;
object->flags |= flags;
if (revs->tag_objects && !(object->flags & UNINTERESTING))
if (revs->tag_objects && !(flags & UNINTERESTING))
add_pending_object(revs, object, tag->tag);
object = parse_object(tag->tagged->sha1);
if (!object)
@ -143,7 +149,6 @@ static struct commit *get_commit_reference(struct rev_info *revs, const char *na
*/
if (object->type == commit_type) {
struct commit *commit = (struct commit *)object;
object->flags |= flags;
if (parse_commit(commit) < 0)
die("unable to parse commit %s", name);
if (flags & UNINTERESTING) {
@ -241,7 +246,7 @@ int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
return REV_TREE_DIFFERENT;
tree_difference = REV_TREE_SAME;
if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "",
&revs->diffopt) < 0)
&revs->pruning) < 0)
return REV_TREE_DIFFERENT;
return tree_difference;
}
@ -264,7 +269,7 @@ int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
empty.size = 0;
tree_difference = 0;
retval = diff_tree(&empty, &real, "", &revs->diffopt);
retval = diff_tree(&empty, &real, "", &revs->pruning);
free(tree);
return retval >= 0 && !tree_difference;
@ -375,6 +380,9 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st
if (revs->prune_fn)
revs->prune_fn(revs, commit);
if (revs->no_walk)
return;
parent = commit->parents;
while (parent) {
struct commit *p = parent->item;
@ -451,21 +459,13 @@ static void limit_list(struct rev_info *revs)
revs->commits = newlist;
}
static void add_one_commit(struct commit *commit, struct rev_info *revs)
{
if (!commit || (commit->object.flags & SEEN))
return;
commit->object.flags |= SEEN;
commit_list_insert(commit, &revs->commits);
}
static int all_flags;
static struct rev_info *all_revs;
static int handle_one_ref(const char *path, const unsigned char *sha1)
{
struct commit *commit = get_commit_reference(all_revs, path, sha1, all_flags);
add_one_commit(commit, all_revs);
struct object *object = get_reference(all_revs, path, sha1, all_flags);
add_pending_object(all_revs, object, "");
return 0;
}
@ -479,9 +479,12 @@ static void handle_all(struct rev_info *revs, unsigned flags)
void init_revisions(struct rev_info *revs)
{
memset(revs, 0, sizeof(*revs));
revs->diffopt.recursive = 1;
revs->diffopt.add_remove = file_add_remove;
revs->diffopt.change = file_change;
revs->abbrev = DEFAULT_ABBREV;
revs->ignore_merges = 1;
revs->pruning.recursive = 1;
revs->pruning.add_remove = file_add_remove;
revs->pruning.change = file_change;
revs->lifo = 1;
revs->dense = 1;
revs->prefix = setup_git_directory();
@ -494,6 +497,10 @@ void init_revisions(struct rev_info *revs)
revs->topo_setter = topo_sort_default_setter;
revs->topo_getter = topo_sort_default_getter;
revs->commit_format = CMIT_FMT_DEFAULT;
diff_setup(&revs->diffopt);
}
/*
@ -509,8 +516,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
const char **unrecognized = argv + 1;
int left = 1;
init_revisions(revs);
/* First, search for "--" */
seen_dashdash = 0;
for (i = 1; i < argc; i++) {
@ -526,13 +531,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
flags = 0;
for (i = 1; i < argc; i++) {
struct commit *commit;
struct object *object;
const char *arg = argv[i];
unsigned char sha1[20];
char *dotdot;
int local_flags;
if (*arg == '-') {
int opts;
if (!strncmp(arg, "--max-count=", 12)) {
revs->max_count = atoi(arg + 12);
continue;
@ -640,6 +646,76 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->unpacked = 1;
continue;
}
if (!strcmp(arg, "-r")) {
revs->diff = 1;
revs->diffopt.recursive = 1;
continue;
}
if (!strcmp(arg, "-t")) {
revs->diff = 1;
revs->diffopt.recursive = 1;
revs->diffopt.tree_in_recursive = 1;
continue;
}
if (!strcmp(arg, "-m")) {
revs->ignore_merges = 0;
continue;
}
if (!strcmp(arg, "-c")) {
revs->diff = 1;
revs->combine_merges = 1;
continue;
}
if (!strcmp(arg, "--cc")) {
revs->diff = 1;
revs->dense_combined_merges = 1;
revs->combine_merges = 1;
continue;
}
if (!strcmp(arg, "-v")) {
revs->verbose_header = 1;
continue;
}
if (!strncmp(arg, "--pretty", 8)) {
revs->verbose_header = 1;
revs->commit_format = get_commit_format(arg+8);
continue;
}
if (!strcmp(arg, "--root")) {
revs->show_root_diff = 1;
continue;
}
if (!strcmp(arg, "--no-commit-id")) {
revs->no_commit_id = 1;
continue;
}
if (!strcmp(arg, "--always")) {
revs->always_show_header = 1;
continue;
}
if (!strcmp(arg, "--no-abbrev")) {
revs->abbrev = 0;
continue;
}
if (!strcmp(arg, "--abbrev")) {
revs->abbrev = DEFAULT_ABBREV;
continue;
}
if (!strcmp(arg, "--abbrev-commit")) {
revs->abbrev_commit = 1;
continue;
}
if (!strcmp(arg, "--full-diff")) {
revs->diff = 1;
revs->full_diff = 1;
continue;
}
opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
if (opts > 0) {
revs->diff = 1;
i += opts - 1;
continue;
}
*unrecognized++ = arg;
left++;
continue;
@ -656,15 +732,15 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
this = "HEAD";
if (!get_sha1(this, from_sha1) &&
!get_sha1(next, sha1)) {
struct commit *exclude;
struct commit *include;
struct object *exclude;
struct object *include;
exclude = get_commit_reference(revs, this, from_sha1, flags ^ UNINTERESTING);
include = get_commit_reference(revs, next, sha1, flags);
exclude = get_reference(revs, this, from_sha1, flags ^ UNINTERESTING);
include = get_reference(revs, next, sha1, flags);
if (!exclude || !include)
die("Invalid revision range %s..%s", arg, next);
add_one_commit(exclude, revs);
add_one_commit(include, revs);
add_pending_object(revs, exclude, this);
add_pending_object(revs, include, next);
continue;
}
*dotdot = '.';
@ -689,32 +765,57 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->prune_data = get_pathspec(revs->prefix, argv + i);
break;
}
commit = get_commit_reference(revs, arg, sha1, flags ^ local_flags);
add_one_commit(commit, revs);
object = get_reference(revs, arg, sha1, flags ^ local_flags);
add_pending_object(revs, object, arg);
}
if (def && !revs->commits) {
if (def && !revs->pending_objects) {
unsigned char sha1[20];
struct commit *commit;
struct object *object;
if (get_sha1(def, sha1) < 0)
die("bad default revision '%s'", def);
commit = get_commit_reference(revs, def, sha1, 0);
add_one_commit(commit, revs);
object = get_reference(revs, def, sha1, 0);
add_pending_object(revs, object, def);
}
if (revs->topo_order || revs->unpacked)
revs->limited = 1;
if (revs->prune_data) {
diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
diff_tree_setup_paths(revs->prune_data, &revs->pruning);
revs->prune_fn = try_to_simplify_commit;
if (!revs->full_diff)
diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
}
if (revs->combine_merges) {
revs->ignore_merges = 0;
if (revs->dense_combined_merges)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
}
revs->diffopt.abbrev = revs->abbrev;
diff_setup_done(&revs->diffopt);
return left;
}
void prepare_revision_walk(struct rev_info *revs)
{
sort_by_date(&revs->commits);
struct object_list *list;
list = revs->pending_objects;
revs->pending_objects = NULL;
while (list) {
struct commit *commit = handle_commit(revs, list->item, list->name);
if (commit) {
if (!(commit->object.flags & SEEN)) {
commit->object.flags |= SEEN;
insert_by_date(commit, &revs->commits);
}
}
list = list->next;
}
if (revs->no_walk)
return;
if (revs->limited)
limit_list(revs);
if (revs->topo_order)

View File

@ -11,6 +11,7 @@
#define ADDED (1u<<7) /* Parents already parsed and added? */
struct rev_info;
struct log_info;
typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);
@ -27,6 +28,7 @@ struct rev_info {
/* Traversal flags */
unsigned int dense:1,
no_merges:1,
no_walk:1,
remove_empty_trees:1,
lifo:1,
topo_order:1,
@ -39,13 +41,32 @@ struct rev_info {
boundary:1,
parents:1;
/* Diff flags */
unsigned int diff:1,
full_diff:1,
show_root_diff:1,
no_commit_id:1,
verbose_header:1,
ignore_merges:1,
combine_merges:1,
dense_combined_merges:1,
always_show_header:1;
/* Format info */
unsigned int shown_one:1,
abbrev_commit:1;
unsigned int abbrev;
enum cmit_fmt commit_format;
struct log_info *loginfo;
/* special limits */
int max_count;
unsigned long max_age;
unsigned long min_age;
/* paths limiting */
/* diff info for patches and for paths limiting */
struct diff_options diffopt;
struct diff_options pruning;
topo_sort_set_fn_t topo_setter;
topo_sort_get_fn_t topo_getter;

View File

@ -49,7 +49,7 @@ test_expect_success 'git diff HEAD' 'cmp diff.expect diff.output'
#test_expect_success 'git-read-tree --reset HEAD' "git-read-tree --reset HEAD ; test \"hello: needs update\" = \"$(git-update-index --refresh)\""
cat > whatchanged.expect << EOF
diff-tree VARIABLE (from root)
commit VARIABLE
Author: VARIABLE
Date: VARIABLE
@ -72,7 +72,7 @@ index 0000000..557db03
EOF
git-whatchanged -p --root | \
sed -e "1s/^\(.\{10\}\).\{40\}/\1VARIABLE/" \
sed -e "1s/^\(.\{7\}\).\{40\}/\1VARIABLE/" \
-e "2,3s/^\(.\{8\}\).*$/\1VARIABLE/" \
> whatchanged.output
test_expect_success 'git-whatchanged -p --root' 'cmp whatchanged.expect whatchanged.output'