You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2011/12/19 19:49:43 UTC
svn commit: r1220893 [14/19] - in /subversion/branches/fs-py: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/ build/win32/
contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/
subversion/bindings/javahl/native/ s...
Modified: subversion/branches/fs-py/subversion/svn/add-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/add-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/add-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/add-cmd.c Mon Dec 19 18:49:34 2011
@@ -51,7 +51,7 @@ svn_cl__add(apr_getopt_t *os,
apr_array_header_t *targets;
int i;
apr_pool_t *iterpool;
- svn_boolean_t seen_nonexistent_target = FALSE;
+ apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
opt_state->targets,
@@ -71,7 +71,6 @@ svn_cl__add(apr_getopt_t *os,
for (i = 0; i < targets->nelts; i++)
{
const char *target = APR_ARRAY_IDX(targets, i, const char *);
- svn_boolean_t success;
svn_pool_clear(iterpool);
SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
@@ -80,21 +79,34 @@ svn_cl__add(apr_getopt_t *os,
opt_state->depth,
opt_state->force, opt_state->no_ignore,
opt_state->parents, ctx, iterpool),
- &success, opt_state->quiet,
+ errors, opt_state->quiet,
SVN_ERR_ENTRY_EXISTS,
SVN_ERR_WC_PATH_NOT_FOUND,
SVN_NO_ERROR));
-
- if (! success)
- seen_nonexistent_target = TRUE;
}
svn_pool_destroy(iterpool);
- if (seen_nonexistent_target)
- return svn_error_create(
- SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Could not add all targets because some targets don't exist"));
- else
- return SVN_NO_ERROR;
+ if (errors->nelts > 0)
+ {
+ svn_error_t *err;
+
+ err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
+ for (i = 0; i < errors->nelts; i++)
+ {
+ apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
+ if (status == SVN_ERR_WC_PATH_NOT_FOUND)
+ err = svn_error_quick_wrap(err,
+ _("Could not add all targets because "
+ "some targets don't exist"));
+ else if (status == SVN_ERR_ENTRY_EXISTS)
+ err = svn_error_quick_wrap(err,
+ _("Could not add all targets because "
+ "some targets are already versioned"));
+ }
+
+ return svn_error_trace(err);
+ }
+
+ return SVN_NO_ERROR;
}
Modified: subversion/branches/fs-py/subversion/svn/blame-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/blame-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/blame-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/blame-cmd.c Mon Dec 19 18:49:34 2011
@@ -283,7 +283,7 @@ svn_cl__blame(apr_getopt_t *os,
if (! opt_state->xml)
SVN_ERR(svn_stream_for_stdout(&bl.out, pool));
else
- bl.sbuf = svn_stringbuf_create("", pool);
+ bl.sbuf = svn_stringbuf_create_empty(pool);
bl.opt_state = opt_state;
Modified: subversion/branches/fs-py/subversion/svn/cat-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/cat-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/cat-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/cat-cmd.c Mon Dec 19 18:49:34 2011
@@ -50,7 +50,8 @@ svn_cl__cat(apr_getopt_t *os,
int i;
svn_stream_t *out;
apr_pool_t *subpool = svn_pool_create(pool);
- svn_boolean_t seen_nonexistent_target = FALSE;
+ apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));
+ svn_error_t *err;
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
opt_state->targets,
@@ -67,7 +68,6 @@ svn_cl__cat(apr_getopt_t *os,
const char *target = APR_ARRAY_IDX(targets, i, const char *);
const char *truepath;
svn_opt_revision_t peg_revision;
- svn_boolean_t success;
svn_pool_clear(subpool);
SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
@@ -79,21 +79,40 @@ svn_cl__cat(apr_getopt_t *os,
SVN_ERR(svn_cl__try(svn_client_cat2(out, truepath, &peg_revision,
&(opt_state->start_revision),
ctx, subpool),
- &success, opt_state->quiet,
+ errors, opt_state->quiet,
SVN_ERR_UNVERSIONED_RESOURCE,
SVN_ERR_ENTRY_NOT_FOUND,
SVN_ERR_CLIENT_IS_DIRECTORY,
SVN_ERR_FS_NOT_FOUND,
SVN_NO_ERROR));
- if (! success)
- seen_nonexistent_target = TRUE;
}
svn_pool_destroy(subpool);
- if (seen_nonexistent_target)
- return svn_error_create(
- SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Could not cat all targets because some targets don't exist"));
- else
- return SVN_NO_ERROR;
+ if (errors->nelts > 0)
+ {
+ err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
+
+ for (i = 0; i < errors->nelts; i++)
+ {
+ apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
+
+ if (status == SVN_ERR_ENTRY_NOT_FOUND ||
+ status == SVN_ERR_FS_NOT_FOUND)
+ err = svn_error_quick_wrap(err,
+ _("Could not cat all targets because "
+ "some targets don't exist"));
+ else if (status == SVN_ERR_UNVERSIONED_RESOURCE)
+ err = svn_error_quick_wrap(err,
+ _("Could not cat all targets because "
+ "some targets are not versioned"));
+ else if (status == SVN_ERR_CLIENT_IS_DIRECTORY)
+ err = svn_error_quick_wrap(err,
+ _("Could not cat all targets because "
+ "some targets are directories"));
+ }
+
+ return svn_error_trace(err);
+ }
+
+ return SVN_NO_ERROR;
}
Modified: subversion/branches/fs-py/subversion/svn/changelist-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/changelist-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/changelist-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/changelist-cmd.c Mon Dec 19 18:49:34 2011
@@ -45,7 +45,7 @@ svn_cl__changelist(apr_getopt_t *os,
svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
apr_array_header_t *targets;
svn_depth_t depth = opt_state->depth;
- svn_boolean_t success = TRUE;
+ apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));
/* If we're not removing changelists, then our first argument should
be the name of a changelist. */
@@ -103,7 +103,7 @@ svn_cl__changelist(apr_getopt_t *os,
svn_client_add_to_changelist(targets, changelist_name,
depth, opt_state->changelists,
ctx, pool),
- &success, opt_state->quiet,
+ errors, opt_state->quiet,
SVN_ERR_UNVERSIONED_RESOURCE,
SVN_ERR_WC_PATH_NOT_FOUND,
SVN_NO_ERROR));
@@ -114,16 +114,36 @@ svn_cl__changelist(apr_getopt_t *os,
svn_client_remove_from_changelists(targets, depth,
opt_state->changelists,
ctx, pool),
- &success, opt_state->quiet,
+ errors, opt_state->quiet,
SVN_ERR_UNVERSIONED_RESOURCE,
SVN_ERR_WC_PATH_NOT_FOUND,
SVN_NO_ERROR));
}
- if (!success)
- return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Could not display info for all targets because "
- "some targets don't exist"));
- else
- return SVN_NO_ERROR;
+ if (errors->nelts > 0)
+ {
+ int i;
+ svn_error_t *err;
+
+ err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
+ for (i = 0; i < errors->nelts; i++)
+ {
+ apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
+
+ if (status == SVN_ERR_WC_PATH_NOT_FOUND)
+ err = svn_error_quick_wrap(err,
+ _("Could not set changelists on "
+ "all targets because some targets "
+ "don't exist"));
+ else if (status == SVN_ERR_UNVERSIONED_RESOURCE)
+ err = svn_error_quick_wrap(err,
+ _("Could not set changelists on "
+ "all targets because some targets "
+ "are not versioned"));
+ }
+
+ return svn_error_trace(err);
+ }
+
+ return SVN_NO_ERROR;
}
Modified: subversion/branches/fs-py/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/cl.h?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/cl.h (original)
+++ subversion/branches/fs-py/subversion/svn/cl.h Mon Dec 19 18:49:34 2011
@@ -230,6 +230,7 @@ typedef struct svn_cl__opt_state_t
svn_boolean_t internal_diff; /* override diff_cmd in config file */
svn_boolean_t use_git_diff_format; /* Use git's extended diff format */
svn_boolean_t allow_mixed_rev; /* Allow operation on mixed-revision WC */
+ svn_boolean_t include_externals; /* Recurses (in)to file & dir externals */
} svn_cl__opt_state_t;
@@ -294,15 +295,14 @@ extern const apr_getopt_option_t svn_cl_
* invoked on an unversioned, nonexistent, or otherwise innocuously
* errorful resource. Meant to be wrapped with SVN_ERR().
*
- * If ERR is null, return SVN_NO_ERROR, setting *SUCCESS to TRUE
- * if SUCCESS is not NULL.
+ * If ERR is null, return SVN_NO_ERROR.
*
* Else if ERR->apr_err is one of the error codes supplied in varargs,
* then handle ERR as a warning (unless QUIET is true), clear ERR, and
- * return SVN_NO_ERROR, setting *SUCCESS to FALSE if SUCCESS is not
- * NULL.
+ * return SVN_NO_ERROR, and push the value of ERR->apr_err into the
+ * ERRORS_SEEN array, if ERRORS_SEEN is not NULL.
*
- * Else return ERR, setting *SUCCESS to FALSE if SUCCESS is not NULL.
+ * Else return ERR.
*
* Typically, error codes like SVN_ERR_UNVERSIONED_RESOURCE,
* SVN_ERR_ENTRY_NOT_FOUND, etc, are supplied in varargs. Don't
@@ -310,7 +310,7 @@ extern const apr_getopt_option_t svn_cl_
*/
svn_error_t *
svn_cl__try(svn_error_t *err,
- svn_boolean_t *success,
+ apr_array_header_t *errors_seen,
svn_boolean_t quiet,
...);
@@ -382,6 +382,9 @@ svn_cl__time_cstring_to_human_cstring(co
/* Print STATUS for PATH to stdout for human consumption. Prints in
abbreviated format by default, or DETAILED format if flag is set.
+ When SUPPRESS_EXTERNALS_PLACEHOLDERS is set, avoid printing
+ externals placeholder lines ("X lines").
+
When DETAILED is set, use SHOW_LAST_COMMITTED to toggle display of
the last-committed-revision and last-committed-author.
@@ -393,10 +396,16 @@ svn_cl__time_cstring_to_human_cstring(co
Increment *TEXT_CONFLICTS, *PROP_CONFLICTS, or *TREE_CONFLICTS if
a conflict was encountered.
- */
+
+ Use CWD_ABSPATH -- the absolute path of the current working
+ directory -- to shorten PATH into something relative to that
+ directory as necessary.
+*/
svn_error_t *
-svn_cl__print_status(const char *path,
+svn_cl__print_status(const char *cwd_abspath,
+ const char *path,
const svn_client_status_t *status,
+ svn_boolean_t suppress_externals_placeholders,
svn_boolean_t detailed,
svn_boolean_t show_last_committed,
svn_boolean_t skip_unrecognized,
@@ -409,9 +418,15 @@ svn_cl__print_status(const char *path,
/* Print STATUS for PATH in XML to stdout. Use POOL for temporary
- allocations. */
+ allocations.
+
+ Use CWD_ABSPATH -- the absolute path of the current working
+ directory -- to shorten PATH into something relative to that
+ directory as necessary.
+ */
svn_error_t *
-svn_cl__print_status_xml(const char *path,
+svn_cl__print_status_xml(const char *cwd_abspath,
+ const char *path,
const svn_client_status_t *status,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
@@ -553,14 +568,10 @@ svn_cl__merge_file_externally(const char
/* Set *NOTIFY_FUNC_P and *NOTIFY_BATON_P to a notifier/baton for all
* operations, allocated in POOL.
- *
- * If don't want a summary line at the end of notifications, set
- * SUPPRESS_FINAL_LINE.
*/
svn_error_t *
svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
void **notify_baton_p,
- svn_boolean_t suppress_final_line,
apr_pool_t *pool);
/* Make the notifier for use with BATON print the appropriate summary
@@ -767,42 +778,19 @@ svn_cl__node_description(const svn_wc_co
const char *wc_repos_root_URL,
apr_pool_t *pool);
-/* Return, in @a *true_targets_p, a copy of @a targets with peg revision
- * specifiers snipped off the end of each element.
- *
- * ### JAF TODO: This function is not good because it does not allow the
- * ### caller to detect if an invalid peg revision was specified.
- * ###
- * ### Callers should never have a need to silently *discard* all peg
- * ### revisions, even if they are doing this *after* saving any peg
- * ### revisions that might be of interest on certain arguments: I don't
- * ### think it can ever be correct to silently ignore a peg revision that
- * ### is specified, whether it makes semantic sense or not.
- * ###
- * ### Instead, callers should parse all the arguments and silently
- * ### ignore an *empty* peg revision part (just an "@", which can be
- * ### used to escape an earlier "@" in the argument) on any argument,
- * ### even an argument on which a peg revision does not make sense,
- * ### but should not silently ignore a non-empty peg when it does not
- * ### make sense.
- * ###
- * ### Something like:
- * ### For each (URL-like?) argument that doesn't accept a peg rev:
- * ### Parse into peg-rev and true-path parts;
- * ### If (peg rev != unspecified)
- * ### Error("This arg doesn't accept a peg rev.").
- * ### Use the true-path part.
+/* Return, in @a *true_targets_p, a shallow copy of @a targets with any
+ * empty peg revision specifier snipped off the end of each element. If any
+ * target has a non-empty peg revision specifier, throw an error. The user
+ * may have specified a peg revision where it doesn't make sense to do so,
+ * or may have forgotten to escape an '@' character in a filename.
*
* This function is useful for subcommands for which peg revisions
- * do not make any sense. Such subcommands still need to allow peg
- * revisions to be specified on the command line so that users of
+ * do not make any sense. Such subcommands still need to allow an empty
+ * peg revision to be specified on the command line so that users of
* the command line client can consistently escape '@' characters
* in filenames by appending an '@' character, regardless of the
* subcommand being used.
*
- * If a peg revision is present but cannot be parsed, an error is thrown.
- * The user has likely forgotten to escape an '@' character in a filename.
- *
* It is safe to pass the address of @a targets as @a true_targets_p.
*
* Do all allocations in @a pool. */
@@ -834,6 +822,23 @@ svn_cl__local_style_skip_ancestor(const
const char *path,
apr_pool_t *pool);
+/* Check that PATH_OR_URL1@REVISION1 is related to PATH_OR_URL2@REVISION2.
+ * Raise an error if not.
+ *
+ * ### Ideally we would also check that they are on different lines of
+ * history. That is easy in common cases, but to give a correct answer in
+ * general we need to know the operative revision(s) as well. For example,
+ * when one location is the branch point from which the other branch was
+ * copied.
+ */
+svn_error_t *
+svn_cl__check_related_source_and_target(const char *path_or_url1,
+ const svn_opt_revision_t *revision1,
+ const char *path_or_url2,
+ const svn_opt_revision_t *revision2,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/branches/fs-py/subversion/svn/commit-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/commit-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/commit-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/commit-cmd.c Mon Dec 19 18:49:34 2011
@@ -166,15 +166,17 @@ svn_cl__commit(apr_getopt_t *os,
}
/* Commit. */
- err = svn_client_commit5(targets,
+ err = svn_client_commit6(targets,
opt_state->depth,
no_unlock,
opt_state->keep_changelists,
TRUE /* commit_as_operations */,
+ opt_state->include_externals, /* file externals */
+ opt_state->include_externals, /* dir externals */
opt_state->changelists,
opt_state->revprop_table,
- ! opt_state->quiet
- ? svn_cl__print_commit_info : NULL,
+ (opt_state->quiet
+ ? NULL : svn_cl__print_commit_info),
NULL,
ctx,
pool);
Modified: subversion/branches/fs-py/subversion/svn/copy-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/copy-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/copy-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/copy-cmd.c Mon Dec 19 18:49:34 2011
@@ -76,7 +76,18 @@ svn_cl__copy(apr_getopt_t *os,
APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source;
}
- SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
+ /* Get DST_PATH (the target path or URL) and check that no peg revision is
+ * specified for it. */
+ {
+ const char *tgt = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *);
+ svn_opt_revision_t peg;
+
+ SVN_ERR(svn_opt_parse_path(&peg, &dst_path, tgt, pool));
+ if (peg.kind != svn_opt_revision_unspecified)
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s': a peg revision is not allowed here"),
+ tgt);
+ }
/* Figure out which type of notification to use.
(There is no need to check that the src paths are homogeneous;
@@ -84,8 +95,6 @@ svn_cl__copy(apr_getopt_t *os,
error if they are not.) */
src_path = APR_ARRAY_IDX(targets, 0, const char *);
srcs_are_urls = svn_path_is_url(src_path);
- dst_path = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *);
- apr_array_pop(targets);
dst_is_url = svn_path_is_url(dst_path);
if ((! srcs_are_urls) && (! dst_is_url))
@@ -127,7 +136,8 @@ svn_cl__copy(apr_getopt_t *os,
err = svn_client_copy6(sources, dst_path, TRUE,
opt_state->parents, opt_state->ignore_externals,
opt_state->revprop_table,
- svn_cl__print_commit_info, NULL,
+ (opt_state->quiet ? NULL : svn_cl__print_commit_info),
+ NULL,
ctx, pool);
if (ctx->log_msg_func3)
Modified: subversion/branches/fs-py/subversion/svn/delete-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/delete-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/delete-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/delete-cmd.c Mon Dec 19 18:49:34 2011
@@ -79,7 +79,9 @@ svn_cl__delete(apr_getopt_t *os,
SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
err = svn_client_delete4(targets, opt_state->force, opt_state->keep_local,
- opt_state->revprop_table, svn_cl__print_commit_info,
+ opt_state->revprop_table,
+ (opt_state->quiet
+ ? NULL : svn_cl__print_commit_info),
NULL, ctx, pool);
if (err)
err = svn_cl__may_need_force(err);
Modified: subversion/branches/fs-py/subversion/svn/diff-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/diff-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/diff-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/diff-cmd.c Mon Dec 19 18:49:34 2011
@@ -89,7 +89,7 @@ summarize_xml(const svn_client_diff_summ
/* Full path to the object being diffed. This is created by taking the
* baton, and appending the target's relative path. */
const char *path = *(const char **)baton;
- svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
/* Tack on the target path, so we can differentiate between different parts
* of the output when we're given multiple targets. */
@@ -197,7 +197,7 @@ svn_cl__diff(apr_getopt_t *os,
SVN_ERR(svn_cl__xml_print_header("diff", pool));
- sb = svn_stringbuf_create("", pool);
+ sb = svn_stringbuf_create_empty(pool);
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "paths", NULL);
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
@@ -419,7 +419,7 @@ svn_cl__diff(apr_getopt_t *os,
if (opt_state->xml)
{
- svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
svn_xml_make_close_tag(&sb, pool, "paths");
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
SVN_ERR(svn_cl__xml_print_footer("diff", pool));
Modified: subversion/branches/fs-py/subversion/svn/import-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/import-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/import-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/import-cmd.c Mon Dec 19 18:49:34 2011
@@ -120,7 +120,8 @@ svn_cl__import(apr_getopt_t *os,
opt_state->no_ignore,
opt_state->force,
opt_state->revprop_table,
- svn_cl__print_commit_info,
+ (opt_state->quiet
+ ? NULL : svn_cl__print_commit_info),
NULL,
ctx,
pool), pool));
Modified: subversion/branches/fs-py/subversion/svn/info-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/info-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/info-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/info-cmd.c Mon Dec 19 18:49:34 2011
@@ -85,7 +85,7 @@ print_info_xml(void *baton,
const svn_client_info2_t *info,
apr_pool_t *pool)
{
- svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
const char *rev_str;
const char *path_prefix = baton;
Modified: subversion/branches/fs-py/subversion/svn/list-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/list-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/list-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/list-cmd.c Mon Dec 19 18:49:34 2011
@@ -156,7 +156,7 @@ print_dirent_xml(void *baton,
if (pb->ctx->cancel_func)
SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton));
- sb = svn_stringbuf_create("", pool);
+ sb = svn_stringbuf_create_empty(pool);
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
"kind", svn_cl__node_kind_str_xml(dirent->kind),
@@ -276,7 +276,7 @@ svn_cl__list(apr_getopt_t *os,
if (opt_state->xml)
{
- svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "list",
"path", truepath[0] == '\0' ? "." : truepath,
NULL);
@@ -308,7 +308,7 @@ svn_cl__list(apr_getopt_t *os,
if (opt_state->xml)
{
- svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
svn_xml_make_close_tag(&sb, pool, "list");
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
Modified: subversion/branches/fs-py/subversion/svn/log-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/log-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/log-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/log-cmd.c Mon Dec 19 18:49:34 2011
@@ -51,8 +51,9 @@ struct log_receiver_baton
/* Client context. */
svn_client_ctx_t *ctx;
- /* The URL target of the log operation. */
- const char *target_url;
+ /* The target of the log operation. */
+ const char *target_path_or_url;
+ svn_opt_revision_t target_peg_revision;
/* Don't print log message body nor its line count. */
svn_boolean_t omit_log_message;
@@ -227,8 +228,7 @@ log_entry_receiver(void *baton,
svn_sort__item_t *item = &(APR_ARRAY_IDX(sorted_paths, i,
svn_sort__item_t));
const char *path = item->key;
- svn_log_changed_path2_t *log_item
- = apr_hash_get(log_entry->changed_paths2, item->key, item->klen);
+ svn_log_changed_path2_t *log_item = item->value;
const char *copy_data = "";
if (lb->ctx->cancel_func)
@@ -274,6 +274,9 @@ log_entry_receiver(void *baton,
SVN_ERR(svn_cmdline_printf(pool, "\n%s\n", message));
}
+ SVN_ERR(svn_cmdline_fflush(stdout));
+ SVN_ERR(svn_cmdline_fflush(stderr));
+
/* Print a diff if requested. */
if (lb->show_diff)
{
@@ -282,7 +285,6 @@ log_entry_receiver(void *baton,
apr_array_header_t *diff_options;
svn_opt_revision_t start_revision;
svn_opt_revision_t end_revision;
- svn_error_t *err;
SVN_ERR(svn_stream_for_stdout(&outstream, pool));
SVN_ERR(svn_stream_for_stderr(&errstream, pool));
@@ -299,89 +301,28 @@ log_entry_receiver(void *baton,
end_revision.kind = svn_opt_revision_number;
end_revision.value.number = log_entry->revision;
- SVN_ERR(svn_cmdline_printf(pool, _("\n")));
- err = svn_client_diff6(diff_options,
- lb->target_url,
- &start_revision,
- lb->target_url,
- &end_revision,
- NULL,
- lb->depth,
- FALSE, /* ignore ancestry */
- TRUE, /* no diff deleted */
- FALSE, /* show copies as adds */
- FALSE, /* ignore content type */
- FALSE, /* use git diff format */
- svn_cmdline_output_encoding(pool),
- outstream,
- errstream,
- NULL,
- lb->ctx, pool);
- if (err)
- {
- /* We get a "path not found" error in case the revision created
- * lb->target_url. Try to show a diff from the parent instead. */
- if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
- {
- const char *parent;
- apr_pool_t *iterpool;
-
- svn_error_clear(err);
-
- parent = svn_uri_dirname(lb->target_url, pool);
- iterpool = svn_pool_create(pool);
- while (strcmp(parent, lb->target_url) != 0)
- {
- svn_pool_clear(iterpool);
- err = svn_client_diff6(diff_options,
- parent,
- &start_revision,
- parent,
- &end_revision,
- NULL,
- lb->depth,
- FALSE, /* ignore ancestry */
- TRUE, /* no diff deleted */
- FALSE, /* show copies as adds */
- FALSE, /* ignore content type */
- FALSE, /* use git diff format */
- svn_cmdline_output_encoding(iterpool),
- outstream,
- errstream,
- NULL,
- lb->ctx, iterpool);
- if (err == SVN_NO_ERROR)
- break;
- else
- {
- if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
- {
- svn_error_clear(err);
- parent = svn_uri_dirname(parent, pool);
- continue;
- }
- if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL ||
- err->apr_err == SVN_ERR_AUTHZ_UNREADABLE ||
- err->apr_err == SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED)
- {
- svn_error_clear(err);
- break;
- }
- return svn_error_trace(err);
- }
- }
- svn_pool_destroy(iterpool);
- }
- else
- return svn_error_trace(err);
- }
-
- SVN_ERR(svn_cmdline_printf(pool, _("\n")));
+ SVN_ERR(svn_stream_printf(outstream, pool, _("\n")));
+ SVN_ERR(svn_client_diff_peg6(diff_options,
+ lb->target_path_or_url,
+ &lb->target_peg_revision,
+ &start_revision, &end_revision,
+ NULL,
+ lb->depth,
+ FALSE, /* ignore ancestry */
+ TRUE, /* no diff deleted */
+ FALSE, /* show copies as adds */
+ FALSE, /* ignore content type */
+ FALSE, /* use git diff format */
+ svn_cmdline_output_encoding(pool),
+ outstream,
+ errstream,
+ NULL,
+ lb->ctx, pool));
+ SVN_ERR(svn_stream_printf(outstream, pool, _("\n")));
+ SVN_ERR(svn_stream_close(outstream));
+ SVN_ERR(svn_stream_close(errstream));
}
- SVN_ERR(svn_cmdline_fflush(stdout));
- SVN_ERR(svn_cmdline_fflush(stderr));
-
if (log_entry->has_children)
APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
@@ -432,7 +373,7 @@ log_entry_receiver_xml(void *baton,
{
struct log_receiver_baton *lb = baton;
/* Collate whole log message into sb before printing. */
- svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
char *revstr;
const char *author;
const char *date;
@@ -568,8 +509,6 @@ svn_cl__log(apr_getopt_t *os,
struct log_receiver_baton lb;
const char *target;
int i;
- svn_opt_revision_t peg_revision;
- const char *true_path;
apr_array_header_t *revprops;
if (!opt_state->xml)
@@ -623,8 +562,6 @@ svn_cl__log(apr_getopt_t *os,
/* Add "." if user passed 0 arguments */
svn_opt_push_implicit_dot_target(targets, pool);
- target = APR_ARRAY_IDX(targets, 0, const char *);
-
/* Determine if they really want a two-revision range. */
if (opt_state->used_change_arg)
{
@@ -646,9 +583,15 @@ svn_cl__log(apr_getopt_t *os,
}
}
- /* Strip peg revision. */
- SVN_ERR(svn_opt_parse_path(&peg_revision, &true_path, target, pool));
- APR_ARRAY_IDX(targets, 0, const char *) = true_path;
+ /* Parse the first target into path-or-url and peg revision. */
+ target = APR_ARRAY_IDX(targets, 0, const char *);
+ SVN_ERR(svn_opt_parse_path(&lb.target_peg_revision, &lb.target_path_or_url,
+ target, pool));
+ if (lb.target_peg_revision.kind == svn_opt_revision_unspecified)
+ lb.target_peg_revision.kind = (svn_path_is_url(target)
+ ? svn_opt_revision_head
+ : svn_opt_revision_working);
+ APR_ARRAY_IDX(targets, 0, const char *) = lb.target_path_or_url;
if (svn_path_is_url(target))
{
@@ -667,8 +610,6 @@ svn_cl__log(apr_getopt_t *os,
lb.ctx = ctx;
lb.omit_log_message = opt_state->quiet;
- SVN_ERR(svn_client_url_from_path2(&lb.target_url, true_path, ctx,
- pool, pool));
lb.show_diff = opt_state->show_diff;
lb.depth = opt_state->depth == svn_depth_unknown ? svn_depth_infinity
: opt_state->depth;
@@ -719,7 +660,7 @@ svn_cl__log(apr_getopt_t *os,
APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
}
SVN_ERR(svn_client_log5(targets,
- &peg_revision,
+ &lb.target_peg_revision,
opt_state->revision_ranges,
opt_state->limit,
opt_state->verbose,
@@ -742,7 +683,7 @@ svn_cl__log(apr_getopt_t *os,
if (!opt_state->quiet)
APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
SVN_ERR(svn_client_log5(targets,
- &peg_revision,
+ &lb.target_peg_revision,
opt_state->revision_ranges,
opt_state->limit,
opt_state->verbose,
Modified: subversion/branches/fs-py/subversion/svn/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/main.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/main.c (original)
+++ subversion/branches/fs-py/subversion/svn/main.c Mon Dec 19 18:49:34 2011
@@ -54,7 +54,7 @@
#include "svn_version.h"
#include "cl.h"
-#include "private/svn_wc_private.h"
+#include "private/svn_opt_private.h"
#include "private/svn_cmdline_private.h"
#include "svn_private_config.h"
@@ -124,6 +124,7 @@ typedef enum svn_cl__longopt_t {
opt_internal_diff,
opt_use_git_diff_format,
opt_allow_mixed_revisions,
+ opt_include_externals,
} svn_cl__longopt_t;
@@ -145,7 +146,11 @@ const apr_getopt_option_t svn_cl__option
{"change", 'c', 1,
N_("the change made by revision ARG (like -r ARG-1:ARG)\n"
" "
- "If ARG is negative this is like -r ARG:ARG-1")},
+ "If ARG is negative this is like -r ARG:ARG-1\n"
+ " "
+ "If ARG is of the form ARG1-ARG2 then this is like\n"
+ " "
+ "ARG1:ARG2, where ARG1 is inclusive")},
{"revision", 'r', 1,
N_("ARG (some commands also take ARG1:ARG2 range)\n"
" "
@@ -295,11 +300,14 @@ const apr_getopt_option_t svn_cl__option
{"accept", opt_accept, 1,
N_("specify automatic conflict resolution action\n"
" "
- "('postpone', 'base', 'mine-conflict',\n"
+ "('postpone', 'working', 'base', 'mine-conflict',\n"
" "
"'theirs-conflict', 'mine-full', 'theirs-full',\n"
" "
- "'edit', 'launch')")},
+ "'edit', 'launch')\n"
+ " "
+ "(shorthand: 'p', 'mc', 'tc', 'mf', 'tf', 'e', 'l')"
+ )},
{"show-revs", opt_show_revs, 1,
N_("specify which collection of revisions to display\n"
" "
@@ -341,6 +349,12 @@ const apr_getopt_option_t svn_cl__option
"Use of this option is not recommended!\n"
" "
"Please run 'svn update' instead.")},
+ {"include-externals", opt_include_externals, 0,
+ N_("Also commit file and dir externals reached by\n"
+ " "
+ "recursion. This does not include externals with a\n"
+ " "
+ "fixed revision. (See the svn:externals property)")},
/* Long-opt Aliases
*
@@ -459,7 +473,7 @@ const svn_opt_subcommand_desc2_t svn_cl_
" If any targets are (or contain) locked items, those will be\n"
" unlocked after a successful commit.\n"),
{'q', 'N', opt_depth, opt_targets, opt_no_unlock, SVN_CL__LOG_MSG_OPTIONS,
- opt_changelist, opt_keep_changelists} },
+ opt_changelist, opt_keep_changelists, opt_include_externals} },
{ "copy", svn_cl__copy, {"cp"}, N_
("Duplicate something in working copy or repository, remembering\n"
@@ -651,7 +665,11 @@ const svn_opt_subcommand_desc2_t svn_cl_
" svn log bar.c@42\n"
" svn log http://www.example.com/repo/project/foo.c\n"
" svn log http://www.example.com/repo/project foo.c bar.c\n"
- " svn log http://www.example.com/repo/project@50 foo.c bar.c\n"),
+ " svn log http://www.example.com/repo/project@50 foo.c bar.c\n"
+ "\n"
+ " This command shows the log entry for the revision the branch\n"
+ " ^/branches/foo was created in:\n"
+ " svn log --stop-on-copy --limit 1 -r0:HEAD ^/branches/foo\n"),
{'r', 'q', 'v', 'g', 'c', opt_targets, opt_stop_on_copy, opt_incremental,
opt_xml, 'l', opt_with_all_revprops, opt_with_no_revprops, opt_with_revprop,
opt_depth, opt_diff, opt_diff_cmd, opt_internal_diff, 'x'},
@@ -659,267 +677,330 @@ const svn_opt_subcommand_desc2_t svn_cl_
{'c', N_("the change made in revision ARG")}} },
{ "merge", svn_cl__merge, {0}, N_
- ("Apply the differences between two sources to a working copy path.\n"
- "usage: 1. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
- " 2. merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]\n"
- " 3. merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
- "\n"
- " 1. The first form is called a \"sync\", or \"cherry-pick\", merge:\n"
- " svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
- "\n"
- " A sync merge is used to merge into a branch any unmerged changes\n"
- " made on its immediate ancestor branch.\n"
- "\n"
- " A cherry-picking merge is used to merge specific revisions from\n"
- " one branch to another.\n"
- "\n"
- " SOURCE is usually a URL. The source of a cherry-picking merge can\n"
- " also be a working copy path, in which case the corresponding URL\n"
- " of the path is used.\n"
- "\n"
- " If REV is specified, it is used as the peg revision for SOURCE,\n"
- " i.e. SOURCE is looked up in the repository at revision REV.\n"
- " If REV is not specified, the HEAD revision is assumed.\n"
- "\n"
- " TARGET_WCPATH is a working copy of the branch the changes will\n"
- " be applied to.\n"
- "\n"
- " '-r N:M' specifies a revision range to be merged. The difference\n"
- " between SOURCE@REV as it existed at revision N, and SOURCE@REV at\n"
- " it existed at revision M, is merged into TARGET_WCPATH. If no\n"
- " revision range is specified, the default range of 0:REV is used.\n"
- " \n"
- " If mergeinfo within TARGET_WCPATH indicates that revisions within\n"
- " the range were already merged, changes made in those revisions\n"
- " are not merged again. If needed, the range is broken into multiple\n"
- " sub-ranges, and each sub-range is merged separately.\n"
- "\n"
- " If N is greater than M, the range is a \"reverse range\".\n"
- " A reverse range can be used to undo changes made to SOURCE\n"
- " between revisions N and M.\n"
- "\n"
- " '-c M' is equivalent to the range '-r <M-1>:M'.\n"
- " '-c -M' does the reverse: '-r M:<M-1>'.\n"
- " \n"
- " Multiple '-c' and/or '-r' options may be specified and mixing of\n"
- " forward and reverse ranges is allowed.\n"
- "\n"
- " - Sync Merge Example -\n"
- "\n"
- " A feature is being developed on a branch called \"feature\".\n"
- " The feature branch is regularly synced with trunk to keep up with\n"
- " changes made there.\n"
- "\n"
- " feature +------------------------o-----\n"
- " / ^\n"
- " / /\n"
- " / .............../\n"
- " trunk ------+------------L--------------R------\n"
- " r100 r200\n"
- " \n"
- " In the above diagram, L marks the \"left\" side of the merge\n"
- " (trunk@100), and R marks the \"right\" side of the merge (trunk@200).\n"
- " The difference between the left and right side is merged into the target.\n"
- "\n"
- " To perform the merge, check out a working copy of the feature\n"
- " branch and run the following command in the top-level directory\n"
- " of the working copy:\n"
- "\n"
- " svn merge ^/trunk\n"
- "\n"
- " The default revision range is -r0:HEAD, so any unmerged changes\n"
- " will be merged.\n"
- "\n"
- " - Cherry-picking Merge Example -\n"
- "\n"
- " A bug has been fixed on trunk on revision 50. This fix needs to\n"
- " be merged from the trunk into the release branch.\n"
- "\n"
- " 1.x-release +-----------------------o-----\n"
- " / ^\n"
- " / |\n"
- " / |\n"
- " trunk ------+--------------------------LR-----\n"
- " r50\n"
- " \n"
- " In the above diagram, L marks the left side of the merge (trunk@49)\n"
- " and R marks the right side of the merge (trunk@50).\n"
- " The difference between the left and right side is merged into the target.\n"
- "\n"
- " To perform the merge, check out a working copy of the release\n"
- " branch and run the following command in the top-level directory\n"
- " of the working copy:\n"
- "\n"
- " svn merge -c50 ^/trunk\n"
- "\n"
- " If several commits to trunk were related to the fix, multiple\n"
- " revisions can be merged:\n"
- "\n"
- " svn merge -c50,54,60 ^/trunk\n"
- "\n"
- "\n"
- " 2. The second form is called a \"reintegrate merge\":\n"
- " svn merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]\n"
- "\n"
- " SOURCE is the URL of a branch to be merged back into (usually) its\n"
- " immediate ancestor branch. If REV is specified, it is used a\n"
- " the peg revision for SOURCE, i.e. SOURCE is looked up in the\n"
- " repository at revision REV. If REV is not specified, the HEAD\n"
- " revision is assumed.\n"
- "\n"
- " TARGET_WCPATH is a working copy of the branch the changes will\n"
- " be applied to.\n"
- "\n"
- " - Reintegrate Merge Example -\n"
- "\n"
- " A feature has been developed on a branch called \"feature\".\n"
- " The feature branch started as a copy of trunk@W. Work on the\n"
- " feature has completed and it should be merged back into the trunk.\n"
- " \n"
- " The feature branch was last synced with its immediate ancestor,\n"
- " the trunk, in revision X. So the difference between trunk@X and\n"
- " feature@HEAD contains the complete set of changes that implement\n"
- " the feature, and no other changes. These changes are applied to\n"
- " the trunk.\n"
- "\n"
- " feature +-------------------------------R\n"
- " / . \\\n"
- " / .............. \\\n"
- " / . v\n"
- " trunk ------+--------------------L------------------o\n"
- " rW rX\n"
- "\n"
- " In the diagram above, L marks the left side of the merge (trunk@X),\n"
- " and R marks the right side of the merge (feature@HEAD). The difference\n"
- " between the left and right side is merged into the target.\n"
- "\n"
- " To perform the merge, check out a working copy of the trunk, and run\n"
- " the following command in the top-level directory of the working copy:\n"
- "\n"
- " svn merge --reintegrate ^/feature\n"
- "\n"
- " To prevent unnecessary merge conflicts, reintegrate merges require\n"
- " that TARGET_WCPATH is not a mixed-revision working copy, has no\n"
- " local modifications, and has no switched subtrees.\n"
- "\n"
- " Reintegrate merges also require that the reintegrate source be fully\n"
- " synced with the target since their common branch point.\n"
- " In the above example this means that all of the changes made\n"
- " on trunk between revision W and revision X are fully merged to\n"
- " the feature branch before it can be reintegrated back to trunk.\n"
- "\n"
- " After the reintegrate merge, the feature branch cannot be synced\n"
- " to the trunk again without merge conflicts. If further work must\n"
- " be done on the feature branch, it should be deleted and then re-created.\n"
- "\n"
- "\n"
- " 3. The third form is called a \"2-URL merge\":\n"
- " svn merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
- "\n"
- " Two source URLs are specified, together with two revisions N and M.\n"
- " The two sources to be compared at the specified revisions, and the\n"
- " difference is applied to TARGET_WCPATH, which is a path to a working\n"
- " copy of another branch.\n"
- "\n"
- " The revisions default to HEAD if omitted.\n"
- "\n"
- " If TARGET_WCPATH is omitted, a default value of '.' is assumed,\n"
- " unless the sources have identical basenames that match a file\n"
- " within '.'; In which case, the differences will be applied to\n"
- " that file.\n"
- "\n"
- " The sources can also be specified as working copy paths, in which\n"
- " case the URLs of the merge sources are derived from the working copies.\n"
- "\n"
- " This is the most flexible type of merge, but also the most difficult\n"
- " to use. It can be used to merge the differences between two (possibly\n"
- " ancestrally unrelated) branches into a working copy of another branch.\n"
- " This type of merge should be used very carefully because the probability\n"
- " of merge conflicts is quite high. In most use cases, a sync, cherry-pick,\n"
- " or reintegrate merge is sufficient and reduces the chances of mistakes.\n"
- "\n"
- " - 2-URL Merge Example -\n"
- "\n"
- " A feature has been developed on a branch called \"feature\".\n"
- " Development for the upcoming 3.0 release has happened in parallel on\n"
- " the \"3.x-release\" branch. The work on the feature branch must be\n"
- " merged to the 3.x-release branch. However, the feature branch and\n"
- " the 3.x-release branch are not directly related, so a 2-URL merge\n"
- " is needed.\n"
- " The feature branch was last synced with its immediate ancestor,\n"
- " the trunk, up to revision 500. So the difference between trunk@500\n"
- " and feature@HEAD contains the complete set of changes related to\n"
- " the feature, and no other changes. These changes are applied to\n"
- " the 3.x-release branch.\n"
- "\n"
- " 3.x-release +-----------------------------------o\n"
- " / ^\n"
- " / /\n"
- " / r500 /\n"
- " trunk ------+------+-----------------L---------> /\n"
- " \\ . /\n"
- " \\ ........... /\n"
- " \\ . /\n"
- " feature +-----------------------------------R\n"
- "\n"
- " In the diagram above, L marks the left side of the merge (trunk@500),\n"
- " and R marks the right side of the merge is (feature@HEAD).\n"
- " The difference between the left and right side is merged into the target.\n"
- "\n"
- " To perform the merge, check out a working copy of the 3.x-release\n"
- " branch and run the following command in the top-level directory\n"
- " of the working copy:\n"
- " \n"
- " svn merge ^/trunk@500 ^/feature\n"
- "\n"
- " Before performing a 2-URL merge, it is a good idea to preview the\n"
- " changes which will be merged, because there is no guarantee that\n"
- " the merge will be free of conflicts. The preview can be done with\n"
- " the svn diff command:\n"
- "\n"
- " svn diff ^/trunk@500 ^/feature@HEAD\n"
- "\n"
- " Note that a 2-URL merge can also merge from foreign repositories.\n"
- " While SOURCE1 and SOURCE2 must both come from the same repository,\n"
- " TARGET_WCPATH may come from a different repository than the sources.\n"
- " However, there are some caveats. Most notably, copies made in the\n"
- " merge source will be transformed into plain additions in the merge\n"
- " target. Also, merge-tracking is not supported.\n"
- "\n"
- "\n"
- " The following applies to all types of merges:\n"
- "\n"
- " To prevent unnecessary merge conflicts, svn merge requires that\n"
- " TARGET_WCPATH is not a mixed-revision working copy.\n"
- " Running 'svn update' before starting a merge ensures that all\n"
- " items in the working copy are based on the same revision.\n"
- "\n"
- " For each merged item a line will be printed with characters reporting\n"
- " the action taken. These characters have the following meaning:\n"
- "\n"
- " A Added\n"
- " D Deleted\n"
- " U Updated\n"
- " C Conflict\n"
- " G Merged\n"
- " E Existed\n"
- " R Replaced\n"
- "\n"
- " Characters in the first column report about the item itself.\n"
- " Characters in the second column report about properties of the item.\n"
- " A 'C' in the third column indicates a tree conflict, while a 'C' in\n"
- " the first and second columns indicate textual conflicts in files\n"
- " and in property values, respectively.\n"
- "\n"
- " NOTE: Subversion uses the svn:mergeinfo property to track merge\n"
- " history. This property is considered at the start of a merge to\n"
- " determine what to merge and it is updated at the conclusion of the\n"
- " merge to describe the merge that took place. Mergeinfo is used only\n"
- " if the two sources are on the same line of history -- if the first\n"
- " source is an ancestor of the second, or vice-versa. This is guaranteed\n"
- " to be the case when using sync merges and reintegrate merges.\n"
- " The --ignore-ancestry option prevents merge tracking and thus\n"
- " ignores mergeinfo, neither considering it nor recording it.\n"),
+ ( /* For this large section, let's keep it unindented for easier
+ * viewing/editing. It has been vim-treated with a textwidth=75 and 'gw'
+ * (with quotes and newlines removed). */
+"Merge changes into a working copy.\n"
+"usage: 1. merge SOURCE[@REV] [TARGET_WCPATH]\n"
+" (the 'sync' merge)\n"
+" 2. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
+" (the 'cherry-pick' merge)\n"
+" 3. merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]\n"
+" (the 'reintegrate' merge)\n"
+" 4. merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
+" (the '2-URL' merge)\n"
+"\n"
+" 1. This form is called a 'sync' (or 'catch-up') merge:\n"
+"\n"
+" svn merge SOURCE[@REV] [TARGET_WCPATH]\n"
+"\n"
+" A sync merge is used to fetch all the latest changes made on a parent\n"
+" branch. In other words, the target branch has originally been created\n"
+" by copying the source branch, and any changes committed on the source\n"
+" branch since branching are applied to the target branch. This uses\n"
+" merge tracking to skip all those revisions that have already been\n"
+" merged, so a sync merge can be repeated periodically to stay up-to-\n"
+" date with the source branch.\n"
+"\n"
+" SOURCE specifies the branch from where the changes will be pulled, and\n"
+" TARGET_WCPATH specifies a working copy of the target branch to which\n"
+" the changes will be applied. Normally SOURCE and TARGET_WCPATH should\n"
+" each correspond to the root of a branch. (If you want to merge only a\n"
+" subtree, then the subtree path must be included in both SOURCE and\n"
+" TARGET_WCPATH; this is discouraged, to avoid subtree mergeinfo.)\n"
+"\n"
+" SOURCE is usually a URL. The optional '@REV' specifies both the peg\n"
+" revision of the URL and the latest revision that will be considered\n"
+" for merging; if REV is not specified, the HEAD revision is assumed. If\n"
+" SOURCE is a working copy path, the corresponding URL of the path is\n"
+" used, and the default value of 'REV' is the base revision (usually the\n"
+" revision last updated to).\n"
+"\n"
+" TARGET_WCPATH is a working copy path; if omitted, '.' is assumed.\n"
+"\n"
+" - Sync Merge Example -\n"
+"\n"
+" A feature is being developed on a branch called 'feature', which has\n"
+" originally been a copy of trunk. The feature branch has been regularly\n"
+" synced with trunk to keep up with the changes made there. The previous\n"
+" sync merges are not shown on this diagram, and the last of them was\n"
+" done when HEAD was r100. Currently, HEAD is r200.\n"
+"\n"
+" feature +------------------------o-----\n"
+" / ^\n"
+" / ............ |\n"
+" / . . /\n"
+" trunk ------+------------L--------------R------\n"
+" r100 r200\n"
+"\n"
+" Subversion will locate all the changes on 'trunk' that have not yet\n"
+" been merged into the 'feature' branch. In this case that is a single\n"
+" range, r100:200. In the diagram above, L marks the left side\n"
+" (trunk@100) and R marks the right side (trunk@200) of the merge. The\n"
+" difference between L and R will be applied to the target working copy\n"
+" path. In this case, the working copy is a clean checkout of the entire\n"
+" 'feature' branch.\n"
+"\n"
+" To perform this sync merge, have a clean working copy of the feature\n"
+" branch and run the following command in its top-level directory:\n"
+"\n"
+" svn merge ^/trunk\n"
+"\n"
+" Note that the merge is now only in your local working copy and still\n"
+" needs to be committed to the repository so that it can be seen by\n"
+" others. You can review the changes and you may have to resolve\n"
+" conflicts before you commit the merge.\n"
+"\n"
+"\n"
+" 2. This form is called a 'cherry-pick' merge:\n"
+"\n"
+" svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
+"\n"
+" A cherry-pick merge is used to merge specific revisions (or revision\n"
+" ranges) from one branch to another. By default, this uses merge\n"
+" tracking to automatically skip any revisions that have already been\n"
+" merged to the target; you can use the --ignore-ancestry option to\n"
+" disable such skipping.\n"
+"\n"
+" SOURCE is usually a URL. The optional '@REV' specifies only the peg\n"
+" revision of the URL and does not affect the merge range; if REV is not\n"
+" specified, the HEAD revision is assumed. If SOURCE is a working copy\n"
+" path, the corresponding URL of the path is used, and the default value\n"
+" of 'REV' is the base revision (usually the revision last updated to).\n"
+"\n"
+" TARGET_WCPATH is a working copy path; if omitted, '.' is assumed.\n"
+"\n"
+" The revision ranges to be merged are specified by the '-r' and/or '-c'\n"
+" options. '-r N:M' refers to the difference in the history of the\n"
+" source branch between revisions N and M. You can use '-c M' to merge\n"
+" single revisions: '-c M' is equivalent to '-r <M-1>:M'. Each such\n"
+" difference is applied to TARGET_WCPATH.\n"
+"\n"
+" If the mergeinfo in TARGET_WCPATH indicates that revisions within the\n"
+" range were already merged, changes made in those revisions are not\n"
+" merged again. If needed, the range is broken into multiple sub-ranges,\n"
+" and each sub-range is merged separately.\n"
+"\n"
+" A 'reverse range' can be used to undo changes. For example, when\n"
+" source and target refer to the same branch, a previously committed\n"
+" revision can be 'undone'. In a reverse range, N is greater than M in\n"
+" '-r N:M', or the '-c' option is used with a negative number: '-c -M'\n"
+" is equivalent to '-r M:<M-1>'.\n"
+"\n"
+" Multiple '-c' and/or '-r' options may be specified and mixing of\n"
+" forward and reverse ranges is allowed.\n"
+"\n"
+" - Cherry-pick Merge Example -\n"
+"\n"
+" A bug has been fixed on trunk in revision 50. This fix needs to\n"
+" be merged from trunk onto the release branch.\n"
+"\n"
+" 1.x-release +-----------------------o-----\n"
+" / ^\n"
+" / |\n"
+" / |\n"
+" trunk ------+--------------------------LR-----\n"
+" r50\n"
+"\n"
+" In the above diagram, L marks the left side (trunk@49) and R marks the\n"
+" right side (trunk@50) of the merge. The difference between the left\n"
+" and right side is applied to the target working copy path.\n"
+"\n"
+" Note that the difference between revision 49 and 50 is exactly those\n"
+" changes that were committed in revision 50, not including changes\n"
+" committed in revision 49.\n"
+"\n"
+" To perform the merge, have a clean working copy of the release branch\n"
+" and run the following command in its top-level directory; remember\n"
+" that the default target is '.':\n"
+"\n"
+" svn merge -c50 ^/trunk\n"
+"\n"
+" You can also cherry-pick several revisions and/or revision ranges:\n"
+"\n"
+" svn merge -c50,54,60 -r65:68 ^/trunk\n"
+"\n"
+"\n"
+" 3. This form is called a 'reintegrate merge':\n"
+"\n"
+" svn merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]\n"
+"\n"
+" In a reintegrate merge, an (e.g. feature) branch is merged back to its\n"
+" originating branch. In other words, the source branch has originally\n"
+" been created by copying the target branch, development has concluded\n"
+" on the source branch and it should now be merged back into the target\n"
+" branch.\n"
+" \n"
+" SOURCE is the URL of a branch to be merged back. If REV is specified,\n"
+" it is used as the peg revision for SOURCE; if REV is not specified,\n"
+" the HEAD revision is assumed.\n"
+"\n"
+" TARGET_WCPATH is a working copy of the branch the changes will be\n"
+" applied to.\n"
+"\n"
+" - Reintegrate Merge Example -\n"
+"\n"
+" A feature has been developed on a branch called 'feature'. The feature\n"
+" branch started as a copy of trunk@W. Work on the feature has completed\n"
+" and it should be merged back into the trunk.\n"
+"\n"
+" The feature branch was last synced with trunk up to revision X. So the\n"
+" difference between trunk@X and feature@HEAD contains the complete set\n"
+" of changes that implement the feature, and no other changes. These\n"
+" changes are applied to trunk.\n"
+"\n"
+" feature +--------------------------------R\n"
+" / . \\\n"
+" / ............. \\\n"
+" / . v\n"
+" trunk ------+--------------------L------------------o\n"
+" rW rX\n"
+"\n"
+" In the diagram above, L marks the left side (trunk@X) and R marks the\n"
+" right side (feature@HEAD) of the merge. The difference between the\n"
+" left and right side is merged into trunk, the target.\n"
+"\n"
+" To perform the merge, have a clean working copy of trunk and run the\n"
+" following command in its top-level directory:\n"
+"\n"
+" svn merge --reintegrate ^/feature\n"
+"\n"
+" To prevent unnecessary merge conflicts, a reintegrate merge requires\n"
+" that TARGET_WCPATH is not a mixed-revision working copy, has no local\n"
+" modifications, and has no switched subtrees.\n"
+"\n"
+" A reintegrate merge also requires that the source branch is coherently\n"
+" synced with the target -- in the above example, this means that all\n"
+" revisions between the branch point W and the last merged revision X\n"
+" are merged to the feature branch, so that there are no unmerged\n"
+" revisions in-between.\n"
+"\n"
+" After the reintegrate merge, the feature branch cannot be synced to\n"
+" the trunk again without merge conflicts. If further work must be done\n"
+" on the feature branch, it should be deleted and then re-created.\n"
+"\n"
+"\n"
+" 4. This form is called a '2-URL merge':\n"
+"\n"
+" svn merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
+"\n"
+" Two source URLs are specified, together with two revisions N and M.\n"
+" The two sources are compared at the specified revisions, and the\n"
+" difference is applied to TARGET_WCPATH, which is a path to a working\n"
+" copy of another branch. The three branches involved can be completely\n"
+" unrelated.\n"
+"\n"
+" You should use this merge variant only if the other variants do not\n"
+" apply to your situation, as this variant can be quite complex to\n"
+" master.\n"
+"\n"
+" If TARGET_WCPATH is omitted, a default value of '.' is assumed.\n"
+" However, in the special case where both sources refer to a file node\n"
+" with the same basename and a similarly named file is also found within\n"
+" '.', the differences will be applied to that local file. The source\n"
+" revisions default to HEAD if omitted.\n"
+"\n"
+" The sources can also be specified as working copy paths, in which case\n"
+" the URLs of the merge sources are derived from the working copies.\n"
+"\n"
+" - 2-URL Merge Example -\n"
+"\n"
+" Two features have been developed on separate branches called 'foo' and\n"
+" 'bar'. It has since become clear that 'bar' should be combined with\n"
+" the 'foo' branch for further development before reintegration.\n"
+"\n"
+" Although both feature branches originate from trunk, they are not\n"
+" directly related -- one is not a direct copy of the other. A 2-URL\n"
+" merge is necessary.\n"
+"\n"
+" The 'bar' branch has been synced with trunk up to revision 500.\n"
+" (If this revision number is not known, it can be located using the\n"
+" 'svn log' and/or 'svn mergeinfo' commands.)\n"
+" The difference between trunk@500 and bar@HEAD contains the complete\n"
+" set of changes related to feature 'bar', and no other changes. These\n"
+" changes are applied to the 'foo' branch.\n"
+"\n"
+" foo +-----------------------------------o\n"
+" / ^\n"
+" / /\n"
+" / r500 /\n"
+" trunk ------+------+-----------------L---------> /\n"
+" \\ . /\n"
+" \\ ............ /\n"
+" \\ . /\n"
+" bar +-----------------------------------R\n"
+"\n"
+" In the diagram above, L marks the left side (trunk@500) and R marks\n"
+" the right side (bar@HEAD) of the merge. The difference between the\n"
+" left and right side is applied to the target working copy path, in\n"
+" this case a working copy of the 'foo' branch.\n"
+"\n"
+" To perform the merge, have a clean working copy of the 'foo' branch\n"
+" and run the following command in its top-level directory:\n"
+"\n"
+" svn merge ^/trunk@500 ^/bar\n"
+"\n"
+" The exact changes applied by a 2-URL merge can be previewed with svn's\n"
+" diff command, which is a good idea to verify if you do not have the\n"
+" luxury of a clean working copy to merge to. In this case:\n"
+"\n"
+" svn diff ^/trunk@500 ^/bar@HEAD\n"
+"\n"
+"\n"
+" The following applies to all types of merges:\n"
+"\n"
+" To prevent unnecessary merge conflicts, svn merge requires that\n"
+" TARGET_WCPATH is not a mixed-revision working copy. Running 'svn update'\n"
+" before starting a merge ensures that all items in the working copy are\n"
+" based on the same revision.\n"
+"\n"
+" If possible, you should have no local modifications in the merge's target\n"
+" working copy prior to the merge, to keep things simpler. It will be\n"
+" easier to revert the merge and to understand the branch's history.\n"
+"\n"
+" Switched sub-paths should also be avoided during merging, as they may\n"
+" cause incomplete merges and create subtree mergeinfo.\n"
+"\n"
+" For each merged item a line will be printed with characters reporting the\n"
+" action taken. These characters have the following meaning:\n"
+"\n"
+" A Added\n"
+" D Deleted\n"
+" U Updated\n"
+" C Conflict\n"
+" G Merged\n"
+" E Existed\n"
+" R Replaced\n"
+"\n"
+" Characters in the first column report about the item itself.\n"
+" Characters in the second column report about properties of the item.\n"
+" A 'C' in the third column indicates a tree conflict, while a 'C' in\n"
+" the first and second columns indicate textual conflicts in files\n"
+" and in property values, respectively.\n"
+"\n"
+" - Merge Tracking -\n"
+"\n"
+" Subversion uses the svn:mergeinfo property to track merge history. This\n"
+" property is considered at the start of a merge to determine what to merge\n"
+" and it is updated at the conclusion of the merge to describe the merge\n"
+" that took place. Mergeinfo is used only if the two sources are on the\n"
+" same line of history -- if the first source is an ancestor of the second,\n"
+" or vice-versa (i.e. if one has originally been created by copying the\n"
+" other). This is verified and enforced when using sync merges and\n"
+" reintegrate merges.\n"
+"\n"
+" The --ignore-ancestry option prevents merge tracking and thus ignores\n"
+" mergeinfo, neither considering it nor recording it.\n"
+"\n"
+" - Merging from foreign repositories -\n"
+"\n"
+" Subversion does support merging from foreign repositories.\n"
+" While all merge source URLs must point to the same repository, the merge\n"
+" target working copy may come from a different repository than the source.\n"
+" However, there are some caveats. Most notably, copies made in the\n"
+" merge source will be transformed into plain additions in the merge\n"
+" target. Also, merge-tracking is not supported for merges from foreign\n"
+" repositories.\n"),
{'r', 'c', 'N', opt_depth, 'q', opt_force, opt_dry_run, opt_merge_cmd,
opt_record_only, 'x', opt_ignore_ancestry, opt_accept, opt_reintegrate,
opt_allow_mixed_revisions} },
@@ -1008,8 +1089,8 @@ const svn_opt_subcommand_desc2_t svn_cl_
"\n"
" Hint: If the patch file was created with Subversion, it will contain\n"
" the number of a revision N the patch will cleanly apply to\n"
- " (look for lines like \"--- foo/bar.txt (revision N)\").\n"
- " To avoid rejects, first update to the revision N using \n"
+ " (look for lines like '--- foo/bar.txt (revision N)').\n"
+ " To avoid rejects, first update to the revision N using\n"
" 'svn update -r N', apply the patch, and then update back to the\n"
" HEAD revision. This way, conflicts can be resolved interactively.\n"
),
@@ -1462,6 +1543,7 @@ main(int argc, const char *argv[])
svn_config_t *cfg_config;
svn_boolean_t descend = TRUE;
svn_boolean_t interactive_conflicts = FALSE;
+ svn_boolean_t use_notifier = TRUE;
apr_hash_t *changelists;
/* Initialize the app. */
@@ -1590,7 +1672,6 @@ main(int argc, const char *argv[])
{
char *end;
svn_revnum_t changeno, changeno_end;
- svn_opt_revision_range_t *range;
const char *change_str =
APR_ARRAY_IDX(change_revs, i, const char *);
const char *s = change_str;
@@ -1662,15 +1743,11 @@ main(int argc, const char *argv[])
changeno_end = changeno - 1;
}
- range = apr_palloc(pool, sizeof(*range));
- range->start.value.number = changeno;
- range->end.value.number = changeno_end;
-
opt_state.used_change_arg = TRUE;
- range->start.kind = svn_opt_revision_number;
- range->end.kind = svn_opt_revision_number;
APR_ARRAY_PUSH(opt_state.revision_ranges,
- svn_opt_revision_range_t *) = range;
+ svn_opt_revision_range_t *)
+ = svn_opt__revision_range_from_revnums(changeno, changeno_end,
+ pool);
}
}
break;
@@ -2017,6 +2094,9 @@ main(int argc, const char *argv[])
case opt_allow_mixed_revisions:
opt_state.allow_mixed_rev = TRUE;
break;
+ case opt_include_externals:
+ opt_state.include_externals = TRUE;
+ break;
default:
/* Hmmm. Perhaps this would be a good place to squirrel away
opts that commands like svn diff might need. Hmmm indeed. */
@@ -2481,12 +2561,21 @@ main(int argc, const char *argv[])
subcommands will populate the ctx->log_msg_baton3. */
ctx->log_msg_func3 = svn_cl__get_log_message;
- /* Set up the notifier. */
- if (((subcommand->cmd_func != svn_cl__status) && !opt_state.quiet)
- || ((subcommand->cmd_func == svn_cl__status) && !opt_state.xml))
+ /* Set up the notifier.
+
+ In general, we use it any time we aren't in --quiet mode. 'svn
+ status' is unique, though, in that we don't want it in --quiet mode
+ unless we're also in --verbose mode. When in --xml mode,
+ though, we never want it. */
+ if (opt_state.quiet)
+ use_notifier = FALSE;
+ if ((subcommand->cmd_func == svn_cl__status) && opt_state.verbose)
+ use_notifier = TRUE;
+ if (opt_state.xml)
+ use_notifier = FALSE;
+ if (use_notifier)
{
- err = svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2,
- FALSE, pool);
+ err = svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, pool);
if (err)
return svn_cmdline_handle_exit_error(err, pool, "svn: ");
}
@@ -2601,6 +2690,15 @@ main(int argc, const char *argv[])
_("Please see the 'svn upgrade' command"));
}
+ /* Tell the user about 'svn cleanup' if any error on the stack
+ was about locked working copies. */
+ if (svn_error_find_cause(err, SVN_ERR_WC_LOCKED))
+ {
+ err = svn_error_quick_wrap(
+ err, _("Run 'svn cleanup' to remove locks "
+ "(type 'svn help cleanup' for details)"));
+ }
+
/* Issue #3014:
* Don't print anything on broken pipes. The pipe was likely
* closed by the process at the other end. We expect that
@@ -2611,14 +2709,6 @@ main(int argc, const char *argv[])
if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
svn_handle_error2(err, stderr, FALSE, "svn: ");
- /* Tell the user about 'svn cleanup' if any error on the stack
- was about locked working copies. */
- if (svn_error_find_cause(err, SVN_ERR_WC_LOCKED))
- svn_error_clear(svn_cmdline_fputs(_("svn: run 'svn cleanup' to "
- "remove locks (type 'svn help "
- "cleanup' for details)\n"),
- stderr, pool));
-
svn_error_clear(err);
svn_pool_destroy(pool);
return EXIT_FAILURE;
Modified: subversion/branches/fs-py/subversion/svn/merge-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/merge-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/merge-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/merge-cmd.c Mon Dec 19 18:49:34 2011
@@ -39,6 +39,63 @@
/*** Code. ***/
+/* Do a reintegrate merge from SOURCE_PATH_OR_URL@SOURCE_PEG_REVISION into
+ * TARGET_WCPATH. Do it with a WC write lock unless DRY_RUN is true. */
+static svn_error_t *
+merge_reintegrate(const char *source_path_or_url,
+ const svn_opt_revision_t *source_peg_revision,
+ const char *target_wcpath,
+ svn_boolean_t dry_run,
+ const apr_array_header_t *merge_options,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ const char *url1, *url2;
+ svn_revnum_t rev1, rev2;
+
+ SVN_ERR(svn_client_find_reintegrate_merge(
+ &url1, &rev1, &url2, &rev2,
+ source_path_or_url, source_peg_revision, target_wcpath,
+ ctx, scratch_pool, scratch_pool));
+
+ if (url1)
+ {
+ svn_opt_revision_t revision1 = { svn_opt_revision_number, { rev1 } };
+ svn_opt_revision_t revision2 = { svn_opt_revision_number, { rev2 } };
+
+ /* Do the merge. Set 'allow_mixed_rev' to true, not because we want
+ * to allow a mixed-rev WC but simply to bypass the check, as it was
+ * already checked in svn_client_find_reintegrate_merge(). */
+ SVN_ERR(svn_client_merge4(url1, &revision1, url2, &revision2,
+ target_wcpath, svn_depth_infinity,
+ FALSE /* ignore_ancestry */,
+ FALSE /* force */,
+ FALSE /* record_only */,
+ dry_run, TRUE /* allow_mixed_rev */,
+ merge_options, ctx, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Throw an error if PATH_OR_URL is a path and REVISION isn't a repository
+ * revision. */
+static svn_error_t *
+ensure_wc_path_has_repo_revision(const char *path_or_url,
+ const svn_opt_revision_t *revision,
+ apr_pool_t *scratch_pool)
+{
+ if (revision->kind != svn_opt_revision_number
+ && revision->kind != svn_opt_revision_date
+ && revision->kind != svn_opt_revision_head
+ && ! svn_path_is_url(path_or_url))
+ return svn_error_createf(
+ SVN_ERR_CLIENT_BAD_REVISION, NULL,
+ _("Invalid merge source '%s'; a working copy path can only be "
+ "used with a repository revision (a number, a date, or head)"),
+ svn_dirent_local_style(path_or_url, scratch_pool));
+ return SVN_NO_ERROR;
+}
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
@@ -55,6 +112,7 @@ svn_cl__merge(apr_getopt_t *os,
svn_opt_revision_t first_range_start, first_range_end, peg_revision1,
peg_revision2;
apr_array_header_t *options, *ranges_to_merge = opt_state->revision_ranges;
+ svn_opt_revision_t unspecified = { svn_opt_revision_unspecified, { 0 } };
/* Merge doesn't support specifying a revision or revision range
when using --reintegrate. */
@@ -175,28 +233,21 @@ svn_cl__merge(apr_getopt_t *os,
_("Too many arguments given"));
/* Set the default value for unspecified paths and peg revision. */
- if (targets->nelts == 0)
- {
- peg_revision1.kind = svn_opt_revision_head;
- }
- else
- {
- /* targets->nelts is 1 ("svn merge SOURCE") or 2 ("svn merge
- SOURCE WCPATH") here. */
- sourcepath2 = sourcepath1;
-
- if (peg_revision1.kind == svn_opt_revision_unspecified)
- peg_revision1.kind = svn_path_is_url(sourcepath1)
- ? svn_opt_revision_head : svn_opt_revision_working;
+ /* targets->nelts is 1 ("svn merge SOURCE") or 2 ("svn merge
+ SOURCE WCPATH") here. */
+ sourcepath2 = sourcepath1;
+
+ if (peg_revision1.kind == svn_opt_revision_unspecified)
+ peg_revision1.kind = svn_path_is_url(sourcepath1)
+ ? svn_opt_revision_head : svn_opt_revision_working;
- if (targets->nelts == 2)
- {
- targetpath = APR_ARRAY_IDX(targets, 1, const char *);
- if (svn_path_is_url(targetpath))
- return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Cannot specify a revision range "
- "with two URLs"));
- }
+ if (targets->nelts == 2)
+ {
+ targetpath = APR_ARRAY_IDX(targets, 1, const char *);
+ if (svn_path_is_url(targetpath))
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Cannot specify a revision range "
+ "with two URLs"));
}
}
else /* using @rev syntax */
@@ -212,16 +263,13 @@ svn_cl__merge(apr_getopt_t *os,
/* Catch 'svn merge wc_path1 wc_path2 [target]' without explicit
revisions--since it ignores local modifications it may not do what
- the user expects. Forcing the user to specify a repository
+ the user expects. That is, it doesn't read from the WC itself, it
+ reads from the WC's URL. Forcing the user to specify a repository
revision should avoid any confusion. */
- if ((first_range_start.kind == svn_opt_revision_unspecified
- && ! svn_path_is_url(sourcepath1))
- ||
- (first_range_end.kind == svn_opt_revision_unspecified
- && ! svn_path_is_url(sourcepath2)))
- return svn_error_create
- (SVN_ERR_CLIENT_BAD_REVISION, 0,
- _("A working copy merge source needs an explicit revision"));
+ SVN_ERR(ensure_wc_path_has_repo_revision(sourcepath1, &first_range_start,
+ pool));
+ SVN_ERR(ensure_wc_path_has_repo_revision(sourcepath2, &first_range_end,
+ pool));
/* Default peg revisions to each URL's youngest revision. */
if (first_range_start.kind == svn_opt_revision_unspecified)
@@ -261,11 +309,11 @@ svn_cl__merge(apr_getopt_t *os,
else if (strcmp(sourcepath1, sourcepath2) == 0)
{
svn_node_kind_t kind;
- const char *decoded_path = svn_path_uri_decode(sourcepath1, pool);
- SVN_ERR(svn_io_check_path(decoded_path, &kind, pool));
+
+ SVN_ERR(svn_io_check_path(sourcepath1, &kind, pool));
if (kind == svn_node_file)
{
- targetpath = decoded_path;
+ targetpath = sourcepath1;
}
}
}
@@ -298,12 +346,18 @@ svn_cl__merge(apr_getopt_t *os,
"with --reintegrate"));
}
- if (! two_sources_specified) /* TODO: Switch order of if */
+ if (opt_state->reintegrate)
{
- /* If we don't have a source, use the target as the source. */
- if (! sourcepath1)
- sourcepath1 = targetpath;
+ SVN_ERR_W(svn_cl__check_related_source_and_target(
+ sourcepath1, &peg_revision1, targetpath, &unspecified,
+ ctx, pool),
+ _("Source and target must be different but related branches"));
+ err = merge_reintegrate(sourcepath1, &peg_revision1, targetpath,
+ opt_state->dry_run, options, ctx, pool);
+ }
+ else if (! two_sources_specified)
+ {
/* If we don't have at least one valid revision range, pick a
good one that spans the entire set of revisions on our
source. */
@@ -316,28 +370,27 @@ svn_cl__merge(apr_getopt_t *os,
range->start.value.number = 1;
range->end = peg_revision1;
APR_ARRAY_PUSH(ranges_to_merge, svn_opt_revision_range_t *) = range;
+
+ /* This must be a 'sync' merge so check branch relationship. */
+ SVN_ERR_W(svn_cl__check_related_source_and_target(
+ sourcepath1, &peg_revision1, targetpath, &unspecified,
+ ctx, pool),
+ _("Source and target must be different but related branches"));
}
- if (opt_state->reintegrate)
- err = svn_client_merge_reintegrate(sourcepath1,
- &peg_revision1,
- targetpath,
- opt_state->dry_run,
- options, ctx, pool);
- else
- err = svn_client_merge_peg4(sourcepath1,
- ranges_to_merge,
- &peg_revision1,
- targetpath,
- opt_state->depth,
- opt_state->ignore_ancestry,
- opt_state->force,
- opt_state->record_only,
- opt_state->dry_run,
- opt_state->allow_mixed_rev,
- options,
- ctx,
- pool);
+ err = svn_client_merge_peg4(sourcepath1,
+ ranges_to_merge,
+ &peg_revision1,
+ targetpath,
+ opt_state->depth,
+ opt_state->ignore_ancestry,
+ opt_state->force,
+ opt_state->record_only,
+ opt_state->dry_run,
+ opt_state->allow_mixed_rev,
+ options,
+ ctx,
+ pool);
}
else
{
Modified: subversion/branches/fs-py/subversion/svn/mergeinfo-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/mergeinfo-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/mergeinfo-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/mergeinfo-cmd.c Mon Dec 19 18:49:34 2011
@@ -67,8 +67,8 @@ svn_cl__mergeinfo(apr_getopt_t *os,
const char *source, *target;
svn_opt_revision_t src_peg_revision, tgt_peg_revision;
/* Default to depth empty. */
- svn_depth_t depth = opt_state->depth == svn_depth_unknown
- ? svn_depth_empty : opt_state->depth;
+ svn_depth_t depth = (opt_state->depth == svn_depth_unknown)
+ ? svn_depth_empty : opt_state->depth;
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
opt_state->targets,
@@ -114,6 +114,11 @@ svn_cl__mergeinfo(apr_getopt_t *os,
tgt_peg_revision.kind = svn_opt_revision_base;
}
+ SVN_ERR_W(svn_cl__check_related_source_and_target(source, &src_peg_revision,
+ target, &tgt_peg_revision,
+ ctx, pool),
+ _("Source and target must be different but related branches"));
+
/* Do the real work, depending on the requested data flavor. */
if (opt_state->show_revs == svn_cl__show_revs_merged)
{