Neels, I hadn't read through your 'notes/hold' doc, which I should have done first. Now I have, and added a bunch of comments - see attached patch.
It would be really helpful if, in the light of your current knowledge and what's been discussed in this thread, you could update that doc and convert it (or part of it) into a complete user reference manual section, describing first the principles and then the exact intended behaviour: "The idea is X ... The new principles are X ... In terms of selecting what to commit it works exactly like X except X ... The exact behaviour of every affected operation is X ... Behaviours that might surprise you at first are X ..." You could put '### Not impl' or '### Currently does X instead of Y' markers where applicable. Move possible alternatives into footnotes or into a different section so we'd have a single complete description on which to base any further discussion. Where you replied to my question about diff: > > And what's this about local-diff? You intend to ignore the whole > > file that is 'held'? Or do you intend to print diffs of [...] > I use 'svn diff' to check the local modifications that are going to be > committed. Right?? How is it obscure to omit local modifications on a > held-back file? (All mods that are already committed *are* shown.) I was not saying we shouldn't affect diffs, I was asking exactly what you intend, because I hadn't thought it through and it wasn't clear. Now I've thought it through a bit more and put my notes in the attached patch, but you may have more to say on it. I still don't understand "All mods that are already committed *are* shown"; you can't be talking about a local diff? About copies: I've noted in the patch that I think copy should not silently ignore local mods, because those mods might be intentional and important. Instead, commit should error out, although I'm not precise about the details. Maybe error on any attempt to commit the add/del/cp/mv/replace of a held-back file if not overridden. In my comments I say only the working props (and not the base props) of the file should determine whether it's held back. That's because I think that definition plays well with nearly all the other behaviour. I first started to write things like "if the base and/or working version has the prop ..." and that got messy and unnecessary. But I haven't fully resolved how this affects deleting the file: a schedule-delete file logically has no working props. - Julian
Index: notes/hold =================================================================== --- notes/hold (revision 1160320) +++ notes/hold (working copy) @@ -13,42 +13,61 @@ Actually, at the time of writing, this w USE CASES ========= Do not commit modifications on selected files, which do have to be versioned, because... -(1) CONVENIENCE -File 'foo' is modified with every click made in my IDE. I want 'foo' to be -skipped on commits unless I explicitly ask svn to commit it. (Instead of -having to take explicit care on every commit to omit the file.) - -(2) LOCAL/GLOBAL -Since all other developers use the same IDE, I want to have the option to tell -all other working copies to hold back 'foo' as well -- but only if all agreed -to that. Else I want to just hold locally. - -(3) SECRET -Every user must locally add their passwords and PIN numbers to file 'foo'. -By default, every working copy should exclude 'foo' from commits. We don't -want any user's mods of 'foo' to even go over the wire (ruling out hooks). +(UC1) IDE CONFIG FILE, LOCAL + File 'foo' is modified with every click made in my IDE: it updates a time + stamp. I want 'foo' to be skipped on commits unless I explicitly ask svn + to commit it. (Instead of having to take explicit care on every commit to + omit the file.) + +(UC2) IDE CONFIG FILE, GLOBAL + Building on [1]. Since all other developers use the same IDE, I want to + tell all other working copies to hold back 'foo' as well, if they all + agree to that. + +(UC3) IDE CONFIG FILE, GLOBAL AND SECRET + Building on [2]. Every user must locally add their passwords and PIN + numbers to file 'foo'. By default, every working copy should exclude + 'foo' from commits. We don't want any user's mods of 'foo' to even go + over the wire. (This last point rules out hooks.) + +(UC4) - Eclipse directory, from issue #3028. + "We have a complete Eclipse instance in our svn repository and we want + to ignore every change in its directory and below. Because Eclipse + more or less at random creates and deletes file from its own directory + we have no way of knowing which individual files may be change or + deleted by starting Eclipse." An update should not re-create files + that were deleted from disk by Eclipse. Let's say a 'global' hold is + required as in [UC2]. -LEGEND: +LEGEND +====== + 'held-back file': A file that's excluded from a commit by svn:hold. + 'overridden': The effect of the 'hold' may be overridden by telling + Subversion not to ignore the modifications on a held-back file that it + otherwise would have ignored. The syntax and scope (per file, per + command or per user) of the override is described in [8]. + DETAILS ======= (4) NAME The property is called "svn:hold". (5) VALUE (5a) BOOLEAN A file is held-back iff it has an svn:hold property, with whichever value, even empty. A fixed set of subcommands heeds svn:hold. + ### JAF: As specified under SUBCOMMANDS, below. OR (5b) LIST OF STRINGS The value of 'svn:hold' determines which subcommands hold the file: - commit: holding back upon commit is *always* implied. - diff: Omit local mods of held-back files from diff. - status: Entirely omit the file from 'svn status' output. @@ -62,85 +81,153 @@ DETAILS Only files should be held-back. 'svn:hold' should not act recursively (for performance and implementation complexity reasons?), and actually, 'svn:hold' should not be allowed to be set on directories. If an entire subtree should be put on hold, users can do 'svn propset -R'. Such a recursive propset should not error out on the first dir encountered, but instead print a warning that svn:hold was only added to the files, ignoring the dirs. + ### JAF: So this rules out use case [UC4]. + ### JAF: A recursive propset should warn or not warn in exactly the same + way as a recursive propset of any other file-only property, whatever + that way is, if those are already self-consistent, unless there is a + good reason to do otherwise. (7) LOCAL HOLD The svn:hold property already acts when it is added locally. This provides a way to hold back files in only the local working copy, no other users nor the repository is affected. See [2]. + ### JAF: Specifically, a file is held back iff the 'svn:hold' property + as described in [5] is set on the working version in the WC, + regardless whether it's set on the WC base version. One consequence is + that a file scheduled for delete is no longer held back from commit. + + ### JAF: It seems the principle is that the hold applies only to text + and property modifications, not to tree changes. + (8) GLOBAL HOLD There must be a --do-not-hold option to 'svn commit'. This allows committing the 'svn:hold' propadd to the repository, so that it is added to every other working copy, resulting in a global hold-by-default. NOTE: My preferred option names would have been --ignore-hold or --no-hold, but unfortunately, both are ambiguous. Depending on the user's intuition, they could mean "ignore the held-back files" or "ignore that files are held-back" or even "commit everything except the svn:hold propadd". --do-not-hold and --disable-hold are the only ones I found that aren't ambiguous like that. +### JAF: Alternatively we could say that files are not held back if they are + explicitly named targets to the 'commit' (or other) command. That has + the advantages of consistency with the way svn:ignore and depth behave, + and of avoiding another command-line option. It does not provide an + easy way to specify all the files in a subtree, but the feature is not + suited to ignoring a whole subtree [UC4] so this is not really a + disadvantage. + SUBCOMMANDS So far, no real point has been made to justify ignoring file mods on any other command except 'commit'. I am adding some as I type: (10) DIFF: if local modifications don't get committed, then there's no need to read about them in a diff of local mods. (Held-back files should *not* omit already-committed modifications.) + ### JAF: What do you mean by 'omit already-committed modifications'? Do + you mean a repos-repos or repos-WC diff should always show all + differences, or do you mean a repos-WC diff should always diff to + the WC base rather than the working version, or something else? + + ### JAF: So, what's the exact behavioural spec? A repos-repos diff shall + show all changes as usual. Unless overridden, a WC-WC diff shall omit + local mods on a held-back file. Unless overridden, a repos-WC diff + shall omit local mods on a held-back file, by diffing against the base + version even if the working version is requested. Diff shall display + an added/deleted/replaced file in the usual way, including any + modifications against the copy-from source, regardless of the + held-back status. + (11) COPY: (12) WC-TO-URL: Copying locally added secrets [3] to a URL is fatal. Any WC-to-URL copy of held-back files should (12a) exclude local mods, or + ### JAF: No, don't silently ignore local mods: they might be + intentional and important. The behaviour of copies is well + established: if you request -rBASE as the source, you copy + the base, else you copy the working version. Instead: [12b]. (12b) just bail if there are local mods, unless they get a --do-not-hold option. (probably easier to do, until [12a] gets implemented) + (13) WC-TO-WC: A WC copy or move will also copy the svn:hold property, and thus isn't that dangerous for [3]. But when a WC-to-WC copy of a subtree that has a held-back file inside is finally committed, the BASE node of the held-back file should indeed be added. Omitting the held-back file completely would imply a delete within the added tree. So a commit should take care to add files that are held-back, but skip all local modifications. + ### JAF: No, don't silently ignore local mods: they might be intentional + and important. Instead: + (13b) Error out if the commit includes a held-back copied file with + local mods and does not specify the do-not-hold option. + (14a) Committing BASE nodes for added held-back files should be limited to copied/moved files, i.e. where the BASE is nonempty. Simply-added held-back files should not be added to the repos at all. OR (14b) If a held-back file is simply-added (not copied/moved), just add an empty file with no props except svn:hold to the repository. + ### JAF: No, don't silently omit the file or commit an empty file. + That's stepping outside the territory that this feature should be + involved in. Instead: + (14c) Error out if the commit includes a held-back added file and does + not specify the do-not-hold option. (15) STATUS: (15a) 'svn status' should show mods on held-back files iff they are modified, with an added status indicator like 'H'. + ### JAF: (And show added/deleted/replaced held-back files as usual.) OR (15b) 'svn status' should omit held-back files even if modified, unless --show-hold is supplied. + ### JAF: (And show added/deleted/replaced held-back files as usual.) (16) UPDATE: Holding off updates from a file could be desirable, but I can't think of any real situation that needs this. If holding back updates is ever implemented, it should definitely be optional, as in [5b]. See also [19]! + ### JAF: No known use case => no special behaviour except [19]; enough said. + So: Update shall issue a warning if it removes the held-back status + from a file. In all other respects, update shall act as usual: for + example, if update deletes a held-back file with local mods, it shall + raise a tree conflict in the usual way. + (17) MERGE: Holding off merges from single files is pure madness. Alas, the whole topic of svn:hold is a nightmare in merge land. Users have to take great care to do The Right Thing: If you merge committed modifications on a locally held-back file, the merge result for it will not be committed -- even if there had not been any local modifications on the held-back file. 'svn merge' should issue a warning that it has merged files that (now) have the 'svn:hold' property in the local working copy, and that, for basic sanity, --do-not-hold should be supplied at commit time. See also [19]! + ### JAF: So: Merge shall issue a warning if it modifies, adds, deletes or + replaces a held-back file (one that is/was held back before and/or + after the merge). Merge shall issue a warning if it changes the + held-back status of a file that has local mods. + (18) SWITCH: Switch should go ahead as always. All it does is pull other BASE nodes in under the local mods, so there is no danger of anything leaking around. But see [19]! + ### JAF: Switch is very similar to update, so see [16]. + (19) UPSTREAM REMOVES 'svn:hold': Users must be warned when update, switch or merge remove the 'svn:hold' property from a file that had local mods. They should maybe even flag some (new??) kind of conflict. See also [31]. + ### JAF: This is a principle of the design. Maybe you could move all the + principles to a section before this SUBCOMMANDS section. + PERFORMANCE DURING COMMIT (20) USUALLY FAST: In the current trial implementation on the 'hold' branch, the 'svn:hold' property is evaluated only on the files that have made it all the way through harvest_committables() with a modified status. Usually, only very