Skip to content

Commit 708cbef

Browse files
committed
Merge branch 'jz/rev-list-exclude-first-parent-only'
"git log" and friends learned an option --exclude-first-parent-only to propagate UNINTERESTING bit down only along the first-parent chain, just like --first-parent option shows commits that lack the UNINTERESTING bit only along the first-parent chain. * jz/rev-list-exclude-first-parent-only: git-rev-list: add --exclude-first-parent-only flag
2 parents d077db1 + 9d505b7 commit 708cbef

File tree

6 files changed

+51
-26
lines changed

6 files changed

+51
-26
lines changed

Documentation/rev-list-options.txt

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,27 @@ again. Equivalent forms are `--min-parents=0` (any commit has 0 or more
122122
parents) and `--max-parents=-1` (negative numbers denote no upper limit).
123123

124124
--first-parent::
125-
Follow only the first parent commit upon seeing a merge
126-
commit. This option can give a better overview when
127-
viewing the evolution of a particular topic branch,
128-
because merges into a topic branch tend to be only about
129-
adjusting to updated upstream from time to time, and
130-
this option allows you to ignore the individual commits
131-
brought in to your history by such a merge.
125+
When finding commits to include, follow only the first
126+
parent commit upon seeing a merge commit. This option
127+
can give a better overview when viewing the evolution of
128+
a particular topic branch, because merges into a topic
129+
branch tend to be only about adjusting to updated upstream
130+
from time to time, and this option allows you to ignore
131+
the individual commits brought in to your history by such
132+
a merge.
132133
ifdef::git-log[]
133134
+
134135
This option also changes default diff format for merge commits
135136
to `first-parent`, see `--diff-merges=first-parent` for details.
136137
endif::git-log[]
137138

139+
--exclude-first-parent-only::
140+
When finding commits to exclude (with a '{caret}'), follow only
141+
the first parent commit upon seeing a merge commit.
142+
This can be used to find the set of changes in a topic branch
143+
from the point where it diverged from the remote branch, given
144+
that arbitrary merges can be valid topic branch changes.
145+
138146
--not::
139147
Reverses the meaning of the '{caret}' prefix (or lack thereof)
140148
for all following revision specifiers, up to the next `--not`.

blame.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2615,7 +2615,7 @@ void assign_blame(struct blame_scoreboard *sb, int opt)
26152615
else {
26162616
commit->object.flags |= UNINTERESTING;
26172617
if (commit->object.parsed)
2618-
mark_parents_uninteresting(commit);
2618+
mark_parents_uninteresting(sb->revs, commit);
26192619
}
26202620
/* treat root commit as boundary */
26212621
if (!commit->parents && !sb->show_root)

revision.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ static void commit_stack_clear(struct commit_stack *stack)
273273
stack->nr = stack->alloc = 0;
274274
}
275275

