Skip to content

Commit 15f65a0

Browse files
Handle one more corner case in push
Change: push-corner-case
1 parent 05a804f commit 15f65a0

File tree

2 files changed

+130
-9
lines changed

2 files changed

+130
-9
lines changed

src/history.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -465,12 +465,12 @@ pub fn unapply_filter(
465465
}
466466

467467
// This will typically be parent_count == 2 and mean we are dealing with a merge
468-
// where the parents have differences outside of the filter. This is only possible
469-
// if one of the parents is a descendant of the target branch and the other is not.
470-
// In that case pick the tree of the one that is a descendant.
468+
// where the parents have differences outside of the filter.
471469
parent_count => {
472470
let mut tid = git2::Oid::zero();
473471
for i in 0..parent_count {
472+
// If one of the parents is a descendant of the target branch and the other is
473+
// not, pick the tree of the one that is a descendant.
474474
if (original_parents_refs[i].id() == original_target)
475475
|| transaction
476476
.repo()
@@ -481,19 +481,39 @@ pub fn unapply_filter(
481481
}
482482
}
483483

484-
if tid != git2::Oid::zero() {
485-
transaction.repo().find_tree(tid)?
486-
} else {
484+
if tid == git2::Oid::zero() {
485+
for i in 0..parent_count {
486+
// If one of the parents has a corresponding commit in the unfiltered target
487+
// branch, pick that one.
488+
if find_original(
489+
transaction,
490+
filterobj,
491+
original_target,
492+
filtered_parent_ids[i],
493+
false,
494+
)? != git2::Oid::zero()
495+
{
496+
tid = new_trees[i];
497+
break;
498+
}
499+
}
500+
}
501+
502+
if tid == git2::Oid::zero() {
487503
// This used to be our only fallback for the parent_count > 1 case.
488504
// It should never happen anymore.
489505
tracing::warn!("rejecting merge");
490506
let msg = format!(
491-
"rejecting merge with {} parents:\n{:?}",
507+
"rejecting merge with {} parents:\n{:?}\n1) {:?}\n2) {:?}",
492508
parent_count,
493-
module_commit.summary().unwrap_or_default()
509+
module_commit.summary().unwrap_or_default(),
510+
original_parents_refs[0].summary().unwrap_or_default(),
511+
original_parents_refs[1].summary().unwrap_or_default(),
494512
);
495513
return Err(josh_error(&msg));
496514
}
515+
516+
transaction.repo().find_tree(tid)?
497517
}
498518
};
499519

