Skip to content

Commit 281eee4

Browse files
committed
revision: keep track of the end-user input from the command line
Given a complex set of revision specifiers on the command line, it is too late to look at the flags of the objects in the initial traversal list at the beginning of limit_list() in order to determine what the objects the end-user explicitly listed on the command line were. The process to move objects from the pending array to the traversal list may have marked objects that are not mentioned as UNINTERESTING, when handle_commit() marked the parents of UNINTERESTING commits mentioned on the command line by calling mark_parents_uninteresting(). This made "rev-list --ancestry-path ^A ..." to mistakenly list commits that are descendants of A's parents but that are not descendants of A itself, as ^A from the command line causes A and its parents marked as UNINTERESTING before coming to limit_list(), and we try to enumerate the commits that are descendants of these commits that are UNINTERESTING before we start walking the history. It actually is too late even if we inspected the pending object array before calling prepare_revision_walk(), as some of the same objects might have been mentioned twice, once as positive and another time as negative. The "rev-list --some-option A --not --all" command may want to notice, even if the resulting set is empty, that the user showed some interest in "A" and do something special about it. Prepare a separate array to keep track of what syntactic element was used to cause each object to appear in the pending array from the command line, and populate it as setup_revisions() parses the command line. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 81f4953 commit 281eee4

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

revision.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,23 @@ static int limit_list(struct rev_info *revs)
797797
return 0;
798798
}
799799

800+
static void add_rev_cmdline(struct rev_info *revs,
801+
struct object *item,
802+
const char *name,
803+
int whence,
804+
unsigned flags)
805+
{
806+
struct rev_cmdline_info *info = &revs->cmdline;
807+
int nr = info->nr;
808+
809+
ALLOC_GROW(info->rev, nr + 1, info->alloc);
810+
info->rev[nr].item = item;
811+
info->rev[nr].name = name;
812+
info->rev[nr].whence = whence;
813+
info->rev[nr].flags = flags;
814+
info->nr++;
815+
}
816+
800817
struct all_refs_cb {
801818
int all_flags;
802819
int warned_bad_reflog;
@@ -809,6 +826,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, int flag,
809826
struct all_refs_cb *cb = cb_data;
810827
struct object *object = get_reference(cb->all_revs, path, sha1,
811828
cb->all_flags);
829+
add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
812830
add_pending_object(cb->all_revs, object, path);
813831
return 0;
814832
}
@@ -835,6 +853,7 @@ static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data)
835853
struct object *o = parse_object(sha1);
836854
if (o) {
837855
o->flags |= cb->all_flags;
856+
/* ??? CMDLINEFLAGS ??? */
838857
add_pending_object(cb->all_revs, o, "");
839858
}
840859
else if (!cb->warned_bad_reflog) {
@@ -871,12 +890,13 @@ static void handle_reflog(struct rev_info *revs, unsigned flags)
871890
for_each_reflog(handle_one_reflog, &cb);
872891
}
873892

874-
static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
893+
static int add_parents_only(struct rev_info *revs, const char *arg_, int flags)
875894
{
876895
unsigned char sha1[20];
877896
struct object *it;
878897
struct commit *commit;
879898
struct commit_list *parents;
899+
const char *arg = arg_;
880900

881901
if (*arg == '^') {
882902
flags ^= UNINTERESTING;
@@ -898,6 +918,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
898918
for (parents = commit->parents; parents; parents = parents->next) {
899919
it = &parents->item->object;
900920
it->flags |= flags;
921+
add_rev_cmdline(revs, it, arg_, REV_CMD_PARENTS_ONLY, flags);
901922
add_pending_object(revs, it, arg);
902923
}
903924
return 1;
@@ -987,7 +1008,7 @@ static void prepare_show_merge(struct rev_info *revs)
9871008
revs->limited = 1;
9881009
}
9891010

990-
int handle_revision_arg(const char *arg, struct rev_info *revs,
1011+
int handle_revision_arg(const char *arg_, struct rev_info *revs,
9911012
int flags,
9921013
int cant_be_filename)
9931014
{
@@ -996,6 +1017,7 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
9961017
struct object *object;
9971018
unsigned char sha1[20];
9981019
int local_flags;
1020+
const char *arg = arg_;
9991021

10001022
dotdot = strstr(arg, "..");
10011023
if (dotdot) {
@@ -1004,6 +1026,7 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
10041026
const char *this = arg;
10051027
int symmetric = *next == '.';
10061028
unsigned int flags_exclude = flags ^ UNINTERESTING;
1029+
unsigned int a_flags;
10071030

10081031
*dotdot = 0;
10091032
next += symmetric;
@@ -1036,10 +1059,15 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
10361059
add_pending_commit_list(revs, exclude,
10371060
flags_exclude);
10381061
free_commit_list(exclude);
1039-
a->object.flags |= flags | SYMMETRIC_LEFT;
1062+
a_flags = flags | SYMMETRIC_LEFT;
10401063
} else
1041-
a->object.flags |= flags_exclude;
1064+
a_flags = flags_exclude;
1065+
a->object.flags |= a_flags;
10421066
b->object.flags |= flags;
1067+
add_rev_cmdline(revs, &a->object, this,
1068+
REV_CMD_LEFT, a_flags);
1069+
add_rev_cmdline(revs, &b->object, next,
1070+
REV_CMD_RIGHT, flags);
10431071
add_pending_object(revs, &a->object, this);
10441072
add_pending_object(revs, &b->object, next);
10451073
return 0;
@@ -1070,6 +1098,7 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
10701098
if (!cant_be_filename)
10711099
verify_non_filename(revs->prefix, arg);
10721100
object = get_reference(revs, arg, sha1, flags ^ local_flags);
1101+
add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
10731102
add_pending_object_with_mode(revs, object, arg, mode);
10741103
return 0;
10751104
}

revision.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,23 @@ struct rev_info;
2323
struct log_info;
2424
struct string_list;
2525

26+
struct rev_cmdline_info {
27+
unsigned int nr;
28+
unsigned int alloc;
29+
struct rev_cmdline_entry {
30+
struct object *item;
31+
const char *name;
32+
enum {
33+
REV_CMD_REF,
34+
REV_CMD_PARENTS_ONLY,
35+
REV_CMD_LEFT,
36+
REV_CMD_RIGHT,
37+
REV_CMD_REV
38+
} whence;
39+
unsigned flags;
40+
} *rev;
41+
};
42+
2643
struct rev_info {
2744
/* Starting list */
2845
struct commit_list *commits;
@@ -31,6 +48,9 @@ struct rev_info {
3148
/* Parents of shown commits */
3249
struct object_array boundary_commits;
3350

51+
/* The end-points specified by the end user */
52+
struct rev_cmdline_info cmdline;
53+
3454
/* Basic information */
3555
const char *prefix;
3656
const char *def;

0 commit comments

Comments
 (0)