blob: 4b12d7ea243e9dad8fd9ed6f1451e654329392ef [file] [log] [blame]
Feature Outline: Issue #2858 / svn:hold
=======================================
This text describes plans and concerns about creating an svn:hold property that
automatically omits paths from commits that have this property set. WIP.
$Date$
This whole file is just my personal opinion, with some additions by other
people. The whole feature is under heavy discussion at the time of writing,
and it is doubtful if it will ever be implemented in this way.
USE CASES
=========
Do not commit modifications on selected files, which do have to be versioned,
because...
(UC1) DO NOT COMMIT MODIFICATIONS, LOCAL
File 'foo' has to be modified to be able to work with my checkout.
E.g. with every click made in my IDE, it updates a time stamp;
or, the file is a config template which needs local configuration.
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) DO NOT COMMIT MODIFICATIONS, GLOBAL
Building on [UC1]. All developers face the same issue and want to skip 'foo'
during commit. I want every new checkout to behave such that 'foo' is
omitted from commit, without further local config necessary.
(All developers must agree before we set up such a global hold, so it should
be optional to have a global hold or just a local hold as [UC1].)
(UC3) DO NOT COMMIT MODIFICATIONS, SECRET AND GLOBAL
Building on [UC2]. 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.
(Not supported by this proposal, see [6])
"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
======
'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
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,
as discussed under SUBCOMMANDS, below.
(6) NODE KINDS
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'.
(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 [UC2].
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, while a locally added file with a locally added
svn:hold prop *is* held back from commit.
(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.
One consequence of a global hold is that the 'svn:hold' prop will propagate to
other branches as the propget gets merged into them along with the other text
edits.
An alternative to adding the --do-not-hold option would be to not hold back
files 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 -- a disadvantage when users
have used a recursive propset to set many files on hold.
SUBCOMMANDS
This discusses how svn:hold may affect other subcommands so that it rounds off
the user experience with that feature and avoids pitfalls arising from it.
(10) DIFF: The currently prevailing opinion is that a local diff should not
be affected by svn:hold. Nevertheless, some use 'svn diff' to look at
exactly those changes that will get committed; for these users, there should
be a local configuration option that makes 'svn diff' not show local
modifications on held-back files. (Note, when 'svn diff -rN' displays the
differences between a revision and the working state, the output should show
all diffs with BASE, ignoring only the local changes. As a general rule, if
'svn:hold' is set on a file, 'svn diff' should act exactly as if the file
was not locally modified.)
(11) COPY:
(12) WC-TO-URL: Copying locally added secrets [UC3] to a URL is fatal. Any
WC-to-URL copy of held-back files that have local mods should warn the
user and refuse to work unless --do-not-hold (or --do-hold) are passed
explicitly.
(13) WC-TO-WC: A WC copy or move will also copy the svn:hold property, and
thus isn't that dangerous for [UC3]. 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
noticing this situation should again warn the user and refuse to work
unless --do-not-hold (or --do-hold) are passed explicitly.
(15) STATUS:
(15a) 'svn status' should show mods on held-back files iff they are
modified, with an added status indicator like 'H'.
(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.
(And show added/deleted/replaced held-back files as usual.)
(16) UPDATE: Update shall issue a warning if it removes the held-back status
from a file that currently has local modifications. 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. See also [19]!
(17) MERGE:
(171) 'merge' should merge modifications to held-back files exactly the
way it does to other files. If a change on a held-back file has been
committed, it is considered an intentional change. So this change should
definitely be merged to the local file.
(172) like update, 'merge' might issue a warning if it removes the
held-back status from a file that had local modifications prior to the
merge. Finding local mods before a merge is uncommon, considering
that the merger follows common practice of merging only into unmodified
working copies. However, it can happen when multiple merges need to be
applied to the same working copy; the warning is useless in such a case,
as if there have only been merges, only intentional changes account for
the local modifications. The proposed warning is for the specific case
where the user merges into a WC that had private changes to held-back
files which should not be committed. (This point is very debatable.)
(173) Say a 'merge' brings in an intentional change on a held-back file,
and assuming there were no local mods before the 'merge'. The next commit
should definitely not skip these changes -- they are part of the merge and
make up an intentional change. Forgetting to commit a modified held-back
file after a merge is almost certainly an error. So when merge brings in a
change on a held-back file, it should probably set a flag on the file that
persists up to the next successful commit, which causes the commit to
complain and abort the entire commit unless the user explicitly passes
--do-not-hold. This gives a safety point for the user to remember to
remove any private data that might still be lying around in (also other)
held-back files.
(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. Switch is very similar to update. See [16], [19]
(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
few files compared to the entire WC tree get committed, and this feature
only adds CPU time for those very few files that are modified.
(21) NON-USUALLY O(n):
When merging, or sometimes anyway, it can happen that up to *all* files of a
WC are modified and would be committed. This would add a little propget CPU
time to every file walked over. (Perf-loss is linear to the amount of files)
(22) WORK AROUND PERF LOSS:
Issuing --do-not-hold on the commit commandline makes commit
as fast as it was before svn:hold. Could make sense if a lot of files are
modified and none of them are / need to be held-back.
(23) OPTIMIZATION:
Assuming props will always be stored as a skeld BLOB in wc.db, and assuming
users get noticeable slowness from svn:hold, a column could be added to
the NODES table indicating presence of an 'svn:hold' prop per node.
- (24) A commit could quickly scan if there are any nodes on hold in the WC
at all and pass --do-not-hold implicitly to obtain [22].
- (25) A commit would already get a held-back flag during read_info, making
the propget superfluous if [5a] svn:hold is a boolean, and even in [5b]
(list-of-strings), as hold-back on commit would always be implied.
PERFORMANCE DURING OTHER SUBCOMMANDS
(30) PERF LOSS BY CHECKS
There are additional checks added to merge, switch and update by [19].
All those checks are still O(n), and checks can be skipped by certain
already-known indicators (like no local mods, no propchanges, ...).
(31) WORK AROUND PERF LOSS
A --no-hold-warnings option for update/merge/switch could disable above
checks. Useful if the user knows there are no local mods that need hold
protection and wants speedup, or even just nonverbosity.
Note that a step like [24] won't work here, as update/merge/switch may bring
in new svn:hold properties.
(32) STATUS
'svn status' has to evaluate one more prop per modified file.