Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Branch Confusion #2

Open
samsieber opened this issue Feb 12, 2019 · 3 comments
Open

Branch Confusion #2

samsieber opened this issue Feb 12, 2019 · 3 comments

Comments

@samsieber
Copy link
Owner

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:

subgit_master_sha -> upstream_feature_sha
subgit_master_sha -> upstream_master_sha

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.

@samsieber
Copy link
Owner Author

samsieber commented Feb 12, 2019

Another scenario:

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.

@samsieber
Copy link
Owner Author

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.

@samsieber
Copy link
Owner Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant