Hi Andreas, without going into detail, I just want to say that using source links without revision is actually a wanted feature and you should not compare this to branch mechanisms of other SVC's. We need this to see immediatly if something breaks due to underling changes (happens often enough with Factory, when a package gets submitted multiple times). The Factory checkin group needs to see this immediatly and the submitting packager as well, since he needs to adapt his changes again. Yes, we need a merge handling for the case the changes conflict, aka the link breaks (using diff3). Michael has almost implemented it, just the osc part is missing. Yes, we can store the used srcmd5 inside of the patch when we generate it. But we will not add it as rev= to the _link file. In short, that links break when conflicting changes happens is actually a feature, not a bug. The OBS helps the developers to get feedback about changes as soon as possible. When you want something like a fixed branch do a "osc linkpac -c" or svn like "copypac". The standard osc branch is something different. bye adrian Am Donnerstag, 16. April 2009 23:59:42 schrieb Andreas Gruenbacher:
Hello,
I've been looking at the way how source links work, and I find their current behavior highly irritating. I would like to share my observations and propose a fix to make things a lot more obvious (without losing functionality). Please bear with me as I try to describe things as completely as necessary; sorry I can't make this short.
I'll use the terms 'link package' for a package that links to another package, and 'target package' for a package that another package links to.
Theory ====== When you ignore the space saving aspect, the key functionality of link packages is to record relative changes to packages. When the target package changes, these changes propagate to link packages (at least conceptually), and the link packages get rebuilt as well. Picture this as follows (with revision numbers in parentheses, time progressing from top to bottom, and expanded links):
target(1) target(2) <--- link(1) link(2) target(3)
We start at target(2). link(1) is created against target(2): initially there are no changes, so link(1) and target(2) are identical. Then link(1) is changed, resulting in link(2). The server computes and stores the diff between target(2) and link(2); let us call this diff(target(2), link(2)). Next, target(2) is changed, resulting in target(3). This triggers a rebuild of target(3) and of a package with the changes in link(2) applied to target(3). Let us call this apply(diff(target(2), link(2)), target(3)).
Another way of saying this is that the build service merges the changes between target(2) and its two descendants target(3) and link(2) and builds the result. Let us call this merge(target(3), target(2), link(2)).
Current behavior and problems ============================= When checking out a link package with osc, you get an expanded package by default: the diff stored in the link gets applied to the most recent version of the target package. This is similar to a merge, but without looking at the common ancestor between the two versions, and there are a number of problems:
* You will not get the same state out of the build service that you have checked in.
* If the changes in the target package and the link package overlap, the diff will not apply, and you will get nothing out of the build service at all.
* Applying patches does not actually guarantee that the changes will be applied correctly and in the correct places. You may end up with subtle mismerges.
* When you create another revision of the link package, you will not know that an implicit "merge" has even happened, and you will not be able to verify the results.
* You will not be able to identify which revisions were made in the link or target package since when the two diverged.
* The build service does not record the revision of the target package that it generated its diffs against. This means that there is no reliable way to reconstruct the original version of a link; one can only guess which revision of the target package the link might have been generated against based on timestamps. No locking is done across packages during checkins, so the timestamps are not guaranteed to be synchronized across packages, either. Concurrent checkins can lead to wrong guesses no matter how smart the guess algorithm is.
* Because the server does not record which revision a link was generated against (the common ancestor when merging), it is not possible to actually perform a correct three-way merge. Any attempt to still try that is broken in one way or another.
Proposed improvements ===================== * When creating a revision of a link package, always store the revision of the target package that the diff was generated against.
* When checking out a link, always expand it against the revision of the target package that the link was created against. That way, links cannot break (unless the target package is deleted). The expansion could be done client or server side; the result would be the same either way: exactly what the user checked in; no magic, and no surprises.
If the server has more recent revisions of the target package available, indicate to the user to perform a merge (either mandatorily or optionally; see the next item).
* When committing a link package, either (a) make sure that the user has been working against the most recent version of the target package, or (b) allow commits to be done against older versions of the target package. Both (a) and (b) require the client to send the revision of the target package it has been using as part of the commit, but that is easy.
* Merging could be implemented as three-way merge, either server or client side, using merge(1) or diff3(1). It's not that hard to implement that from scratch. What's more, when importing build service packages into a version control system, merging would come for free.
Other version control systems, starting back with rcs(1), use merge(1) or a variant thereof. I have played around with the two when implementing the --merge option in GNU patch, and after giving it some real thought, I also went with the merge(1) format because the results are a lot more practical.)
Thanks for your help with this!
Andreas
-- Adrian Schroeter SUSE Linux Products GmbH email: adrian@suse.de -- To unsubscribe, e-mail: opensuse-packaging+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-packaging+help@opensuse.org