summaryrefslogtreecommitdiff
path: root/subversion/svn/svn.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/svn/svn.c')
-rw-r--r--subversion/svn/svn.c2983
1 files changed, 2983 insertions, 0 deletions
diff --git a/subversion/svn/svn.c b/subversion/svn/svn.c
new file mode 100644
index 0000000..38d4ce1
--- /dev/null
+++ b/subversion/svn/svn.c
@@ -0,0 +1,2983 @@
+/*
+ * svn.c: Subversion command line client main file.
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include <string.h>
+#include <assert.h>
+
+#include <apr_strings.h>
+#include <apr_tables.h>
+#include <apr_general.h>
+#include <apr_signal.h>
+
+#include "svn_cmdline.h"
+#include "svn_pools.h"
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_config.h"
+#include "svn_string.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_delta.h"
+#include "svn_diff.h"
+#include "svn_error.h"
+#include "svn_io.h"
+#include "svn_opt.h"
+#include "svn_utf.h"
+#include "svn_auth.h"
+#include "svn_hash.h"
+#include "svn_version.h"
+#include "cl.h"
+
+#include "private/svn_opt_private.h"
+#include "private/svn_cmdline_private.h"
+#include "private/svn_subr_private.h"
+
+#include "svn_private_config.h"
+
+
+/*** Option Processing ***/
+
+/* Add an identifier here for long options that don't have a short
+ option. Options that have both long and short options should just
+ use the short option letter as identifier. */
+typedef enum svn_cl__longopt_t {
+ opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
+ opt_auth_username,
+ opt_autoprops,
+ opt_changelist,
+ opt_config_dir,
+ opt_config_options,
+ /* diff options */
+ opt_diff_cmd,
+ opt_internal_diff,
+ opt_no_diff_added,
+ opt_no_diff_deleted,
+ opt_show_copies_as_adds,
+ opt_notice_ancestry,
+ opt_summarize,
+ opt_use_git_diff_format,
+ opt_ignore_properties,
+ opt_properties_only,
+ opt_patch_compatible,
+ /* end of diff options */
+ opt_dry_run,
+ opt_editor_cmd,
+ opt_encoding,
+ opt_force_log,
+ opt_force,
+ opt_keep_changelists,
+ opt_ignore_ancestry,
+ opt_ignore_externals,
+ opt_incremental,
+ opt_merge_cmd,
+ opt_native_eol,
+ opt_new_cmd,
+ opt_no_auth_cache,
+ opt_no_autoprops,
+ opt_no_ignore,
+ opt_no_unlock,
+ opt_non_interactive,
+ opt_force_interactive,
+ opt_old_cmd,
+ opt_record_only,
+ opt_relocate,
+ opt_remove,
+ opt_revprop,
+ opt_stop_on_copy,
+ opt_strict,
+ opt_targets,
+ opt_depth,
+ opt_set_depth,
+ opt_version,
+ opt_xml,
+ opt_keep_local,
+ opt_with_revprop,
+ opt_with_all_revprops,
+ opt_with_no_revprops,
+ opt_parents,
+ opt_accept,
+ opt_show_revs,
+ opt_reintegrate,
+ opt_trust_server_cert,
+ opt_strip,
+ opt_ignore_keywords,
+ opt_reverse_diff,
+ opt_ignore_whitespace,
+ opt_diff,
+ opt_allow_mixed_revisions,
+ opt_include_externals,
+ opt_show_inherited_props,
+ opt_search,
+ opt_search_and
+} svn_cl__longopt_t;
+
+
+/* Option codes and descriptions for the command line client.
+ *
+ * The entire list must be terminated with an entry of nulls.
+ */
+const apr_getopt_option_t svn_cl__options[] =
+{
+ {"force", opt_force, 0, N_("force operation to run")},
+ {"force-log", opt_force_log, 0,
+ N_("force validity of log message source")},
+ {"help", 'h', 0, N_("show help on a subcommand")},
+ {NULL, '?', 0, N_("show help on a subcommand")},
+ {"message", 'm', 1, N_("specify log message ARG")},
+ {"quiet", 'q', 0, N_("print nothing, or only summary information")},
+ {"recursive", 'R', 0, N_("descend recursively, same as --depth=infinity")},
+ {"non-recursive", 'N', 0, N_("obsolete; try --depth=files or --depth=immediates")},
+ {"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\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"
+ " "
+ "A revision argument can be one of:\n"
+ " "
+ " NUMBER revision number\n"
+ " "
+ " '{' DATE '}' revision at start of the date\n"
+ " "
+ " 'HEAD' latest in repository\n"
+ " "
+ " 'BASE' base rev of item's working copy\n"
+ " "
+ " 'COMMITTED' last commit at or before BASE\n"
+ " "
+ " 'PREV' revision just before COMMITTED")},
+ {"file", 'F', 1, N_("read log message from file ARG")},
+ {"incremental", opt_incremental, 0,
+ N_("give output suitable for concatenation")},
+ {"encoding", opt_encoding, 1,
+ N_("treat value as being in charset encoding ARG")},
+ {"version", opt_version, 0, N_("show program version information")},
+ {"verbose", 'v', 0, N_("print extra information")},
+ {"show-updates", 'u', 0, N_("display update information")},
+ {"username", opt_auth_username, 1, N_("specify a username ARG")},
+ {"password", opt_auth_password, 1, N_("specify a password ARG")},
+ {"extensions", 'x', 1,
+ N_("Specify differencing options for external diff or\n"
+ " "
+ "internal diff or blame. Default: '-u'. Options are\n"
+ " "
+ "separated by spaces. Internal diff and blame take:\n"
+ " "
+ " -u, --unified: Show 3 lines of unified context\n"
+ " "
+ " -b, --ignore-space-change: Ignore changes in\n"
+ " "
+ " amount of white space\n"
+ " "
+ " -w, --ignore-all-space: Ignore all white space\n"
+ " "
+ " --ignore-eol-style: Ignore changes in EOL style\n"
+ " "
+ " -p, --show-c-function: Show C function name")},
+ {"targets", opt_targets, 1,
+ N_("pass contents of file ARG as additional args")},
+ {"depth", opt_depth, 1,
+ N_("limit operation by depth ARG ('empty', 'files',\n"
+ " "
+ "'immediates', or 'infinity')")},
+ {"set-depth", opt_set_depth, 1,
+ N_("set new working copy depth to ARG ('exclude',\n"
+ " "
+ "'empty', 'files', 'immediates', or 'infinity')")},
+ {"xml", opt_xml, 0, N_("output in XML")},
+ {"strict", opt_strict, 0, N_("use strict semantics")},
+ {"stop-on-copy", opt_stop_on_copy, 0,
+ N_("do not cross copies while traversing history")},
+ {"no-ignore", opt_no_ignore, 0,
+ N_("disregard default and svn:ignore and\n"
+ " "
+ "svn:global-ignores property ignores")},
+ {"no-auth-cache", opt_no_auth_cache, 0,
+ N_("do not cache authentication tokens")},
+ {"trust-server-cert", opt_trust_server_cert, 0,
+ N_("accept SSL server certificates from unknown\n"
+ " "
+ "certificate authorities without prompting (but only\n"
+ " "
+ "with '--non-interactive')") },
+ {"non-interactive", opt_non_interactive, 0,
+ N_("do no interactive prompting (default is to prompt\n"
+ " "
+ "only if standard input is a terminal device)")},
+ {"force-interactive", opt_force_interactive, 0,
+ N_("do interactive prompting even if standard input\n"
+ " "
+ "is not a terminal device")},
+ {"dry-run", opt_dry_run, 0,
+ N_("try operation but make no changes")},
+ {"ignore-ancestry", opt_ignore_ancestry, 0,
+ N_("disable merge tracking; diff nodes as if related")},
+ {"ignore-externals", opt_ignore_externals, 0,
+ N_("ignore externals definitions")},
+ {"diff3-cmd", opt_merge_cmd, 1, N_("use ARG as merge command")},
+ {"editor-cmd", opt_editor_cmd, 1, N_("use ARG as external editor")},
+ {"record-only", opt_record_only, 0,
+ N_("merge only mergeinfo differences")},
+ {"old", opt_old_cmd, 1, N_("use ARG as the older target")},
+ {"new", opt_new_cmd, 1, N_("use ARG as the newer target")},
+ {"revprop", opt_revprop, 0,
+ N_("operate on a revision property (use with -r)")},
+ {"relocate", opt_relocate, 0, N_("relocate via URL-rewriting")},
+ {"config-dir", opt_config_dir, 1,
+ N_("read user configuration files from directory ARG")},
+ {"config-option", opt_config_options, 1,
+ N_("set user configuration option in the format:\n"
+ " "
+ " FILE:SECTION:OPTION=[VALUE]\n"
+ " "
+ "For example:\n"
+ " "
+ " servers:global:http-library=serf")},
+ {"auto-props", opt_autoprops, 0, N_("enable automatic properties")},
+ {"no-auto-props", opt_no_autoprops, 0, N_("disable automatic properties")},
+ {"native-eol", opt_native_eol, 1,
+ N_("use a different EOL marker than the standard\n"
+ " "
+ "system marker for files with the svn:eol-style\n"
+ " "
+ "property set to 'native'.\n"
+ " "
+ "ARG may be one of 'LF', 'CR', 'CRLF'")},
+ {"limit", 'l', 1, N_("maximum number of log entries")},
+ {"no-unlock", opt_no_unlock, 0, N_("don't unlock the targets")},
+ {"remove", opt_remove, 0, N_("remove changelist association")},
+ {"changelist", opt_changelist, 1,
+ N_("operate only on members of changelist ARG")},
+ {"keep-changelists", opt_keep_changelists, 0,
+ N_("don't delete changelists after commit")},
+ {"keep-local", opt_keep_local, 0, N_("keep path in working copy")},
+ {"with-all-revprops", opt_with_all_revprops, 0,
+ N_("retrieve all revision properties")},
+ {"with-no-revprops", opt_with_no_revprops, 0,
+ N_("retrieve no revision properties")},
+ {"with-revprop", opt_with_revprop, 1,
+ N_("set revision property ARG in new revision\n"
+ " "
+ "using the name[=value] format")},
+ {"parents", opt_parents, 0, N_("make intermediate directories")},
+ {"use-merge-history", 'g', 0,
+ N_("use/display additional information from merge\n"
+ " "
+ "history")},
+ {"accept", opt_accept, 1,
+ N_("specify automatic conflict resolution action\n"
+ " "
+ "('postpone', 'working', 'base', 'mine-conflict',\n"
+ " "
+ "'theirs-conflict', 'mine-full', 'theirs-full',\n"
+ " "
+ "'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"
+ " "
+ "('merged', 'eligible')")},
+ {"reintegrate", opt_reintegrate, 0,
+ N_("deprecated")},
+ {"strip", opt_strip, 1,
+ N_("number of leading path components to strip from\n"
+ " "
+ "paths parsed from the patch file. --strip 0\n"
+ " "
+ "is the default and leaves paths unmodified.\n"
+ " "
+ "--strip 1 would change the path\n"
+ " "
+ "'doc/fudge/crunchy.html' to 'fudge/crunchy.html'.\n"
+ " "
+ "--strip 2 would leave just 'crunchy.html'\n"
+ " "
+ "The expected component separator is '/' on all\n"
+ " "
+ "platforms. A leading '/' counts as one component.")},
+ {"ignore-keywords", opt_ignore_keywords, 0,
+ N_("don't expand keywords")},
+ {"reverse-diff", opt_reverse_diff, 0,
+ N_("apply the unidiff in reverse")},
+ {"ignore-whitespace", opt_ignore_whitespace, 0,
+ N_("ignore whitespace during pattern matching")},
+ {"diff", opt_diff, 0, N_("produce diff output")}, /* maps to show_diff */
+ /* diff options */
+ {"diff-cmd", opt_diff_cmd, 1, N_("use ARG as diff command")},
+ {"internal-diff", opt_internal_diff, 0,
+ N_("override diff-cmd specified in config file")},
+ {"no-diff-added", opt_no_diff_added, 0,
+ N_("do not print differences for added files")},
+ {"no-diff-deleted", opt_no_diff_deleted, 0,
+ N_("do not print differences for deleted files")},
+ {"show-copies-as-adds", opt_show_copies_as_adds, 0,
+ N_("don't diff copied or moved files with their source")},
+ {"notice-ancestry", opt_notice_ancestry, 0,
+ N_("diff unrelated nodes as delete and add")},
+ {"summarize", opt_summarize, 0, N_("show a summary of the results")},
+ {"git", opt_use_git_diff_format, 0,
+ N_("use git's extended diff format")},
+ {"ignore-properties", opt_ignore_properties, 0,
+ N_("ignore properties during the operation")},
+ {"properties-only", opt_properties_only, 0,
+ N_("show only properties during the operation")},
+ {"patch-compatible", opt_patch_compatible, 0,
+ N_("generate diff suitable for generic third-party\n"
+ " "
+ "patch tools; currently the same as\n"
+ " "
+ "--show-copies-as-adds --ignore-properties"
+ )},
+ /* end of diff options */
+ {"allow-mixed-revisions", opt_allow_mixed_revisions, 0,
+ N_("Allow operation on mixed-revision working copy.\n"
+ " "
+ "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)")},
+ {"show-inherited-props", opt_show_inherited_props, 0,
+ N_("retrieve target's inherited properties")},
+ {"search", opt_search, 1,
+ N_("use ARG as search pattern (glob syntax)")},
+ {"search-and", opt_search_and, 1,
+ N_("combine ARG with the previous search pattern")},
+
+ /* Long-opt Aliases
+ *
+ * These have NULL desriptions, but an option code that matches some
+ * other option (whose description should probably mention its aliases).
+ */
+
+ {"cl", opt_changelist, 1, NULL},
+
+ {0, 0, 0, 0},
+};
+
+
+
+/*** Command dispatch. ***/
+
+/* Our array of available subcommands.
+ *
+ * The entire list must be terminated with an entry of nulls.
+ *
+ * In most of the help text "PATH" is used where a working copy path is
+ * required, "URL" where a repository URL is required and "TARGET" when
+ * either a path or a url can be used. Hmm, should this be part of the
+ * help text?
+ */
+
+/* Options that apply to all commands. (While not every command may
+ currently require authentication or be interactive, allowing every
+ command to take these arguments allows scripts to just pass them
+ willy-nilly to every invocation of 'svn') . */
+const int svn_cl__global_options[] =
+{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive,
+ opt_force_interactive, opt_trust_server_cert, opt_config_dir,
+ opt_config_options, 0
+};
+
+/* Options for giving a log message. (Some of these also have other uses.)
+ */
+#define SVN_CL__LOG_MSG_OPTIONS 'm', 'F', \
+ opt_force_log, \
+ opt_editor_cmd, \
+ opt_encoding, \
+ opt_with_revprop
+
+const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
+{
+ { "add", svn_cl__add, {0}, N_
+ ("Put files and directories under version control, scheduling\n"
+ "them for addition to repository. They will be added in next commit.\n"
+ "usage: add PATH...\n"),
+ {opt_targets, 'N', opt_depth, 'q', opt_force, opt_no_ignore, opt_autoprops,
+ opt_no_autoprops, opt_parents },
+ {{opt_parents, N_("add intermediate parents")}} },
+
+ { "blame", svn_cl__blame, {"praise", "annotate", "ann"}, N_
+ ("Output the content of specified files or\n"
+ "URLs with revision and author information in-line.\n"
+ "usage: blame TARGET[@REV]...\n"
+ "\n"
+ " If specified, REV determines in which revision the target is first\n"
+ " looked up.\n"),
+ {'r', 'v', 'g', opt_incremental, opt_xml, 'x', opt_force} },
+
+ { "cat", svn_cl__cat, {0}, N_
+ ("Output the content of specified files or URLs.\n"
+ "usage: cat TARGET[@REV]...\n"
+ "\n"
+ " If specified, REV determines in which revision the target is first\n"
+ " looked up.\n"),
+ {'r'} },
+
+ { "changelist", svn_cl__changelist, {"cl"}, N_
+ ("Associate (or dissociate) changelist CLNAME with the named files.\n"
+ "usage: 1. changelist CLNAME PATH...\n"
+ " 2. changelist --remove PATH...\n"),
+ { 'q', 'R', opt_depth, opt_remove, opt_targets, opt_changelist} },
+
+ { "checkout", svn_cl__checkout, {"co"}, N_
+ ("Check out a working copy from a repository.\n"
+ "usage: checkout URL[@REV]... [PATH]\n"
+ "\n"
+ " If specified, REV determines in which revision the URL is first\n"
+ " looked up.\n"
+ "\n"
+ " If PATH is omitted, the basename of the URL will be used as\n"
+ " the destination. If multiple URLs are given each will be checked\n"
+ " out into a sub-directory of PATH, with the name of the sub-directory\n"
+ " being the basename of the URL.\n"
+ "\n"
+ " If --force is used, unversioned obstructing paths in the working\n"
+ " copy destination do not automatically cause the check out to fail.\n"
+ " If the obstructing path is the same type (file or directory) as the\n"
+ " corresponding path in the repository it becomes versioned but its\n"
+ " contents are left 'as-is' in the working copy. This means that an\n"
+ " obstructing directory's unversioned children may also obstruct and\n"
+ " become versioned. For files, any content differences between the\n"
+ " obstruction and the repository are treated like a local modification\n"
+ " to the working copy. All properties from the repository are applied\n"
+ " to the obstructing path.\n"
+ "\n"
+ " See also 'svn help update' for a list of possible characters\n"
+ " reporting the action taken.\n"),
+ {'r', 'q', 'N', opt_depth, opt_force, opt_ignore_externals} },
+
+ { "cleanup", svn_cl__cleanup, {0}, N_
+ ("Recursively clean up the working copy, removing write locks, resuming\n"
+ "unfinished operations, etc.\n"
+ "usage: cleanup [WCPATH...]\n"
+ "\n"
+ " Finish any unfinished business in the working copy at WCPATH, and remove\n"
+ " write locks (shown as 'L' by the 'svn status' command) from the working\n"
+ " copy. Usually, this is only necessary if a Subversion client has crashed\n"
+ " while using the working copy, leaving it in an unusable state.\n"
+ "\n"
+ " WARNING: There is no mechanism that will protect write locks still\n"
+ " being used by other Subversion clients. Running this command\n"
+ " while another client is using the working copy can corrupt\n"
+ " the working copy beyond repair!\n"),
+ {opt_merge_cmd} },
+
+ { "commit", svn_cl__commit, {"ci"},
+ N_("Send changes from your working copy to the repository.\n"
+ "usage: commit [PATH...]\n"
+ "\n"
+ " A log message must be provided, but it can be empty. If it is not\n"
+ " given by a --message or --file option, an editor will be started.\n"
+ " 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_include_externals} },
+
+ { "copy", svn_cl__copy, {"cp"}, N_
+ ("Copy files and directories in a working copy or repository.\n"
+ "usage: copy SRC[@REV]... DST\n"
+ "\n"
+ " SRC and DST can each be either a working copy (WC) path or URL:\n"
+ " WC -> WC: copy and schedule for addition (with history)\n"
+ " WC -> URL: immediately commit a copy of WC to URL\n"
+ " URL -> WC: check out URL into WC, schedule for addition\n"
+ " URL -> URL: complete server-side copy; used to branch and tag\n"
+ " All the SRCs must be of the same type. When copying multiple sources,\n"
+ " they will be added as children of DST, which must be a directory.\n"
+ "\n"
+ " WARNING: For compatibility with previous versions of Subversion,\n"
+ " copies performed using two working copy paths (WC -> WC) will not\n"
+ " contact the repository. As such, they may not, by default, be able\n"
+ " to propagate merge tracking information from the source of the copy\n"
+ " to the destination.\n"),
+ {'r', 'q', opt_ignore_externals, opt_parents, SVN_CL__LOG_MSG_OPTIONS} },
+
+ { "delete", svn_cl__delete, {"del", "remove", "rm"}, N_
+ ("Remove files and directories from version control.\n"
+ "usage: 1. delete PATH...\n"
+ " 2. delete URL...\n"
+ "\n"
+ " 1. Each item specified by a PATH is scheduled for deletion upon\n"
+ " the next commit. Files, and directories that have not been\n"
+ " committed, are immediately removed from the working copy\n"
+ " unless the --keep-local option is given.\n"
+ " PATHs that are, or contain, unversioned or modified items will\n"
+ " not be removed unless the --force or --keep-local option is given.\n"
+ "\n"
+ " 2. Each item specified by a URL is deleted from the repository\n"
+ " via an immediate commit.\n"),
+ {opt_force, 'q', opt_targets, SVN_CL__LOG_MSG_OPTIONS, opt_keep_local} },
+
+ { "diff", svn_cl__diff, {"di"}, N_
+ ("Display local changes or differences between two revisions or paths.\n"
+ "usage: 1. diff\n"
+ " 2. diff [-c M | -r N[:M]] [TARGET[@REV]...]\n"
+ " 3. diff [-r N[:M]] --old=OLD-TGT[@OLDREV] [--new=NEW-TGT[@NEWREV]] \\\n"
+ " [PATH...]\n"
+ " 4. diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]\n"
+ " 5. diff OLD-URL[@OLDREV] NEW-PATH[@NEWREV]\n"
+ " 6. diff OLD-PATH[@OLDREV] NEW-URL[@NEWREV]\n"
+ "\n"
+ " 1. Use just 'svn diff' to display local modifications in a working copy.\n"
+ "\n"
+ " 2. Display the changes made to TARGETs as they are seen in REV between\n"
+ " two revisions. TARGETs may be all working copy paths or all URLs.\n"
+ " If TARGETs are working copy paths, N defaults to BASE and M to the\n"
+ " working copy; if URLs, N must be specified and M defaults to HEAD.\n"
+ " The '-c M' option is equivalent to '-r N:M' where N = M-1.\n"
+ " Using '-c -M' does the reverse: '-r M:N' where N = M-1.\n"
+ "\n"
+ " 3. Display the differences between OLD-TGT as it was seen in OLDREV and\n"
+ " NEW-TGT as it was seen in NEWREV. PATHs, if given, are relative to\n"
+ " OLD-TGT and NEW-TGT and restrict the output to differences for those\n"
+ " paths. OLD-TGT and NEW-TGT may be working copy paths or URL[@REV].\n"
+ " NEW-TGT defaults to OLD-TGT if not specified. -r N makes OLDREV default\n"
+ " to N, -r N:M makes OLDREV default to N and NEWREV default to M.\n"
+ " If OLDREV or NEWREV are not specified, they default to WORKING for\n"
+ " working copy targets and to HEAD for URL targets.\n"
+ "\n"
+ " Either or both OLD-TGT and NEW-TGT may also be paths to unversioned\n"
+ " targets. Revisions cannot be specified for unversioned targets.\n"
+ " Both targets must be of the same node kind (file or directory).\n"
+ " Diffing unversioned targets against URL targets is not supported.\n"
+ "\n"
+ " 4. Shorthand for 'svn diff --old=OLD-URL[@OLDREV] --new=NEW-URL[@NEWREV]'\n"
+ " 5. Shorthand for 'svn diff --old=OLD-URL[@OLDREV] --new=NEW-PATH[@NEWREV]'\n"
+ " 6. Shorthand for 'svn diff --old=OLD-PATH[@OLDREV] --new=NEW-URL[@NEWREV]'\n"),
+ {'r', 'c', opt_old_cmd, opt_new_cmd, 'N', opt_depth, opt_diff_cmd,
+ opt_internal_diff, 'x', opt_no_diff_added, opt_no_diff_deleted,
+ opt_ignore_properties, opt_properties_only,
+ opt_show_copies_as_adds, opt_notice_ancestry, opt_summarize, opt_changelist,
+ opt_force, opt_xml, opt_use_git_diff_format, opt_patch_compatible} },
+ { "export", svn_cl__export, {0}, N_
+ ("Create an unversioned copy of a tree.\n"
+ "usage: 1. export [-r REV] URL[@PEGREV] [PATH]\n"
+ " 2. export [-r REV] PATH1[@PEGREV] [PATH2]\n"
+ "\n"
+ " 1. Exports a clean directory tree from the repository specified by\n"
+ " URL, at revision REV if it is given, otherwise at HEAD, into\n"
+ " PATH. If PATH is omitted, the last component of the URL is used\n"
+ " for the local directory name.\n"
+ "\n"
+ " 2. Exports a clean directory tree from the working copy specified by\n"
+ " PATH1, at revision REV if it is given, otherwise at WORKING, into\n"
+ " PATH2. If PATH2 is omitted, the last component of the PATH1 is used\n"
+ " for the local directory name. If REV is not specified, all local\n"
+ " changes will be preserved. Files not under version control will\n"
+ " not be copied.\n"
+ "\n"
+ " If specified, PEGREV determines in which revision the target is first\n"
+ " looked up.\n"),
+ {'r', 'q', 'N', opt_depth, opt_force, opt_native_eol, opt_ignore_externals,
+ opt_ignore_keywords} },
+
+ { "help", svn_cl__help, {"?", "h"}, N_
+ ("Describe the usage of this program or its subcommands.\n"
+ "usage: help [SUBCOMMAND...]\n"),
+ {0} },
+ /* This command is also invoked if we see option "--help", "-h" or "-?". */
+
+ { "import", svn_cl__import, {0}, N_
+ ("Commit an unversioned file or tree into the repository.\n"
+ "usage: import [PATH] URL\n"
+ "\n"
+ " Recursively commit a copy of PATH to URL.\n"
+ " If PATH is omitted '.' is assumed.\n"
+ " Parent directories are created as necessary in the repository.\n"
+ " If PATH is a directory, the contents of the directory are added\n"
+ " directly under URL.\n"
+ " Unversionable items such as device files and pipes are ignored\n"
+ " if --force is specified.\n"),
+ {'q', 'N', opt_depth, opt_autoprops, opt_force, opt_no_autoprops,
+ SVN_CL__LOG_MSG_OPTIONS, opt_no_ignore} },
+
+ { "info", svn_cl__info, {0}, N_
+ ("Display information about a local or remote item.\n"
+ "usage: info [TARGET[@REV]...]\n"
+ "\n"
+ " Print information about each TARGET (default: '.').\n"
+ " TARGET may be either a working-copy path or URL. If specified, REV\n"
+ " determines in which revision the target is first looked up.\n"),
+ {'r', 'R', opt_depth, opt_targets, opt_incremental, opt_xml, opt_changelist}
+ },
+
+ { "list", svn_cl__list, {"ls"}, N_
+ ("List directory entries in the repository.\n"
+ "usage: list [TARGET[@REV]...]\n"
+ "\n"
+ " List each TARGET file and the contents of each TARGET directory as\n"
+ " they exist in the repository. If TARGET is a working copy path, the\n"
+ " corresponding repository URL will be used. If specified, REV determines\n"
+ " in which revision the target is first looked up.\n"
+ "\n"
+ " The default TARGET is '.', meaning the repository URL of the current\n"
+ " working directory.\n"
+ "\n"
+ " With --verbose, the following fields will be shown for each item:\n"
+ "\n"
+ " Revision number of the last commit\n"
+ " Author of the last commit\n"
+ " If locked, the letter 'O'. (Use 'svn info URL' to see details)\n"
+ " Size (in bytes)\n"
+ " Date and time of the last commit\n"),
+ {'r', 'v', 'R', opt_depth, opt_incremental, opt_xml,
+ opt_include_externals },
+ {{opt_include_externals, N_("include externals definitions")}} },
+
+ { "lock", svn_cl__lock, {0}, N_
+ ("Lock working copy paths or URLs in the repository, so that\n"
+ "no other user can commit changes to them.\n"
+ "usage: lock TARGET...\n"
+ "\n"
+ " Use --force to steal the lock from another user or working copy.\n"),
+ { opt_targets, 'm', 'F', opt_force_log, opt_encoding, opt_force },
+ {{'F', N_("read lock comment from file ARG")},
+ {'m', N_("specify lock comment ARG")},
+ {opt_force_log, N_("force validity of lock comment source")}} },
+
+ { "log", svn_cl__log, {0}, N_
+ ("Show the log messages for a set of revision(s) and/or path(s).\n"
+ "usage: 1. log [PATH][@REV]\n"
+ " 2. log URL[@REV] [PATH...]\n"
+ "\n"
+ " 1. Print the log messages for the URL corresponding to PATH\n"
+ " (default: '.'). If specified, REV is the revision in which the\n"
+ " URL is first looked up, and the default revision range is REV:1.\n"
+ " If REV is not specified, the default revision range is BASE:1,\n"
+ " since the URL might not exist in the HEAD revision.\n"
+ "\n"
+ " 2. Print the log messages for the PATHs (default: '.') under URL.\n"
+ " If specified, REV is the revision in which the URL is first\n"
+ " looked up, and the default revision range is REV:1; otherwise,\n"
+ " the URL is looked up in HEAD, and the default revision range is\n"
+ " HEAD:1.\n"
+ "\n"
+ " Multiple '-c' or '-r' options may be specified (but not a\n"
+ " combination of '-c' and '-r' options), and mixing of forward and\n"
+ " reverse ranges is allowed.\n"
+ "\n"
+ " With -v, also print all affected paths with each log message.\n"
+ " With -q, don't print the log message body itself (note that this is\n"
+ " compatible with -v).\n"
+ "\n"
+ " Each log message is printed just once, even if more than one of the\n"
+ " affected paths for that revision were explicitly requested. Logs\n"
+ " follow copy history by default. Use --stop-on-copy to disable this\n"
+ " behavior, which can be useful for determining branchpoints.\n"
+ "\n"
+ " The --depth option is only valid in combination with the --diff option\n"
+ " and limits the scope of the displayed diff to the specified depth.\n"
+ "\n"
+ " If the --search option is used, log messages are displayed only if the\n"
+ " provided search pattern matches any of the author, date, log message\n"
+ " text (unless --quiet is used), or, if the --verbose option is also\n"
+ " provided, a changed path.\n"
+ " The search pattern may include \"glob syntax\" wildcards:\n"
+ " ? matches any single character\n"
+ " * matches a sequence of arbitrary characters\n"
+ " [abc] matches any of the characters listed inside the brackets\n"
+ " If multiple --search options are provided, a log message is shown if\n"
+ " it matches any of the provided search patterns. If the --search-and\n"
+ " option is used, that option's argument is combined with the pattern\n"
+ " from the previous --search or --search-and option, and a log message\n"
+ " is shown only if it matches the combined search pattern.\n"
+ " If --limit is used in combination with --search, --limit restricts the\n"
+ " number of log messages searched, rather than restricting the output\n"
+ " to a particular number of matching log messages.\n"
+ "\n"
+ " Examples:\n"
+ "\n"
+ " Show the latest 5 log messages for the current working copy\n"
+ " directory and display paths changed in each commit:\n"
+ " svn log -l 5 -v\n"
+ "\n"
+ " Show the log for bar.c as of revision 42:\n"
+ " svn log bar.c@42\n"
+ "\n"
+ " Show log messages and diffs for each commit to foo.c:\n"
+ " svn log --diff http://www.example.com/repo/project/foo.c\n"
+ " (Because the above command uses a full URL it does not require\n"
+ " a working copy.)\n"
+ "\n"
+ " Show log messages for the children foo.c and bar.c of the directory\n"
+ " '/trunk' as it appeared in revision 50, using the ^/ URL shortcut:\n"
+ " svn log ^/trunk@50 foo.c bar.c\n"
+ "\n"
+ " Show the log messages for any incoming changes to foo.c during the\n"
+ " next 'svn update':\n"
+ " svn log -r BASE:HEAD foo.c\n"
+ "\n"
+ " Show the log message for the revision in which /branches/foo\n"
+ " was created:\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', opt_search,
+ opt_search_and, },
+ {{opt_with_revprop, N_("retrieve revision property ARG")},
+ {'c', N_("the change made in revision ARG")}} },
+
+ { "merge", svn_cl__merge, {0}, 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 'complete' merge)\n"
+" 2. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
+" (the 'cherry-pick' merge)\n"
+" 3. merge SOURCE1[@REV1] SOURCE2[@REV2] [TARGET_WCPATH]\n"
+" (the '2-URL' merge)\n"
+"\n"
+" 1. This form, with one source path and no revision range, is called\n"
+" a 'complete' merge:\n"
+"\n"
+" svn merge SOURCE[@REV] [TARGET_WCPATH]\n"
+"\n"
+" The complete merge is used for the 'sync' and 'reintegrate' merges\n"
+" in the 'feature branch' pattern described below. It finds all the\n"
+" changes on the source branch that have not already been merged to the\n"
+" target branch, and merges them into the working copy. Merge tracking\n"
+" is used to know which changes have already been merged.\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 generally\n"
+" assumed. There are some special cases:\n"
+"\n"
+" - If SOURCE is a URL:\n"
+"\n"
+" - If the basename of the URL and the basename of '.' are the\n"
+" same, then the differences are applied to '.'. Otherwise,\n"
+" if a file with the same basename as that of the URL is found\n"
+" within '.', then the differences are applied to that file.\n"
+" In all other cases, the target defaults to '.'.\n"
+"\n"
+" - If SOURCE is a working copy path:\n"
+"\n"
+" - If the source is a file, then differences are applied to that\n"
+" file (useful for reverse-merging earlier changes). Otherwise,\n"
+" if the source is a directory, then the target defaults to '.'.\n"
+"\n"
+" In normal usage the working copy should be up to date, at a single\n"
+" revision, with no local modifications and no switched subtrees.\n"
+"\n"
+" - The 'Feature Branch' Merging Pattern -\n"
+"\n"
+" In this commonly used work flow, known also as the 'development\n"
+" branch' pattern, a developer creates a branch and commits a series of\n"
+" changes that implement a new feature. The developer periodically\n"
+" merges all the latest changes from the parent branch so as to keep the\n"
+" development branch up to date with those changes. When the feature is\n"
+" complete, the developer performs a merge from the feature branch to\n"
+" the parent branch to re-integrate the changes.\n"
+"\n"
+" parent --+----------o------o-o-------------o--\n"
+" \\ \\ \\ /\n"
+" \\ merge merge merge\n"
+" \\ \\ \\ /\n"
+" feature +--o-o-------o----o-o----o-------\n"
+"\n"
+" A merge from the parent branch to the feature branch is called a\n"
+" 'sync' or 'catch-up' merge, and a merge from the feature branch to the\n"
+" parent branch is called a 'reintegrate' merge.\n"
+"\n"
+" - Sync Merge Example -\n"
+" ............\n"
+" . .\n"
+" trunk --+------------L--------------R------\n"
+" \\ \\\n"
+" \\ |\n"
+" \\ v\n"
+" feature +------------------------o-----\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 (trunk@100)\n"
+" and R marks the right side (trunk@200) of the merge source. 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"
+" - Reintegrate Merge Example -\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"
+" rW rX\n"
+" trunk ------+--------------------L------------------o\n"
+" \\ . ^\n"
+" \\ ............. /\n"
+" \\ . /\n"
+" feature +--------------------------------R\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 ^/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"
+"\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 generally\n"
+" assumed. The special cases noted above in the 'complete' merge form\n"
+" also apply here.\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>'. Undoing changes like this is also known\n"
+" as performing a 'reverse merge'.\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 '2-URL merge':\n"
+"\n"
+" svn merge SOURCE1[@REV1] SOURCE2[@REV2] [TARGET_WCPATH]\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"
+" Two source URLs are specified, identifying two trees on the same\n"
+" branch or on different branches. The trees are compared and the\n"
+" difference from SOURCE1@REV1 to SOURCE2@REV2 is applied to the\n"
+" working copy of the target branch at TARGET_WCPATH. The target\n"
+" branch may be the same as one or both sources, or different again.\n"
+" The three branches involved can be completely unrelated.\n"
+"\n"
+" TARGET_WCPATH is a working copy path; if omitted, '.' is generally\n"
+" assumed. The special cases noted above in the 'complete' merge form\n"
+" also apply here.\n"
+"\n"
+" SOURCE1 and/or SOURCE2 can also be specified as a working copy path,\n"
+" in which case the merge source URL is derived from the working copy.\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, 'v'} },
+
+ { "mergeinfo", svn_cl__mergeinfo, {0}, N_
+ ("Display merge-related information.\n"
+ "usage: 1. mergeinfo SOURCE[@REV] [TARGET[@REV]]\n"
+ " 2. mergeinfo --show-revs=WHICH SOURCE[@REV] [TARGET[@REV]]\n"
+ "\n"
+ " 1. Summarize the history of merging between SOURCE and TARGET. The graph\n"
+ " shows, from left to right:\n"
+ " the youngest common ancestor of the branches;\n"
+ " the latest full merge in either direction, and thus the common base\n"
+ " that will be used for the next complete merge;\n"
+ " the repository path and revision number of the tip of each branch.\n"
+ "\n"
+ " 2. Print the revision numbers on SOURCE that have been merged to TARGET\n"
+ " (with --show-revs=merged), or that have not been merged to TARGET\n"
+ " (with --show-revs=eligible). Print only revisions in which there was\n"
+ " at least one change in SOURCE.\n"
+ "\n"
+ " If --revision (-r) is provided, filter the displayed information to\n"
+ " show only that which is associated with the revisions within the\n"
+ " specified range. Revision numbers, dates, and the 'HEAD' keyword are\n"
+ " valid range values.\n"
+ "\n"
+ " SOURCE and TARGET are the source and target branch URLs, respectively.\n"
+ " (If a WC path is given, the corresponding base URL is used.) The default\n"
+ " TARGET is the current working directory ('.'). REV specifies the revision\n"
+ " to be considered the tip of the branch; the default for SOURCE is HEAD,\n"
+ " and the default for TARGET is HEAD for a URL or BASE for a WC path.\n"
+ "\n"
+ " The depth can be 'empty' or 'infinity'; the default is 'empty'.\n"),
+ {'r', 'R', opt_depth, opt_show_revs} },
+
+ { "mkdir", svn_cl__mkdir, {0}, N_
+ ("Create a new directory under version control.\n"
+ "usage: 1. mkdir PATH...\n"
+ " 2. mkdir URL...\n"
+ "\n"
+ " Create version controlled directories.\n"
+ "\n"
+ " 1. Each directory specified by a working copy PATH is created locally\n"
+ " and scheduled for addition upon the next commit.\n"
+ "\n"
+ " 2. Each directory specified by a URL is created in the repository via\n"
+ " an immediate commit.\n"
+ "\n"
+ " In both cases, all the intermediate directories must already exist,\n"
+ " unless the --parents option is given.\n"),
+ {'q', opt_parents, SVN_CL__LOG_MSG_OPTIONS} },
+
+ { "move", svn_cl__move, {"mv", "rename", "ren"}, N_
+ ("Move (rename) an item in a working copy or repository.\n"
+ "usage: move SRC... DST\n"
+ "\n"
+ " SRC and DST can both be working copy (WC) paths or URLs:\n"
+ " WC -> WC: move an item in a working copy, as a local change to\n"
+ " be committed later (with or without further changes)\n"
+ " URL -> URL: move an item in the repository directly, immediately\n"
+ " creating a new revision in the repository\n"
+ " All the SRCs must be of the same type. When moving multiple sources,\n"
+ " they will be added as children of DST, which must be a directory.\n"
+ "\n"
+ " SRC and DST of WC -> WC moves must be committed in the same revision.\n"
+ " Furthermore, WC -> WC moves will refuse to move a mixed-revision subtree.\n"
+ " To avoid unnecessary conflicts, it is recommended to run 'svn update'\n"
+ " to update the subtree to a single revision before moving it.\n"
+ " The --allow-mixed-revisions option is provided for backward compatibility.\n"
+ "\n"
+ " The --revision option has no use and is deprecated.\n"),
+ {'r', 'q', opt_force, opt_parents, opt_allow_mixed_revisions,
+ SVN_CL__LOG_MSG_OPTIONS} },
+
+ { "patch", svn_cl__patch, {0}, N_
+ ("Apply a patch to a working copy.\n"
+ "usage: patch PATCHFILE [WCPATH]\n"
+ "\n"
+ " Apply a unidiff patch in PATCHFILE to the working copy WCPATH.\n"
+ " If WCPATH is omitted, '.' is assumed.\n"
+ "\n"
+ " A unidiff patch suitable for application to a working copy can be\n"
+ " produced with the 'svn diff' command or third-party diffing tools.\n"
+ " Any non-unidiff content of PATCHFILE is ignored, except for Subversion\n"
+ " property diffs as produced by 'svn diff'.\n"
+ "\n"
+ " Changes listed in the patch will either be applied or rejected.\n"
+ " If a change does not match at its exact line offset, it may be applied\n"
+ " earlier or later in the file if a match is found elsewhere for the\n"
+ " surrounding lines of context provided by the patch.\n"
+ " A change may also be applied with fuzz, which means that one\n"
+ " or more lines of context are ignored when matching the change.\n"
+ " If no matching context can be found for a change, the change conflicts\n"
+ " and will be written to a reject file with the extension .svnpatch.rej.\n"
+ "\n"
+ " For each patched file 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 (with local uncommitted changes)\n"
+ "\n"
+ " Changes applied with an offset or fuzz are reported on lines starting\n"
+ " with the '>' symbol. You should review such changes carefully.\n"
+ "\n"
+ " If the patch removes all content from a file, that file is scheduled\n"
+ " for deletion. If the patch creates a new file, that file is scheduled\n"
+ " for addition. Use 'svn revert' to undo deletions and additions you\n"
+ " do not agree with.\n"
+ "\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"
+ " 'svn update -r N', apply the patch, and then update back to the\n"
+ " HEAD revision. This way, conflicts can be resolved interactively.\n"
+ ),
+ {'q', opt_dry_run, opt_strip, opt_reverse_diff,
+ opt_ignore_whitespace} },
+
+ { "propdel", svn_cl__propdel, {"pdel", "pd"}, N_
+ ("Remove a property from files, dirs, or revisions.\n"
+ "usage: 1. propdel PROPNAME [PATH...]\n"
+ " 2. propdel PROPNAME --revprop -r REV [TARGET]\n"
+ "\n"
+ " 1. Removes versioned props in working copy.\n"
+ " 2. Removes unversioned remote prop on repos revision.\n"
+ " TARGET only determines which repository to access.\n"),
+ {'q', 'R', opt_depth, 'r', opt_revprop, opt_changelist} },
+
+ { "propedit", svn_cl__propedit, {"pedit", "pe"}, N_
+ ("Edit a property with an external editor.\n"
+ "usage: 1. propedit PROPNAME TARGET...\n"
+ " 2. propedit PROPNAME --revprop -r REV [TARGET]\n"
+ "\n"
+ " 1. Edits versioned prop in working copy or repository.\n"
+ " 2. Edits unversioned remote prop on repos revision.\n"
+ " TARGET only determines which repository to access.\n"
+ "\n"
+ " See 'svn help propset' for more on setting properties.\n"),
+ {'r', opt_revprop, SVN_CL__LOG_MSG_OPTIONS, opt_force} },
+
+ { "propget", svn_cl__propget, {"pget", "pg"}, N_
+ ("Print the value of a property on files, dirs, or revisions.\n"
+ "usage: 1. propget PROPNAME [TARGET[@REV]...]\n"
+ " 2. propget PROPNAME --revprop -r REV [TARGET]\n"
+ "\n"
+ " 1. Prints versioned props. If specified, REV determines in which\n"
+ " revision the target is first looked up.\n"
+ " 2. Prints unversioned remote prop on repos revision.\n"
+ " TARGET only determines which repository to access.\n"
+ "\n"
+ " With --verbose, the target path and the property name are printed on\n"
+ " separate lines before each value, like 'svn proplist --verbose'.\n"
+ " Otherwise, if there is more than one TARGET or a depth other than\n"
+ " 'empty', the target path is printed on the same line before each value.\n"
+ "\n"
+ " By default, an extra newline is printed after the property value so that\n"
+ " the output looks pretty. With a single TARGET and depth 'empty', you can\n"
+ " use the --strict option to disable this (useful when redirecting a binary\n"
+ " property value to a file, for example).\n"),
+ {'v', 'R', opt_depth, 'r', opt_revprop, opt_strict, opt_xml,
+ opt_changelist, opt_show_inherited_props },
+ {{'v', N_("print path, name and value on separate lines")},
+ {opt_strict, N_("don't print an extra newline")}} },
+
+ { "proplist", svn_cl__proplist, {"plist", "pl"}, N_
+ ("List all properties on files, dirs, or revisions.\n"
+ "usage: 1. proplist [TARGET[@REV]...]\n"
+ " 2. proplist --revprop -r REV [TARGET]\n"
+ "\n"
+ " 1. Lists versioned props. If specified, REV determines in which\n"
+ " revision the target is first looked up.\n"
+ " 2. Lists unversioned remote props on repos revision.\n"
+ " TARGET only determines which repository to access.\n"
+ "\n"
+ " With --verbose, the property values are printed as well, like 'svn propget\n"
+ " --verbose'. With --quiet, the paths are not printed.\n"),
+ {'v', 'R', opt_depth, 'r', 'q', opt_revprop, opt_xml, opt_changelist,
+ opt_show_inherited_props },
+ {{'v', N_("print path, name and value on separate lines")},
+ {'q', N_("don't print the path")}} },
+
+ { "propset", svn_cl__propset, {"pset", "ps"}, N_
+ ("Set the value of a property on files, dirs, or revisions.\n"
+ "usage: 1. propset PROPNAME PROPVAL PATH...\n"
+ " 2. propset PROPNAME --revprop -r REV PROPVAL [TARGET]\n"
+ "\n"
+ " 1. Changes a versioned file or directory property in a working copy.\n"
+ " 2. Changes an unversioned property on a repository revision.\n"
+ " (TARGET only determines which repository to access.)\n"
+ "\n"
+ " The value may be provided with the --file option instead of PROPVAL.\n"
+ "\n"
+ " Property names starting with 'svn:' are reserved. Subversion recognizes\n"
+ " the following special versioned properties on a file:\n"
+ " svn:keywords - Keywords to be expanded. Valid keywords are:\n"
+ " URL, HeadURL - The URL for the head version of the file.\n"
+ " Author, LastChangedBy - The last person to modify the file.\n"
+ " Date, LastChangedDate - The date/time the file was last modified.\n"
+ " Rev, Revision, - The last revision the file changed.\n"
+ " LastChangedRevision\n"
+ " Id - A compressed summary of the previous four.\n"
+ " Header - Similar to Id but includes the full URL.\n"
+ "\n"
+ " Custom keywords can be defined with a format string separated from\n"
+ " the keyword name with '='. Valid format substitutions are:\n"
+ " %a - The author of the revision given by %r.\n"
+ " %b - The basename of the URL of the file.\n"
+ " %d - Short format of the date of the revision given by %r.\n"
+ " %D - Long format of the date of the revision given by %r.\n"
+ " %P - The file's path, relative to the repository root.\n"
+ " %r - The number of the revision which last changed the file.\n"
+ " %R - The URL to the root of the repository.\n"
+ " %u - The URL of the file.\n"
+ " %_ - A space (keyword definitions cannot contain a literal space).\n"
+ " %% - A literal '%'.\n"
+ " %H - Equivalent to %P%_%r%_%d%_%a.\n"
+ " %I - Equivalent to %b%_%r%_%d%_%a.\n"
+ " Example custom keyword definition: MyKeyword=%r%_%a%_%P\n"
+ " Once a custom keyword has been defined for a file, it can be used\n"
+ " within the file like any other keyword: $MyKeyword$\n"
+ "\n"
+ " svn:executable - If present, make the file executable. Use\n"
+ " 'svn propdel svn:executable PATH...' to clear.\n"
+ " svn:eol-style - One of 'native', 'LF', 'CR', 'CRLF'.\n"
+ " svn:mime-type - The mimetype of the file. Used to determine\n"
+ " whether to merge the file, and how to serve it from Apache.\n"
+ " A mimetype beginning with 'text/' (or an absent mimetype) is\n"
+ " treated as text. Anything else is treated as binary.\n"
+ " svn:needs-lock - If present, indicates that the file should be locked\n"
+ " before it is modified. Makes the working copy file read-only\n"
+ " when it is not locked. Use 'svn propdel svn:needs-lock PATH...'\n"
+ " to clear.\n"
+ "\n"
+ " Subversion recognizes the following special versioned properties on a\n"
+ " directory:\n"
+ " svn:ignore - A list of file glob patterns to ignore, one per line.\n"
+ " svn:global-ignores - Like svn:ignore, but inheritable.\n"
+ " svn:externals - A list of module specifiers, one per line, in the\n"
+ " following format similar to the syntax of 'svn checkout':\n"
+ " [-r REV] URL[@PEG] LOCALPATH\n"
+ " Example:\n"
+ " http://example.com/repos/zig foo/bar\n"
+ " The LOCALPATH is relative to the directory having this property.\n"
+ " To pin the external to a known revision, specify the optional REV:\n"
+ " -r25 http://example.com/repos/zig foo/bar\n"
+ " To unambiguously identify an element at a path which may have been\n"
+ " subsequently deleted or renamed, specify the optional PEG revision:\n"
+ " -r25 http://example.com/repos/zig@42 foo/bar\n"
+ " The URL may be a full URL or a relative URL starting with one of:\n"
+ " ../ to the parent directory of the extracted external\n"
+ " ^/ to the repository root\n"
+ " / to the server root\n"
+ " // to the URL scheme\n"
+ " Use of the following format is discouraged but is supported for\n"
+ " interoperability with Subversion 1.4 and earlier clients:\n"
+ " LOCALPATH [-r PEG] URL\n"
+ " The ambiguous format 'relative_path relative_path' is taken as\n"
+ " 'relative_url relative_path' with peg revision support.\n"
+ " Lines starting with a '#' character are ignored.\n"),
+ {'F', opt_encoding, 'q', 'r', opt_targets, 'R', opt_depth, opt_revprop,
+ opt_force, opt_changelist },
+ {{'F', N_("read property value from file ARG")}} },
+
+ { "relocate", svn_cl__relocate, {0}, N_
+ ("Relocate the working copy to point to a different repository root URL.\n"
+ "usage: 1. relocate FROM-PREFIX TO-PREFIX [PATH...]\n"
+ " 2. relocate TO-URL [PATH]\n"
+ "\n"
+ " Rewrite working copy URL metadata to reflect a syntactic change only.\n"
+ " This is used when a repository's root URL changes (such as a scheme\n"
+ " or hostname change) but your working copy still reflects the same\n"
+ " directory within the same repository.\n"
+ "\n"
+ " 1. FROM-PREFIX and TO-PREFIX are initial substrings of the working\n"
+ " copy's current and new URLs, respectively. (You may specify the\n"
+ " complete old and new URLs if you wish.) Use 'svn info' to determine\n"
+ " the current working copy URL.\n"
+ "\n"
+ " 2. TO-URL is the (complete) new repository URL to use for PATH.\n"
+ "\n"
+ " Examples:\n"
+ " svn relocate http:// svn:// project1 project2\n"
+ " svn relocate http://www.example.com/repo/project \\\n"
+ " svn://svn.example.com/repo/project\n"),
+ {opt_ignore_externals} },
+
+ { "resolve", svn_cl__resolve, {0}, N_
+ ("Resolve conflicts on working copy files or directories.\n"
+ "usage: resolve [PATH...]\n"
+ "\n"
+ " By default, perform interactive conflict resolution on PATH.\n"
+ " In this mode, the command is recursive by default (depth 'infinity').\n"
+ "\n"
+ " The --accept=ARG option prevents interactive prompting and forces\n"
+ " conflicts on PATH to be resolved in the manner specified by ARG.\n"
+ " In this mode, the command is not recursive by default (depth 'empty').\n"),
+ {opt_targets, 'R', opt_depth, 'q', opt_accept},
+ {{opt_accept, N_("specify automatic conflict resolution source\n"
+ " "
+ "('base', 'working', 'mine-conflict',\n"
+ " "
+ "'theirs-conflict', 'mine-full', 'theirs-full')")}} },
+
+ { "resolved", svn_cl__resolved, {0}, N_
+ ("Remove 'conflicted' state on working copy files or directories.\n"
+ "usage: resolved PATH...\n"
+ "\n"
+ " Note: this subcommand does not semantically resolve conflicts or\n"
+ " remove conflict markers; it merely removes the conflict-related\n"
+ " artifact files and allows PATH to be committed again. It has been\n"
+ " deprecated in favor of running 'svn resolve --accept working'.\n"),
+ {opt_targets, 'R', opt_depth, 'q'} },
+
+ { "revert", svn_cl__revert, {0}, N_
+ ("Restore pristine working copy state (undo local changes).\n"
+ "usage: revert PATH...\n"
+ "\n"
+ " Revert changes in the working copy at or within PATH, and remove\n"
+ " conflict markers as well, if any.\n"
+ "\n"
+ " This subcommand does not revert already committed changes.\n"
+ " For information about undoing already committed changes, search\n"
+ " the output of 'svn help merge' for 'undo'.\n"),
+ {opt_targets, 'R', opt_depth, 'q', opt_changelist} },
+
+ { "status", svn_cl__status, {"stat", "st"}, N_
+ ("Print the status of working copy files and directories.\n"
+ "usage: status [PATH...]\n"
+ "\n"
+ " With no args, print only locally modified items (no network access).\n"
+ " With -q, print only summary information about locally modified items.\n"
+ " With -u, add working revision and server out-of-date information.\n"
+ " With -v, print full revision information on every item.\n"
+ "\n"
+ " The first seven columns in the output are each one character wide:\n"
+ " First column: Says if item was added, deleted, or otherwise changed\n"
+ " ' ' no modifications\n"
+ " 'A' Added\n"
+ " 'C' Conflicted\n"
+ " 'D' Deleted\n"
+ " 'I' Ignored\n"
+ " 'M' Modified\n"
+ " 'R' Replaced\n"
+ " 'X' an unversioned directory created by an externals definition\n"
+ " '?' item is not under version control\n"
+ " '!' item is missing (removed by non-svn command) or incomplete\n"
+ " '~' versioned item obstructed by some item of a different kind\n"
+ " Second column: Modifications of a file's or directory's properties\n"
+ " ' ' no modifications\n"
+ " 'C' Conflicted\n"
+ " 'M' Modified\n"
+ " Third column: Whether the working copy is locked for writing by\n"
+ " another Subversion client modifying the working copy\n"
+ " ' ' not locked for writing\n"
+ " 'L' locked for writing\n"
+ " Fourth column: Scheduled commit will contain addition-with-history\n"
+ " ' ' no history scheduled with commit\n"
+ " '+' history scheduled with commit\n"
+ " Fifth column: Whether the item is switched or a file external\n"
+ " ' ' normal\n"
+ " 'S' the item has a Switched URL relative to the parent\n"
+ " 'X' a versioned file created by an eXternals definition\n"
+ " Sixth column: Whether the item is locked in repository for exclusive commit\n"
+ " (without -u)\n"
+ " ' ' not locked by this working copy\n"
+ " 'K' locked by this working copy, but lock might be stolen or broken\n"
+ " (with -u)\n"
+ " ' ' not locked in repository, not locked by this working copy\n"
+ " 'K' locked in repository, lock owned by this working copy\n"
+ " 'O' locked in repository, lock owned by another working copy\n"
+ " 'T' locked in repository, lock owned by this working copy was stolen\n"
+ " 'B' not locked in repository, lock owned by this working copy is broken\n"
+ " Seventh column: Whether the item is the victim of a tree conflict\n"
+ " ' ' normal\n"
+ " 'C' tree-Conflicted\n"
+ " If the item is a tree conflict victim, an additional line is printed\n"
+ " after the item's status line, explaining the nature of the conflict.\n"
+ "\n"
+ " The out-of-date information appears in the ninth column (with -u):\n"
+ " '*' a newer revision exists on the server\n"
+ " ' ' the working copy is up to date\n"
+ "\n"
+ " Remaining fields are variable width and delimited by spaces:\n"
+ " The working revision (with -u or -v; '-' if the item is copied)\n"
+ " The last committed revision and last committed author (with -v)\n"
+ " The working copy path is always the final field, so it can\n"
+ " include spaces.\n"
+ "\n"
+ " The presence of a question mark ('?') where a working revision, last\n"
+ " committed revision, or last committed author was expected indicates\n"
+ " that the information is unknown or irrelevant given the state of the\n"
+ " item (for example, when the item is the result of a copy operation).\n"
+ " The question mark serves as a visual placeholder to facilitate parsing.\n"
+ "\n"
+ " Example output:\n"
+ " svn status wc\n"
+ " M wc/bar.c\n"
+ " A + wc/qax.c\n"
+ "\n"
+ " svn status -u wc\n"
+ " M 965 wc/bar.c\n"
+ " * 965 wc/foo.c\n"
+ " A + - wc/qax.c\n"
+ " Status against revision: 981\n"
+ "\n"
+ " svn status --show-updates --verbose wc\n"
+ " M 965 938 kfogel wc/bar.c\n"
+ " * 965 922 sussman wc/foo.c\n"
+ " A + - 687 joe wc/qax.c\n"
+ " 965 687 joe wc/zig.c\n"
+ " Status against revision: 981\n"
+ "\n"
+ " svn status\n"
+ " M wc/bar.c\n"
+ " ! C wc/qaz.c\n"
+ " > local missing, incoming edit upon update\n"
+ " D wc/qax.c\n"),
+ { 'u', 'v', 'N', opt_depth, 'q', opt_no_ignore, opt_incremental, opt_xml,
+ opt_ignore_externals, opt_changelist},
+ {{'q', N_("don't print unversioned items")}} },
+
+ { "switch", svn_cl__switch, {"sw"}, N_
+ ("Update the working copy to a different URL within the same repository.\n"
+ "usage: 1. switch URL[@PEGREV] [PATH]\n"
+ " 2. switch --relocate FROM-PREFIX TO-PREFIX [PATH...]\n"
+ "\n"
+ " 1. Update the working copy to mirror a new URL within the repository.\n"
+ " This behavior is similar to 'svn update', and is the way to\n"
+ " move a working copy to a branch or tag within the same repository.\n"
+ " If specified, PEGREV determines in which revision the target is first\n"
+ " looked up.\n"
+ "\n"
+ " If --force is used, unversioned obstructing paths in the working\n"
+ " copy do not automatically cause a failure if the switch attempts to\n"
+ " add the same path. If the obstructing path is the same type (file\n"
+ " or directory) as the corresponding path in the repository it becomes\n"
+ " versioned but its contents are left 'as-is' in the working copy.\n"
+ " This means that an obstructing directory's unversioned children may\n"
+ " also obstruct and become versioned. For files, any content differences\n"
+ " between the obstruction and the repository are treated like a local\n"
+ " modification to the working copy. All properties from the repository\n"
+ " are applied to the obstructing path.\n"
+ "\n"
+ " Use the --set-depth option to set a new working copy depth on the\n"
+ " targets of this operation.\n"
+ "\n"
+ " By default, Subversion will refuse to switch a working copy path to\n"
+ " a new URL with which it shares no common version control ancestry.\n"
+ " Use the '--ignore-ancestry' option to override this sanity check.\n"
+ "\n"
+ " 2. The '--relocate' option is deprecated. This syntax is equivalent to\n"
+ " 'svn relocate FROM-PREFIX TO-PREFIX [PATH]'.\n"
+ "\n"
+ " See also 'svn help update' for a list of possible characters\n"
+ " reporting the action taken.\n"
+ "\n"
+ " Examples:\n"
+ " svn switch ^/branches/1.x-release\n"
+ " svn switch --relocate http:// svn://\n"
+ " svn switch --relocate http://www.example.com/repo/project \\\n"
+ " svn://svn.example.com/repo/project\n"),
+ { 'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_relocate,
+ opt_ignore_externals, opt_ignore_ancestry, opt_force, opt_accept},
+ {{opt_ignore_ancestry,
+ N_("allow switching to a node with no common ancestor")}}
+ },
+
+ { "unlock", svn_cl__unlock, {0}, N_
+ ("Unlock working copy paths or URLs.\n"
+ "usage: unlock TARGET...\n"
+ "\n"
+ " Use --force to break the lock.\n"),
+ { opt_targets, opt_force } },
+
+ { "update", svn_cl__update, {"up"}, N_
+ ("Bring changes from the repository into the working copy.\n"
+ "usage: update [PATH...]\n"
+ "\n"
+ " If no revision is given, bring working copy up-to-date with HEAD rev.\n"
+ " Else synchronize working copy to revision given by -r.\n"
+ "\n"
+ " For each updated 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 'B' in the third column signifies that the lock for the file has\n"
+ " been broken or stolen.\n"
+ " A 'C' in the fourth 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"
+ " If --force is used, unversioned obstructing paths in the working\n"
+ " copy do not automatically cause a failure if the update attempts to\n"
+ " add the same path. If the obstructing path is the same type (file\n"
+ " or directory) as the corresponding path in the repository it becomes\n"
+ " versioned but its contents are left 'as-is' in the working copy.\n"
+ " This means that an obstructing directory's unversioned children may\n"
+ " also obstruct and become versioned. For files, any content differences\n"
+ " between the obstruction and the repository are treated like a local\n"
+ " modification to the working copy. All properties from the repository\n"
+ " are applied to the obstructing path. Obstructing paths are reported\n"
+ " in the first column with code 'E'.\n"
+ "\n"
+ " If the specified update target is missing from the working copy but its\n"
+ " immediate parent directory is present, checkout the target into its\n"
+ " parent directory at the specified depth. If --parents is specified,\n"
+ " create any missing parent directories of the target by checking them\n"
+ " out, too, at depth=empty.\n"
+ "\n"
+ " Use the --set-depth option to set a new working copy depth on the\n"
+ " targets of this operation.\n"),
+ {'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_force,
+ opt_ignore_externals, opt_changelist, opt_editor_cmd, opt_accept,
+ opt_parents} },
+
+ { "upgrade", svn_cl__upgrade, {0}, N_
+ ("Upgrade the metadata storage format for a working copy.\n"
+ "usage: upgrade [WCPATH...]\n"
+ "\n"
+ " Local modifications are preserved.\n"),
+ { 'q' } },
+
+ { NULL, NULL, {0}, NULL, {0} }
+};
+
+
+/* Version compatibility check */
+static svn_error_t *
+check_lib_versions(void)
+{
+ static const svn_version_checklist_t checklist[] =
+ {
+ { "svn_subr", svn_subr_version },
+ { "svn_client", svn_client_version },
+ { "svn_wc", svn_wc_version },
+ { "svn_ra", svn_ra_version },
+ { "svn_delta", svn_delta_version },
+ { "svn_diff", svn_diff_version },
+ { NULL, NULL }
+ };
+ SVN_VERSION_DEFINE(my_version);
+
+ return svn_ver_check_list2(&my_version, checklist, svn_ver_equal);
+}
+
+
+/* A flag to see if we've been cancelled by the client or not. */
+static volatile sig_atomic_t cancelled = FALSE;
+
+/* A signal handler to support cancellation. */
+static void
+signal_handler(int signum)
+{
+ apr_signal(signum, SIG_IGN);
+ cancelled = TRUE;
+}
+
+/* Our cancellation callback. */
+svn_error_t *
+svn_cl__check_cancel(void *baton)
+{
+ if (cancelled)
+ return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal"));
+ else
+ return SVN_NO_ERROR;
+}
+
+/* Add a --search argument to OPT_STATE.
+ * These options start a new search pattern group. */
+static void
+add_search_pattern_group(svn_cl__opt_state_t *opt_state,
+ const char *pattern,
+ apr_pool_t *result_pool)
+{
+ apr_array_header_t *group = NULL;
+
+ if (opt_state->search_patterns == NULL)
+ opt_state->search_patterns = apr_array_make(result_pool, 1,
+ sizeof(apr_array_header_t *));
+
+ group = apr_array_make(result_pool, 1, sizeof(const char *));
+ APR_ARRAY_PUSH(group, const char *) = pattern;
+ APR_ARRAY_PUSH(opt_state->search_patterns, apr_array_header_t *) = group;
+}
+
+/* Add a --search-and argument to OPT_STATE.
+ * These patterns are added to an existing pattern group, if any. */
+static void
+add_search_pattern_to_latest_group(svn_cl__opt_state_t *opt_state,
+ const char *pattern,
+ apr_pool_t *result_pool)
+{
+ apr_array_header_t *group;
+
+ if (opt_state->search_patterns == NULL)
+ {
+ add_search_pattern_group(opt_state, pattern, result_pool);
+ return;
+ }
+
+ group = APR_ARRAY_IDX(opt_state->search_patterns,
+ opt_state->search_patterns->nelts - 1,
+ apr_array_header_t *);
+ APR_ARRAY_PUSH(group, const char *) = pattern;
+}
+
+
+/*** Main. ***/
+
+/* Report and clear the error ERR, and return EXIT_FAILURE. Suppress the
+ * error message if it is SVN_ERR_IO_PIPE_WRITE_ERROR. */
+#define EXIT_ERROR(err) \
+ svn_cmdline_handle_exit_error(err, NULL, "svn: ")
+
+/* A redefinition of the public SVN_INT_ERR macro, that suppresses the
+ * error message if it is SVN_ERR_IO_PIPE_WRITE_ERROR. */
+#undef SVN_INT_ERR
+#define SVN_INT_ERR(expr) \
+ do { \
+ svn_error_t *svn_err__temp = (expr); \
+ if (svn_err__temp) \
+ return EXIT_ERROR(svn_err__temp); \
+ } while (0)
+
+static int
+sub_main(int argc, const char *argv[], apr_pool_t *pool)
+{
+ svn_error_t *err;
+ int opt_id;
+ apr_getopt_t *os;
+ svn_cl__opt_state_t opt_state = { 0, { 0 } };
+ svn_client_ctx_t *ctx;
+ apr_array_header_t *received_opts;
+ int i;
+ const svn_opt_subcommand_desc2_t *subcommand = NULL;
+ const char *dash_m_arg = NULL, *dash_F_arg = NULL;
+ svn_cl__cmd_baton_t command_baton;
+ svn_auth_baton_t *ab;
+ svn_config_t *cfg_config;
+ svn_boolean_t descend = TRUE;
+ svn_boolean_t interactive_conflicts = FALSE;
+ svn_boolean_t force_interactive = FALSE;
+ svn_cl__conflict_stats_t *conflict_stats
+ = svn_cl__conflict_stats_create(pool);
+ svn_boolean_t use_notifier = TRUE;
+ svn_boolean_t reading_file_from_stdin = FALSE;
+ apr_hash_t *changelists;
+ apr_hash_t *cfg_hash;
+
+ received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
+
+ /* Check library versions */
+ SVN_INT_ERR(check_lib_versions());
+
+#if defined(WIN32) || defined(__CYGWIN__)
+ /* Set the working copy administrative directory name. */
+ if (getenv("SVN_ASP_DOT_NET_HACK"))
+ {
+ SVN_INT_ERR(svn_wc_set_adm_dir("_svn", pool));
+ }
+#endif
+
+ /* Initialize the RA library. */
+ SVN_INT_ERR(svn_ra_initialize(pool));
+
+ /* Init our changelists hash. */
+ changelists = apr_hash_make(pool);
+
+ /* Begin processing arguments. */
+ opt_state.start_revision.kind = svn_opt_revision_unspecified;
+ opt_state.end_revision.kind = svn_opt_revision_unspecified;
+ opt_state.revision_ranges =
+ apr_array_make(pool, 0, sizeof(svn_opt_revision_range_t *));
+ opt_state.depth = svn_depth_unknown;
+ opt_state.set_depth = svn_depth_unknown;
+ opt_state.accept_which = svn_cl__accept_unspecified;
+ opt_state.show_revs = svn_cl__show_revs_invalid;
+
+ /* No args? Show usage. */
+ if (argc <= 1)
+ {
+ SVN_INT_ERR(svn_cl__help(NULL, NULL, pool));
+ return EXIT_FAILURE;
+ }
+
+ /* Else, parse options. */
+ SVN_INT_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
+
+ os->interleave = 1;
+ while (1)
+ {
+ const char *opt_arg;
+ const char *utf8_opt_arg;
+
+ /* Parse the next option. */
+ apr_status_t apr_err = apr_getopt_long(os, svn_cl__options, &opt_id,
+ &opt_arg);
+ if (APR_STATUS_IS_EOF(apr_err))
+ break;
+ else if (apr_err)
+ {
+ SVN_INT_ERR(svn_cl__help(NULL, NULL, pool));
+ return EXIT_FAILURE;
+ }
+
+ /* Stash the option code in an array before parsing it. */
+ APR_ARRAY_PUSH(received_opts, int) = opt_id;
+
+ switch (opt_id) {
+ case 'l':
+ {
+ err = svn_cstring_atoi(&opt_state.limit, opt_arg);
+ if (err)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Non-numeric limit argument given"));
+ return EXIT_ERROR(err);
+ }
+ if (opt_state.limit <= 0)
+ {
+ err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Argument to --limit must be positive"));
+ return EXIT_ERROR(err);
+ }
+ }
+ break;
+ case 'm':
+ /* Note that there's no way here to detect if the log message
+ contains a zero byte -- if it does, then opt_arg will just
+ be shorter than the user intended. Oh well. */
+ opt_state.message = apr_pstrdup(pool, opt_arg);
+ dash_m_arg = opt_arg;
+ break;
+ case 'c':
+ {
+ apr_array_header_t *change_revs =
+ svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, pool);
+
+ if (opt_state.old_target)
+ {
+ err = svn_error_create
+ (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Can't specify -c with --old"));
+ return EXIT_ERROR(err);
+ }
+
+ for (i = 0; i < change_revs->nelts; i++)
+ {
+ char *end;
+ svn_revnum_t changeno, changeno_end;
+ const char *change_str =
+ APR_ARRAY_IDX(change_revs, i, const char *);
+ const char *s = change_str;
+ svn_boolean_t is_negative;
+
+ /* Check for a leading minus to allow "-c -r42".
+ * The is_negative flag is used to handle "-c -42" and "-c -r42".
+ * The "-c r-42" case is handled by strtol() returning a
+ * negative number. */
+ is_negative = (*s == '-');
+ if (is_negative)
+ s++;
+
+ /* Allow any number of 'r's to prefix a revision number. */
+ while (*s == 'r')
+ s++;
+ changeno = changeno_end = strtol(s, &end, 10);
+ if (end != s && *end == '-')
+ {
+ if (changeno < 0 || is_negative)
+ {
+ err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
+ NULL,
+ _("Negative number in range (%s)"
+ " not supported with -c"),
+ change_str);
+ return EXIT_ERROR(err);
+ }
+ s = end + 1;
+ while (*s == 'r')
+ s++;
+ changeno_end = strtol(s, &end, 10);
+ }
+ if (end == change_str || *end != '\0')
+ {
+ err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Non-numeric change argument (%s) "
+ "given to -c"), change_str);
+ return EXIT_ERROR(err);
+ }
+
+ if (changeno == 0)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("There is no change 0"));
+ return EXIT_ERROR(err);
+ }
+
+ if (is_negative)
+ changeno = -changeno;
+
+ /* Figure out the range:
+ -c N -> -r N-1:N
+ -c -N -> -r N:N-1
+ -c M-N -> -r M-1:N for M < N
+ -c M-N -> -r M:N-1 for M > N
+ -c -M-N -> error (too confusing/no valid use case)
+ */
+ if (changeno > 0)
+ {
+ if (changeno <= changeno_end)
+ changeno--;
+ else
+ changeno_end--;
+ }
+ else
+ {
+ changeno = -changeno;
+ changeno_end = changeno - 1;
+ }
+
+ opt_state.used_change_arg = TRUE;
+ APR_ARRAY_PUSH(opt_state.revision_ranges,
+ svn_opt_revision_range_t *)
+ = svn_opt__revision_range_from_revnums(changeno, changeno_end,
+ pool);
+ }
+ }
+ break;
+ case 'r':
+ opt_state.used_revision_arg = TRUE;
+ if (svn_opt_parse_revision_to_range(opt_state.revision_ranges,
+ opt_arg, pool) != 0)
+ {
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ err = svn_error_createf
+ (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Syntax error in revision argument '%s'"),
+ utf8_opt_arg);
+ return EXIT_ERROR(err);
+ }
+ break;
+ case 'v':
+ opt_state.verbose = TRUE;
+ break;
+ case 'u':
+ opt_state.update = TRUE;
+ break;
+ case 'h':
+ case '?':
+ opt_state.help = TRUE;
+ break;
+ case 'q':
+ opt_state.quiet = TRUE;
+ break;
+ case opt_incremental:
+ opt_state.incremental = TRUE;
+ break;
+ case 'F':
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ SVN_INT_ERR(svn_stringbuf_from_file2(&(opt_state.filedata),
+ utf8_opt_arg, pool));
+ reading_file_from_stdin = (strcmp(utf8_opt_arg, "-") == 0);
+ dash_F_arg = opt_arg;
+ break;
+ case opt_targets:
+ {
+ svn_stringbuf_t *buffer, *buffer_utf8;
+
+ /* We need to convert to UTF-8 now, even before we divide
+ the targets into an array, because otherwise we wouldn't
+ know what delimiter to use for svn_cstring_split(). */
+
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ SVN_INT_ERR(svn_stringbuf_from_file2(&buffer, utf8_opt_arg, pool));
+ SVN_INT_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool));
+ opt_state.targets = svn_cstring_split(buffer_utf8->data, "\n\r",
+ TRUE, pool);
+ }
+ break;
+ case opt_force:
+ opt_state.force = TRUE;
+ break;
+ case opt_force_log:
+ opt_state.force_log = TRUE;
+ break;
+ case opt_dry_run:
+ opt_state.dry_run = TRUE;
+ break;
+ case opt_revprop:
+ opt_state.revprop = TRUE;
+ break;
+ case 'R':
+ opt_state.depth = svn_depth_infinity;
+ break;
+ case 'N':
+ descend = FALSE;
+ break;
+ case opt_depth:
+ err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
+ if (err)
+ return EXIT_ERROR
+ (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Error converting depth "
+ "from locale to UTF-8")));
+ opt_state.depth = svn_depth_from_word(utf8_opt_arg);
+ if (opt_state.depth == svn_depth_unknown
+ || opt_state.depth == svn_depth_exclude)
+ {
+ return EXIT_ERROR
+ (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid depth; try "
+ "'empty', 'files', 'immediates', "
+ "or 'infinity'"),
+ utf8_opt_arg));
+ }
+ break;
+ case opt_set_depth:
+ err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
+ if (err)
+ return EXIT_ERROR
+ (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Error converting depth "
+ "from locale to UTF-8")));
+ opt_state.set_depth = svn_depth_from_word(utf8_opt_arg);
+ /* svn_depth_exclude is okay for --set-depth. */
+ if (opt_state.set_depth == svn_depth_unknown)
+ {
+ return EXIT_ERROR
+ (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid depth; try "
+ "'exclude', 'empty', 'files', "
+ "'immediates', or 'infinity'"),
+ utf8_opt_arg));
+ }
+ break;
+ case opt_version:
+ opt_state.version = TRUE;
+ break;
+ case opt_auth_username:
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_username,
+ opt_arg, pool));
+ break;
+ case opt_auth_password:
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
+ opt_arg, pool));
+ break;
+ case opt_encoding:
+ opt_state.encoding = apr_pstrdup(pool, opt_arg);
+ break;
+ case opt_xml:
+ opt_state.xml = TRUE;
+ break;
+ case opt_stop_on_copy:
+ opt_state.stop_on_copy = TRUE;
+ break;
+ case opt_strict:
+ opt_state.strict = TRUE;
+ break;
+ case opt_no_ignore:
+ opt_state.no_ignore = TRUE;
+ break;
+ case opt_no_auth_cache:
+ opt_state.no_auth_cache = TRUE;
+ break;
+ case opt_non_interactive:
+ opt_state.non_interactive = TRUE;
+ break;
+ case opt_force_interactive:
+ force_interactive = TRUE;
+ break;
+ case opt_trust_server_cert:
+ opt_state.trust_server_cert = TRUE;
+ break;
+ case opt_no_diff_added:
+ opt_state.diff.no_diff_added = TRUE;
+ break;
+ case opt_no_diff_deleted:
+ opt_state.diff.no_diff_deleted = TRUE;
+ break;
+ case opt_ignore_properties:
+ opt_state.diff.ignore_properties = TRUE;
+ break;
+ case opt_show_copies_as_adds:
+ opt_state.diff.show_copies_as_adds = TRUE;
+ break;
+ case opt_notice_ancestry:
+ opt_state.diff.notice_ancestry = TRUE;
+ break;
+ case opt_ignore_ancestry:
+ opt_state.ignore_ancestry = TRUE;
+ break;
+ case opt_ignore_externals:
+ opt_state.ignore_externals = TRUE;
+ break;
+ case opt_relocate:
+ opt_state.relocate = TRUE;
+ break;
+ case 'x':
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.extensions,
+ opt_arg, pool));
+ break;
+ case opt_diff_cmd:
+ opt_state.diff.diff_cmd = apr_pstrdup(pool, opt_arg);
+ break;
+ case opt_merge_cmd:
+ opt_state.merge_cmd = apr_pstrdup(pool, opt_arg);
+ break;
+ case opt_record_only:
+ opt_state.record_only = TRUE;
+ break;
+ case opt_editor_cmd:
+ opt_state.editor_cmd = apr_pstrdup(pool, opt_arg);
+ break;
+ case opt_old_cmd:
+ if (opt_state.used_change_arg)
+ {
+ err = svn_error_create
+ (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Can't specify -c with --old"));
+ return EXIT_ERROR(err);
+ }
+ opt_state.old_target = apr_pstrdup(pool, opt_arg);
+ break;
+ case opt_new_cmd:
+ opt_state.new_target = apr_pstrdup(pool, opt_arg);
+ break;
+ case opt_config_dir:
+ {
+ const char *path_utf8;
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&path_utf8, opt_arg, pool));
+ opt_state.config_dir = svn_dirent_internal_style(path_utf8, pool);
+ }
+ break;
+ case opt_config_options:
+ if (!opt_state.config_options)
+ opt_state.config_options =
+ apr_array_make(pool, 1,
+ sizeof(svn_cmdline__config_argument_t*));
+
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+ SVN_INT_ERR(svn_cmdline__parse_config_option(opt_state.config_options,
+ opt_arg, pool));
+ break;
+ case opt_autoprops:
+ opt_state.autoprops = TRUE;
+ break;
+ case opt_no_autoprops:
+ opt_state.no_autoprops = TRUE;
+ break;
+ case opt_native_eol:
+ if ( !strcmp("LF", opt_arg) || !strcmp("CR", opt_arg) ||
+ !strcmp("CRLF", opt_arg))
+ opt_state.native_eol = apr_pstrdup(pool, opt_arg);
+ else
+ {
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ err = svn_error_createf
+ (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Syntax error in native-eol argument '%s'"),
+ utf8_opt_arg);
+ return EXIT_ERROR(err);
+ }
+ break;
+ case opt_no_unlock:
+ opt_state.no_unlock = TRUE;
+ break;
+ case opt_summarize:
+ opt_state.diff.summarize = TRUE;
+ break;
+ case opt_remove:
+ opt_state.remove = TRUE;
+ break;
+ case opt_changelist:
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.changelist = utf8_opt_arg;
+ if (opt_state.changelist[0] == '\0')
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Changelist names must not be empty"));
+ return EXIT_ERROR(err);
+ }
+ svn_hash_sets(changelists, opt_state.changelist, (void *)1);
+ break;
+ case opt_keep_changelists:
+ opt_state.keep_changelists = TRUE;
+ break;
+ case opt_keep_local:
+ opt_state.keep_local = TRUE;
+ break;
+ case opt_with_all_revprops:
+ /* If --with-all-revprops is specified along with one or more
+ * --with-revprops options, --with-all-revprops takes precedence. */
+ opt_state.all_revprops = TRUE;
+ break;
+ case opt_with_no_revprops:
+ opt_state.no_revprops = TRUE;
+ break;
+ case opt_with_revprop:
+ SVN_INT_ERR(svn_opt_parse_revprop(&opt_state.revprop_table,
+ opt_arg, pool));
+ break;
+ case opt_parents:
+ opt_state.parents = TRUE;
+ break;
+ case 'g':
+ opt_state.use_merge_history = TRUE;
+ break;
+ case opt_accept:
+ opt_state.accept_which = svn_cl__accept_from_word(opt_arg);
+ if (opt_state.accept_which == svn_cl__accept_invalid)
+ return EXIT_ERROR
+ (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid --accept value"),
+ opt_arg));
+ break;
+ case opt_show_revs:
+ opt_state.show_revs = svn_cl__show_revs_from_word(opt_arg);
+ if (opt_state.show_revs == svn_cl__show_revs_invalid)
+ return EXIT_ERROR
+ (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid --show-revs value"),
+ opt_arg));
+ break;
+ case opt_reintegrate:
+ opt_state.reintegrate = TRUE;
+ break;
+ case opt_strip:
+ {
+ err = svn_cstring_atoi(&opt_state.strip, opt_arg);
+ if (err)
+ {
+ err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Invalid strip count '%s'"), opt_arg);
+ return EXIT_ERROR(err);
+ }
+ if (opt_state.strip < 0)
+ {
+ err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Argument to --strip must be positive"));
+ return EXIT_ERROR(err);
+ }
+ }
+ break;
+ case opt_ignore_keywords:
+ opt_state.ignore_keywords = TRUE;
+ break;
+ case opt_reverse_diff:
+ opt_state.reverse_diff = TRUE;
+ break;
+ case opt_ignore_whitespace:
+ opt_state.ignore_whitespace = TRUE;
+ break;
+ case opt_diff:
+ opt_state.show_diff = TRUE;
+ break;
+ case opt_internal_diff:
+ opt_state.diff.internal_diff = TRUE;
+ break;
+ case opt_patch_compatible:
+ opt_state.diff.patch_compatible = TRUE;
+ break;
+ case opt_use_git_diff_format:
+ opt_state.diff.use_git_diff_format = TRUE;
+ break;
+ case opt_allow_mixed_revisions:
+ opt_state.allow_mixed_rev = TRUE;
+ break;
+ case opt_include_externals:
+ opt_state.include_externals = TRUE;
+ break;
+ case opt_show_inherited_props:
+ opt_state.show_inherited_props = TRUE;
+ break;
+ case opt_properties_only:
+ opt_state.diff.properties_only = TRUE;
+ break;
+ case opt_search:
+ add_search_pattern_group(&opt_state, opt_arg, pool);
+ break;
+ case opt_search_and:
+ add_search_pattern_to_latest_group(&opt_state, opt_arg, pool);
+ default:
+ /* Hmmm. Perhaps this would be a good place to squirrel away
+ opts that commands like svn diff might need. Hmmm indeed. */
+ break;
+ }
+ }
+
+ /* The --non-interactive and --force-interactive options are mutually
+ * exclusive. */
+ if (opt_state.non_interactive && force_interactive)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--non-interactive and --force-interactive "
+ "are mutually exclusive"));
+ return EXIT_ERROR(err);
+ }
+ else
+ opt_state.non_interactive = !svn_cmdline__be_interactive(
+ opt_state.non_interactive,
+ force_interactive);
+
+ /* Turn our hash of changelists into an array of unique ones. */
+ SVN_INT_ERR(svn_hash_keys(&(opt_state.changelists), changelists, pool));
+
+ /* ### This really belongs in libsvn_client. The trouble is,
+ there's no one place there to run it from, no
+ svn_client_init(). We'd have to add it to all the public
+ functions that a client might call. It's unmaintainable to do
+ initialization from within libsvn_client itself, but it seems
+ burdensome to demand that all clients call svn_client_init()
+ before calling any other libsvn_client function... On the other
+ hand, the alternative is effectively to demand that they call
+ svn_config_ensure() instead, so maybe we should have a generic
+ init function anyway. Thoughts? */
+ SVN_INT_ERR(svn_config_ensure(opt_state.config_dir, pool));
+
+ /* If the user asked for help, then the rest of the arguments are
+ the names of subcommands to get help on (if any), or else they're
+ just typos/mistakes. Whatever the case, the subcommand to
+ actually run is svn_cl__help(). */
+ if (opt_state.help)
+ subcommand = svn_opt_get_canonical_subcommand2(svn_cl__cmd_table, "help");
+
+ /* If we're not running the `help' subcommand, then look for a
+ subcommand in the first argument. */
+ if (subcommand == NULL)
+ {
+ if (os->ind >= os->argc)
+ {
+ if (opt_state.version)
+ {
+ /* Use the "help" subcommand to handle the "--version" option. */
+ static const svn_opt_subcommand_desc2_t pseudo_cmd =
+ { "--version", svn_cl__help, {0}, "",
+ {opt_version, /* must accept its own option */
+ 'q', /* brief output */
+ 'v', /* verbose output */
+ opt_config_dir /* all commands accept this */
+ } };
+
+ subcommand = &pseudo_cmd;
+ }
+ else
+ {
+ svn_error_clear
+ (svn_cmdline_fprintf(stderr, pool,
+ _("Subcommand argument required\n")));
+ svn_error_clear(svn_cl__help(NULL, NULL, pool));
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ const char *first_arg = os->argv[os->ind++];
+ subcommand = svn_opt_get_canonical_subcommand2(svn_cl__cmd_table,
+ first_arg);
+ if (subcommand == NULL)
+ {
+ const char *first_arg_utf8;
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
+ first_arg, pool));
+ svn_error_clear
+ (svn_cmdline_fprintf(stderr, pool,
+ _("Unknown subcommand: '%s'\n"),
+ first_arg_utf8));
+ svn_error_clear(svn_cl__help(NULL, NULL, pool));
+
+ /* Be kind to people who try 'svn undo'. */
+ if (strcmp(first_arg_utf8, "undo") == 0)
+ {
+ svn_error_clear
+ (svn_cmdline_fprintf(stderr, pool,
+ _("Undo is done using either the "
+ "'svn revert' or the 'svn merge' "
+ "command.\n")));
+ }
+
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ /* Check that the subcommand wasn't passed any inappropriate options. */
+ for (i = 0; i < received_opts->nelts; i++)
+ {
+ opt_id = APR_ARRAY_IDX(received_opts, i, int);
+
+ /* All commands implicitly accept --help, so just skip over this
+ when we see it. Note that we don't want to include this option
+ in their "accepted options" list because it would be awfully
+ redundant to display it in every commands' help text. */
+ if (opt_id == 'h' || opt_id == '?')
+ continue;
+
+ if (! svn_opt_subcommand_takes_option3(subcommand, opt_id,
+ svn_cl__global_options))
+ {
+ const char *optstr;
+ const apr_getopt_option_t *badopt =
+ svn_opt_get_option_from_code2(opt_id, svn_cl__options,
+ subcommand, pool);
+ svn_opt_format_option(&optstr, badopt, FALSE, pool);
+ if (subcommand->name[0] == '-')
+ svn_error_clear(svn_cl__help(NULL, NULL, pool));
+ else
+ svn_error_clear
+ (svn_cmdline_fprintf
+ (stderr, pool, _("Subcommand '%s' doesn't accept option '%s'\n"
+ "Type 'svn help %s' for usage.\n"),
+ subcommand->name, optstr, subcommand->name));
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Only merge and log support multiple revisions/revision ranges. */
+ if (subcommand->cmd_func != svn_cl__merge
+ && subcommand->cmd_func != svn_cl__log)
+ {
+ if (opt_state.revision_ranges->nelts > 1)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Multiple revision arguments "
+ "encountered; can't specify -c twice, "
+ "or both -c and -r"));
+ return EXIT_ERROR(err);
+ }
+ }
+
+ /* Disallow simultaneous use of both --depth and --set-depth. */
+ if ((opt_state.depth != svn_depth_unknown)
+ && (opt_state.set_depth != svn_depth_unknown))
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--depth and --set-depth are mutually "
+ "exclusive"));
+ return EXIT_ERROR(err);
+ }
+
+ /* Disallow simultaneous use of both --with-all-revprops and
+ --with-no-revprops. */
+ if (opt_state.all_revprops && opt_state.no_revprops)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--with-all-revprops and --with-no-revprops "
+ "are mutually exclusive"));
+ return EXIT_ERROR(err);
+ }
+
+ /* Disallow simultaneous use of both --with-revprop and
+ --with-no-revprops. */
+ if (opt_state.revprop_table && opt_state.no_revprops)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--with-revprop and --with-no-revprops "
+ "are mutually exclusive"));
+ return EXIT_ERROR(err);
+ }
+
+ /* Disallow simultaneous use of both -m and -F, when they are
+ both used to pass a commit message or lock comment. ('propset'
+ takes the property value, not a commit message, from -F.)
+ */
+ if (opt_state.filedata && opt_state.message
+ && subcommand->cmd_func != svn_cl__propset)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--message (-m) and --file (-F) "
+ "are mutually exclusive"));
+ return EXIT_ERROR(err);
+ }
+
+ /* --trust-server-cert can only be used with --non-interactive */
+ if (opt_state.trust_server_cert && !opt_state.non_interactive)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--trust-server-cert requires "
+ "--non-interactive"));
+ return EXIT_ERROR(err);
+ }
+
+ /* Disallow simultaneous use of both --diff-cmd and
+ --internal-diff. */
+ if (opt_state.diff.diff_cmd && opt_state.diff.internal_diff)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--diff-cmd and --internal-diff "
+ "are mutually exclusive"));
+ return EXIT_ERROR(err);
+ }
+
+ /* Ensure that 'revision_ranges' has at least one item, and make
+ 'start_revision' and 'end_revision' match that item. */
+ if (opt_state.revision_ranges->nelts == 0)
+ {
+ svn_opt_revision_range_t *range = apr_palloc(pool, sizeof(*range));
+ range->start.kind = svn_opt_revision_unspecified;
+ range->end.kind = svn_opt_revision_unspecified;
+ APR_ARRAY_PUSH(opt_state.revision_ranges,
+ svn_opt_revision_range_t *) = range;
+ }
+ opt_state.start_revision = APR_ARRAY_IDX(opt_state.revision_ranges, 0,
+ svn_opt_revision_range_t *)->start;
+ opt_state.end_revision = APR_ARRAY_IDX(opt_state.revision_ranges, 0,
+ svn_opt_revision_range_t *)->end;
+
+ err = svn_config_get_config(&cfg_hash, opt_state.config_dir, pool);
+ if (err)
+ {
+ /* Fallback to default config if the config directory isn't readable
+ or is not a directory. */
+ if (APR_STATUS_IS_EACCES(err->apr_err)
+ || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
+ {
+ svn_config_t *empty_cfg;
+
+ svn_handle_warning2(stderr, err, "svn: ");
+ svn_error_clear(err);
+ cfg_hash = apr_hash_make(pool);
+ SVN_INT_ERR(svn_config_create2(&empty_cfg, FALSE, FALSE, pool));
+ svn_hash_sets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, empty_cfg);
+ SVN_INT_ERR(svn_config_create2(&empty_cfg, FALSE, FALSE, pool));
+ svn_hash_sets(cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, empty_cfg);
+ }
+ else
+ return EXIT_ERROR(err);
+ }
+
+ /* Relocation is infinite-depth only. */
+ if (opt_state.relocate)
+ {
+ if (opt_state.depth != svn_depth_unknown)
+ {
+ err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+ _("--relocate and --depth are mutually "
+ "exclusive"));
+ return EXIT_ERROR(err);
+ }
+ if (! descend)
+ {
+ err = svn_error_create(
+ SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+ _("--relocate and --non-recursive (-N) are mutually "
+ "exclusive"));
+ return EXIT_ERROR(err);
+ }
+ }
+
+ /* Only a few commands can accept a revision range; the rest can take at
+ most one revision number. */
+ if (subcommand->cmd_func != svn_cl__blame
+ && subcommand->cmd_func != svn_cl__diff
+ && subcommand->cmd_func != svn_cl__log
+ && subcommand->cmd_func != svn_cl__mergeinfo
+ && subcommand->cmd_func != svn_cl__merge)
+ {
+ if (opt_state.end_revision.kind != svn_opt_revision_unspecified)
+ {
+ err = svn_error_create(SVN_ERR_CLIENT_REVISION_RANGE, NULL, NULL);
+ return EXIT_ERROR(err);
+ }
+ }
+
+ /* -N has a different meaning depending on the command */
+ if (!descend)
+ {
+ if (subcommand->cmd_func == svn_cl__status)
+ {
+ opt_state.depth = svn_depth_immediates;
+ }
+ else if (subcommand->cmd_func == svn_cl__revert
+ || subcommand->cmd_func == svn_cl__add
+ || subcommand->cmd_func == svn_cl__commit)
+ {
+ /* In pre-1.5 Subversion, some commands treated -N like
+ --depth=empty, so force that mapping here. Anyway, with
+ revert it makes sense to be especially conservative,
+ since revert can lose data. */
+ opt_state.depth = svn_depth_empty;
+ }
+ else
+ {
+ opt_state.depth = svn_depth_files;
+ }
+ }
+
+ cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG);
+
+ /* Update the options in the config */
+ if (opt_state.config_options)
+ {
+ svn_error_clear(
+ svn_cmdline__apply_config_options(cfg_hash,
+ opt_state.config_options,
+ "svn: ", "--config-option"));
+ }
+
+#if !defined(SVN_CL_NO_EXCLUSIVE_LOCK)
+ {
+ const char *exclusive_clients_option;
+ apr_array_header_t *exclusive_clients;
+
+ svn_config_get(cfg_config, &exclusive_clients_option,
+ SVN_CONFIG_SECTION_WORKING_COPY,
+ SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE_CLIENTS,
+ NULL);
+ exclusive_clients = svn_cstring_split(exclusive_clients_option,
+ " ,", TRUE, pool);
+ for (i = 0; i < exclusive_clients->nelts; ++i)
+ {
+ const char *exclusive_client = APR_ARRAY_IDX(exclusive_clients, i,
+ const char *);
+
+ /* This blocks other clients from accessing the wc.db so it must
+ be explicitly enabled.*/
+ if (!strcmp(exclusive_client, "svn"))
+ svn_config_set(cfg_config,
+ SVN_CONFIG_SECTION_WORKING_COPY,
+ SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE,
+ "true");
+ }
+ }
+#endif
+
+ /* Create a client context object. */
+ command_baton.opt_state = &opt_state;
+ SVN_INT_ERR(svn_client_create_context2(&ctx, cfg_hash, pool));
+ command_baton.ctx = ctx;
+
+ /* If we're running a command that could result in a commit, verify
+ that any log message we were given on the command line makes
+ sense (unless we've also been instructed not to care). This may
+ access the working copy so do it after setting the locking mode. */
+ if ((! opt_state.force_log)
+ && (subcommand->cmd_func == svn_cl__commit
+ || subcommand->cmd_func == svn_cl__copy
+ || subcommand->cmd_func == svn_cl__delete
+ || subcommand->cmd_func == svn_cl__import
+ || subcommand->cmd_func == svn_cl__mkdir
+ || subcommand->cmd_func == svn_cl__move
+ || subcommand->cmd_func == svn_cl__lock
+ || subcommand->cmd_func == svn_cl__propedit))
+ {
+ /* If the -F argument is a file that's under revision control,
+ that's probably not what the user intended. */
+ if (dash_F_arg)
+ {
+ svn_node_kind_t kind;
+ const char *local_abspath;
+ const char *fname_utf8 = svn_dirent_internal_style(dash_F_arg, pool);
+
+ err = svn_dirent_get_absolute(&local_abspath, fname_utf8, pool);
+
+ if (!err)
+ {
+ err = svn_wc_read_kind2(&kind, ctx->wc_ctx, local_abspath, TRUE,
+ FALSE, pool);
+
+ if (!err && kind != svn_node_none && kind != svn_node_unknown)
+ {
+ if (subcommand->cmd_func != svn_cl__lock)
+ {
+ err = svn_error_create(
+ SVN_ERR_CL_LOG_MESSAGE_IS_VERSIONED_FILE, NULL,
+ _("Log message file is a versioned file; "
+ "use '--force-log' to override"));
+ }
+ else
+ {
+ err = svn_error_create(
+ SVN_ERR_CL_LOG_MESSAGE_IS_VERSIONED_FILE, NULL,
+ _("Lock comment file is a versioned file; "
+ "use '--force-log' to override"));
+ }
+ return EXIT_ERROR(err);
+ }
+ }
+ svn_error_clear(err);
+ }
+
+ /* If the -m argument is a file at all, that's probably not what
+ the user intended. */
+ if (dash_m_arg)
+ {
+ apr_finfo_t finfo;
+ if (apr_stat(&finfo, dash_m_arg,
+ APR_FINFO_MIN, pool) == APR_SUCCESS)
+ {
+ if (subcommand->cmd_func != svn_cl__lock)
+ {
+ err = svn_error_create
+ (SVN_ERR_CL_LOG_MESSAGE_IS_PATHNAME, NULL,
+ _("The log message is a pathname "
+ "(was -F intended?); use '--force-log' to override"));
+ }
+ else
+ {
+ err = svn_error_create
+ (SVN_ERR_CL_LOG_MESSAGE_IS_PATHNAME, NULL,
+ _("The lock comment is a pathname "
+ "(was -F intended?); use '--force-log' to override"));
+ }
+ return EXIT_ERROR(err);
+ }
+ }
+ }
+
+ /* XXX: Only diff_cmd for now, overlay rest later and stop passing
+ opt_state altogether? */
+ if (opt_state.diff.diff_cmd)
+ svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF_CMD, opt_state.diff.diff_cmd);
+ if (opt_state.merge_cmd)
+ svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF3_CMD, opt_state.merge_cmd);
+ if (opt_state.diff.internal_diff)
+ svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF_CMD, NULL);
+
+ /* Check for mutually exclusive args --auto-props and --no-auto-props */
+ if (opt_state.autoprops && opt_state.no_autoprops)
+ {
+ err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+ _("--auto-props and --no-auto-props are "
+ "mutually exclusive"));
+ return EXIT_ERROR(err);
+ }
+
+ /* Update auto-props-enable option, and populate the MIME types map,
+ for add/import commands */
+ if (subcommand->cmd_func == svn_cl__add
+ || subcommand->cmd_func == svn_cl__import)
+ {
+ const char *mimetypes_file;
+ svn_config_get(cfg_config, &mimetypes_file,
+ SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_MIMETYPES_FILE, FALSE);
+ if (mimetypes_file && *mimetypes_file)
+ {
+ SVN_INT_ERR(svn_io_parse_mimetypes_file(&(ctx->mimetypes_map),
+ mimetypes_file, pool));
+ }
+
+ if (opt_state.autoprops)
+ {
+ svn_config_set_bool(cfg_config, SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, TRUE);
+ }
+ if (opt_state.no_autoprops)
+ {
+ svn_config_set_bool(cfg_config, SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, FALSE);
+ }
+ }
+
+ /* Update the 'keep-locks' runtime option */
+ if (opt_state.no_unlock)
+ svn_config_set_bool(cfg_config, SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_NO_UNLOCK, TRUE);
+
+ /* Set the log message callback function. Note that individual
+ subcommands will populate the ctx->log_msg_baton3. */
+ ctx->log_msg_func3 = svn_cl__get_log_message;
+
+ /* 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)
+ {
+ SVN_INT_ERR(svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2,
+ conflict_stats, pool));
+ }
+
+ /* Set up our cancellation support. */
+ ctx->cancel_func = svn_cl__check_cancel;
+ apr_signal(SIGINT, signal_handler);
+#ifdef SIGBREAK
+ /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
+ apr_signal(SIGBREAK, signal_handler);
+#endif
+#ifdef SIGHUP
+ apr_signal(SIGHUP, signal_handler);
+#endif
+#ifdef SIGTERM
+ apr_signal(SIGTERM, signal_handler);
+#endif
+
+#ifdef SIGPIPE
+ /* Disable SIGPIPE generation for the platforms that have it. */
+ apr_signal(SIGPIPE, SIG_IGN);
+#endif
+
+#ifdef SIGXFSZ
+ /* Disable SIGXFSZ generation for the platforms that have it, otherwise
+ * working with large files when compiled against an APR that doesn't have
+ * large file support will crash the program, which is uncool. */
+ apr_signal(SIGXFSZ, SIG_IGN);
+#endif
+
+ /* Set up Authentication stuff. */
+ SVN_INT_ERR(svn_cmdline_create_auth_baton(&ab,
+ opt_state.non_interactive,
+ opt_state.auth_username,
+ opt_state.auth_password,
+ opt_state.config_dir,
+ opt_state.no_auth_cache,
+ opt_state.trust_server_cert,
+ cfg_config,
+ ctx->cancel_func,
+ ctx->cancel_baton,
+ pool));
+
+ ctx->auth_baton = ab;
+
+ if (opt_state.non_interactive)
+ {
+ if (opt_state.accept_which == svn_cl__accept_edit)
+ return EXIT_ERROR(
+ svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--accept=%s incompatible with"
+ " --non-interactive"),
+ SVN_CL__ACCEPT_EDIT));
+
+ if (opt_state.accept_which == svn_cl__accept_launch)
+ return EXIT_ERROR(
+ svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--accept=%s incompatible with"
+ " --non-interactive"),
+ SVN_CL__ACCEPT_LAUNCH));
+
+ /* The default action when we're non-interactive is to postpone
+ * conflict resolution. */
+ if (opt_state.accept_which == svn_cl__accept_unspecified)
+ opt_state.accept_which = svn_cl__accept_postpone;
+ }
+
+ /* Check whether interactive conflict resolution is disabled by
+ * the configuration file. If no --accept option was specified
+ * we postpone all conflicts in this case. */
+ SVN_INT_ERR(svn_config_get_bool(cfg_config, &interactive_conflicts,
+ SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS,
+ TRUE));
+ if (!interactive_conflicts)
+ {
+ /* Make 'svn resolve' non-interactive. */
+ if (subcommand->cmd_func == svn_cl__resolve)
+ opt_state.non_interactive = TRUE;
+
+ /* We're not resolving conflicts interactively. If no --accept option
+ * was provided the default behaviour is to postpone all conflicts. */
+ if (opt_state.accept_which == svn_cl__accept_unspecified)
+ opt_state.accept_which = svn_cl__accept_postpone;
+ }
+
+ /* Install the default conflict handler. */
+ {
+ svn_cl__interactive_conflict_baton_t *b;
+
+ ctx->conflict_func = NULL;
+ ctx->conflict_baton = NULL;
+
+ ctx->conflict_func2 = svn_cl__conflict_func_interactive;
+ SVN_INT_ERR(svn_cl__get_conflict_func_interactive_baton(
+ &b,
+ opt_state.accept_which,
+ ctx->config, opt_state.editor_cmd, conflict_stats,
+ ctx->cancel_func, ctx->cancel_baton, pool));
+ ctx->conflict_baton2 = b;
+ }
+
+ /* And now we finally run the subcommand. */
+ err = (*subcommand->cmd_func)(os, &command_baton, pool);
+ if (err)
+ {
+ /* For argument-related problems, suggest using the 'help'
+ subcommand. */
+ if (err->apr_err == SVN_ERR_CL_INSUFFICIENT_ARGS
+ || err->apr_err == SVN_ERR_CL_ARG_PARSING_ERROR)
+ {
+ err = svn_error_quick_wrap(
+ err, apr_psprintf(pool,
+ _("Try 'svn help %s' for more information"),
+ subcommand->name));
+ }
+ if (err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
+ {
+ err = svn_error_quick_wrap(err,
+ _("Please see the 'svn upgrade' command"));
+ }
+
+ if (err->apr_err == SVN_ERR_AUTHN_FAILED && opt_state.non_interactive)
+ {
+ err = svn_error_quick_wrap(err,
+ _("Authentication failed and interactive"
+ " prompting is disabled; see the"
+ " --force-interactive option"));
+ if (reading_file_from_stdin)
+ err = svn_error_quick_wrap(err,
+ _("Reading file from standard input "
+ "because of -F option; this can "
+ "interfere with interactive "
+ "prompting"));
+ }
+
+ /* 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)"));
+ }
+
+ if (err->apr_err == SVN_ERR_SQLITE_BUSY)
+ {
+ err = svn_error_quick_wrap(err,
+ _("Another process is blocking the "
+ "working copy database, or the "
+ "underlying filesystem does not "
+ "support file locking; if the working "
+ "copy is on a network filesystem, make "
+ "sure file locking has been enabled "
+ "on the file server"));
+ }
+
+ if (svn_error_find_cause(err, SVN_ERR_RA_CANNOT_CREATE_TUNNEL) &&
+ (opt_state.auth_username || opt_state.auth_password))
+ {
+ err = svn_error_quick_wrap(
+ err, _("When using svn+ssh:// URLs, keep in mind that the "
+ "--username and --password options are ignored "
+ "because authentication is performed by SSH, not "
+ "Subversion"));
+ }
+
+ /* Ensure that stdout is flushed, so the user will see any write errors.
+ This makes sure that output is not silently lost. */
+ err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+ return EXIT_ERROR(err);
+ }
+ else
+ {
+ /* Ensure that stdout is flushed, so the user will see any write errors.
+ This makes sure that output is not silently lost. */
+ SVN_INT_ERR(svn_cmdline_fflush(stdout));
+
+ return EXIT_SUCCESS;
+ }
+}
+
+int
+main(int argc, const char *argv[])
+{
+ apr_pool_t *pool;
+ int exit_code;
+
+ /* Initialize the app. */
+ if (svn_cmdline_init("svn", stderr) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ /* Create our top-level pool. Use a separate mutexless allocator,
+ * given this application is single threaded.
+ */
+ pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+ exit_code = sub_main(argc, argv, pool);
+
+ svn_pool_destroy(pool);
+ return exit_code;
+}