Skip to content

Commit 5e04dff

Browse files
committed
filter-repo: add new --no-ff option
Some projects have a strict --no-ff merging policy. With the default behavior of --prune-degenerate, we can prune merge commits in a way that transforms the history into a fast-forward merge. Consider this example: * There are two independent commits or branches, named B & C, which are both built on top of A so that history look like this diagram: A \ \ \ B \ -C * Someone runs the following sequence of commands: * git checkout A * git merge --no-ff B * git merge --no-ff C * This will result in a history that looks like: A---AB---AC \ \ / / \ B / \ / -C- * Later, someone comes along and runs filter-repo, specifying to remove the only path(s) that were modified by B. That would naturally remove commit B and the no-longer-necessary merge commit AB. For someone using a strict no-ff policy, the desired history is A---AC \ / C However, the default handling for --prune-degenerate would notice that AC merely merges C into its own ancestor A, whereas the original AC merged C into something separate (namely, AB). So, it would say that AC has become degenerate and prune it, leaving the simple history of A \ C For projects not using a strict no-ff policy, this simpler history is probably better, but for folks that want a strict no-ff policy, it is unfortunate. Provide a --no-ff option to tweak the --prune-degenerate behavior so that it ignores the first parent being an ancestor of another parent (leaving the first parent unpruned even if it is or becomes degenerate in this fashion). Signed-off-by: Elijah Newren <[email protected]>
1 parent 41787ff commit 5e04dff

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

git-filter-repo

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1870,6 +1870,11 @@ EXAMPLES
18701870
"merge commits have no file changes, they can be pruned. The "
18711871
"default ('auto') is to only prune empty merge commits which "
18721872
"become degenerate (not which started as such)."))
1873+
parents.add_argument('--no-ff', action='store_true',
1874+
help=_("Even if the first parent is or becomes an ancestor of another "
1875+
"parent, do not prune it. This modifies how "
1876+
"--prune-degenerate behaves, and may be useful in projects who "
1877+
"always use merge --no-ff."))
18731878

18741879
callback = parser.add_argument_group(title=_("Generic callback code snippets"))
18751880
callback.add_argument('--filename-callback', metavar="FUNCTION_BODY",
@@ -3034,6 +3039,12 @@ class RepoFilter(object):
30343039
self._orig_graph.is_ancestor(orig_parents[cur],
30353040
orig_parents[other]):
30363041
continue
3042+
# Some folks want their history to have all first parents be merge
3043+
# commits (except for any root commits), and always do a merge --no-ff.
3044+
# For such folks, don't remove the first parent even if it's an
3045+
# ancestor of other commits.
3046+
if self._args.no_ff and cur == 0:
3047+
continue
30373048
# Okay so the cur-th parent is an ancestor of the other-th parent,
30383049
# and it wasn't that way in the original repository; mark the
30393050
# cur-th parent as removable.

t/t9390-filter-repo.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ filter_testcase empty less-empty-keepme --path keepme --prune-empty=never \
4747
filter_testcase degenerate degenerate-keepme --path moduleA/keepme
4848
filter_testcase degenerate degenerate-moduleA --path moduleA
4949
filter_testcase degenerate degenerate-globme --path-glob *me
50+
filter_testcase degenerate degenerate-keepme-noff --path moduleA/keepme --no-ff
5051
filter_testcase unusual unusual-filtered --path ''
5152
filter_testcase unusual unusual-mailmap --mailmap ../t9390/sample-mailmap
5253

t/t9390/degenerate-keepme-noff

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
feature done
2+
blob
3+
mark :1
4+
data 10
5+
keepme v1
6+
7+
reset refs/heads/master
8+
commit refs/heads/master
9+
mark :2
10+
author Full Name <[email protected]> 2000000000 +0100
11+
committer Full Name <[email protected]> 2000000000 +0100
12+
data 2
13+
A
14+
M 100644 :1 moduleA/keepme
15+
16+
blob
17+
mark :3
18+
data 10
19+
keepme v2
20+
21+
commit refs/heads/branchO
22+
mark :4
23+
author Full Name <[email protected]> 2000050000 +0100
24+
committer Full Name <[email protected]> 2000050000 +0100
25+
data 2
26+
G
27+
from :2
28+
M 100644 :3 moduleA/keepme
29+
30+
commit refs/heads/branchI
31+
mark :5
32+
author Full Name <[email protected]> 2000070000 +0100
33+
committer Full Name <[email protected]> 2000070000 +0100
34+
data 29
35+
I: Merge commit 'D' into 'H'
36+
from :4
37+
merge :2
38+
39+
commit refs/heads/branchO
40+
mark :6
41+
author Full Name <[email protected]> 2000080000 +0100
42+
committer Full Name <[email protected]> 2000080000 +0100
43+
data 29
44+
J: Merge commit 'H' into 'D'
45+
from :2
46+
merge :4
47+
48+
blob
49+
mark :7
50+
data 10
51+
keepme v3
52+
53+
commit refs/heads/branchO
54+
mark :8
55+
author Full Name <[email protected]> 2000092000 +0100
56+
committer Full Name <[email protected]> 2000092000 +0100
57+
data 2
58+
L
59+
from :6
60+
M 100644 :7 moduleA/keepme
61+
62+
commit refs/heads/master
63+
mark :9
64+
author Full Name <[email protected]> 2000099000 +0100
65+
committer Full Name <[email protected]> 2000099000 +0100
66+
data 29
67+
P: Merge commit 'M' into 'N'
68+
from :2
69+
merge :8
70+
71+
blob
72+
mark :10
73+
data 10
74+
keepme v4
75+
76+
commit refs/heads/master
77+
mark :11
78+
author Full Name <[email protected]> 3000000000 +0100
79+
committer Full Name <[email protected]> 3000000000 +0100
80+
data 2
81+
Q
82+
from :9
83+
M 100644 :10 moduleA/keepme
84+
85+
blob
86+
mark :12
87+
data 10
88+
keepme v5
89+
90+
commit refs/heads/master
91+
mark :13
92+
author Full Name <[email protected]> 3000030000 +0100
93+
committer Full Name <[email protected]> 3000030000 +0100
94+
data 2
95+
T
96+
from :11
97+
M 100644 :12 moduleA/keepme
98+
99+
blob
100+
mark :14
101+
data 10
102+
keepme v6
103+
104+
commit refs/heads/master
105+
mark :15
106+
author Full Name <[email protected]> 3000060000 +0100
107+
committer Full Name <[email protected]> 3000060000 +0100
108+
data 2
109+
W
110+
from :13
111+
M 100644 :14 moduleA/keepme
112+
113+
done

0 commit comments

Comments
 (0)