Merge branch 'lt/decorate'

* lt/decorate:
  rev-list documentation: clarify the two parts of history simplification
  Document "git log --simplify-by-decoration"
  Document "git log --source"
  revision traversal: '--simplify-by-decoration'
  Make '--decorate' set an explicit 'show_decorations' flag
  revision: make tree comparison functions take commits rather than trees
  Add a 'source' decorator for commits

Conflicts:
	Documentation/rev-list-options.txt
This commit is contained in:
Junio C Hamano 2008-11-12 21:51:19 -08:00
commit b2b80c107f
8 changed files with 113 additions and 14 deletions

View file

@ -40,6 +40,10 @@ include::diff-options.txt[]
--decorate::
Print out the ref names of any commits that are shown.
--source::
Print out the ref name given on the command line by which each
commit was reached.
--full-diff::
Without this flag, "git log -p <path>..." shows commits that
touch the specified paths, and diffs about the same specified

View file

@ -285,8 +285,52 @@ See also linkgit:git-reflog[1].
History Simplification
~~~~~~~~~~~~~~~~~~~~~~
When optional paths are given, 'git rev-list' simplifies commits with
various strategies, according to the options you have selected.
Sometimes you are only interested in parts of the history, for example the
commits modifying a particular <path>. But there are two parts of
'History Simplification', one part is selecting the commits and the other
is how to do it, as there are various strategies to simplify the history.
The following options select the commits to be shown:
<paths>::
Commits modifying the given <paths> are selected.
--simplify-by-decoration::
Commits that are referred by some branch or tag are selected.
Note that extra commits can be shown to give a meaningful history.
The following options affect the way the simplification is performed:
Default mode::
Simplifies the history to the simplest history explaining the
final state of the tree. Simplest because it prunes some side
branches if the end result is the same (i.e. merging branches
with the same content)
--full-history::
As the default mode but does not prune some history.
--dense::
Only the selected commits are shown, plus some to have a
meaningful history.
--sparse::
All commits in the simplified history are shown.
--simplify-merges::
Additional option to '--full-history' to remove some needless
merges from the resulting history, as there are no selected
commits contributing to this merge.
A more detailed explanation follows.
Suppose you specified `foo` as the <paths>. We shall call commits
that modify `foo` !TREESAME, and the rest TREESAME. (In a diff
@ -456,6 +500,14 @@ Note the major differences in `N` and `P` over '\--full-history':
removed completely, because it had one parent and is TREESAME.
--
The '\--simplify-by-decoration' option allows you to view only the
big picture of the topology of the history, by omitting commits
that are not referenced by tags. Commits are marked as !TREESAME
(in other words, kept after history simplification rules described
above) if (1) they are referenced by tags, or (2) they change the
contents of the paths given on the command line. All other
commits are marked as TREESAME (subject to be simplified away).
ifdef::git-rev-list[]
Bisection Helpers
~~~~~~~~~~~~~~~~~

View file

@ -28,7 +28,6 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
struct rev_info *rev)
{
int i;
int decorate = 0;
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
@ -55,7 +54,9 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
const char *arg = argv[i];
if (!strcmp(arg, "--decorate")) {
load_ref_decorations();
decorate = 1;
rev->show_decorations = 1;
} else if (!strcmp(arg, "--source")) {
rev->show_source = 1;
} else
die("unrecognized argument: %s", arg);
}

View file

@ -100,7 +100,7 @@ static void show_commit(struct commit *commit)
children = children->next;
}
}
show_decorations(commit);
show_decorations(&revs, commit);
if (revs.commit_format == CMIT_FMT_ONELINE)
putchar(' ');
else

View file

