From 3381c790e5ca04326d26e1dd9ff482961c6e425b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 8 Apr 2006 17:05:58 -0700 Subject: [PATCH 1/3] Make "--parents" logs also be incremental The parent rewriting feature caused us to create the whole history in one go, and then simplify it later, because of how rewrite_parents() had been written. However, with a little tweaking, it's perfectly possible to do even that one incrementally. Right now, this doesn't really much matter, because every user of "--parents" will probably generally _also_ use "--topo-order", which will cause the old non-incremental behaviour anyway. However, I'm hopeful that we could make even the topological sort incremental, or at least _partially_ so (for example, make it incremental up to the first merge). In the meantime, this at least moves things in the right direction, and removes a strange special case. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- http-push.c | 10 +++++----- rev-list.c | 4 ++-- revision.c | 21 ++++++++++----------- revision.h | 1 + 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/http-push.c b/http-push.c index b60fa8d241..57cefdea53 100644 --- a/http-push.c +++ b/http-push.c @@ -59,12 +59,12 @@ enum XML_Status { #define LOCK_TIME 600 #define LOCK_REFRESH 30 -/* bits #0-4 in revision.h */ +/* bits #0-6 in revision.h */ -#define LOCAL (1u << 5) -#define REMOTE (1u << 6) -#define FETCHING (1u << 7) -#define PUSHING (1u << 8) +#define LOCAL (1u << 7) +#define REMOTE (1u << 8) +#define FETCHING (1u << 9) +#define PUSHING (1u << 10) /* We allow "recursive" symbolic refs. Only within reason, though */ #define MAXDEPTH 5 diff --git a/rev-list.c b/rev-list.c index 1301502627..359195b547 100644 --- a/rev-list.c +++ b/rev-list.c @@ -7,9 +7,9 @@ #include "tree-walk.h" #include "revision.h" -/* bits #0-5 in revision.h */ +/* bits #0-6 in revision.h */ -#define COUNTED (1u<<6) +#define COUNTED (1u<<7) static const char rev_list_usage[] = "git-rev-list [OPTION] ... [ -- paths... ]\n" diff --git a/revision.c b/revision.c index ce35b5a7e6..fe26562381 100644 --- a/revision.c +++ b/revision.c @@ -340,6 +340,10 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st { struct commit_list *parent = commit->parents; + if (commit->object.flags & ADDED) + return; + commit->object.flags |= ADDED; + /* * If the commit is uninteresting, don't try to * prune parents - we want the maximal uninteresting @@ -705,13 +709,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch if (revs->prune_data) { diff_tree_setup_paths(revs->prune_data); revs->prune_fn = try_to_simplify_commit; - - /* - * If we fix up parent data, we currently cannot - * do that on-the-fly. - */ - if (revs->parents) - revs->limited = 1; } return left; @@ -728,10 +725,12 @@ void prepare_revision_walk(struct rev_info *revs) revs->topo_getter); } -static int rewrite_one(struct commit **pp) +static int rewrite_one(struct rev_info *revs, struct commit **pp) { for (;;) { struct commit *p = *pp; + if (!revs->limited) + add_parents_to_list(revs, p, &revs->commits); if (p->object.flags & (TREECHANGE | UNINTERESTING)) return 0; if (!p->parents) @@ -740,12 +739,12 @@ static int rewrite_one(struct commit **pp) } } -static void rewrite_parents(struct commit *commit) +static void rewrite_parents(struct rev_info *revs, struct commit *commit) { struct commit_list **pp = &commit->parents; while (*pp) { struct commit_list *parent = *pp; - if (rewrite_one(&parent->item) < 0) { + if (rewrite_one(revs, &parent->item) < 0) { *pp = parent->next; continue; } @@ -802,7 +801,7 @@ struct commit *get_revision(struct rev_info *revs) if (!(commit->object.flags & TREECHANGE)) continue; if (revs->parents) - rewrite_parents(commit); + rewrite_parents(revs, commit); } commit->object.flags |= SHOWN; return commit; diff --git a/revision.h b/revision.h index 0caeecf00f..83d28d5205 100644 --- a/revision.h +++ b/revision.h @@ -7,6 +7,7 @@ #define SHOWN (1u<<3) #define TMP_MARK (1u<<4) /* for isolated cases; clean after use */ #define BOUNDARY (1u<<5) +#define ADDED (1u<<6) /* Parents already parsed and added? */ struct rev_info; From a13ba129cdc66b60eef177696084ff80034069b7 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Sun, 9 Apr 2006 15:43:17 +0200 Subject: [PATCH 2/3] Improve the git-diff-tree -c/-cc documentation This tries to clarify the -c/-cc documentation and clean up the style and grammar. Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- Documentation/git-diff-tree.txt | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt index 9153e4cf2a..2169169850 100644 --- a/Documentation/git-diff-tree.txt +++ b/Documentation/git-diff-tree.txt @@ -60,7 +60,8 @@ separated with a single space are given. -m:: By default, "git-diff-tree --stdin" does not show differences for merge commits. With this flag, it shows - differences to that commit from all of its parents. + differences to that commit from all of its parents. See + also '-c'. -s:: By default, "git-diff-tree --stdin" shows differences, @@ -81,19 +82,25 @@ separated with a single space are given. git-diff-tree outputs a line with the commit ID when applicable. This flag suppressed the commit ID output. --c,--cc:: - These flags change the way a merge commit is displayed +-c:: + This flag changes the way a merge commit is displayed (which means it is useful only when the command is given one , or '--stdin'). It shows the differences - from each of the parents to the merge result - simultaneously, instead of showing pairwise diff between - a parent and the result one at a time, which '-m' option - output does. '--cc' further compresses the output by - omiting hunks that show differences from only one + from each of the parents to the merge result simultaneously + instead of showing pairwise diff between a parent and the + result one at a time (which is what the '-m' option does). + Furthermore, it lists only files which were modified + from all parents. + +-cc:: + This flag changes the way a merge commit patch is displayed, + in a similar way to the '-c' option. It implies the '-c' + and '-p' options and further compresses the patch output + by omitting hunks that show differences from only one parent, or show the same change from all but one parent for an Octopus merge. When this optimization makes all hunks disappear, the commit itself and the commit log - message is not shown, just like any other "empty diff" cases. + message is not shown, just like in any other "empty diff" case. --always:: Show the commit itself and the commit log message even From 77882f60d9df2fd410ba7d732b01738315643c05 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 10 Apr 2006 15:57:24 -0700 Subject: [PATCH 3/3] Retire diffcore-pathspec. Nobody except diff-stages used it -- the callers instead filtered the input to diffcore themselves. Make diff-stages do that as well and retire diffcore-pathspec. Signed-off-by: Junio C Hamano --- Makefile | 2 +- diff-stages.c | 17 ++++++----- diff.c | 2 -- diff.h | 1 - diffcore-pathspec.c | 70 --------------------------------------------- 5 files changed, 11 insertions(+), 81 deletions(-) delete mode 100644 diffcore-pathspec.c diff --git a/Makefile b/Makefile index 6b10eaa413..a979205ec5 100644 --- a/Makefile +++ b/Makefile @@ -197,7 +197,7 @@ LIB_H = \ tree-walk.h DIFF_OBJS = \ - diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \ + diff.o diffcore-break.o diffcore-order.o \ diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \ diffcore-delta.o diff --git a/diff-stages.c b/diff-stages.c index 9968d6ce1c..dcd20e79e4 100644 --- a/diff-stages.c +++ b/diff-stages.c @@ -11,15 +11,17 @@ static const char diff_stages_usage[] = "git-diff-stages [] [...]" COMMON_DIFF_OPTIONS_HELP; -static void diff_stages(int stage1, int stage2) +static void diff_stages(int stage1, int stage2, const char **pathspec) { int i = 0; while (i < active_nr) { struct cache_entry *ce, *stages[4] = { NULL, }; struct cache_entry *one, *two; const char *name; - int len; + int len, skip; + ce = active_cache[i]; + skip = !ce_path_match(ce, pathspec); len = ce_namelen(ce); name = ce->name; for (;;) { @@ -34,7 +36,8 @@ static void diff_stages(int stage1, int stage2) } one = stages[stage1]; two = stages[stage2]; - if (!one && !two) + + if (skip || (!one && !two)) continue; if (!one) diff_addremove(&diff_options, '+', ntohl(two->ce_mode), @@ -54,8 +57,8 @@ static void diff_stages(int stage1, int stage2) int main(int ac, const char **av) { int stage1, stage2; - - setup_git_directory(); + const char *prefix = setup_git_directory(); + const char **pathspec = NULL; git_config(git_diff_config); read_cache(); @@ -89,12 +92,12 @@ int main(int ac, const char **av) usage(diff_stages_usage); av += 3; /* The rest from av[0] are for paths restriction. */ - diff_options.paths = av; + pathspec = get_pathspec(prefix, av); if (diff_setup_done(&diff_options) < 0) usage(diff_stages_usage); - diff_stages(stage1, stage2); + diff_stages(stage1, stage2, pathspec); diffcore_std(&diff_options); diff_flush(&diff_options); return 0; diff --git a/diff.c b/diff.c index 30e4d50b95..2fa285a8ef 100644 --- a/diff.c +++ b/diff.c @@ -1375,8 +1375,6 @@ static void diffcore_apply_filter(const char *filter) void diffcore_std(struct diff_options *options) { - if (options->paths && options->paths[0]) - diffcore_pathspec(options->paths); if (options->break_opt != -1) diffcore_break(options->break_opt); if (options->detect_rename) diff --git a/diff.h b/diff.h index 0cebec113f..a02ef28201 100644 --- a/diff.h +++ b/diff.h @@ -20,7 +20,6 @@ typedef void (*add_remove_fn_t)(struct diff_options *options, const char *base, const char *path); struct diff_options { - const char **paths; const char *filter; const char *orderfile; const char *pickaxe; diff --git a/diffcore-pathspec.c b/diffcore-pathspec.c deleted file mode 100644 index 139fe882f9..0000000000 --- a/diffcore-pathspec.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2005 Junio C Hamano - */ -#include "cache.h" -#include "diff.h" -#include "diffcore.h" - -struct path_spec { - const char *spec; - int len; -}; - -static int matches_pathspec(const char *name, struct path_spec *s, int cnt) -{ - int i; - int namelen; - - if (cnt == 0) - return 1; - - namelen = strlen(name); - for (i = 0; i < cnt; i++) { - int len = s[i].len; - if (namelen < len) - continue; - if (memcmp(s[i].spec, name, len)) - continue; - if (s[i].spec[len-1] == '/' || - name[len] == 0 || - name[len] == '/') - return 1; - if (!len) - return 1; - } - return 0; -} - -void diffcore_pathspec(const char **pathspec) -{ - struct diff_queue_struct *q = &diff_queued_diff; - int i, speccnt; - struct diff_queue_struct outq; - struct path_spec *spec; - - outq.queue = NULL; - outq.nr = outq.alloc = 0; - - for (i = 0; pathspec[i]; i++) - ; - speccnt = i; - if (!speccnt) - return; - - spec = xmalloc(sizeof(*spec) * speccnt); - for (i = 0; pathspec[i]; i++) { - spec[i].spec = pathspec[i]; - spec[i].len = strlen(pathspec[i]); - } - - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - if (matches_pathspec(p->two->path, spec, speccnt)) - diff_q(&outq, p); - else - diff_free_filepair(p); - } - free(q->queue); - *q = outq; - return; -}