You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, subgit-sync has to be limited to running on a single branch. This bug is backed by a (currently broken) test, aptly named branch_confusion.
The basic gist of it that if someone pushes to master in the upstream, then pushes to a feature branch branched from master in the upstream, a commit to master in the subgit will take the commit from the feature branch and add it to the master branch.
The problem is, when the feature branch is merged, we now have two mappings for a the master branch in the subgit:
So that's saying the commit in the subgit for master is the commit you would use in the subgit for adding a commit to the upstream_feature_sha commit or the upstream_master_sha. The issue is that when copying commits from the subgit, we just pick the most recent. The fix would be to exclude any mappings that aren't in the target branch we're looking to pick to, which gets tricky.
One possible solution is to take the old_sha from the branch we're pushing to and looking up the mapping based off of that, but I'm not sure how that'd hold up in the face of merge commits and such.
let master = "somesha";
let feature_0 = commit_to(master, HAS_SUBGIT_CHANGES);
let feature_1 = commit_to(feature_0, NO_SUBGIT_CHANGES);
let feature_2 = commit_to(feature_1, NO_SUBGIT_CHANGES);
In this scenario, this generates a subgit mapping with
let master = "somesha";
let feature_0 = commit_to(master);
let feature_1 = feature_0.clone();
let feature_2 = feature_0.clone();
So the feature_1 and feature_2 branches are different in the upstream, but the same in subgit. If you merge one of those feature branches into master from within the subgit repo, what should happen upstream - how do you know which one to merge? You could try to look at the merge message to see what branch was merged, but that's asking from trouble. Consider what happens if you delete the feature_1 and feature_2 branches from the upstream - someone could still have them in the subgit and do the merge and push it. Yet apart from that, there's now way to know :(
A conservative solution might work however - you could push the common ancestor of any tips (in the above example, feature 0). Yet then you have to figure that out, which may or may not be doable. But that looks like the only reasonable route to take.
This problem only comes from doing merges from the subgit side, because as of now, the subgit has to be a perfect subset of the upstream. At some point in the future, you could imagine releasing that restriction (who knows why though). E.g. you could map automation/frontend in upstream to automation_tests/ in the subgit. Then for algorithmic purposes, they are both subgits.
So, to express things in less of terms of subgit vs upstream (which is already how the code looks at it - a set of filters & locations), we want to express how to handle merges in terms of what mappings exist. And when the upstream a perfect superset of the subgit, that means each upstream commit will never map to more than one subgit commit (which of course doesn't stop one subgit commit from mapping to more than one upstream commit).
So, when copying commits and lookup up parents in the destination:
If there is only on mapping for a parent, use it
If there is more than one mapping... well, it gets tricky. Ergo, the point of this ticket.
OK, so it gets worse - when looking up parents, we need to be very judicious:
If in the above scenario (involving master, feature_0, feature_1 and feature_2) you are in the subgit repo and you commit to any branch you'd expect a push to work. You'd also expect any merges involving one of those branches to be able to be pushed.
So now we have a couple of questions / things to get right:
Say you push a copy of a branch (say feature_1) - ideally it should mirror the branch it was copied from upstream, but not necessary. E.g. if you feature_1 to a new branch (feature_3) in subgit, ideally in the upstream feature_1 and feature_3 would match. It's not necessary. So we need resolution for when pushing a new branch. We might be able to get away picking at random, but picking a common ancestor would probably be enough.
You commit to a confused sha branch (say feature_1). When you push, it should work. You need to get the upstream old branch and apply commits to it. Nothing more, nothing less... unless you rewrite git history before pushing.... 🤕.
If you rewrite the git history, all bets are off.
You merge a branch into a confused sha branch (say into feature_1). When you push, it should work.
You merge a confused sha branch into a confused sha branch - pushing should work - it should succeed but not pull in extra changes/other unrelated branches.
Activity
samsieber commentedon Feb 12, 2019
Another scenario:
In this scenario, this generates a subgit mapping with
So the feature_1 and feature_2 branches are different in the upstream, but the same in subgit. If you merge one of those feature branches into master from within the subgit repo, what should happen upstream - how do you know which one to merge? You could try to look at the merge message to see what branch was merged, but that's asking from trouble. Consider what happens if you delete the feature_1 and feature_2 branches from the upstream - someone could still have them in the subgit and do the merge and push it. Yet apart from that, there's now way to know :(
A conservative solution might work however - you could push the common ancestor of any tips (in the above example, feature 0). Yet then you have to figure that out, which may or may not be doable. But that looks like the only reasonable route to take.
samsieber commentedon Feb 12, 2019
This problem only comes from doing merges from the subgit side, because as of now, the subgit has to be a perfect subset of the upstream. At some point in the future, you could imagine releasing that restriction (who knows why though). E.g. you could map
automation/frontendin upstream toautomation_tests/in the subgit. Then for algorithmic purposes, they are both subgits.So, to express things in less of terms of subgit vs upstream (which is already how the code looks at it - a set of filters & locations), we want to express how to handle merges in terms of what mappings exist. And when the upstream a perfect superset of the subgit, that means each upstream commit will never map to more than one subgit commit (which of course doesn't stop one subgit commit from mapping to more than one upstream commit).
So, when copying commits and lookup up parents in the destination:
samsieber commentedon Feb 12, 2019
OK, so it gets worse - when looking up parents, we need to be very judicious:
If in the above scenario (involving master, feature_0, feature_1 and feature_2) you are in the subgit repo and you commit to any branch you'd expect a push to work. You'd also expect any merges involving one of those branches to be able to be pushed.
So now we have a couple of questions / things to get right: