You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Johan Corveleyn <jc...@gmail.com> on 2011/04/16 10:17:35 UTC

[PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Hi,

Following discussion in [1], I tried to write a patch for issue #3702
("svn ren TODO todo" not work on windows). As mentioned by Bert in
comment to the issue [2], we need to avoid letting 'svn move' convert
the destination path to on-disk casing in this case, so that's what
the below patch does.

However, it seems that's not enough. I'm getting further, but now the
move is blocked libsvn_client/copy.c. The error I'm getting now is:

    svn: E155007: Path 'C:\Temp\test\todo' is not a directory

The problem is that, in copy.c#svn_client_move6, it first tries the
move, but if the dst_path already exists (which comes down to an
apr_stat inside copy.c#verify_wc_srcs_and_dsts), it tries the move
again with moving the src_path to a child of (the presumed directory)
dst_path:

libsvn_client/copy.c: 2313
[[[
  err = try_copy(sources, dst_path,
                 TRUE /* is_move */,
                 make_parents,
                 FALSE,
                 revprop_table,
                 commit_callback, commit_baton,
                 ctx,
                 subpool);

  /* If the destination exists, try to move the sources as children of the
     destination. */
  if (move_as_child && err && (src_paths->nelts == 1)
        && (err->apr_err == SVN_ERR_ENTRY_EXISTS
            || err->apr_err == SVN_ERR_FS_ALREADY_EXISTS))
    {
      ...
      err = try_copy(sources,
                     dst_is_url
                         ? svn_path_url_add_component2(dst_path,
                                                       src_basename, pool)
                         : svn_dirent_join(dst_path, src_basename, pool),
                      ...
]]]

So, a fix in the client layer is needed as well. Any suggestions on
how to best approach this?

Right now, I'm thinking the fix should be in verify_wc_srcs_and_dsts
(similar to the "special case" of my below patch for move-cmd.c):
while checking each copy_pair, if the dst_path already exists, check
the "true path" of dst_path (APR_FILEPATH_TRUENAME), and see if it's
the same as the src_path. If so, don't return an already-exists-error.
But I'm not sure if that's correct, may have side-effects, ...

Thoughts?


Below is the patch-in-progress for svn/move-cmd.c. Any feedback on
this patch is also welcome of course. I'm pretty sure it's not perfect
:-), but it allowed me to get further.

Note: it's definitely not finished yet, because for getting the
"original dst_path", I only look at the apr_getopt_t *os structure,
and not at the opt_state->targets. I should probably consider both,
just like cmdline.c#svn_client_args_to_target_array does. But I don't
know yet how to do that nicely/concisely (maybe introduce another
helper function somewhere? In cmdline.c?). Any suggestions welcome
:-).

Log message:
Allow case-only renames on case-insensitive filesystems (issue #3702).

* subversion/svn/move-cmd.c
  (svn_cl__move): If the targets are paths, and there are exactly two, and
   the normalized DST_PATH and SRC_PATH are equal, canonicalize the original
   DST_PATH again, but without converting it to on-disk casing.
-------
Patch:
[[[
Index: subversion/svn/move-cmd.c
===================================================================
--- subversion/svn/move-cmd.c   (revision 1092816)
+++ subversion/svn/move-cmd.c   (working copy)
@@ -30,6 +30,7 @@
 #include "svn_client.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_utf.h"
 #include "cl.h"

 #include "svn_private_config.h"
@@ -76,6 +77,27 @@ svn_cl__move(apr_getopt_t *os,
           (SVN_ERR_CL_UNNECESSARY_LOG_MESSAGE, NULL,
            _("Local, non-commit operations do not take a log message "
              "or revision properties"));
+
+      /* For allowing case-only renames on Windows (issue #3702):
+         If DST_PATH is a path, and there is exactly one source path, check if
+         the normalized DST_PATH and SRC_PATH are equal. If so, canonicalize
+         the original DST_PATH again, but without converting it to on-disk
+         casing, so we can pass the intended destination to
+         svn_client_move6. */
+      if (targets->nelts == 1)
+        {
+          const char *src_path = APR_ARRAY_IDX(targets, targets->nelts - 1,
+                                               const char *);
+
+          if (strcmp(src_path, dst_path) == 0)
+            {
+              const char *utf8_target;
+
+              SVN_ERR(svn_utf_cstring_to_utf8(&utf8_target,
+                                              os->argv[os->argc - 1], pool));
+              dst_path = svn_dirent_canonicalize(utf8_target, pool);
+            }
+        }
     }

   if (ctx->log_msg_func3)
]]]


[1] http://svn.haxx.se/dev/archive-2011-04/0232.shtml
[2] http://subversion.tigris.org/issues/show_bug.cgi?id=3702#desc6

Cheers,
-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
2011/4/16 Branko Čibej <br...@e-reka.si>:
> On 16.04.2011 16:14, Johan Corveleyn wrote:
>> Do I have to worry about differences between on-disk casing and wc-db
>> casing of a path? Is that possible? I guess it is by using non-svn
>> commands, but I bet that's an invalid state of the wc (I know that in
>> 1.6, if you run into this, svn gets all confused (marking the file it
>> has in metadata as deleted, and your on-disk file as unversioned)).
>> That's definitely out of scope for the change I'm trying to make.
>
> "Valid state" is kinda fuzzy, and since some tools (still) insist on
> changing file case every which way, this case can realistically be
> expected to happen every once in a while. But certainly more than just
> rename are affected by it, so I guess it's not realistic to try to deal
> with the problem in your patch.
>
> The most famousest case where this can happen is if you try to check out
> "Foo" and "fOO" in the same directory on a case-insensitive file system.
> Our answer to that has been, "don't do that"; and it would take very
> significant surgery in the client and WC libraries to make it work. I'm
> unaware of any version control system that handles such cases correctly.
>
> By the way, does your patch deal with the case where an "svn update"
> results in a case-only rename?

AFAIK, that already works correctly (at least it did in 1.5 and 1.6 -
we regularly had that situation at work - no problem, the filename is
changed to the correct casing during "update").

The only problem I'm trying to address is that "svn move" still blocks
a case-only rename on Windows at the command-line / client layers,
although WC-NG can now handle it. WC-1 couldn't handle it in the
working copy, but WC-NG can.

As explained by Bert in the last comment of issue #3702: "svn ren TODO
todoQ; svn ren todoQ todo" now works with WC-NG, while it didn't work
in the past. But "svn ren TODO todo" is still blocked, because it's
internally converted to "svn ren TODO TODO" (both paths converted to
on-disk casing).

-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Branko Čibej <br...@e-reka.si>.
On 16.04.2011 16:14, Johan Corveleyn wrote:
> Do I have to worry about differences between on-disk casing and wc-db
> casing of a path? Is that possible? I guess it is by using non-svn
> commands, but I bet that's an invalid state of the wc (I know that in
> 1.6, if you run into this, svn gets all confused (marking the file it
> has in metadata as deleted, and your on-disk file as unversioned)).
> That's definitely out of scope for the change I'm trying to make.

"Valid state" is kinda fuzzy, and since some tools (still) insist on
changing file case every which way, this case can realistically be
expected to happen every once in a while. But certainly more than just
rename are affected by it, so I guess it's not realistic to try to deal
with the problem in your patch.

The most famousest case where this can happen is if you try to check out
"Foo" and "fOO" in the same directory on a case-insensitive file system.
Our answer to that has been, "don't do that"; and it would take very
significant surgery in the client and WC libraries to make it work. I'm
unaware of any version control system that handles such cases correctly.

By the way, does your patch deal with the case where an "svn update"
results in a case-only rename?

-- Brane

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
2011/4/16 Branko Čibej <br...@e-reka.si>:
> On 16.04.2011 10:17, Johan Corveleyn wrote:
>> Hi,
>>
>> Following discussion in [1], I tried to write a patch for issue #3702
>> ("svn ren TODO todo" not work on windows). As mentioned by Bert in
>> comment to the issue [2], we need to avoid letting 'svn move' convert
>> the destination path to on-disk casing in this case, so that's what
>> the below patch does.
> [...]
>
> Your biggest headache is going to be dealing with the fact that the WC
> database is case-sensitive, as in, for example:
>
>    svn mv foo foo
>
> where the file on disk (and in the database) is actually called Foo. The
> above operation is perfectly valid on case-insensitive file systems. The
> other case is where neither the source nor the destination name of the
> rename match the name case in wc-db.

Yes, but I think I covered that. Disregarding for a minute the problem
that libsvn_client still disallows the move, the flow is now as
follows, after my patch:

(1) Normalize all paths to their on-disk representation (the existing
code which was already there, using apr_filepath_merge with flag
APR_FILEPATH_TRUENAME).

(2) Now the patch comes in effect: if the normalized dst_path is equal
to the normalized src_path, we potentially have a case-only rename. In
that case, re-normalize the dst_path without converting to on-disk
representation, and try to do the move with that dst_path.

If the file on disk is Foo, then "svn mv foo foo" would then be
transformed to a move of Foo (on-disk rep) to foo (not converted to
on-disk rep). Which is exactly what I would expect as a user, because
that's what happens on Windows when you do the same with the native
"move" command.

> N.B.: You are absolutely not allowed to do a case-insensitive comparison
> of file names anywhere. You must let the filesystem decide if Foo and
> fOO refer to the same file. This is because the file system can (and
> often will) have different ideas about case folding than the current
> locale does. This implies that, if you "svn mv foo foo", and the file on
> disk is "fOO" but the entry in the wc-db is "Foo", you have to scan the
> directory in wc-db and check if the truename of any of those entries
> matches the truename of the rename source. This is not very optimal at
> all, but I don't see any other sure way of getting correct results.

Thanks for the heads up. When I do a comparison in libsvn_client (as I
described), I think I'll let apr_filepath_merge with flag
APR_FILEPATH_TRUENAME do this (or some similar function), just like
the existing code does (like in
libsvn_subr/opt.c#svn_opt__arg_canonicalize_path) - or just call that
function in opt.c or something. So I'll definitely not try to ignore
case myself.

Do I have to worry about differences between on-disk casing and wc-db
casing of a path? Is that possible? I guess it is by using non-svn
commands, but I bet that's an invalid state of the wc (I know that in
1.6, if you run into this, svn gets all confused (marking the file it
has in metadata as deleted, and your on-disk file as unversioned)).
That's definitely out of scope for the change I'm trying to make.

Cheers,
-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Branko Čibej <br...@e-reka.si>.
On 16.04.2011 10:17, Johan Corveleyn wrote:
> Hi,
>
> Following discussion in [1], I tried to write a patch for issue #3702
> ("svn ren TODO todo" not work on windows). As mentioned by Bert in
> comment to the issue [2], we need to avoid letting 'svn move' convert
> the destination path to on-disk casing in this case, so that's what
> the below patch does.
[...]

Your biggest headache is going to be dealing with the fact that the WC
database is case-sensitive, as in, for example:

    svn mv foo foo

where the file on disk (and in the database) is actually called Foo. The
above operation is perfectly valid on case-insensitive file systems. The
other case is where neither the source nor the destination name of the
rename match the name case in wc-db.

N.B.: You are absolutely not allowed to do a case-insensitive comparison
of file names anywhere. You must let the filesystem decide if Foo and
fOO refer to the same file. This is because the file system can (and
often will) have different ideas about case folding than the current
locale does. This implies that, if you "svn mv foo foo", and the file on
disk is "fOO" but the entry in the wc-db is "Foo", you have to scan the
directory in wc-db and check if the truename of any of those entries
matches the truename of the rename source. This is not very optimal at
all, but I don't see any other sure way of getting correct results.

-- Brane

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
Johan Corveleyn wrote on Tue, May 03, 2011 at 23:29:26 +0200:
> On Tue, May 3, 2011 at 10:17 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> > Johan Corveleyn wrote on Tue, May 03, 2011 at 21:49:48 +0200:
> >> On Mon, Apr 25, 2011 at 11:26 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> >> > Johan Corveleyn wrote on Mon, Apr 25, 2011 at 23:10:21 +0200:
> >> >> On Mon, Apr 25, 2011 at 5:03 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> >> >> > Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
> >> >> >> 2011/4/22 Branko Čibej <br...@e-reka.si>:
> >> >> >> > Meh. For now, just hack a special case so that committing one half of a
> >> >> >> > case-only rename will automagically commit the other half. Shouldn't be
> >> >> >> > too hard to do, and it's almost impossible to do the wrong thing --
> >> >> >> > after all, you're constrained by a) staying in the same directory, and
> >> >> >> > b) both halves of a rename resolving to the same on-disk file on a
> >> >> >> > case-insensitive file system.
> >> >> >>
> >> >> >> Sounds like another option. A small change here and there to make
> >> >> >> case-only renames work specifically (and not solve the more general
> >> >> >> problem of fixing path-guessing via wc-db or truepaths).
> >> >> >>
> >> >> >> The fact of the matter is that, for sane setups/companies,
> >> >> >> case-clashes are going to be really rare, *except when doing case-only
> >> >> >> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
> >> >> >> repository that's un-checkoutable on a case-insensitive filesystem
> >> >> >> anyway. So I'd expect companies that have to support case-insensitive
> >> >> >> clients to keep real case-clashes out of their repository (or fix them
> >> >> >> as soon as they are discovered).
> >> >> >>
> >> >> >> So maybe "case-only rename" (and perhaps "case-only replace"
> >> >> >> (delete+add w/o history)) is the only use-case we need to go for. But
> >> >> >> apart from commit, we should maybe also make "revert" possible, as
> >> >> >> well as adding to and removing from changelists ... (hm, commit would
> >> >> >> be the main thing I guess, revert can always be done in two steps
> >> >> >> (revert the add, then the delete), changelists ... oh well).
> >> >> >>
> >> >> >
> >> >> > Another use-case:
> >> >> >
> >> >> > When r1 contains a file 'Foo', r2 contains a file 'foo', the working
> >> >> > copy is at uniform revision r2, and the user types 'svn up -r1 Foo'.
> >> >> >
> >> >> > There is also a variant where Foo@r1 is a directory rather than a file,
> >> >> > but that's getting contrived.
> >> >>
> >> >> And I guess 'Foo' no longer exists in r2, and 'foo' didn't exist in
> >> >> r1? Maybe 'Foo' got renamed to 'foo'? Or maybe there is no historical
> >> >> relationship?
> >> >>
> >> >> Anyway, I think this also works right now, without any special tricks:
> >> >>
> >> >> - 'svn up -r1 Foo' gets canonicalized to 'svn up -r1 foo', the file
> >> >> on-disk, and currently present in the working copy.
> >> >>
> >> >> - If 'foo's ancestor is 'Foo', 'foo' gets deleted and 'Foo' is
> >> >> downloaded from the repository, by the update editor.
> >> >>
> >> >> The update editor currently has no problems with handling case-only
> >> >> renames on case-insensitive filesystems.
> >> >>
> >> >
> >> > Sorry for not being clear.
> >> >
> >> > In my example I intended 'foo' and 'Foo' to be two separate lines of
> >> > history.
> >> >
> >> > % svnadmin create r1
> >> > % svn co file://`pwd`/r1 wc1
> >> > % cd wc1
> >> > % svn mkdir iota
> >> > % svn ci -m r1
> >> > % svn rm iota
> >> > % svn mkdir IOTA
> >> > % svn ci -m r2
> >> > % svn up -r2
> >> > % option #1:   svn up -r1 iota
> >> > % option #2:   svn up -r1 iota IOTA
> >> >
> >> > For option #1, I specified 'iota', so I expect svn to error out saying
> >> > "You asked me to create ./iota but I can't because ./IOTA exists" (never
> >> > mind whether or not it's versioned).
> >>
> >> I'm confused. If you type "svn up -r1 iota", the iota is a target of
> >> the PATH variety, or in any case you're trying to address something in
> >> the working copy. At this point there is no ambiguity: you're actually
> >> referring to IOTA (the on-disk truepath), because what else is there
> >> (there is no iota present on disk, nor in the wc metadata)?
> >>
> >
> > There is ^/iota@1.  Just take IOTA out of the picture and try it:
> >
> > % svnadmin create r1
> > % svn co file://`pwd`/r1 wc1
> > % cd wc1
> > % touch iota && svn add iota
> > % svn ci -m r1 iota
> > % svn rm iota
> > % svn ci -m r2
> > % svn up -r2
> > % svn up -r1 iota
> >
> >> So you're really asking to update IOTA to r1, in which it didn't
> >> exist.
> >
> > No, I'm asking to restore 'iota' from r1, in which it did exist.
> 
> Wow, I didn't even know that was possible :-). Reading "svn help up",
> I guess the last paragraph explains it:
> 
> ------
>   If the specified update target is missing from the working copy but its
>   immediate parent directory is present, checkout the target into its
>   parent directory at the specified depth.  If --parents is specified,
>   create any missing parent directories of the target by checking them
>   out, too, at depth=empty.
> ------
> 
> Getting back to your case-clashing example:
> 
> > % svnadmin create r1
> > % svn co file://`pwd`/r1 wc1
> > % cd wc1
> > % svn mkdir iota
> > % svn ci -m r1
> > % svn rm iota
> > % svn mkdir IOTA
> > % svn ci -m r2
> > % svn up -r2
> > % option #1:   svn up -r1 iota
> > % option #2:   svn up -r1 iota IOTA
> >
> > For option #1, I specified 'iota', so I expect svn to error out saying
> > "You asked me to create ./iota but I can't because ./IOTA exists" (never
> > mind whether or not it's versioned).
> >
> > Option #2 is what I'd expect to work to get me iota@1 (at the expense of
> > shifting IOTA@2 to not-present(?) state, but that's the best I can do
> > given the filesystem's limitations).  It's probably a bit tricky unless
> > we can ensure the editor sends IOTA before iota, though...
> 
> Ok, if we'd have an option --literal-path, I'd go for your suggested
> way of handling it (don't know about the not-presentness of IOTA@2 in
> option #2).
> 

:-)

> But, in the absence of such an option, I wouldn't try to support this.
> Otherwise, you're going even further than issue #3865 ('svn' on
> Windows cannot address scheduled-for-delete file, if another file
> differing only in case is present on disk). You're trying to target
> some path that's *missing* from the working copy, while a
> case-clashing file is present in the working copy. To do that, the
> client would first have to contact the repository to see if 'iota' is
> perhaps present in the repository at r1, before it can finally do the
> truepath conversion and decide you're actually meaning IOTA but
> mistyped the case :-).
> 
> I.e.: without an explicit flag, I would let the client do the truepath
> canonicalization first (but after checking the wc-db (for case-only
> renames/replaces), and only after that try the "if it's missing, check
> it out from its parent" trick.
> 

In the absence of such a flag it's indeed ambiguous whether the intended
semantics are to refer to ^/iota@1 or ./IOTA@2.  If you're saying that
the former semantics is too costly (performance-wise) --- and I believe
it's also less historically compatible with past releases --- then +1
here to the latter semantics.

> Cheers,
> -- 
> Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
On Tue, May 3, 2011 at 10:17 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> Johan Corveleyn wrote on Tue, May 03, 2011 at 21:49:48 +0200:
>> On Mon, Apr 25, 2011 at 11:26 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
>> > Johan Corveleyn wrote on Mon, Apr 25, 2011 at 23:10:21 +0200:
>> >> On Mon, Apr 25, 2011 at 5:03 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
>> >> > Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
>> >> >> 2011/4/22 Branko Čibej <br...@e-reka.si>:
>> >> >> > Meh. For now, just hack a special case so that committing one half of a
>> >> >> > case-only rename will automagically commit the other half. Shouldn't be
>> >> >> > too hard to do, and it's almost impossible to do the wrong thing --
>> >> >> > after all, you're constrained by a) staying in the same directory, and
>> >> >> > b) both halves of a rename resolving to the same on-disk file on a
>> >> >> > case-insensitive file system.
>> >> >>
>> >> >> Sounds like another option. A small change here and there to make
>> >> >> case-only renames work specifically (and not solve the more general
>> >> >> problem of fixing path-guessing via wc-db or truepaths).
>> >> >>
>> >> >> The fact of the matter is that, for sane setups/companies,
>> >> >> case-clashes are going to be really rare, *except when doing case-only
>> >> >> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
>> >> >> repository that's un-checkoutable on a case-insensitive filesystem
>> >> >> anyway. So I'd expect companies that have to support case-insensitive
>> >> >> clients to keep real case-clashes out of their repository (or fix them
>> >> >> as soon as they are discovered).
>> >> >>
>> >> >> So maybe "case-only rename" (and perhaps "case-only replace"
>> >> >> (delete+add w/o history)) is the only use-case we need to go for. But
>> >> >> apart from commit, we should maybe also make "revert" possible, as
>> >> >> well as adding to and removing from changelists ... (hm, commit would
>> >> >> be the main thing I guess, revert can always be done in two steps
>> >> >> (revert the add, then the delete), changelists ... oh well).
>> >> >>
>> >> >
>> >> > Another use-case:
>> >> >
>> >> > When r1 contains a file 'Foo', r2 contains a file 'foo', the working
>> >> > copy is at uniform revision r2, and the user types 'svn up -r1 Foo'.
>> >> >
>> >> > There is also a variant where Foo@r1 is a directory rather than a file,
>> >> > but that's getting contrived.
>> >>
>> >> And I guess 'Foo' no longer exists in r2, and 'foo' didn't exist in
>> >> r1? Maybe 'Foo' got renamed to 'foo'? Or maybe there is no historical
>> >> relationship?
>> >>
>> >> Anyway, I think this also works right now, without any special tricks:
>> >>
>> >> - 'svn up -r1 Foo' gets canonicalized to 'svn up -r1 foo', the file
>> >> on-disk, and currently present in the working copy.
>> >>
>> >> - If 'foo's ancestor is 'Foo', 'foo' gets deleted and 'Foo' is
>> >> downloaded from the repository, by the update editor.
>> >>
>> >> The update editor currently has no problems with handling case-only
>> >> renames on case-insensitive filesystems.
>> >>
>> >
>> > Sorry for not being clear.
>> >
>> > In my example I intended 'foo' and 'Foo' to be two separate lines of
>> > history.
>> >
>> > % svnadmin create r1
>> > % svn co file://`pwd`/r1 wc1
>> > % cd wc1
>> > % svn mkdir iota
>> > % svn ci -m r1
>> > % svn rm iota
>> > % svn mkdir IOTA
>> > % svn ci -m r2
>> > % svn up -r2
>> > % option #1:   svn up -r1 iota
>> > % option #2:   svn up -r1 iota IOTA
>> >
>> > For option #1, I specified 'iota', so I expect svn to error out saying
>> > "You asked me to create ./iota but I can't because ./IOTA exists" (never
>> > mind whether or not it's versioned).
>>
>> I'm confused. If you type "svn up -r1 iota", the iota is a target of
>> the PATH variety, or in any case you're trying to address something in
>> the working copy. At this point there is no ambiguity: you're actually
>> referring to IOTA (the on-disk truepath), because what else is there
>> (there is no iota present on disk, nor in the wc metadata)?
>>
>
> There is ^/iota@1.  Just take IOTA out of the picture and try it:
>
> % svnadmin create r1
> % svn co file://`pwd`/r1 wc1
> % cd wc1
> % touch iota && svn add iota
> % svn ci -m r1 iota
> % svn rm iota
> % svn ci -m r2
> % svn up -r2
> % svn up -r1 iota
>
>> So you're really asking to update IOTA to r1, in which it didn't
>> exist.
>
> No, I'm asking to restore 'iota' from r1, in which it did exist.

Wow, I didn't even know that was possible :-). Reading "svn help up",
I guess the last paragraph explains it:

------
  If the specified update target is missing from the working copy but its
  immediate parent directory is present, checkout the target into its
  parent directory at the specified depth.  If --parents is specified,
  create any missing parent directories of the target by checking them
  out, too, at depth=empty.
------

Getting back to your case-clashing example:

> % svnadmin create r1
> % svn co file://`pwd`/r1 wc1
> % cd wc1
> % svn mkdir iota
> % svn ci -m r1
> % svn rm iota
> % svn mkdir IOTA
> % svn ci -m r2
> % svn up -r2
> % option #1:   svn up -r1 iota
> % option #2:   svn up -r1 iota IOTA
>
> For option #1, I specified 'iota', so I expect svn to error out saying
> "You asked me to create ./iota but I can't because ./IOTA exists" (never
> mind whether or not it's versioned).
>
> Option #2 is what I'd expect to work to get me iota@1 (at the expense of
> shifting IOTA@2 to not-present(?) state, but that's the best I can do
> given the filesystem's limitations).  It's probably a bit tricky unless
> we can ensure the editor sends IOTA before iota, though...

Ok, if we'd have an option --literal-path, I'd go for your suggested
way of handling it (don't know about the not-presentness of IOTA@2 in
option #2).

But, in the absence of such an option, I wouldn't try to support this.
Otherwise, you're going even further than issue #3865 ('svn' on
Windows cannot address scheduled-for-delete file, if another file
differing only in case is present on disk). You're trying to target
some path that's *missing* from the working copy, while a
case-clashing file is present in the working copy. To do that, the
client would first have to contact the repository to see if 'iota' is
perhaps present in the repository at r1, before it can finally do the
truepath conversion and decide you're actually meaning IOTA but
mistyped the case :-).

I.e.: without an explicit flag, I would let the client do the truepath
canonicalization first (but after checking the wc-db (for case-only
renames/replaces), and only after that try the "if it's missing, check
it out from its parent" trick.

Cheers,
-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
Johan Corveleyn wrote on Tue, May 03, 2011 at 21:49:48 +0200:
> On Mon, Apr 25, 2011 at 11:26 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> > Johan Corveleyn wrote on Mon, Apr 25, 2011 at 23:10:21 +0200:
> >> On Mon, Apr 25, 2011 at 5:03 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> >> > Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
> >> >> 2011/4/22 Branko Čibej <br...@e-reka.si>:
> >> >> > Meh. For now, just hack a special case so that committing one half of a
> >> >> > case-only rename will automagically commit the other half. Shouldn't be
> >> >> > too hard to do, and it's almost impossible to do the wrong thing --
> >> >> > after all, you're constrained by a) staying in the same directory, and
> >> >> > b) both halves of a rename resolving to the same on-disk file on a
> >> >> > case-insensitive file system.
> >> >>
> >> >> Sounds like another option. A small change here and there to make
> >> >> case-only renames work specifically (and not solve the more general
> >> >> problem of fixing path-guessing via wc-db or truepaths).
> >> >>
> >> >> The fact of the matter is that, for sane setups/companies,
> >> >> case-clashes are going to be really rare, *except when doing case-only
> >> >> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
> >> >> repository that's un-checkoutable on a case-insensitive filesystem
> >> >> anyway. So I'd expect companies that have to support case-insensitive
> >> >> clients to keep real case-clashes out of their repository (or fix them
> >> >> as soon as they are discovered).
> >> >>
> >> >> So maybe "case-only rename" (and perhaps "case-only replace"
> >> >> (delete+add w/o history)) is the only use-case we need to go for. But
> >> >> apart from commit, we should maybe also make "revert" possible, as
> >> >> well as adding to and removing from changelists ... (hm, commit would
> >> >> be the main thing I guess, revert can always be done in two steps
> >> >> (revert the add, then the delete), changelists ... oh well).
> >> >>
> >> >
> >> > Another use-case:
> >> >
> >> > When r1 contains a file 'Foo', r2 contains a file 'foo', the working
> >> > copy is at uniform revision r2, and the user types 'svn up -r1 Foo'.
> >> >
> >> > There is also a variant where Foo@r1 is a directory rather than a file,
> >> > but that's getting contrived.
> >>
> >> And I guess 'Foo' no longer exists in r2, and 'foo' didn't exist in
> >> r1? Maybe 'Foo' got renamed to 'foo'? Or maybe there is no historical
> >> relationship?
> >>
> >> Anyway, I think this also works right now, without any special tricks:
> >>
> >> - 'svn up -r1 Foo' gets canonicalized to 'svn up -r1 foo', the file
> >> on-disk, and currently present in the working copy.
> >>
> >> - If 'foo's ancestor is 'Foo', 'foo' gets deleted and 'Foo' is
> >> downloaded from the repository, by the update editor.
> >>
> >> The update editor currently has no problems with handling case-only
> >> renames on case-insensitive filesystems.
> >>
> >
> > Sorry for not being clear.
> >
> > In my example I intended 'foo' and 'Foo' to be two separate lines of
> > history.
> >
> > % svnadmin create r1
> > % svn co file://`pwd`/r1 wc1
> > % cd wc1
> > % svn mkdir iota
> > % svn ci -m r1
> > % svn rm iota
> > % svn mkdir IOTA
> > % svn ci -m r2
> > % svn up -r2
> > % option #1:   svn up -r1 iota
> > % option #2:   svn up -r1 iota IOTA
> >
> > For option #1, I specified 'iota', so I expect svn to error out saying
> > "You asked me to create ./iota but I can't because ./IOTA exists" (never
> > mind whether or not it's versioned).
> 
> I'm confused. If you type "svn up -r1 iota", the iota is a target of
> the PATH variety, or in any case you're trying to address something in
> the working copy. At this point there is no ambiguity: you're actually
> referring to IOTA (the on-disk truepath), because what else is there
> (there is no iota present on disk, nor in the wc metadata)?
> 

There is ^/iota@1.  Just take IOTA out of the picture and try it:

% svnadmin create r1
% svn co file://`pwd`/r1 wc1
% cd wc1
% touch iota && svn add iota
% svn ci -m r1 iota
% svn rm iota
% svn ci -m r2
% svn up -r2
% svn up -r1 iota

> So you're really asking to update IOTA to r1, in which it didn't
> exist.

No, I'm asking to restore 'iota' from r1, in which it did exist.

> So this is a perfectly valid operation, which would result the
> deletion of IOTA (and nothing else).
> 
> > Option #2 is what I'd expect to work to get me iota@1 (at the expense of
> > shifting IOTA@2 to not-present(?) state, but that's the best I can do
> > given the filesystem's limitations).  It's probably a bit tricky unless
> > we can ensure the editor sends IOTA before iota, though...
> 
> No, this is identical to option #1, I think. There is no iota on-disk,
> nor is there in wc-metadata, so you can only be referring two times to
> IOTA.
> 

(see above)

> -- 
> Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
On Mon, Apr 25, 2011 at 11:26 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> Johan Corveleyn wrote on Mon, Apr 25, 2011 at 23:10:21 +0200:
>> On Mon, Apr 25, 2011 at 5:03 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
>> > Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
>> >> 2011/4/22 Branko Čibej <br...@e-reka.si>:
>> >> > Meh. For now, just hack a special case so that committing one half of a
>> >> > case-only rename will automagically commit the other half. Shouldn't be
>> >> > too hard to do, and it's almost impossible to do the wrong thing --
>> >> > after all, you're constrained by a) staying in the same directory, and
>> >> > b) both halves of a rename resolving to the same on-disk file on a
>> >> > case-insensitive file system.
>> >>
>> >> Sounds like another option. A small change here and there to make
>> >> case-only renames work specifically (and not solve the more general
>> >> problem of fixing path-guessing via wc-db or truepaths).
>> >>
>> >> The fact of the matter is that, for sane setups/companies,
>> >> case-clashes are going to be really rare, *except when doing case-only
>> >> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
>> >> repository that's un-checkoutable on a case-insensitive filesystem
>> >> anyway. So I'd expect companies that have to support case-insensitive
>> >> clients to keep real case-clashes out of their repository (or fix them
>> >> as soon as they are discovered).
>> >>
>> >> So maybe "case-only rename" (and perhaps "case-only replace"
>> >> (delete+add w/o history)) is the only use-case we need to go for. But
>> >> apart from commit, we should maybe also make "revert" possible, as
>> >> well as adding to and removing from changelists ... (hm, commit would
>> >> be the main thing I guess, revert can always be done in two steps
>> >> (revert the add, then the delete), changelists ... oh well).
>> >>
>> >
>> > Another use-case:
>> >
>> > When r1 contains a file 'Foo', r2 contains a file 'foo', the working
>> > copy is at uniform revision r2, and the user types 'svn up -r1 Foo'.
>> >
>> > There is also a variant where Foo@r1 is a directory rather than a file,
>> > but that's getting contrived.
>>
>> And I guess 'Foo' no longer exists in r2, and 'foo' didn't exist in
>> r1? Maybe 'Foo' got renamed to 'foo'? Or maybe there is no historical
>> relationship?
>>
>> Anyway, I think this also works right now, without any special tricks:
>>
>> - 'svn up -r1 Foo' gets canonicalized to 'svn up -r1 foo', the file
>> on-disk, and currently present in the working copy.
>>
>> - If 'foo's ancestor is 'Foo', 'foo' gets deleted and 'Foo' is
>> downloaded from the repository, by the update editor.
>>
>> The update editor currently has no problems with handling case-only
>> renames on case-insensitive filesystems.
>>
>
> Sorry for not being clear.
>
> In my example I intended 'foo' and 'Foo' to be two separate lines of
> history.
>
> % svnadmin create r1
> % svn co file://`pwd`/r1 wc1
> % cd wc1
> % svn mkdir iota
> % svn ci -m r1
> % svn rm iota
> % svn mkdir IOTA
> % svn ci -m r2
> % svn up -r2
> % option #1:   svn up -r1 iota
> % option #2:   svn up -r1 iota IOTA
>
> For option #1, I specified 'iota', so I expect svn to error out saying
> "You asked me to create ./iota but I can't because ./IOTA exists" (never
> mind whether or not it's versioned).

I'm confused. If you type "svn up -r1 iota", the iota is a target of
the PATH variety, or in any case you're trying to address something in
the working copy. At this point there is no ambiguity: you're actually
referring to IOTA (the on-disk truepath), because what else is there
(there is no iota present on disk, nor in the wc metadata)?

So you're really asking to update IOTA to r1, in which it didn't
exist. So this is a perfectly valid operation, which would result the
deletion of IOTA (and nothing else).

> Option #2 is what I'd expect to work to get me iota@1 (at the expense of
> shifting IOTA@2 to not-present(?) state, but that's the best I can do
> given the filesystem's limitations).  It's probably a bit tricky unless
> we can ensure the editor sends IOTA before iota, though...

No, this is identical to option #1, I think. There is no iota on-disk,
nor is there in wc-metadata, so you can only be referring two times to
IOTA.

-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
Johan Corveleyn wrote on Mon, Apr 25, 2011 at 23:10:21 +0200:
> On Mon, Apr 25, 2011 at 5:03 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> > Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
> >> 2011/4/22 Branko Čibej <br...@e-reka.si>:
> >> > Meh. For now, just hack a special case so that committing one half of a
> >> > case-only rename will automagically commit the other half. Shouldn't be
> >> > too hard to do, and it's almost impossible to do the wrong thing --
> >> > after all, you're constrained by a) staying in the same directory, and
> >> > b) both halves of a rename resolving to the same on-disk file on a
> >> > case-insensitive file system.
> >>
> >> Sounds like another option. A small change here and there to make
> >> case-only renames work specifically (and not solve the more general
> >> problem of fixing path-guessing via wc-db or truepaths).
> >>
> >> The fact of the matter is that, for sane setups/companies,
> >> case-clashes are going to be really rare, *except when doing case-only
> >> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
> >> repository that's un-checkoutable on a case-insensitive filesystem
> >> anyway. So I'd expect companies that have to support case-insensitive
> >> clients to keep real case-clashes out of their repository (or fix them
> >> as soon as they are discovered).
> >>
> >> So maybe "case-only rename" (and perhaps "case-only replace"
> >> (delete+add w/o history)) is the only use-case we need to go for. But
> >> apart from commit, we should maybe also make "revert" possible, as
> >> well as adding to and removing from changelists ... (hm, commit would
> >> be the main thing I guess, revert can always be done in two steps
> >> (revert the add, then the delete), changelists ... oh well).
> >>
> >
> > Another use-case:
> >
> > When r1 contains a file 'Foo', r2 contains a file 'foo', the working
> > copy is at uniform revision r2, and the user types 'svn up -r1 Foo'.
> >
> > There is also a variant where Foo@r1 is a directory rather than a file,
> > but that's getting contrived.
> 
> And I guess 'Foo' no longer exists in r2, and 'foo' didn't exist in
> r1? Maybe 'Foo' got renamed to 'foo'? Or maybe there is no historical
> relationship?
> 
> Anyway, I think this also works right now, without any special tricks:
> 
> - 'svn up -r1 Foo' gets canonicalized to 'svn up -r1 foo', the file
> on-disk, and currently present in the working copy.
> 
> - If 'foo's ancestor is 'Foo', 'foo' gets deleted and 'Foo' is
> downloaded from the repository, by the update editor.
> 
> The update editor currently has no problems with handling case-only
> renames on case-insensitive filesystems.
> 

Sorry for not being clear.

In my example I intended 'foo' and 'Foo' to be two separate lines of
history.

% svnadmin create r1
% svn co file://`pwd`/r1 wc1
% cd wc1
% svn mkdir iota
% svn ci -m r1
% svn rm iota
% svn mkdir IOTA
% svn ci -m r2
% svn up -r2
% option #1:   svn up -r1 iota
% option #2:   svn up -r1 iota IOTA

For option #1, I specified 'iota', so I expect svn to error out saying
"You asked me to create ./iota but I can't because ./IOTA exists" (never
mind whether or not it's versioned).

Option #2 is what I'd expect to work to get me iota@1 (at the expense of
shifting IOTA@2 to not-present(?) state, but that's the best I can do
given the filesystem's limitations).  It's probably a bit tricky unless
we can ensure the editor sends IOTA before iota, though...

> Cheers,
> -- 
> Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
On Mon, Apr 25, 2011 at 5:03 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
>> 2011/4/22 Branko Čibej <br...@e-reka.si>:
>> > Meh. For now, just hack a special case so that committing one half of a
>> > case-only rename will automagically commit the other half. Shouldn't be
>> > too hard to do, and it's almost impossible to do the wrong thing --
>> > after all, you're constrained by a) staying in the same directory, and
>> > b) both halves of a rename resolving to the same on-disk file on a
>> > case-insensitive file system.
>>
>> Sounds like another option. A small change here and there to make
>> case-only renames work specifically (and not solve the more general
>> problem of fixing path-guessing via wc-db or truepaths).
>>
>> The fact of the matter is that, for sane setups/companies,
>> case-clashes are going to be really rare, *except when doing case-only
>> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
>> repository that's un-checkoutable on a case-insensitive filesystem
>> anyway. So I'd expect companies that have to support case-insensitive
>> clients to keep real case-clashes out of their repository (or fix them
>> as soon as they are discovered).
>>
>> So maybe "case-only rename" (and perhaps "case-only replace"
>> (delete+add w/o history)) is the only use-case we need to go for. But
>> apart from commit, we should maybe also make "revert" possible, as
>> well as adding to and removing from changelists ... (hm, commit would
>> be the main thing I guess, revert can always be done in two steps
>> (revert the add, then the delete), changelists ... oh well).
>>
>
> Another use-case:
>
> When r1 contains a file 'Foo', r2 contains a file 'foo', the working
> copy is at uniform revision r2, and the user types 'svn up -r1 Foo'.
>
> There is also a variant where Foo@r1 is a directory rather than a file,
> but that's getting contrived.

And I guess 'Foo' no longer exists in r2, and 'foo' didn't exist in
r1? Maybe 'Foo' got renamed to 'foo'? Or maybe there is no historical
relationship?

Anyway, I think this also works right now, without any special tricks:

- 'svn up -r1 Foo' gets canonicalized to 'svn up -r1 foo', the file
on-disk, and currently present in the working copy.

- If 'foo's ancestor is 'Foo', 'foo' gets deleted and 'Foo' is
downloaded from the repository, by the update editor.

The update editor currently has no problems with handling case-only
renames on case-insensitive filesystems.

Cheers,
-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
> 2011/4/22 Branko Čibej <br...@e-reka.si>:
> > Meh. For now, just hack a special case so that committing one half of a
> > case-only rename will automagically commit the other half. Shouldn't be
> > too hard to do, and it's almost impossible to do the wrong thing --
> > after all, you're constrained by a) staying in the same directory, and
> > b) both halves of a rename resolving to the same on-disk file on a
> > case-insensitive file system.
> 
> Sounds like another option. A small change here and there to make
> case-only renames work specifically (and not solve the more general
> problem of fixing path-guessing via wc-db or truepaths).
> 
> The fact of the matter is that, for sane setups/companies,
> case-clashes are going to be really rare, *except when doing case-only
> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
> repository that's un-checkoutable on a case-insensitive filesystem
> anyway. So I'd expect companies that have to support case-insensitive
> clients to keep real case-clashes out of their repository (or fix them
> as soon as they are discovered).
> 
> So maybe "case-only rename" (and perhaps "case-only replace"
> (delete+add w/o history)) is the only use-case we need to go for. But
> apart from commit, we should maybe also make "revert" possible, as
> well as adding to and removing from changelists ... (hm, commit would
> be the main thing I guess, revert can always be done in two steps
> (revert the add, then the delete), changelists ... oh well).
> 

Another use-case:

When r1 contains a file 'Foo', r2 contains a file 'foo', the working
copy is at uniform revision r2, and the user types 'svn up -r1 Foo'.

There is also a variant where Foo@r1 is a directory rather than a file,
but that's getting contrived.

> I'd love to hear some more input ...
> 
> Cheers,

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
On Mon, Apr 25, 2011 at 4:56 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
>> 2011/4/22 Branko Čibej <br...@e-reka.si>:
>> > Meh. For now, just hack a special case so that committing one half of a
>> > case-only rename will automagically commit the other half. Shouldn't be
>> > too hard to do, and it's almost impossible to do the wrong thing --
>> > after all, you're constrained by a) staying in the same directory, and
>> > b) both halves of a rename resolving to the same on-disk file on a
>> > case-insensitive file system.
>>
>> Sounds like another option. A small change here and there to make
>> case-only renames work specifically (and not solve the more general
>> problem of fixing path-guessing via wc-db or truepaths).
>>
>> The fact of the matter is that, for sane setups/companies,
>> case-clashes are going to be really rare, *except when doing case-only
>> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
>> repository that's un-checkoutable on a case-insensitive filesystem
>
> Un-checkoutable at depth >= svn_depth_files (assuming those 'foo' are
> files rather than directories).
>
> It makes perfect sense to me to have, say, both trunk/config.txt and
> trunk/CONFIG.txt, and tell people to do
>
>        svn up --set-depth=exclude config.txt     # remove the uppercase one
>        && svn up --set-depth=infinity config.txt # pull the lowercase one
>        ,
>
> for example.  It's a very cheap and effective way of ensuring at most
> one of the conflicting config.txt files is present.
>
> "Case-insensitive filesystems: it's not a bug, it's a feature."
>
> ---
>
> I'm not going to guess whether (and how many) people use Subversion this
> way; I'm only saying that the above workflow allows for coexisting
> case-clashing files and is supported by our released code.

Ok, disregarding for a second that I think this is pretty contrived
:-), I think this works perfectly well right now AFAICS. Because you
first (have to) exclude/remove the one that's currently on-disk, there
is no longer any truepath conversion going on after that. So the user
is then free to choose whichever of the case-clashing files to get
from the repository. There is no need to enable the user to specify a
case-clashing file (wc-item) while another one is on-disk.

Cheers,
-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
Johan Corveleyn wrote on Mon, Apr 25, 2011 at 01:08:24 +0200:
> 2011/4/22 Branko Čibej <br...@e-reka.si>:
> > Meh. For now, just hack a special case so that committing one half of a
> > case-only rename will automagically commit the other half. Shouldn't be
> > too hard to do, and it's almost impossible to do the wrong thing --
> > after all, you're constrained by a) staying in the same directory, and
> > b) both halves of a rename resolving to the same on-disk file on a
> > case-insensitive file system.
> 
> Sounds like another option. A small change here and there to make
> case-only renames work specifically (and not solve the more general
> problem of fixing path-guessing via wc-db or truepaths).
> 
> The fact of the matter is that, for sane setups/companies,
> case-clashes are going to be really rare, *except when doing case-only
> renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
> repository that's un-checkoutable on a case-insensitive filesystem

Un-checkoutable at depth >= svn_depth_files (assuming those 'foo' are
files rather than directories).

It makes perfect sense to me to have, say, both trunk/config.txt and
trunk/CONFIG.txt, and tell people to do

        svn up --set-depth=exclude config.txt     # remove the uppercase one
        && svn up --set-depth=infinity config.txt # pull the lowercase one
        ,
        
for example.  It's a very cheap and effective way of ensuring at most
one of the conflicting config.txt files is present.

"Case-insensitive filesystems: it's not a bug, it's a feature."

---

I'm not going to guess whether (and how many) people use Subversion this
way; I'm only saying that the above workflow allows for coexisting
case-clashing files and is supported by our released code.

> anyway. So I'd expect companies that have to support case-insensitive
> clients to keep real case-clashes out of their repository (or fix them
> as soon as they are discovered).
> 
> So maybe "case-only rename" (and perhaps "case-only replace"
> (delete+add w/o history)) is the only use-case we need to go for. But
> apart from commit, we should maybe also make "revert" possible, as
> well as adding to and removing from changelists ... (hm, commit would
> be the main thing I guess, revert can always be done in two steps
> (revert the add, then the delete), changelists ... oh well).
> 
> I'd love to hear some more input ...
> 
> Cheers,
> -- 
> Johan
> 
> [1] http://subversion.tigris.org/issues/show_bug.cgi?id=3865 ('svn' on
> Windows cannot address scheduled-for-delete file, if another file
> differing only in case is present on disk)

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
On Sat, Apr 23, 2011 at 11:13 AM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> On Sat, 23 Apr 2011 11:55 +0300, "Daniel Shahaf" <d....@daniel.shahaf.name> wrote:
>> On Fri, 22 Apr 2011 23:07 +0200, "Johan Corveleyn" <jc...@gmail.com> wrote:
>> > On Thu, Apr 21, 2011 at 3:07 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
>> > > Johan Corveleyn wrote on Mon, Apr 18, 2011 at 20:01:20 +0200:
>> > >> - In fact: the same problem holds true for other commands as well: how
>> > >> to revert both sides of this move? Ok, one can revert in two steps ...
>> > >>
>> > >> - Maybe a more general solution is needed, so all commands can
>> > >> adequately see which path the user actually means? The "truepath"
>> > >> corresponding to a given path (modulo case), or really the path in the
>> > >> case given by the user? A shot in the dark: (1) first look in the
>> > >> wc-db - if the path matches a path in the wc-db, accept it as is, else
>> > >> (2) convert it to its truepath (path on the filesystem that matches
>> > >> modulo case). Except for "svn move", as implemented in this patch ...
>> > >>
>> > >
>> > > How about
>> > >
>> > > * default: whatever we do today
>> > >  (so, convert all arguments (including --targets) to truepath).
>> > >
>> > > * svn --I-love-mysterious-case-errors-so-don't-convert-to-truepath:
>> > >  don't convert to truepath at all, just pass arguments straight down
>> > >  the library stack.  If you specify 'Foo' and the wc has 'foo', you get
>> > >  a normal "'Foo' does not exist" error.
>> > >
>> > > Among other things, this avoids calling into the wc during argument
>> > > parsing.  <handwave>I also think it will allow for fixing at least two
>> > > of the issues raised in this thread.</handwave>
>> >
>> > Hmmm, not sure. I understand the "avoids calling into the wc during
>> > argument parsing" argument. But, with my user-hat on, that sounds like
>> > an implementation detail, unnecessarily constraining the tool. Since
>>
>> The other side of the coin is calling it an intentional limitation resulting from our self-imposed layered (multiple libraries) design.
>>
>> > svn allows me to address working-copy items, which are not necessarily
>> > present as local files on disk, and those wc-items are more
>> > "fine-grained" than the on-disk paths, it makes sense to me that svn
>> > first checks if the user isn't actually trying to address a wc-item,
>> > before trying to fold it into an on-disk path. That is, everywhere
>> > where a wc-item is possible as an argument.
>> >
>>
>> Or, more simply, move the truepath canonicalization out of the cmdline client: it has no right to second-guess which case (among the N cases which may be present in the wc the user had in mind (e.g., if 'Foo' 'FOo' 'FOO' all exist,
>
> exist in the DB but not on disk.  The command I have in mind is 'svn up --set-depth=files fOO/'.
>
>> but their parent dir is at depth empty (and let's assumed an unversioned 'foo' exists, too))).
>>
>
> I'm not implying that the truepath canonicalization should be removed entirely, it might make sense to do it somewhere further down the stack to still allow wrong-case target specification in cases where the wrong case is not ambiguous.
>

Hm, I'm not sure where it would go then. I don't know the layers quite
so well, so maybe I just don't see it. But it might be difficult to
find a good spot, "as late as possible", to do the truepath
canonicalization. If there is a good way to do this, it might be a
good long term solution to issue #3865 [1], but probably a lot of work
also ...

Then there is Brane's suggestion of just special-casing the commit,
which might just be good enough ...

2011/4/22 Branko Čibej <br...@e-reka.si>:
> Meh. For now, just hack a special case so that committing one half of a
> case-only rename will automagically commit the other half. Shouldn't be
> too hard to do, and it's almost impossible to do the wrong thing --
> after all, you're constrained by a) staying in the same directory, and
> b) both halves of a rename resolving to the same on-disk file on a
> case-insensitive file system.

Sounds like another option. A small change here and there to make
case-only renames work specifically (and not solve the more general
problem of fixing path-guessing via wc-db or truepaths).

The fact of the matter is that, for sane setups/companies,
case-clashes are going to be really rare, *except when doing case-only
renames*. A repository holding 'Foo', 'FOo' and 'FOO' would be a
repository that's un-checkoutable on a case-insensitive filesystem
anyway. So I'd expect companies that have to support case-insensitive
clients to keep real case-clashes out of their repository (or fix them
as soon as they are discovered).

So maybe "case-only rename" (and perhaps "case-only replace"
(delete+add w/o history)) is the only use-case we need to go for. But
apart from commit, we should maybe also make "revert" possible, as
well as adding to and removing from changelists ... (hm, commit would
be the main thing I guess, revert can always be done in two steps
(revert the add, then the delete), changelists ... oh well).

I'd love to hear some more input ...

Cheers,
-- 
Johan

[1] http://subversion.tigris.org/issues/show_bug.cgi?id=3865 ('svn' on
Windows cannot address scheduled-for-delete file, if another file
differing only in case is present on disk)

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
On Sat, 23 Apr 2011 11:55 +0300, "Daniel Shahaf" <d....@daniel.shahaf.name> wrote:
> On Fri, 22 Apr 2011 23:07 +0200, "Johan Corveleyn" <jc...@gmail.com> wrote:
> > On Thu, Apr 21, 2011 at 3:07 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> > > Johan Corveleyn wrote on Mon, Apr 18, 2011 at 20:01:20 +0200:
> > >> - In fact: the same problem holds true for other commands as well: how
> > >> to revert both sides of this move? Ok, one can revert in two steps ...
> > >>
> > >> - Maybe a more general solution is needed, so all commands can
> > >> adequately see which path the user actually means? The "truepath"
> > >> corresponding to a given path (modulo case), or really the path in the
> > >> case given by the user? A shot in the dark: (1) first look in the
> > >> wc-db - if the path matches a path in the wc-db, accept it as is, else
> > >> (2) convert it to its truepath (path on the filesystem that matches
> > >> modulo case). Except for "svn move", as implemented in this patch ...
> > >>
> > >
> > > How about
> > >
> > > * default: whatever we do today
> > >  (so, convert all arguments (including --targets) to truepath).
> > >
> > > * svn --I-love-mysterious-case-errors-so-don't-convert-to-truepath:
> > >  don't convert to truepath at all, just pass arguments straight down
> > >  the library stack.  If you specify 'Foo' and the wc has 'foo', you get
> > >  a normal "'Foo' does not exist" error.
> > >
> > > Among other things, this avoids calling into the wc during argument
> > > parsing.  <handwave>I also think it will allow for fixing at least two
> > > of the issues raised in this thread.</handwave>
> > 
> > Hmmm, not sure. I understand the "avoids calling into the wc during
> > argument parsing" argument. But, with my user-hat on, that sounds like
> > an implementation detail, unnecessarily constraining the tool. Since
> 
> The other side of the coin is calling it an intentional limitation resulting from our self-imposed layered (multiple libraries) design.
> 
> > svn allows me to address working-copy items, which are not necessarily
> > present as local files on disk, and those wc-items are more
> > "fine-grained" than the on-disk paths, it makes sense to me that svn
> > first checks if the user isn't actually trying to address a wc-item,
> > before trying to fold it into an on-disk path. That is, everywhere
> > where a wc-item is possible as an argument.
> > 
> 
> Or, more simply, move the truepath canonicalization out of the cmdline client: it has no right to second-guess which case (among the N cases which may be present in the wc the user had in mind (e.g., if 'Foo' 'FOo' 'FOO' all exist,

exist in the DB but not on disk.  The command I have in mind is 'svn up --set-depth=files fOO/'.

> but their parent dir is at depth empty (and let's assumed an unversioned 'foo' exists, too))).
> 

I'm not implying that the truepath canonicalization should be removed entirely, it might make sense to do it somewhere further down the stack to still allow wrong-case target specification in cases where the wrong case is not ambiguous.

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
On Fri, 22 Apr 2011 23:07 +0200, "Johan Corveleyn" <jc...@gmail.com> wrote:
> On Thu, Apr 21, 2011 at 3:07 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> > Johan Corveleyn wrote on Mon, Apr 18, 2011 at 20:01:20 +0200:
> >> - In fact: the same problem holds true for other commands as well: how
> >> to revert both sides of this move? Ok, one can revert in two steps ...
> >>
> >> - Maybe a more general solution is needed, so all commands can
> >> adequately see which path the user actually means? The "truepath"
> >> corresponding to a given path (modulo case), or really the path in the
> >> case given by the user? A shot in the dark: (1) first look in the
> >> wc-db - if the path matches a path in the wc-db, accept it as is, else
> >> (2) convert it to its truepath (path on the filesystem that matches
> >> modulo case). Except for "svn move", as implemented in this patch ...
> >>
> >
> > How about
> >
> > * default: whatever we do today
> >  (so, convert all arguments (including --targets) to truepath).
> >
> > * svn --I-love-mysterious-case-errors-so-don't-convert-to-truepath:
> >  don't convert to truepath at all, just pass arguments straight down
> >  the library stack.  If you specify 'Foo' and the wc has 'foo', you get
> >  a normal "'Foo' does not exist" error.
> >
> > Among other things, this avoids calling into the wc during argument
> > parsing.  <handwave>I also think it will allow for fixing at least two
> > of the issues raised in this thread.</handwave>
> 
> Hmmm, not sure. I understand the "avoids calling into the wc during
> argument parsing" argument. But, with my user-hat on, that sounds like
> an implementation detail, unnecessarily constraining the tool. Since

The other side of the coin is calling it an intentional limitation resulting from our self-imposed layered (multiple libraries) design.

> svn allows me to address working-copy items, which are not necessarily
> present as local files on disk, and those wc-items are more
> "fine-grained" than the on-disk paths, it makes sense to me that svn
> first checks if the user isn't actually trying to address a wc-item,
> before trying to fold it into an on-disk path. That is, everywhere
> where a wc-item is possible as an argument.
> 

Or, more simply, move the truepath canonicalization out of the cmdline client: it has no right to second-guess which case (among the N cases which may be present in the wc the user had in mind (e.g., if 'Foo' 'FOo' 'FOO' all exist, but their parent dir is at depth empty (and let's assumed an unversioned 'foo' exists, too))).

> But maybe I'm getting carried away a bit :-). A specific option would
> probably solve the issue much more easily at the expense of some minor
> ugliness. And you're right, allowing the user to specify that paths
> are to be interpreted literally, would probably already fix two of the
> issues.
> 
> >> - Note that the above problem is already present now on trunk (without
> >> my patch): since we can now represent case-clashing paths in the WC
> >> even on a case-insensitive filesystem. (See Bert's example in [2],
> >> "svn ren TODO todoQ; svn ren todoQ todo").
> >>
> >
> > P.S.  The long --option name should be shortened before commit, but I'm
> > +1 on not removing the single quote before commit; just leave it in
> > there literally.
> 
> Heh :-). I hope you're joking. How about --literal-paths or something
> like that?
> 

Yeah, feel free.  I didn't want to call the option --bikeshed in the previous email because that's non-self-describing.

And, by the way... I was only half joking.  I had in mind cmd.exe users when I wrote this --- and IIRC they wouldn't have to quote the ' in the option name --- but I had overlooked people using a native-windows svn.exe from a cygwin shell (who \would\ have to quote the ').

> Your "single qoute" made me think of something else: can we avoid a
> special option, and specify that paths which are quoted (single,
> double, ... whatever works) are to be interpreted literally? Probably
> not, I guess, since shells tend to process those things before svn
> sees them.

Correct.  And, moreover, if you wrote

% svn info \"foo\"

then svn would look for a file called "foo" (*including* the quotes), since " is a valid pathname character.  (Similar example: 'git clone . ssh://foo.example.com/bar' does 'mkdir ssh:/'. (The correct syntax would use 'push'.))

> But who knows, maybe there is a nice (cross-platform) way
> to "escape" path arguments so we know not to fold them to truepath?
> </daydreaming>
> 

Feel free to suggest some magic syntax, like ^/. Or just make it the default --- as per my example above, this may be argued to be a bug in the cmdline client, which allows you to flip the default without waiting to 2.0.

> Cheers,
> -- 
> Johan
> 

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Branko Čibej <br...@e-reka.si>.
On 22.04.2011 23:07, Johan Corveleyn wrote:
> On Thu, Apr 21, 2011 at 3:07 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
>> Johan Corveleyn wrote on Mon, Apr 18, 2011 at 20:01:20 +0200:
>>> - In fact: the same problem holds true for other commands as well: how
>>> to revert both sides of this move? Ok, one can revert in two steps ...
>>>
>>> - Maybe a more general solution is needed, so all commands can
>>> adequately see which path the user actually means? The "truepath"
>>> corresponding to a given path (modulo case), or really the path in the
>>> case given by the user? A shot in the dark: (1) first look in the
>>> wc-db - if the path matches a path in the wc-db, accept it as is, else
>>> (2) convert it to its truepath (path on the filesystem that matches
>>> modulo case). Except for "svn move", as implemented in this patch ...
>>>
>> How about
>>
>> * default: whatever we do today
>>  (so, convert all arguments (including --targets) to truepath).
>>
>> * svn --I-love-mysterious-case-errors-so-don't-convert-to-truepath:
>>  don't convert to truepath at all, just pass arguments straight down
>>  the library stack.  If you specify 'Foo' and the wc has 'foo', you get
>>  a normal "'Foo' does not exist" error.
>>
>> Among other things, this avoids calling into the wc during argument
>> parsing.  <handwave>I also think it will allow for fixing at least two
>> of the issues raised in this thread.</handwave>
> Hmmm, not sure. I understand the "avoids calling into the wc during
> argument parsing" argument. But, with my user-hat on, that sounds like
> an implementation detail, unnecessarily constraining the tool. Since
> svn allows me to address working-copy items, which are not necessarily
> present as local files on disk, and those wc-items are more
> "fine-grained" than the on-disk paths, it makes sense to me that svn
> first checks if the user isn't actually trying to address a wc-item,
> before trying to fold it into an on-disk path. That is, everywhere
> where a wc-item is possible as an argument.
>
> But maybe I'm getting carried away a bit :-). A specific option would
> probably solve the issue much more easily at the expense of some minor
> ugliness. And you're right, allowing the user to specify that paths
> are to be interpreted literally, would probably already fix two of the
> issues.
>
>>> - Note that the above problem is already present now on trunk (without
>>> my patch): since we can now represent case-clashing paths in the WC
>>> even on a case-insensitive filesystem. (See Bert's example in [2],
>>> "svn ren TODO todoQ; svn ren todoQ todo").
>>>
>> P.S.  The long --option name should be shortened before commit, but I'm
>> +1 on not removing the single quote before commit; just leave it in
>> there literally.
> Heh :-). I hope you're joking. How about --literal-paths or something
> like that?
>
> Your "single qoute" made me think of something else: can we avoid a
> special option, and specify that paths which are quoted (single,
> double, ... whatever works) are to be interpreted literally? Probably
> not, I guess, since shells tend to process those things before svn
> sees them. But who knows, maybe there is a nice (cross-platform) way
> to "escape" path arguments so we know not to fold them to truepath?
> </daydreaming>

Meh. For now, just hack a special case so that committing one half of a
case-only rename will automagically commit the other half. Shouldn't be
too hard to do, and it's almost impossible to do the wrong thing --
after all, you're constrained by a) staying in the same directory, and
b) both halves of a rename resolving to the same on-disk file on a
case-insensitive file system.

-- Brane

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
On Thu, Apr 21, 2011 at 3:07 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> Johan Corveleyn wrote on Mon, Apr 18, 2011 at 20:01:20 +0200:
>> - In fact: the same problem holds true for other commands as well: how
>> to revert both sides of this move? Ok, one can revert in two steps ...
>>
>> - Maybe a more general solution is needed, so all commands can
>> adequately see which path the user actually means? The "truepath"
>> corresponding to a given path (modulo case), or really the path in the
>> case given by the user? A shot in the dark: (1) first look in the
>> wc-db - if the path matches a path in the wc-db, accept it as is, else
>> (2) convert it to its truepath (path on the filesystem that matches
>> modulo case). Except for "svn move", as implemented in this patch ...
>>
>
> How about
>
> * default: whatever we do today
>  (so, convert all arguments (including --targets) to truepath).
>
> * svn --I-love-mysterious-case-errors-so-don't-convert-to-truepath:
>  don't convert to truepath at all, just pass arguments straight down
>  the library stack.  If you specify 'Foo' and the wc has 'foo', you get
>  a normal "'Foo' does not exist" error.
>
> Among other things, this avoids calling into the wc during argument
> parsing.  <handwave>I also think it will allow for fixing at least two
> of the issues raised in this thread.</handwave>

Hmmm, not sure. I understand the "avoids calling into the wc during
argument parsing" argument. But, with my user-hat on, that sounds like
an implementation detail, unnecessarily constraining the tool. Since
svn allows me to address working-copy items, which are not necessarily
present as local files on disk, and those wc-items are more
"fine-grained" than the on-disk paths, it makes sense to me that svn
first checks if the user isn't actually trying to address a wc-item,
before trying to fold it into an on-disk path. That is, everywhere
where a wc-item is possible as an argument.

But maybe I'm getting carried away a bit :-). A specific option would
probably solve the issue much more easily at the expense of some minor
ugliness. And you're right, allowing the user to specify that paths
are to be interpreted literally, would probably already fix two of the
issues.

>> - Note that the above problem is already present now on trunk (without
>> my patch): since we can now represent case-clashing paths in the WC
>> even on a case-insensitive filesystem. (See Bert's example in [2],
>> "svn ren TODO todoQ; svn ren todoQ todo").
>>
>
> P.S.  The long --option name should be shortened before commit, but I'm
> +1 on not removing the single quote before commit; just leave it in
> there literally.

Heh :-). I hope you're joking. How about --literal-paths or something
like that?

Your "single qoute" made me think of something else: can we avoid a
special option, and specify that paths which are quoted (single,
double, ... whatever works) are to be interpreted literally? Probably
not, I guess, since shells tend to process those things before svn
sees them. But who knows, maybe there is a nice (cross-platform) way
to "escape" path arguments so we know not to fold them to truepath?
</daydreaming>

Cheers,
-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
Johan Corveleyn wrote on Mon, Apr 18, 2011 at 20:01:20 +0200:
> - In fact: the same problem holds true for other commands as well: how
> to revert both sides of this move? Ok, one can revert in two steps ...
> 
> - Maybe a more general solution is needed, so all commands can
> adequately see which path the user actually means? The "truepath"
> corresponding to a given path (modulo case), or really the path in the
> case given by the user? A shot in the dark: (1) first look in the
> wc-db - if the path matches a path in the wc-db, accept it as is, else
> (2) convert it to its truepath (path on the filesystem that matches
> modulo case). Except for "svn move", as implemented in this patch ...
> 

How about

* default: whatever we do today
  (so, convert all arguments (including --targets) to truepath).

* svn --I-love-mysterious-case-errors-so-don't-convert-to-truepath:
  don't convert to truepath at all, just pass arguments straight down
  the library stack.  If you specify 'Foo' and the wc has 'foo', you get
  a normal "'Foo' does not exist" error.

Among other things, this avoids calling into the wc during argument
parsing.  <handwave>I also think it will allow for fixing at least two
of the issues raised in this thread.</handwave>

> - Note that the above problem is already present now on trunk (without
> my patch): since we can now represent case-clashing paths in the WC
> even on a case-insensitive filesystem. (See Bert's example in [2],
> "svn ren TODO todoQ; svn ren todoQ todo").
> 

P.S.  The long --option name should be shortened before commit, but I'm
+1 on not removing the single quote before commit; just leave it in
there literally.

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
On Wed, Apr 20, 2011 at 11:22 PM, Johan Corveleyn <jc...@gmail.com> wrote:
> 2011/4/18 Branko Čibej <br...@e-reka.si>:
>> On 18.04.2011 20:01, Johan Corveleyn wrote:
>>> BUT it raises some additional questions/issues:
>>>
>>> - How to commit such a move? Committing the parent directory
>>> recursively works fine, but if you try to specify only the move
>>> targets (src and dst paths), commit runs into the same problem as what
>>> I was trying to address here: both paths are converted to their
>>> "truepath", which means only the added side is seen by commit (the
>>> only part that's still on the filesystem):
>>>
>>>     C:\Temp\test4>svn mv foo2 Foo2
>>>     A         Foo2
>>>     D         foo2
>>>
>>>     C:\Temp\test4>svn commit -mtest foo2 Foo2
>>>     Adding         Foo2
>>>
>>>     Committed revision 96322.
>>>
>>> This is very undesirable, because after this commit this cannot be
>>> checked out or updated anymore on a Windows client (case-clashing
>>> files).
>>>
>>> - In fact: the same problem holds true for other commands as well: how
>>> to revert both sides of this move? Ok, one can revert in two steps ...
>>>
>>> - Maybe a more general solution is needed, so all commands can
>>> adequately see which path the user actually means? The "truepath"
>>> corresponding to a given path (modulo case), or really the path in the
>>> case given by the user? A shot in the dark: (1) first look in the
>>> wc-db - if the path matches a path in the wc-db, accept it as is, else
>>> (2) convert it to its truepath (path on the filesystem that matches
>>> modulo case). Except for "svn move", as implemented in this patch ...
>>>
>>> - Note that the above problem is already present now on trunk (without
>>> my patch): since we can now represent case-clashing paths in the WC
>>> even on a case-insensitive filesystem. (See Bert's example in [2],
>>> "svn ren TODO todoQ; svn ren todoQ todo").
>>
>> This is a larger question, and I believe it should be left for 1.8. In
>> general, I doubt it's a good idea to allow users to commit or revert
>> only one-half of a (local) move, at least not without --force; but
>> that's the situation today. It would be even nicer if the client library
>> were smart enough to automagically commit the deletion of the source of
>> the move in "reasonable" cases ... and the solution would seem to be
>> called "atomic renames".
>>
>> (Note that, if we had atomic renames as first-class citizens (in the WC,
>> RA and FS), one could still simulate the current behaviour in those very
>> rare cases when it's desirable simply by doing copy+delete explicitly.)
>
> Yes, I know about this problem, and I agree that it would be best to
> leave a thorough solution for later ("atomic renames" certainly seems
> the way to go, anything else would be more patchwork). So I realize
> that the user currently has to make sure he commits both sides of the
> move together (or let the UI do that for him).
>
> But the problem is that this is impossible in this case, with current
> trunk code, at least with the cmdline UI in combination with
> specifying explicit targets. After doing "svn mv TODO todoQ; svn mv
> todoQ todo", one can never commit the scheduled delete of TODO, unless
> committing the parent directory (or higher). Same with "svn rm TODO;
> svn add todo" or similar.
>
> I think I should create a new issue for this problem, because it seems
> more general than "making case-only renames work". It's a new problem
> that can happen since WC-NG (wasn't possible before, I think, because
> WC-1 would give errors at the point of adding the case-clashing file
> to the working-copy). It's specific to the cmdline layer though, when
> it tries to guess the targets the user really means, by looking for
> the "truepaths" of the given targets...

For the record (and completeness of the archives), I filed this as issue #3865:

http://subversion.tigris.org/issues/show_bug.cgi?id=3865 ('svn' on
Windows cannot address scheduled-for-delete file, if another file
differing only in case is present on disk)

Cheers,
-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
2011/4/18 Branko Čibej <br...@e-reka.si>:
> On 18.04.2011 20:01, Johan Corveleyn wrote:
>> BUT it raises some additional questions/issues:
>>
>> - How to commit such a move? Committing the parent directory
>> recursively works fine, but if you try to specify only the move
>> targets (src and dst paths), commit runs into the same problem as what
>> I was trying to address here: both paths are converted to their
>> "truepath", which means only the added side is seen by commit (the
>> only part that's still on the filesystem):
>>
>>     C:\Temp\test4>svn mv foo2 Foo2
>>     A         Foo2
>>     D         foo2
>>
>>     C:\Temp\test4>svn commit -mtest foo2 Foo2
>>     Adding         Foo2
>>
>>     Committed revision 96322.
>>
>> This is very undesirable, because after this commit this cannot be
>> checked out or updated anymore on a Windows client (case-clashing
>> files).
>>
>> - In fact: the same problem holds true for other commands as well: how
>> to revert both sides of this move? Ok, one can revert in two steps ...
>>
>> - Maybe a more general solution is needed, so all commands can
>> adequately see which path the user actually means? The "truepath"
>> corresponding to a given path (modulo case), or really the path in the
>> case given by the user? A shot in the dark: (1) first look in the
>> wc-db - if the path matches a path in the wc-db, accept it as is, else
>> (2) convert it to its truepath (path on the filesystem that matches
>> modulo case). Except for "svn move", as implemented in this patch ...
>>
>> - Note that the above problem is already present now on trunk (without
>> my patch): since we can now represent case-clashing paths in the WC
>> even on a case-insensitive filesystem. (See Bert's example in [2],
>> "svn ren TODO todoQ; svn ren todoQ todo").
>
> This is a larger question, and I believe it should be left for 1.8. In
> general, I doubt it's a good idea to allow users to commit or revert
> only one-half of a (local) move, at least not without --force; but
> that's the situation today. It would be even nicer if the client library
> were smart enough to automagically commit the deletion of the source of
> the move in "reasonable" cases ... and the solution would seem to be
> called "atomic renames".
>
> (Note that, if we had atomic renames as first-class citizens (in the WC,
> RA and FS), one could still simulate the current behaviour in those very
> rare cases when it's desirable simply by doing copy+delete explicitly.)

Yes, I know about this problem, and I agree that it would be best to
leave a thorough solution for later ("atomic renames" certainly seems
the way to go, anything else would be more patchwork). So I realize
that the user currently has to make sure he commits both sides of the
move together (or let the UI do that for him).

But the problem is that this is impossible in this case, with current
trunk code, at least with the cmdline UI in combination with
specifying explicit targets. After doing "svn mv TODO todoQ; svn mv
todoQ todo", one can never commit the scheduled delete of TODO, unless
committing the parent directory (or higher). Same with "svn rm TODO;
svn add todo" or similar.

I think I should create a new issue for this problem, because it seems
more general than "making case-only renames work". It's a new problem
that can happen since WC-NG (wasn't possible before, I think, because
WC-1 would give errors at the point of adding the case-clashing file
to the working-copy). It's specific to the cmdline layer though, when
it tries to guess the targets the user really means, by looking for
the "truepaths" of the given targets...

Cheers,
-- 
Johan

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Branko Čibej <br...@e-reka.si>.
On 18.04.2011 20:01, Johan Corveleyn wrote:
> BUT it raises some additional questions/issues:
>
> - How to commit such a move? Committing the parent directory
> recursively works fine, but if you try to specify only the move
> targets (src and dst paths), commit runs into the same problem as what
> I was trying to address here: both paths are converted to their
> "truepath", which means only the added side is seen by commit (the
> only part that's still on the filesystem):
>
>     C:\Temp\test4>svn mv foo2 Foo2
>     A         Foo2
>     D         foo2
>
>     C:\Temp\test4>svn commit -mtest foo2 Foo2
>     Adding         Foo2
>
>     Committed revision 96322.
>
> This is very undesirable, because after this commit this cannot be
> checked out or updated anymore on a Windows client (case-clashing
> files).
>
> - In fact: the same problem holds true for other commands as well: how
> to revert both sides of this move? Ok, one can revert in two steps ...
>
> - Maybe a more general solution is needed, so all commands can
> adequately see which path the user actually means? The "truepath"
> corresponding to a given path (modulo case), or really the path in the
> case given by the user? A shot in the dark: (1) first look in the
> wc-db - if the path matches a path in the wc-db, accept it as is, else
> (2) convert it to its truepath (path on the filesystem that matches
> modulo case). Except for "svn move", as implemented in this patch ...
>
> - Note that the above problem is already present now on trunk (without
> my patch): since we can now represent case-clashing paths in the WC
> even on a case-insensitive filesystem. (See Bert's example in [2],
> "svn ren TODO todoQ; svn ren todoQ todo").

This is a larger question, and I believe it should be left for 1.8. In
general, I doubt it's a good idea to allow users to commit or revert
only one-half of a (local) move, at least not without --force; but
that's the situation today. It would be even nicer if the client library
were smart enough to automagically commit the deletion of the source of
the move in "reasonable" cases ... and the solution would seem to be
called "atomic renames".

(Note that, if we had atomic renames as first-class citizens (in the WC,
RA and FS), one could still simulate the current behaviour in those very
rare cases when it's desirable simply by doing copy+delete explicitly.)

-- Brane

Re: [PATCH] First step for issue #3702 (case-only renames on Windows) - now blocked by libsvn_client

Posted by Johan Corveleyn <jc...@gmail.com>.
On Sat, Apr 16, 2011 at 10:17 AM, Johan Corveleyn <jc...@gmail.com> wrote:
> Hi,
>
> Following discussion in [1], I tried to write a patch for issue #3702
> ("svn ren TODO todo" not work on windows). As mentioned by Bert in
> comment to the issue [2], we need to avoid letting 'svn move' convert
> the destination path to on-disk casing in this case, so that's what
> the below patch does.
>
> However, it seems that's not enough. I'm getting further, but now the
> move is blocked libsvn_client/copy.c. The error I'm getting now is:
>
> � �svn: E155007: Path 'C:\Temp\test\todo' is not a directory
>
> The problem is that, in copy.c#svn_client_move6, it first tries the
> move, but if the dst_path already exists (which comes down to an
> apr_stat inside copy.c#verify_wc_srcs_and_dsts), it tries the move
> again with moving the src_path to a child of (the presumed directory)
> dst_path:
>
> libsvn_client/copy.c: 2313
> [[[
> �err = try_copy(sources, dst_path,
> � � � � � � � � TRUE /* is_move */,
> � � � � � � � � make_parents,
> � � � � � � � � FALSE,
> � � � � � � � � revprop_table,
> � � � � � � � � commit_callback, commit_baton,
> � � � � � � � � ctx,
> � � � � � � � � subpool);
>
> �/* If the destination exists, try to move the sources as children of the
> � � destination. */
> �if (move_as_child && err && (src_paths->nelts == 1)
> � � � �&& (err->apr_err == SVN_ERR_ENTRY_EXISTS
> � � � � � �|| err->apr_err == SVN_ERR_FS_ALREADY_EXISTS))
> � �{
> � � �...
> � � �err = try_copy(sources,
> � � � � � � � � � � dst_is_url
> � � � � � � � � � � � � ? svn_path_url_add_component2(dst_path,
> � � � � � � � � � � � � � � � � � � � � � � � � � � � src_basename, pool)
> � � � � � � � � � � � � : svn_dirent_join(dst_path, src_basename, pool),
> � � � � � � � � � � �...
> ]]]
>
> So, a fix in the client layer is needed as well. Any suggestions on
> how to best approach this?
>
> Right now, I'm thinking the fix should be in verify_wc_srcs_and_dsts
> (similar to the "special case" of my below patch for move-cmd.c):
> while checking each copy_pair, if the dst_path already exists, check
> the "true path" of dst_path (APR_FILEPATH_TRUENAME), and see if it's
> the same as the src_path. If so, don't return an already-exists-error.
> But I'm not sure if that's correct, may have side-effects, ...

In attachment is a second attempted patch that implements the above
suggestion: in copy.c, when verifying srcs_and_dsts, if a dst clashes
with an existing file, check if its truepath is the same as the src
(if so, let it go through). This uses some copy-pasted code from
opt.c, so maybe some refactoring is needed here ... Or another way to
pass both the truepath and the originally-requested-path.

After that the "svn move" went through, but the moved file was deleted
from the file system. I fixed that by setting keep_local to TRUE in
the call to svn_wc_delete4 in do_wc_to_wc_moves_with_locks2. At first
sight this seems ok to me, but I'm very much in unfamiliar territory,
so I'm not sure at all :-). See the comment in the patch for some
additional explanation.

Comments, review, ... very much appreciated.

With this patch, one can perform case-only renames on Windows.

BUT it raises some additional questions/issues:

- How to commit such a move? Committing the parent directory
recursively works fine, but if you try to specify only the move
targets (src and dst paths), commit runs into the same problem as what
I was trying to address here: both paths are converted to their
"truepath", which means only the added side is seen by commit (the
only part that's still on the filesystem):

    C:\Temp\test4>svn mv foo2 Foo2
    A         Foo2
    D         foo2

    C:\Temp\test4>svn commit -mtest foo2 Foo2
    Adding         Foo2

    Committed revision 96322.

This is very undesirable, because after this commit this cannot be
checked out or updated anymore on a Windows client (case-clashing
files).

- In fact: the same problem holds true for other commands as well: how
to revert both sides of this move? Ok, one can revert in two steps ...

- Maybe a more general solution is needed, so all commands can
adequately see which path the user actually means? The "truepath"
corresponding to a given path (modulo case), or really the path in the
case given by the user? A shot in the dark: (1) first look in the
wc-db - if the path matches a path in the wc-db, accept it as is, else
(2) convert it to its truepath (path on the filesystem that matches
modulo case). Except for "svn move", as implemented in this patch ...

- Note that the above problem is already present now on trunk (without
my patch): since we can now represent case-clashing paths in the WC
even on a case-insensitive filesystem. (See Bert's example in [2],
"svn ren TODO todoQ; svn ren todoQ todo").

Cheers,
-- 
Johan

> [1] http://svn.haxx.se/dev/archive-2011-04/0232.shtml
> [2] http://subversion.tigris.org/issues/show_bug.cgi?id=3702#desc6