276-
static void mark_one_parent_uninteresting(struct commit *commit,
276+
static void mark_one_parent_uninteresting(struct rev_info *revs, struct commit *commit,
277277
struct commit_stack *pending)
278278
{
279279
struct commit_list *l;
@@ -290,20 +290,26 @@ static void mark_one_parent_uninteresting(struct commit *commit,
290290
* wasn't uninteresting), in which case we need
291291
* to mark its parents recursively too..
292292
*/
293-
for (l = commit->parents; l; l = l->next)
293+
for (l = commit->parents; l; l = l->next) {
294294
commit_stack_push(pending, l->item);
295+
if (revs && revs->exclude_first_parent_only)
296+
break;
297+
}
295298
}
296299

297-
void mark_parents_uninteresting(struct commit *commit)
300+
void mark_parents_uninteresting(struct rev_info *revs, struct commit *commit)
298301
{
299302
struct commit_stack pending = COMMIT_STACK_INIT;
300303
struct commit_list *l;
301304

302-
for (l = commit->parents; l; l = l->next)
303-
mark_one_parent_uninteresting(l->item, &pending);
305+
for (l = commit->parents; l; l = l->next) {
306+
mark_one_parent_uninteresting(revs, l->item, &pending);
307+
if (revs && revs->exclude_first_parent_only)
308+
break;
309+
}
304310

305311
while (pending.nr > 0)
306-
mark_one_parent_uninteresting(commit_stack_pop(&pending),
312+
mark_one_parent_uninteresting(revs, commit_stack_pop(&pending),
307313
&pending);
308314

309315
commit_stack_clear(&pending);
@@ -441,7 +447,7 @@ static struct commit *handle_commit(struct rev_info *revs,
441447
if (repo_parse_commit(revs->repo, commit) < 0)
442448
die("unable to parse commit %s", name);
443449
if (flags & UNINTERESTING) {
444-
mark_parents_uninteresting(commit);
450+
mark_parents_uninteresting(revs, commit);
445451

446452
if (!revs->topo_order || !generation_numbers_enabled(the_repository))
447453
revs->limited = 1;
@@ -1124,14 +1130,16 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
11241130
if (repo_parse_commit_gently(revs->repo, p, 1) < 0)
11251131
continue;
11261132
if (p->parents)
1127-
mark_parents_uninteresting(p);
1133+
mark_parents_uninteresting(revs, p);
11281134
if (p->object.flags & SEEN)
11291135
continue;
11301136
p->object.flags |= (SEEN | NOT_USER_GIVEN);
11311137
if (list)
11321138
commit_list_insert_by_date(p, list);
11331139
if (queue)
11341140
prio_queue_put(queue, p);
1141+
if (revs->exclude_first_parent_only)
1142+
break;
11351143
}
11361144
return 0;
11371145
}
@@ -1422,7 +1430,7 @@ static int limit_list(struct rev_info *revs)
14221430
if (process_parents(revs, commit, &original_list, NULL) < 0)
14231431
return -1;
14241432
if (obj->flags & UNINTERESTING) {
1425-
mark_parents_uninteresting(commit);
1433+
mark_parents_uninteresting(revs, commit);
14261434
slop = still_interesting(original_list, date, slop, &interesting_cache);
14271435
if (slop)
14281436
continue;
@@ -2223,6 +2231,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
22232231
return argcount;
22242232
} else if (!strcmp(arg, "--first-parent")) {
22252233
revs->first_parent_only = 1;
2234+
} else if (!strcmp(arg, "--exclude-first-parent-only")) {
2235+
revs->exclude_first_parent_only = 1;
22262236
} else if (!strcmp(arg, "--ancestry-path")) {
22272237
revs->ancestry_path = 1;
22282238
revs->simplify_history = 0;
@@ -3345,7 +3355,7 @@ static void explore_walk_step(struct rev_info *revs)
33453355
return;
33463356

33473357
if (c->object.flags & UNINTERESTING)
3348-
mark_parents_uninteresting(c);
3358+
mark_parents_uninteresting(revs, c);
33493359

33503360
for (p = c->parents; p; p = p->next)
33513361
test_flag_and_insert(&info->explore_queue, p->item, TOPO_WALK_EXPLORED);

revision.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ struct rev_info {
158158
bisect:1,
159159
ancestry_path:1,
160160
first_parent_only:1,
161+
exclude_first_parent_only:1,
161162
line_level_traverse:1,
162163
tree_blobs_in_commit_order:1,
163164

@@ -402,7 +403,7 @@ const char *get_revision_mark(const struct rev_info *revs,
402403
void put_revision_mark(const struct rev_info *revs,
403404
const struct commit *commit);
404405

405-
void mark_parents_uninteresting(struct commit *commit);
406+
void mark_parents_uninteresting(struct rev_info *revs, struct commit *commit);
406407
void mark_tree_uninteresting(struct repository *r, struct tree *tree);
407408
void mark_trees_uninteresting_sparse(struct repository *r, struct oidset *trees);
408409

shallow.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ static int mark_uninteresting(const char *refname, const struct object_id *oid,
603603
if (!commit)
604604
return 0;
605605
commit->object.flags |= UNINTERESTING;
606-
mark_parents_uninteresting(commit);
606+
mark_parents_uninteresting(NULL, commit);
607607
return 0;
608608
}
609609

t/t6012-rev-list-simplify.sh

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@ unnote () {
1616
}
1717

1818
#
19-
# Create a test repo with interesting commit graph:
19+
# Create a test repo with an interesting commit graph:
2020
#
21-
# A--B----------G--H--I--K--L
22-
# \ \ / /
23-
# \ \ / /
24-
# C------E---F J
25-
# \_/
21+
# A-----B-----G--H--I--K--L
22+
# \ \ / /
23+
# \ \ / /
24+
# C--D--E--F J
2625
#
2726
# The commits are laid out from left-to-right starting with
2827
# the root commit A and terminating at the tip commit L.
@@ -142,6 +141,13 @@ check_result 'I B A' --author-date-order -- file
142141
check_result 'H' --first-parent -- another-file
143142
check_result 'H' --first-parent --topo-order -- another-file
144143

144+
check_result 'L K I H G B A' --first-parent L
145+
check_result 'F E D C' --exclude-first-parent-only F ^L
146+
check_result '' F ^L
147+
check_result 'L K I H G J' L ^F
148+
check_result 'L K I H G B J' --exclude-first-parent-only L ^F
149+
check_result 'L K I H G B' --exclude-first-parent-only --first-parent L ^F
150+
145151
check_result 'E C B A' --full-history E -- lost
146152
test_expect_success 'full history simplification without parent' '
147153
printf "%s\n" E C B A >expect &&

0 commit comments

Comments
 (0)