* subversion/libsvn_repos/repos.c
[svn.git] / notes / sparse-directories.txt
blobb6fa601a970aaed5d0d6662a25599b102910db4c
1                 Implementing Sparse Directory Support in SVN
2            (a.k.a. "sparse checkouts" / "incomplete directories")
4 Contents
5 ========
7    0. Goals
8    1. Design
9    2. User Interface
10    3. Examples
11    4. Implementation Strategy
12    5. Compatibility Matters
13    6. API Changes
14    7. Work Remaining
16 0. Goals
17 ========
19    Many users have very large trees of which they only want to
20    checkout certain parts.  In Subversion <= 1.4, 'checkout -N' is not
21    up to this task.
23    Subversion 1.5 introduces the idea of "depth" (controlled via the
24    '--depth' and '--set-depth' options) as a replacement for mere
25    non-recursiveness (formerly controlled via the '-N' option).  Depth
26    allows working copies to have exactly the contents the user wants,
27    leaving out everything else.
29 1. Design
30 =========
32    We have a new "depth" field in .svn/entries, which has (currently)
33    four possible values: depth-empty, depth-files, depth-immediates,
34    and depth-infinity.  Only this_dir entries may have depths other
35    than depth-infinity.
36    
37       depth-empty ------>  Updates will not pull in any files or
38                            subdirectories not already present.
39    
40       depth-files ------>  Updates will pull in any files not already
41                            present, but not subdirectories.
42    
43       depth-immediates ->  Updates will pull in any files or
44                            subdirectories not already present; those
45                            subdirectories' this_dir entries will
46                            have depth-empty.
47    
48       depth-infinity --->  Updates will pull in any files or
49                            subdirectories not already present; those
50                            subdirectories' this_dir entries will
51                            have depth-infinity.  Equivalent to
52                            today's default update behavior.
53    
54    The new '--depth' option limits how far an operation descends, and
55    the new '--set-depth' option changes the depth of a working copy tree.
57    The new options are explained in more detail in 'Usage' below, but
58    these two concepts will aid understanding:
60       "ambient depth" -----> The depth, or combination of depths,
61                              of a given working copy.
63       "requested depth" ---> The depth the user requested for a
64                              particular operation (e.g., checkout,
65                              update, switch).  This is sometimes
66                              called the "operational depth".
68    When when running an operation in a working copy, the requested
69    depth never goes deeper than the ambient depth.  For example, if
70    you run 'svn status --depth=infinity' in a working copy directory
71    that was checked out with '--depth=immediates', the status will go
72    as far as depth immediates.  That is, it descends all the way
73    ("infinity") into what's available, but in this case what's
74    available is shallower than infinity.
76 2. User interface
77 =================
78    
79    Affected commands:
80    
81        * checkout
82        * switch
83        * update
84        * status
85        * info
86    
87    Quick start:
89    Run checkout with --depth=empty or --depth=files.  When you need
90    additional files or directories, pull them in with 'svn up NAME'
91    (passing --depth for directories as appropriate).
92    
93    Not-so-quick start:
95    checkout without --depth or -N behaves the same as it does today,
96    which is the same as with --depth=infinity.
98    checkout --depth=(empty|files|immediates) creates a working copy
99    that is (empty | has only files | has files and empty subdirs).
101    Inside such a working copy, running 'svn up' by itself will update
102    only what is already present, but running 'svn up OMITTED_SUBDIR'
103    will cause OMITTED_SUBDIR to be brought in at depth-infinity, while
104    the rest of the parent working copy remains at its previous depth.
106    The --depth option limits how far an operation recurses.  The
107    operation will reach whatever is inside the intersection of the
108    ambient depth and the requested depth (see 'Design' section for
109    definitions).
111    The --depth option never changes the depth of an existing dir.
112    Instead, use the new '--set-depth=NEW_DEPTH' option for that.
113    Right now, --set-depth can only extend (that is, make deeper) a
114    directory.  In the future, it will also be able to contract; see
115    issue #2843.
117    For most commands, '-N' is a synonym for '--depth=files'.  This
118    changes the existing -N behavior, but only in trivial ways.
119    
120    'svn info' lists depth, iff invoked on a directory whose depth is
121    not the default (depth infinity).
122    
123 3. Examples
124 ===========
125    
126    svn co http://.../A
127    
128        Same as today; everything has depth-infinity.
129    
130    svn co -N http://.../A
131    
132        Today, this creates wc containing only mu.  Now, this will be
133        identical to 'svn co --depth=files /A'.
134    
135    svn co --depth=empty http://.../A Awc
136    
137        Creates wc Awc, but empty: no files, no subdirectories.
138    
139        Awc/.svn/entries                this_dir    depth-empty
140    
141    svn co --depth=files http://.../A Awc1
142    
143        Creates wc Awc1 with all files (i.e., Awc1/mu) but no
144        subdirectories.
145    
146        Awc1/.svn/entries               this_dir    depth-files
147        ...
148    
149    svn co --depth=immediates http://.../A Awc2
150    
151        Creates wc Awc2 with all files and all subdirectories, but
152        subdirectories are empty.
153    
154        Awc2/.svn/entries               this_dir    depth-immediates
155                                        B
156                                        C
157        Awc2/B/.svn/entries             this_dir    depth-empty
158        Awc2/C/.svn/entries             this_dir    depth-empty
159        ...
160    
161    svn up Awc/B:
162    
163        Since B is not yet checked out, add it at depth infinity.
164    
165        Awc/.svn/entries                this_dir    depth-empty
166                                        B
167        Awc/B/.svn/entries              this_dir    depth-infinity
168                                        ...
169        Awc/B/E/.svn/entries            this_dir    depth-infinity
170                                        ...
171        ...
172    
173    svn up Awc
174    
175        Since A is already checked out, don't change its depth, just
176        update it.  B and everything under it is at depth-infinity,
177        so it will be updated just as today.
178    
179    svn up --depth=immediates Awc/D
180    
181        Since D is not yet checked out, add it at depth-immediates.
182    
183        Awc/.svn/entries                this_dir    depth-empty
184                                        B
185                                        D
186        Awc/D/.svn/entries              this_dir    depth-immediates
187                                        ...
188        Awc/D/G/.svn/entries            this_dir    depth-empty
189        ...
190    
191    svn up --depth=infinity Awc
192    
193        Update Awc at depth-empty, and Awc/B at depth-infinity, since
194        those are the ambient depths of those two directories already.
195    
196        Awc/.svn/entries                this_dir    depth-empty
197                                        ...
198        Awc/B/.svn/entries              this_dir    depth-infinity
199                                        ...
200    
201    svn up --set-depth=infinity Awc
202    
203        Pull everything into Awc, resulting in a working copy that is
204        just as if it had been checked out with no --depth flag at all.
205    
206        Awc/.svn/entries                this_dir    depth-infiniti
207    
209    ########################################################################
210    #                                                                      #
211    #         ######################################################       #
212    #         ###                                                ###       #
213    #         ###  THIS IS NOT YET IMPLEMENTED, SEE ISSUE #2843  ###       #
214    #         ###                                                ###       #
215    #         ######################################################       #
216    #                                                                      #
217    # svn up --depth=empty Awc/B/E                                         #
218    #                                                                      #
219    #     Remove everything under E, but leave E as an empty directory     #
220    #     since B is depth-infinity.                                       #
221    #                                                                      #
222    #     Awc/.svn/entries                this_dir    depth-infinity       #
223    #                                     B                                #
224    #                                     D                                #
225    #     Awc/B/.svn/entries              this_dir    depth-infinity       #
226    #                                     ...                              #
227    #     Awc/B/E/.svn/entries            this_dir    depth-empty          #
228    #     ...                                                              #
229    #                                                                      #
230    ########################################################################
233 4. Implementation Strategy
234 ==========================
235    
236    It would be nice if all this could be accomplished with just simple
237    tweaks to how we drive the update reporter (svn_ra_reporter2_t).
238    However, it's not that easy.
239    
240    Handling 'checkout --depth=empty' would be easy.  It should get us
241    an empty directory at depth-empty, with no files and no subdirs,
242    and if we just report it as at HEAD every time, the server will
243    never send updates down (hmmm, this could be a problem for getting
244    dir property updates, though).  Then any files or subdirs we have
245    explicitly included we can just report at their respective
246    revisions, and get proper updates; at least that'll work for the
247    depth infinity ones.
248    
249    But consider 'checkout --depth=immediates'.  The desired state is a
250    depth-immediates directory D, with all files up-to-date, and with
251    skeleton subdirs at depth empty.  Plain updates should preserve this
252    state of affairs.
253    
254    If we report D as at its BASE revision, files at their BASE
255    revisions, and subdirs at HEAD, then:
256    
257       - When new files appear in the repos, they'll get sent down (good)
258       - When new subdirs appear, they'll get sent down in full (bad)
259    
260    But if we don't report subdirs as at HEAD, then the server will try to
261    update them (bad).  And if we report D at HEAD, then the working copy
262    won't receive new files that have appeared in the repository since D's
263    BASE revision (note that we *can* get updates for files we already
264    have, though, by continuing to report them at their respective BASEs).
265    
266    The same logic applies to subdirectories at depth-files or
267    depth-immediates.
268    
269    So, for efficient depth handling, the client directly reports the
270    desired depth to the server; i.e., we extend the RA protocol.
271    
272    Meanwhile, legacy servers will send back a bunch of information the
273    client doesn't want, and the client just ignores it, and the user
274    never knows except for the fact that everything seems slow (but
275    once their servers are upgraded, it'll speed up).
277 5. Compatibility Matters
278 ========================
280    This feature introduces two new concepts into the RA protocol which
281    will not be understood by older servers:
283       * Reported Depths -- the depths associated with individual paths
284         included by the client in the description (via the
285         svn_ra_reporter_t) of its working copy state.  
287       * Requested Depth -- the single depth value used to limit the
288         scope of the server's response to the client.
289         
290    As such, it's useful to understand how these concepts will be
291    handled across the compatibility matrix of depth-aware and
292    non-depth-aware clients and servers.
294    NOTE: in the sections below, it is not necessarily that case that a
295    value or state which is said to be "transmitted" literally has a
296    presence in the RA protocol.  Some such bits of state have default
297    values in the protocol and can therefore be effectively transmitted
298    while not literally identifiable in a network trace of the
299    client-server traffic.
301    Depth-aware Clients (DACs)
303       DACs will transmit reported depths (with "infinity" as the
304       default) and will transmit a requested depth (with "unknown" as
305       the default).  They will also -- for the sake of older,
306       non-depth-aware servers (NDASs) -- transmit a requested recurse
307       value derived from the requested depth:
308    
309          depth        recurse
310          -----        -------
311          empty        no
312          files        no
313          unknown      yes
314          immediates   yes
315          infinity     yes
317       When speaking to an NDAS, the requested recurse value is the
318       only thing the server understands , but is obviously more
319       "grainy" than the requested depth concept.  The DAC, therefore,
320       must filter out any additional, unwanted data that the server
321       transmits in its response.  (This filtering will happen in the
322       RA implementation itself so the RA APIs behave as expected
323       regardless of the server's pedigree.)
325       When speaking to a depth-aware server (DAS), the requested
326       recurse value is ignored.  A requested depth of "unknown" means
327       "only send information about the stuff in my report,
328       depth-aware-ily".  Other requested depth values are honored by
329       the server properly, and the DAC must handle the transformation
330       of any working copy depths from their pre-update to their
331       post-update depths and content as described in `3. Examples'.
333    Non-depth-aware Clients (NDACs)
335       NDACs will never transmit reported depths and never transmit a
336       requested depth.  But they will transmit a requested recurse
337       value (either "yes" or "no", with "yes" being the default).  (A
338       DAS uses the presence of a requested depth in the actual protocol
339       to distinguish DACs from NDACs, and knows to ignore the
340       requested recurse value transmitted by a DAC.)
342       When speaking to an NDAS, what happens happens.  It's the past,
343       man -- you don't get to define the interaction this late in the
344       game!
346       When speaking to a DAS, the not-reported depths are treated like
347       reported depths of "infinity", and the reported recurse values
348       "yes" and "no" map to depths of "infinity" and "files",
349       respectively.
351 6. API Changes
352 ==============
354    A new enum type 'svn_depth_t depth' is defined in svn_types.h.
355    Both client and server side now understand the concept of depth,
356    and the basic update use cases handle depth.  See depth_tests.py.
358    On the client side, most of the svn_client.h interfaces that
359    formerly took 'svn_boolean_t recurse' have been revved and their
360    successors take 'svn_depth_t depth' instead.  (The -N option is
361    deprecated, but it still works: it simply maps to --depth=files,
362    which results in the same behavior as -N used to.)
364    Some of this recurse-becomes-depth change has propagated down into
365    libsvn_wc, which now stores a depth field in svn_wc_entry_t (and
366    therefore in .svn/entries).  The update reporter knows to report
367    differing depths to the server, in the same way it already reports
368    differing revisions.  In other words, take the concept of "mixed
369    revision" working copies and extend it to "mixed depth" working
370    copies.
372    On the server side, most of the significant changes are in
373    libsvn_repos/reporter.c.  The code that receives update reports now
374    receives notice of paths that have different depths from their
375    parent, and of course the overall update operation has a global
376    depth, which applies whenever not shadowed by some local depth for
377    a given path.
379    The RA code on both sides knows how to send and receive depths; the
380    relevant svn_ra_* APIs now take depth arguments, which sometimes
381    supersede older 'recurse' booleans.  In these cases, the RA layer
382    does the usual compatibility dance: receiving "recurse=FALSE" from
383    an older client causes the server to behave as if "depth=files"
384    had been transmitted.
386 7. Work Remaining
387 =================
389    The list of outstanding issues is shown by this issue tracker query
390    (showing Summary fields that start with "[sparse-directories]"):
392 <http://subversion.tigris.org/issues/buglist.cgi?component=subversion&issue_status=NEW&issue_status=STARTED&issue_status=REOPENED&short_desc=%5Bsparse-directories%5D&short_desc_type=casesubstring>