Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit 143f1ea

Browse files
kjbracey2gitster
authored andcommitted
simplify-merges: drop merge from irrelevant side branch
Reimplement commit 4b7f53d on top of the new simplify-merges infrastructure, tightening the condition to only consider root parents; the original version incorrectly dropped parents that were TREESAME to anything. Original log message follows. The merge simplification rule stated in 6546b59 (revision traversal: show full history with merge simplification, 2008-07-31) still treated merge commits too specially. Namely, in a history with this shape: ---o---o---M / x---x---x where three 'x' were on a history completely unrelated to the main history 'o' and do not touch any of the paths we are following, we still said that after simplifying all of the parents of M, 'x' (which is the leftmost 'x' that rightmost 'x simplifies down to) and 'o' (which would be the last commit on the main history that touches the paths we are following) are independent from each other, and both need to be kept. That is incorrect; when the side branch 'x' never touches the paths, it should be removed to allow M to simplify down to the last commit on the main history that touches the paths. Suggested-by: Junio C Hamano <[email protected]> Signed-off-by: Kevin Bracey <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9c129ea commit 143f1ea

File tree

3 files changed

+47
-15
lines changed

3 files changed

+47
-15
lines changed

Documentation/rev-list-options.txt

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -342,13 +342,13 @@ In the following, we will always refer to the same example history to
342342
illustrate the differences between simplification settings. We assume
343343
that you are filtering for a file `foo` in this commit graph:
344344
-----------------------------------------------------------------------
345-
.-A---M---N---O---P
346-
/ / / / /
347-
I B C D E
348-
\ / / / /
349-
`-------------'
345+
.-A---M---N---O---P---Q
346+
/ / / / / /
347+
I B C D E Y
348+
\ / / / / /
349+
`-------------' X
350350
-----------------------------------------------------------------------
351-
The horizontal line of history A---P is taken to be the first parent of
351+
The horizontal line of history A---Q is taken to be the first parent of
352352
each merge. The commits are:
353353

354354
* `I` is the initial commit, in which `foo` exists with contents
@@ -369,6 +369,10 @@ each merge. The commits are:
369369
* `E` changes `quux` to "xyzzy", and its merge `P` combines the
370370
strings to "quux xyzzy". `P` is TREESAME to `O`, but not to `E`.
371371

372+
* `X` is an indpendent root commit that added a new file `side`, and `Y`
373+
modified it. `Y` is TREESAME to `X`. Its merge `Q` added `side` to `P`, and
374+
`Q` is TREESAME to `P`, but not to `Y`.
375+
372376
'rev-list' walks backwards through history, including or excluding
373377
commits based on whether '\--full-history' and/or parent rewriting
374378
(via '\--parents' or '\--children') are used. The following settings
@@ -409,7 +413,7 @@ parent lines.
409413
the example, we get
410414
+
411415
-----------------------------------------------------------------------
412-
I A B N D O P
416+
I A B N D O P Q
413417
-----------------------------------------------------------------------
414418
+
415419
`M` was excluded because it is TREESAME to both parents. `E`,
@@ -430,7 +434,7 @@ Along each parent, prune away commits that are not included
430434
themselves. This results in
431435
+
432436
-----------------------------------------------------------------------
433-
.-A---M---N---O---P
437+
.-A---M---N---O---P---Q
434438
/ / / / /
435439
I B / D /
436440
\ / / / /
@@ -440,7 +444,7 @@ themselves. This results in
440444
Compare to '\--full-history' without rewriting above. Note that `E`
441445
was pruned away because it is TREESAME, but the parent list of P was
442446
rewritten to contain `E`'s parent `I`. The same happened for `C` and
443-
`N`.
447+
`N`, and `X`, `Y` and `Q`.
444448

445449
In addition to the above settings, you can change whether TREESAME
446450
affects inclusion:
@@ -470,9 +474,9 @@ history according to the following rules:
470474
* Set `C'` to `C`.
471475
+
472476
* Replace each parent `P` of `C'` with its simplification `P'`. In
473-
the process, drop parents that are ancestors of other parents, and
474-
remove duplicates, but take care to never drop all parents that
475-
we are TREESAME to.
477+
the process, drop parents that are ancestors of other parents or that are
478+
root commits TREESAME to an empty tree, and remove duplicates, but take care
479+
to never drop all parents that we are TREESAME to.
476480
+
477481
* If after this parent rewriting, `C'` is a root or merge commit (has
478482
zero or >1 parents), a boundary commit, or !TREESAME, it remains.
@@ -490,14 +494,18 @@ The effect of this is best shown by way of comparing to
490494
`---------'
491495
-----------------------------------------------------------------------
492496
+
493-
Note the major differences in `N` and `P` over '--full-history':
497+
Note the major differences in `N`, `P` and `Q` over '--full-history':
494498
+
495499
--
496500
* `N`'s parent list had `I` removed, because it is an ancestor of the
497501
other parent `M`. Still, `N` remained because it is !TREESAME.
498502
+
499503
* `P`'s parent list similarly had `I` removed. `P` was then
500504
removed completely, because it had one parent and is TREESAME.
505+
+
506+
* `Q`'s parent list had `Y` simplified to `X`. `X` was then removed, because it
507+
was a TREESAME root. `Q` was then removed completely, because it had one
508+
parent and is TREESAME.
501509
--
502510

503511
Finally, there is a fifth simplification mode available:

revision.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2136,6 +2136,22 @@ static int mark_redundant_parents(struct rev_info *revs, struct commit *commit)
21362136
return marked;
21372137
}
21382138

2139+
static int mark_treesame_root_parents(struct rev_info *revs, struct commit *commit)
2140+
{
2141+
struct commit_list *p;
2142+
int marked = 0;
2143+
2144+
for (p = commit->parents; p; p = p->next) {
2145+
struct commit *parent = p->item;
2146+
if (!parent->parents && (parent->object.flags & TREESAME)) {
2147+
parent->object.flags |= TMP_MARK;
2148+
marked++;
2149+
}
2150+
}
2151+
2152+
return marked;
2153+
}
2154+
21392155
/*
21402156
* Awkward naming - this means one parent we are TREESAME to.
21412157
* cf mark_treesame_root_parents: root parents that are TREESAME (to an
@@ -2301,10 +2317,18 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
23012317
* / / o: a commit that touches the paths;
23022318
* ---o----'
23032319
*
2304-
* Detect and simplify this case.
2320+
* Further, a merge of an independent branch that doesn't
2321+
* touch the path will reduce to a treesame root parent:
2322+
*
2323+
* ----o----X X: the commit we are looking at;
2324+
* / o: a commit that touches the paths;
2325+
* r r: a root commit not touching the paths
2326+
*
2327+
* Detect and simplify both cases.
23052328
*/
23062329
if (1 < cnt) {
23072330
int marked = mark_redundant_parents(revs, commit);
2331+
marked += mark_treesame_root_parents(revs, commit);
23082332
if (marked)
23092333
marked -= leave_one_treesame_to_parent(revs, commit);
23102334
if (marked)

t/t6012-rev-list-simplify.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ check_result 'L K J I H G F E D C B A' --full-history
110110
check_result 'K I H E C B A' --full-history -- file
111111
check_result 'K I H E C B A' --full-history --topo-order -- file
112112
check_result 'K I H E C B A' --full-history --date-order -- file
113-
check_outcome failure 'I E C B A' --simplify-merges -- file
113+
check_result 'I E C B A' --simplify-merges -- file
114114
check_result 'I B A' -- file
115115
check_result 'I B A' --topo-order -- file
116116
check_result 'H' --first-parent -- another-file

0 commit comments

Comments
 (0)