@ -52,11 +52,15 @@ static void show_parents(struct commit *commit, int abbrev)
}
}
void show_decorations(struct commit *commit)
void show_decorations(struct rev_info *opt, struct commit *commit)
{
const char *prefix;
struct name_decoration *decoration;
if (opt->show_source && commit->util)
printf(" %s", (char *) commit->util);
if (!opt->show_decorations)
return;
decoration = lookup_decoration(&name_decoration, &commit->object);
if (!decoration)
return;
@ -279,7 +283,7 @@ void show_log(struct rev_info *opt)
fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
if (opt->print_parents)
show_parents(commit, abbrev_commit);
show_decorations(commit);
show_decorations(opt, commit);
if (opt->graph && !graph_is_commit_finished(opt->graph)) {
putchar('\n');
graph_show_remainder(opt->graph);
@ -352,7 +356,7 @@ void show_log(struct rev_info *opt)
printf(" (from %s)",
diff_unique_abbrev(parent->object.sha1,
abbrev_commit));
show_decorations(commit);
show_decorations(opt, commit);
printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
if (opt->commit_format == CMIT_FMT_ONELINE) {
putchar(' ');

View file

@ -12,7 +12,7 @@ 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);
void show_decorations(struct commit *commit);
void show_decorations(struct rev_info *opt, struct commit *commit);
void log_write_email_headers(struct rev_info *opt, const char *name,
const char **subject_p,
const char **extra_headers_p,

View file

@ -11,6 +11,7 @@
#include "reflog-walk.h"
#include "patch-ids.h"
#include "decorate.h"
#include "log-tree.h"
volatile show_early_output_fn_t show_early_output;
@ -199,6 +200,8 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
mark_parents_uninteresting(commit);
revs->limited = 1;
}
if (revs->show_source && !commit->util)
commit->util = (void *) name;
return commit;
}
@ -292,10 +295,31 @@ static void file_change(struct diff_options *options,
DIFF_OPT_SET(options, HAS_CHANGES);
}
static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct commit *commit)
{
struct tree *t1 = parent->tree;
struct tree *t2 = commit->tree;
if (!t1)
return REV_TREE_NEW;
if (revs->simplify_by_decoration) {
/*
* If we are simplifying by decoration, then the commit
* is worth showing if it has a tag pointing at it.
*/
if (lookup_decoration(&name_decoration, &commit->object))
return REV_TREE_DIFFERENT;
/*
* A commit that is not pointed by a tag is uninteresting
* if we are not limited by path. This means that you will
* see the usual "commits that touch the paths" plus any
* tagged commit by specifying both --simplify-by-decoration
* and pathspec.
*/
if (!revs->prune_data)
return REV_TREE_SAME;
}
if (!t2)
return REV_TREE_DIFFERENT;
tree_difference = REV_TREE_SAME;
@ -306,12 +330,13 @@ static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree
return tree_difference;
}
static int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
{
int retval;
void *tree;
unsigned long size;
struct tree_desc empty, real;
struct tree *t1 = commit->tree;
if (!t1)
return 0;
@ -345,7 +370,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
return;
if (!commit->parents) {
if (rev_same_tree_as_empty(revs, commit->tree))
if (rev_same_tree_as_empty(revs, commit))
commit->object.flags |= TREESAME;
return;
}
@ -365,7 +390,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
die("cannot simplify commit %s (because of %s)",
sha1_to_hex(commit->object.sha1),
sha1_to_hex(p->object.sha1));
switch (rev_compare_tree(revs, p->tree, commit->tree)) {
switch (rev_compare_tree(revs, p, commit)) {
case REV_TREE_SAME:
tree_same = 1;
if (!revs->simplify_history || (p->object.flags & UNINTERESTING)) {
@ -385,7 +410,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
case REV_TREE_NEW:
if (revs->remove_empty_trees &&
rev_same_tree_as_empty(revs, p->tree)) {
rev_same_tree_as_empty(revs, p)) {
/* We are adding all the specified
* paths from this parent, so the
* history beyond this parent is not
@ -484,6 +509,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
if (parse_commit(p) < 0)
return -1;
if (revs->show_source && !p->util)
p->util = commit->util;
p->object.flags |= left_flag;
if (!(p->object.flags & SEEN)) {
p->object.flags |= SEEN;
@ -1033,6 +1060,14 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->rewrite_parents = 1;
revs->simplify_history = 0;
revs->limited = 1;
} else if (!strcmp(arg, "--simplify-by-decoration")) {
revs->simplify_merges = 1;
revs->rewrite_parents = 1;
revs->simplify_history = 0;
revs->simplify_by_decoration = 1;
revs->limited = 1;
revs->prune = 1;
load_ref_decorations();
} else if (!strcmp(arg, "--date-order")) {
revs->lifo = 0;
revs->topo_order = 1;

View file

@ -43,6 +43,7 @@ struct rev_info {
lifo:1,
topo_order:1,
simplify_merges:1,
simplify_by_decoration:1,
tag_objects:1,
tree_objects:1,
blob_objects:1,
@ -53,6 +54,8 @@ struct rev_info {
left_right:1,
rewrite_parents:1,
print_parents:1,
show_source:1,
show_decorations:1,
reverse:1,
reverse_output_stage:1,
cherry_pick:1,