blob: e828b0bfe32afb7f8a072d57c0d7142533af3945 [file] [log] [blame]
-*- Text -*-
Externals handling in wc-ng
===========================
A long time ago, we introduced svn:externals in Subversion as a solution to
using multiple independent components.
When updating we process svn:externals changes, by walking over all directories
that have (or had) svn:externals properties defined on them.
Then we take all the old and the new definitions and put them in a list. And
then we start comparing them, following this schema
* For all directories that have and/or had svn:externals
+ For all definitions that were and/or are defined
- If it does not exist locally
o If the definition is not removed: Checkout
- If it is unchanged: update it
- If the definition is just removed, remove the external
- If the definition was modified
o If it is switchable within a repository: switch
o Else: remove and then reinstall the new definition
- If the definition is new: checkout
(There are some small variations around relative externals, unmatched externals
and revision locked externals, but this is the primary idea)
This schema allows a read-only working copy to fully follow svn:externals
changes without any user interaction as long as any intermediate update is
followed.
For an incoming update on 'svn update' this is easy, as we have the old and the
new versions of the property and we can just run the external update schema.
Ok, pretty straightforward, but things get much harder once you start looking
at how to change svn:externals definitions locally.
Handling changes to svn:externals
=================================
The easiest way to handle this, is how we do it today (r1102626). We only apply
svn:externals changes when they are applied to the BASE layer. In this case we
can follow the original external update schema.
But this is not what any normal subversion user likes, because you have to
commit a potentially invalid external description just to test it. To avoid
this hassle you would like to prefer changes before committing, but then the
external update schema doesn't work any more.
The external update schema needs the difference between an old and a new
definition to update your working copy, but with local property changes you
only have access to the last version and probably some older version, but not
to the previous version.
[[
> If you do
> Assuming you committed
> $ svn propset svn:externals A .
> $ svn up .
> (updates externals to match definition nothing->A)
>
> $ svn ci -m""
> $ svn propset svn:externals B .
> $ svn update .
>
> Then currently this updates the directory to the definition A (just to be
> safe), while you (and many others) would like it to go to B.
>
> So assume the preferred scenario this would do the update A->B
>
> But then you have the even likely case
> $ svn propset svn:externals C
> $ svn update .
>
> This would then apply A->C, so this could potentially break your working
> copy, by leaving traces of B.
>
> We really need the step B->C here, but there is no way to access B, because
> it wasn't committed. It just lived in a local property change.
]]
Before Subversion 1.6, it wasn't such a big problem when the external update
schema broke down on the working copy where svn:externals were edited. You just
deleted the subdirectory and ran svn update again. But then we introduced file
externals....
"We really need some store with old (applied) svn:externals definitions, so we
would only have to update externals from that to the latest definition"
(Issue #2267, #3351, #3823)
Wc-1.0 File Externals
=====================
Just before we released Subversion 1.6 somebody noticed that you could switch
an added file (really a bug) and that you could use that to do svn:external
like things with that. Within a few days some support to manage these externals
was added and the file externals as we know them were born.
These file externals were added as part of the working copy where they are
located with a special registration in their svn_wc_entry_t. (Note: this didn't
have to be the same working copy as where the definition lived).
One noticable limitation was that they had to be from the same repository as
the directory they are placed in.
The existing externals update schema handled did this really well and file
externals were released as part of Subversion 1.6.
But when you mix the feature of editing svn:externals and file externals,
things get ugly. If you add a file external to svn:external; then perform an
update and then revert the definition of the file external before committing,
you will find that this file external will still be in your working copy.
(And there is no real way to fix this).
The 'file externals' problem
============================
When we introduced file externals, we expected this to be easy to maintain,
as essentially we already supported switched files.
But then somebody noticed that you could delete file externals via 'svn rm',
and then the external was removed... but not where it was placed, but at
the place where it was added from. So we added some tests to detect that
specific case. We never had that problem with directory externals.
(Same problem with moving files)
Then somebody noticed that merge was recording more merge information when
you had file externals. So we added some tests to detect and work around that.
(And I think about 20 similar cases in different places of our code).
We never expected any of this when we introduced file externals as an
easy feature.
[[
<@cmpilato> A file external -- like any other external -- shouldn't be an add at all in a copy situation.
<@Bert> cmpilato: But a file external is not like 'any other external'... It is like 'any other switch'
<@cmpilato> That mindset is 90% of the problem with file externals.
<@cmpilato> They were never intended to behave as switches.
<@cmpilato> Switch was simply the low-hanging mechanism that was used to shoehorn them in.
<@cmpilato> They were always intended to behave like dir externals.
<@cmpilato> hrm. we don't appear to be honoring the --ignore-externals option to 'svn cp WC WC' either...
]]
"Why can't file externals be more like 'normal' externals?"
(Issue #3589, #3518, #3351, #3665, #3816, #3843)
The WC-NG Externals store
=========================
After holding back several changes to more file externals corner cases on
"we should really design file externals before adding more features" these
three questions got me thinking:
"We really need some store with old (applied) svn:externals definitions, so
we would only have to update externals from that to the latest definition"
"Why can't file externals be more like 'normal' externals?"
And later (via private mail):
"Will this allow to exclude externals from WC? (Use-case: watching repo
of public project with number of externals)"
So we have three separate requests to store some information on externals,
which we couldn't store before.
- Handling externals changes -
For every applied external we would like to have:
* Where it was defined
* What is its definition
* If it has a fixed revision or not.
This allows applying svn:externals changes from any previous state to the last
state by just comparing the actual propery values against what is stored.
- Moving file externals into their own storage -
If we want to make file externals like 'normal externals, we should remove
their presence from their parent working copy and just handle them as
independent filesystem objects.
For that we need some storage location of 'all the relevant information it
would have in the past'.
* Repository, repos_relpath, revision.
* Presence (always status normal. Can't be deleted, moved, etc.)
* Kind (always file or symlink)
* Properties
* Checksum
* Changed date, author, revision
* Recorded size and mod time
- Excluding externals -
To allow excluding externals we need some kind of presence flag containing
'normal' and 'excluded' per external.
### Combine these three ideas and you have the EXTERNALS table for format 29