tests/filter/subtree_prefix.t

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Work in the subtree, and sync that back.
8383
[1] :prefix=subtree
8484
[4] :/subtree
8585
[4] :at_commit=c036f944faafb865e0585e4fa5e005afa0aeea3f[:prefix=subtree]
86-
$ git log --graph --pretty=%s refs/heads/master
86+
$ git log --graph --pretty=%s refs/heads/master
8787
* add even more content
8888
* subtree edit from main repo
8989
* subtree merge
@@ -106,3 +106,104 @@ And then re-extract, which should re-construct the same subtree.
106106
[5] :/subtree
107107
[5] :at_commit=c036f944faafb865e0585e4fa5e005afa0aeea3f[:prefix=subtree]
108108
$ test $(git rev-parse subtree) = $(git rev-parse subtree2)
109+
110+
Simulate a feature branch on the main repo that crosses subtree changes
111+
$ git checkout master 2>/dev/null
112+
$ git checkout -b feature1 2>/dev/null
113+
$ git reset --hard $SUBTREE_TIP >/dev/null
114+
$ echo work > feature1
115+
$ git add feature1 >/dev/null
116+
$ git commit -m feature1 >/dev/null
117+
$ git checkout master 2>/dev/null
118+
$ git merge feature1 --no-ff >/dev/null
119+
120+
On the subtree, simulate some independent work, and then a sync, then some more work.
121+
$ git checkout subtree 2>/dev/null
122+
$ echo work > subfeature1
123+
$ git add subfeature1 >/dev/null
124+
$ git commit -m subfeature1 >/dev/null
125+
$ josh-filter -s :at_commit=$SUBTREE_TIP[:prefix=subtree]:/subtree refs/heads/master --update refs/heads/subtree-sync >/dev/null
126+
$ git merge subtree-sync --no-ff >/dev/null
127+
$ echo work > subfeature2
128+
$ git add subfeature2 >/dev/null
129+
$ git commit -m subfeature2 >/dev/null
130+
131+
And another main tree feature off of SUBTREE_TIP
132+
$ git checkout -b feature2 2>/dev/null
133+
$ git reset --hard $SUBTREE_TIP >/dev/null
134+
$ echo work > feature2
135+
$ git add feature2 >/dev/null
136+
$ git commit -m feature2 >/dev/null
137+
$ git checkout master 2>/dev/null
138+
$ git merge feature2 --no-ff >/dev/null
139+
140+
And finally, sync first from main to sub and then back.
141+
$ git checkout subtree 2>/dev/null
142+
$ josh-filter -s :at_commit=$SUBTREE_TIP[:prefix=subtree]:/subtree refs/heads/master --update refs/heads/subtree-sync >/dev/null
143+
$ git merge subtree-sync --no-ff >/dev/null
144+
145+
$ git log --graph --pretty=%s refs/heads/master
146+
* Merge branch 'feature2'
147+
|\
148+
| * feature2
149+
* | Merge branch 'feature1'
150+
|\ \
151+
| * | feature1
152+
| |/
153+
* | add even more content
154+
* | subtree edit from main repo
155+
* | subtree merge
156+
|\|
157+
| * add file2 (in subtree)
158+
* add file1
159+
$ git log --graph --pretty=%s refs/heads/subtree
160+
* Merge branch 'subtree-sync' into subtree
161+
|\
162+
| * Merge branch 'feature2'
163+
| |\
164+
| | * feature2
165+
* | | subfeature2
166+
* | | Merge branch 'subtree-sync' into subtree
167+
|\| |
168+
| * | Merge branch 'feature1'
169+
| |\ \
170+
| | * | feature1
171+
| | |/
172+
* | / subfeature1
173+
|/ /
174+
* | add even more content
175+
* | subtree edit from main repo
176+
|/
177+
* add file2 (in subtree)
178+
$ josh-filter -s :at_commit=$SUBTREE_TIP[:prefix=subtree]:/subtree refs/heads/master --update refs/heads/subtree --reverse
179+
[1] :prefix=subtree
180+
[9] :/subtree
181+
[9] :at_commit=c036f944faafb865e0585e4fa5e005afa0aeea3f[:prefix=subtree]
182+
183+
$ git log --graph --pretty=%H:%s refs/heads/master
184+
* 6ac0ba56575859cfaacd5818084333e532ffc442:Merge branch 'subtree-sync' into subtree
185+
|\
186+
| * 38a6d753c8b17b4c6721050befbccff012dfde85:Merge branch 'feature2'
187+
| |\
188+
| | * 221f5ceab31209c3d3b16d5b2485ea54c465eca6:feature2
189+
* | | 75e90f7f1b54cc343f2f75dcdee33650654a52a6:subfeature2
190+
* | | 3fa497039e5b384cb44b704e6e96f52e0ae599c9:Merge branch 'subtree-sync' into subtree
191+
|\| |
192+
| * | 2739fb8f0b3f6d5a264fb89ea20674fe34790321:Merge branch 'feature1'
193+
| |\ \
194+
| | * | dbfaf5dd32fc39ce3c0ebe61864406bb7e2ad113:feature1
195+
| | |/
196+
* | / 59b5c1623da3f89229c6dd36f8baf2e5868d0288:subfeature1
197+
|/ /
198+
* | 103bfec17c47adbe70a95fca90caefb989b6cda6:add even more content
199+
* | 41130c5d66736545562212f820cdbfbb3d3779c4:subtree edit from main repo
200+
* | 0642c36d6b53f7e829531aed848e3ceff0762c64:subtree merge
201+
|\|
202+
| * c036f944faafb865e0585e4fa5e005afa0aeea3f:add file2 (in subtree)
203+
* 0b4cf6c9efbbda1eada39fa9c1d21d2525b027bb:add file1
204+
205+
$ git ls-tree --name-only -r 3fa497039e5b384cb44b704e6e96f52e0ae599c9
206+
feature1
207+
file1
208+
subtree/file2
209+
subtree/subfeature1

0 commit comments

Comments
 (0)