svn.c revision 251886
1/* 2 * svn.c: Subversion command line client main file. 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24/* ==================================================================== */ 25 26 27 28/*** Includes. ***/ 29 30#include <string.h> 31#include <assert.h> 32 33#include <apr_strings.h> 34#include <apr_tables.h> 35#include <apr_general.h> 36#include <apr_signal.h> 37 38#include "svn_cmdline.h" 39#include "svn_pools.h" 40#include "svn_wc.h" 41#include "svn_client.h" 42#include "svn_config.h" 43#include "svn_string.h" 44#include "svn_dirent_uri.h" 45#include "svn_path.h" 46#include "svn_delta.h" 47#include "svn_diff.h" 48#include "svn_error.h" 49#include "svn_io.h" 50#include "svn_opt.h" 51#include "svn_utf.h" 52#include "svn_auth.h" 53#include "svn_hash.h" 54#include "svn_version.h" 55#include "cl.h" 56 57#include "private/svn_opt_private.h" 58#include "private/svn_cmdline_private.h" 59 60#include "svn_private_config.h" 61 62 63/*** Option Processing ***/ 64 65/* Add an identifier here for long options that don't have a short 66 option. Options that have both long and short options should just 67 use the short option letter as identifier. */ 68typedef enum svn_cl__longopt_t { 69 opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID, 70 opt_auth_username, 71 opt_autoprops, 72 opt_changelist, 73 opt_config_dir, 74 opt_config_options, 75 /* diff options */ 76 opt_diff_cmd, 77 opt_internal_diff, 78 opt_no_diff_added, 79 opt_no_diff_deleted, 80 opt_show_copies_as_adds, 81 opt_notice_ancestry, 82 opt_summarize, 83 opt_use_git_diff_format, 84 opt_ignore_properties, 85 opt_properties_only, 86 opt_patch_compatible, 87 /* end of diff options */ 88 opt_dry_run, 89 opt_editor_cmd, 90 opt_encoding, 91 opt_force_log, 92 opt_force, 93 opt_keep_changelists, 94 opt_ignore_ancestry, 95 opt_ignore_externals, 96 opt_incremental, 97 opt_merge_cmd, 98 opt_native_eol, 99 opt_new_cmd, 100 opt_no_auth_cache, 101 opt_no_autoprops, 102 opt_no_ignore, 103 opt_no_unlock, 104 opt_non_interactive, 105 opt_force_interactive, 106 opt_old_cmd, 107 opt_record_only, 108 opt_relocate, 109 opt_remove, 110 opt_revprop, 111 opt_stop_on_copy, 112 opt_strict, 113 opt_targets, 114 opt_depth, 115 opt_set_depth, 116 opt_version, 117 opt_xml, 118 opt_keep_local, 119 opt_with_revprop, 120 opt_with_all_revprops, 121 opt_with_no_revprops, 122 opt_parents, 123 opt_accept, 124 opt_show_revs, 125 opt_reintegrate, 126 opt_trust_server_cert, 127 opt_strip, 128 opt_ignore_keywords, 129 opt_reverse_diff, 130 opt_ignore_whitespace, 131 opt_diff, 132 opt_allow_mixed_revisions, 133 opt_include_externals, 134 opt_show_inherited_props, 135 opt_search, 136 opt_search_and 137} svn_cl__longopt_t; 138 139 140/* Option codes and descriptions for the command line client. 141 * 142 * The entire list must be terminated with an entry of nulls. 143 */ 144const apr_getopt_option_t svn_cl__options[] = 145{ 146 {"force", opt_force, 0, N_("force operation to run")}, 147 {"force-log", opt_force_log, 0, 148 N_("force validity of log message source")}, 149 {"help", 'h', 0, N_("show help on a subcommand")}, 150 {NULL, '?', 0, N_("show help on a subcommand")}, 151 {"message", 'm', 1, N_("specify log message ARG")}, 152 {"quiet", 'q', 0, N_("print nothing, or only summary information")}, 153 {"recursive", 'R', 0, N_("descend recursively, same as --depth=infinity")}, 154 {"non-recursive", 'N', 0, N_("obsolete; try --depth=files or --depth=immediates")}, 155 {"change", 'c', 1, 156 N_("the change made by revision ARG (like -r ARG-1:ARG)\n" 157 " " 158 "If ARG is negative this is like -r ARG:ARG-1\n" 159 " " 160 "If ARG is of the form ARG1-ARG2 then this is like\n" 161 " " 162 "ARG1:ARG2, where ARG1 is inclusive")}, 163 {"revision", 'r', 1, 164 N_("ARG (some commands also take ARG1:ARG2 range)\n" 165 " " 166 "A revision argument can be one of:\n" 167 " " 168 " NUMBER revision number\n" 169 " " 170 " '{' DATE '}' revision at start of the date\n" 171 " " 172 " 'HEAD' latest in repository\n" 173 " " 174 " 'BASE' base rev of item's working copy\n" 175 " " 176 " 'COMMITTED' last commit at or before BASE\n" 177 " " 178 " 'PREV' revision just before COMMITTED")}, 179 {"file", 'F', 1, N_("read log message from file ARG")}, 180 {"incremental", opt_incremental, 0, 181 N_("give output suitable for concatenation")}, 182 {"encoding", opt_encoding, 1, 183 N_("treat value as being in charset encoding ARG")}, 184 {"version", opt_version, 0, N_("show program version information")}, 185 {"verbose", 'v', 0, N_("print extra information")}, 186 {"show-updates", 'u', 0, N_("display update information")}, 187 {"username", opt_auth_username, 1, N_("specify a username ARG")}, 188 {"password", opt_auth_password, 1, N_("specify a password ARG")}, 189 {"extensions", 'x', 1, 190 N_("Specify differencing options for external diff or\n" 191 " " 192 "internal diff or blame. Default: '-u'. Options are\n" 193 " " 194 "separated by spaces. Internal diff and blame take:\n" 195 " " 196 " -u, --unified: Show 3 lines of unified context\n" 197 " " 198 " -b, --ignore-space-change: Ignore changes in\n" 199 " " 200 " amount of white space\n" 201 " " 202 " -w, --ignore-all-space: Ignore all white space\n" 203 " " 204 " --ignore-eol-style: Ignore changes in EOL style\n" 205 " " 206 " -p, --show-c-function: Show C function name")}, 207 {"targets", opt_targets, 1, 208 N_("pass contents of file ARG as additional args")}, 209 {"depth", opt_depth, 1, 210 N_("limit operation by depth ARG ('empty', 'files',\n" 211 " " 212 "'immediates', or 'infinity')")}, 213 {"set-depth", opt_set_depth, 1, 214 N_("set new working copy depth to ARG ('exclude',\n" 215 " " 216 "'empty', 'files', 'immediates', or 'infinity')")}, 217 {"xml", opt_xml, 0, N_("output in XML")}, 218 {"strict", opt_strict, 0, N_("use strict semantics")}, 219 {"stop-on-copy", opt_stop_on_copy, 0, 220 N_("do not cross copies while traversing history")}, 221 {"no-ignore", opt_no_ignore, 0, 222 N_("disregard default and svn:ignore and\n" 223 " " 224 "svn:global-ignores property ignores")}, 225 {"no-auth-cache", opt_no_auth_cache, 0, 226 N_("do not cache authentication tokens")}, 227 {"trust-server-cert", opt_trust_server_cert, 0, 228 N_("accept SSL server certificates from unknown\n" 229 " " 230 "certificate authorities without prompting (but only\n" 231 " " 232 "with '--non-interactive')") }, 233 {"non-interactive", opt_non_interactive, 0, 234 N_("do no interactive prompting (default is to prompt\n" 235 " " 236 "only if standard input is a terminal device)")}, 237 {"force-interactive", opt_force_interactive, 0, 238 N_("do interactive prompting even if standard input\n" 239 " " 240 "is not a terminal device")}, 241 {"dry-run", opt_dry_run, 0, 242 N_("try operation but make no changes")}, 243 {"ignore-ancestry", opt_ignore_ancestry, 0, 244 N_("disable merge tracking; diff nodes as if related")}, 245 {"ignore-externals", opt_ignore_externals, 0, 246 N_("ignore externals definitions")}, 247 {"diff3-cmd", opt_merge_cmd, 1, N_("use ARG as merge command")}, 248 {"editor-cmd", opt_editor_cmd, 1, N_("use ARG as external editor")}, 249 {"record-only", opt_record_only, 0, 250 N_("merge only mergeinfo differences")}, 251 {"old", opt_old_cmd, 1, N_("use ARG as the older target")}, 252 {"new", opt_new_cmd, 1, N_("use ARG as the newer target")}, 253 {"revprop", opt_revprop, 0, 254 N_("operate on a revision property (use with -r)")}, 255 {"relocate", opt_relocate, 0, N_("relocate via URL-rewriting")}, 256 {"config-dir", opt_config_dir, 1, 257 N_("read user configuration files from directory ARG")}, 258 {"config-option", opt_config_options, 1, 259 N_("set user configuration option in the format:\n" 260 " " 261 " FILE:SECTION:OPTION=[VALUE]\n" 262 " " 263 "For example:\n" 264 " " 265 " servers:global:http-library=serf")}, 266 {"auto-props", opt_autoprops, 0, N_("enable automatic properties")}, 267 {"no-auto-props", opt_no_autoprops, 0, N_("disable automatic properties")}, 268 {"native-eol", opt_native_eol, 1, 269 N_("use a different EOL marker than the standard\n" 270 " " 271 "system marker for files with the svn:eol-style\n" 272 " " 273 "property set to 'native'.\n" 274 " " 275 "ARG may be one of 'LF', 'CR', 'CRLF'")}, 276 {"limit", 'l', 1, N_("maximum number of log entries")}, 277 {"no-unlock", opt_no_unlock, 0, N_("don't unlock the targets")}, 278 {"remove", opt_remove, 0, N_("remove changelist association")}, 279 {"changelist", opt_changelist, 1, 280 N_("operate only on members of changelist ARG")}, 281 {"keep-changelists", opt_keep_changelists, 0, 282 N_("don't delete changelists after commit")}, 283 {"keep-local", opt_keep_local, 0, N_("keep path in working copy")}, 284 {"with-all-revprops", opt_with_all_revprops, 0, 285 N_("retrieve all revision properties")}, 286 {"with-no-revprops", opt_with_no_revprops, 0, 287 N_("retrieve no revision properties")}, 288 {"with-revprop", opt_with_revprop, 1, 289 N_("set revision property ARG in new revision\n" 290 " " 291 "using the name[=value] format")}, 292 {"parents", opt_parents, 0, N_("make intermediate directories")}, 293 {"use-merge-history", 'g', 0, 294 N_("use/display additional information from merge\n" 295 " " 296 "history")}, 297 {"accept", opt_accept, 1, 298 N_("specify automatic conflict resolution action\n" 299 " " 300 "('postpone', 'working', 'base', 'mine-conflict',\n" 301 " " 302 "'theirs-conflict', 'mine-full', 'theirs-full',\n" 303 " " 304 "'edit', 'launch')\n" 305 " " 306 "(shorthand: 'p', 'mc', 'tc', 'mf', 'tf', 'e', 'l')" 307 )}, 308 {"show-revs", opt_show_revs, 1, 309 N_("specify which collection of revisions to display\n" 310 " " 311 "('merged', 'eligible')")}, 312 {"reintegrate", opt_reintegrate, 0, 313 N_("deprecated")}, 314 {"strip", opt_strip, 1, 315 N_("number of leading path components to strip from\n" 316 " " 317 "paths parsed from the patch file. --strip 0\n" 318 " " 319 "is the default and leaves paths unmodified.\n" 320 " " 321 "--strip 1 would change the path\n" 322 " " 323 "'doc/fudge/crunchy.html' to 'fudge/crunchy.html'.\n" 324 " " 325 "--strip 2 would leave just 'crunchy.html'\n" 326 " " 327 "The expected component separator is '/' on all\n" 328 " " 329 "platforms. A leading '/' counts as one component.")}, 330 {"ignore-keywords", opt_ignore_keywords, 0, 331 N_("don't expand keywords")}, 332 {"reverse-diff", opt_reverse_diff, 0, 333 N_("apply the unidiff in reverse")}, 334 {"ignore-whitespace", opt_ignore_whitespace, 0, 335 N_("ignore whitespace during pattern matching")}, 336 {"diff", opt_diff, 0, N_("produce diff output")}, /* maps to show_diff */ 337 /* diff options */ 338 {"diff-cmd", opt_diff_cmd, 1, N_("use ARG as diff command")}, 339 {"internal-diff", opt_internal_diff, 0, 340 N_("override diff-cmd specified in config file")}, 341 {"no-diff-added", opt_no_diff_added, 0, 342 N_("do not print differences for added files")}, 343 {"no-diff-deleted", opt_no_diff_deleted, 0, 344 N_("do not print differences for deleted files")}, 345 {"show-copies-as-adds", opt_show_copies_as_adds, 0, 346 N_("don't diff copied or moved files with their source")}, 347 {"notice-ancestry", opt_notice_ancestry, 0, 348 N_("diff unrelated nodes as delete and add")}, 349 {"summarize", opt_summarize, 0, N_("show a summary of the results")}, 350 {"git", opt_use_git_diff_format, 0, 351 N_("use git's extended diff format")}, 352 {"ignore-properties", opt_ignore_properties, 0, 353 N_("ignore properties during the operation")}, 354 {"properties-only", opt_properties_only, 0, 355 N_("show only properties during the operation")}, 356 {"patch-compatible", opt_patch_compatible, 0, 357 N_("generate diff suitable for generic third-party\n" 358 " " 359 "patch tools; currently the same as\n" 360 " " 361 "--show-copies-as-adds --ignore-properties" 362 )}, 363 /* end of diff options */ 364 {"allow-mixed-revisions", opt_allow_mixed_revisions, 0, 365 N_("Allow operation on mixed-revision working copy.\n" 366 " " 367 "Use of this option is not recommended!\n" 368 " " 369 "Please run 'svn update' instead.")}, 370 {"include-externals", opt_include_externals, 0, 371 N_("Also commit file and dir externals reached by\n" 372 " " 373 "recursion. This does not include externals with a\n" 374 " " 375 "fixed revision. (See the svn:externals property)")}, 376 {"show-inherited-props", opt_show_inherited_props, 0, 377 N_("retrieve target's inherited properties")}, 378 {"search", opt_search, 1, 379 N_("use ARG as search pattern (glob syntax)")}, 380 {"search-and", opt_search_and, 1, 381 N_("combine ARG with the previous search pattern")}, 382 383 /* Long-opt Aliases 384 * 385 * These have NULL desriptions, but an option code that matches some 386 * other option (whose description should probably mention its aliases). 387 */ 388 389 {"cl", opt_changelist, 1, NULL}, 390 391 {0, 0, 0, 0}, 392}; 393 394 395 396/*** Command dispatch. ***/ 397 398/* Our array of available subcommands. 399 * 400 * The entire list must be terminated with an entry of nulls. 401 * 402 * In most of the help text "PATH" is used where a working copy path is 403 * required, "URL" where a repository URL is required and "TARGET" when 404 * either a path or a url can be used. Hmm, should this be part of the 405 * help text? 406 */ 407 408/* Options that apply to all commands. (While not every command may 409 currently require authentication or be interactive, allowing every 410 command to take these arguments allows scripts to just pass them 411 willy-nilly to every invocation of 'svn') . */ 412const int svn_cl__global_options[] = 413{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive, 414 opt_force_interactive, opt_trust_server_cert, opt_config_dir, 415 opt_config_options, 0 416}; 417 418/* Options for giving a log message. (Some of these also have other uses.) 419 */ 420#define SVN_CL__LOG_MSG_OPTIONS 'm', 'F', \ 421 opt_force_log, \ 422 opt_editor_cmd, \ 423 opt_encoding, \ 424 opt_with_revprop 425 426const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] = 427{ 428 { "add", svn_cl__add, {0}, N_ 429 ("Put files and directories under version control, scheduling\n" 430 "them for addition to repository. They will be added in next commit.\n" 431 "usage: add PATH...\n"), 432 {opt_targets, 'N', opt_depth, 'q', opt_force, opt_no_ignore, opt_autoprops, 433 opt_no_autoprops, opt_parents }, 434 {{opt_parents, N_("add intermediate parents")}} }, 435 436 { "blame", svn_cl__blame, {"praise", "annotate", "ann"}, N_ 437 ("Output the content of specified files or\n" 438 "URLs with revision and author information in-line.\n" 439 "usage: blame TARGET[@REV]...\n" 440 "\n" 441 " If specified, REV determines in which revision the target is first\n" 442 " looked up.\n"), 443 {'r', 'v', 'g', opt_incremental, opt_xml, 'x', opt_force} }, 444 445 { "cat", svn_cl__cat, {0}, N_ 446 ("Output the content of specified files or URLs.\n" 447 "usage: cat TARGET[@REV]...\n" 448 "\n" 449 " If specified, REV determines in which revision the target is first\n" 450 " looked up.\n"), 451 {'r'} }, 452 453 { "changelist", svn_cl__changelist, {"cl"}, N_ 454 ("Associate (or dissociate) changelist CLNAME with the named files.\n" 455 "usage: 1. changelist CLNAME PATH...\n" 456 " 2. changelist --remove PATH...\n"), 457 { 'q', 'R', opt_depth, opt_remove, opt_targets, opt_changelist} }, 458 459 { "checkout", svn_cl__checkout, {"co"}, N_ 460 ("Check out a working copy from a repository.\n" 461 "usage: checkout URL[@REV]... [PATH]\n" 462 "\n" 463 " If specified, REV determines in which revision the URL is first\n" 464 " looked up.\n" 465 "\n" 466 " If PATH is omitted, the basename of the URL will be used as\n" 467 " the destination. If multiple URLs are given each will be checked\n" 468 " out into a sub-directory of PATH, with the name of the sub-directory\n" 469 " being the basename of the URL.\n" 470 "\n" 471 " If --force is used, unversioned obstructing paths in the working\n" 472 " copy destination do not automatically cause the check out to fail.\n" 473 " If the obstructing path is the same type (file or directory) as the\n" 474 " corresponding path in the repository it becomes versioned but its\n" 475 " contents are left 'as-is' in the working copy. This means that an\n" 476 " obstructing directory's unversioned children may also obstruct and\n" 477 " become versioned. For files, any content differences between the\n" 478 " obstruction and the repository are treated like a local modification\n" 479 " to the working copy. All properties from the repository are applied\n" 480 " to the obstructing path.\n" 481 "\n" 482 " See also 'svn help update' for a list of possible characters\n" 483 " reporting the action taken.\n"), 484 {'r', 'q', 'N', opt_depth, opt_force, opt_ignore_externals} }, 485 486 { "cleanup", svn_cl__cleanup, {0}, N_ 487 ("Recursively clean up the working copy, removing locks, resuming\n" 488 "unfinished operations, etc.\n" 489 "usage: cleanup [WCPATH...]\n"), 490 {opt_merge_cmd} }, 491 492 { "commit", svn_cl__commit, {"ci"}, 493 N_("Send changes from your working copy to the repository.\n" 494 "usage: commit [PATH...]\n" 495 "\n" 496 " A log message must be provided, but it can be empty. If it is not\n" 497 " given by a --message or --file option, an editor will be started.\n" 498 " If any targets are (or contain) locked items, those will be\n" 499 " unlocked after a successful commit.\n"), 500 {'q', 'N', opt_depth, opt_targets, opt_no_unlock, SVN_CL__LOG_MSG_OPTIONS, 501 opt_changelist, opt_keep_changelists, opt_include_externals} }, 502 503 { "copy", svn_cl__copy, {"cp"}, N_ 504 ("Copy files and directories in a working copy or repository.\n" 505 "usage: copy SRC[@REV]... DST\n" 506 "\n" 507 " SRC and DST can each be either a working copy (WC) path or URL:\n" 508 " WC -> WC: copy and schedule for addition (with history)\n" 509 " WC -> URL: immediately commit a copy of WC to URL\n" 510 " URL -> WC: check out URL into WC, schedule for addition\n" 511 " URL -> URL: complete server-side copy; used to branch and tag\n" 512 " All the SRCs must be of the same type. When copying multiple sources,\n" 513 " they will be added as children of DST, which must be a directory.\n" 514 "\n" 515 " WARNING: For compatibility with previous versions of Subversion,\n" 516 " copies performed using two working copy paths (WC -> WC) will not\n" 517 " contact the repository. As such, they may not, by default, be able\n" 518 " to propagate merge tracking information from the source of the copy\n" 519 " to the destination.\n"), 520 {'r', 'q', opt_ignore_externals, opt_parents, SVN_CL__LOG_MSG_OPTIONS} }, 521 522 { "delete", svn_cl__delete, {"del", "remove", "rm"}, N_ 523 ("Remove files and directories from version control.\n" 524 "usage: 1. delete PATH...\n" 525 " 2. delete URL...\n" 526 "\n" 527 " 1. Each item specified by a PATH is scheduled for deletion upon\n" 528 " the next commit. Files, and directories that have not been\n" 529 " committed, are immediately removed from the working copy\n" 530 " unless the --keep-local option is given.\n" 531 " PATHs that are, or contain, unversioned or modified items will\n" 532 " not be removed unless the --force or --keep-local option is given.\n" 533 "\n" 534 " 2. Each item specified by a URL is deleted from the repository\n" 535 " via an immediate commit.\n"), 536 {opt_force, 'q', opt_targets, SVN_CL__LOG_MSG_OPTIONS, opt_keep_local} }, 537 538 { "diff", svn_cl__diff, {"di"}, N_ 539 ("Display local changes or differences between two revisions or paths.\n" 540 "usage: 1. diff\n" 541 " 2. diff [-c M | -r N[:M]] [TARGET[@REV]...]\n" 542 " 3. diff [-r N[:M]] --old=OLD-TGT[@OLDREV] [--new=NEW-TGT[@NEWREV]] \\\n" 543 " [PATH...]\n" 544 " 4. diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]\n" 545 " 5. diff OLD-URL[@OLDREV] NEW-PATH[@NEWREV]\n" 546 " 6. diff OLD-PATH[@OLDREV] NEW-URL[@NEWREV]\n" 547 "\n" 548 " 1. Use just 'svn diff' to display local modifications in a working copy.\n" 549 "\n" 550 " 2. Display the changes made to TARGETs as they are seen in REV between\n" 551 " two revisions. TARGETs may be all working copy paths or all URLs.\n" 552 " If TARGETs are working copy paths, N defaults to BASE and M to the\n" 553 " working copy; if URLs, N must be specified and M defaults to HEAD.\n" 554 " The '-c M' option is equivalent to '-r N:M' where N = M-1.\n" 555 " Using '-c -M' does the reverse: '-r M:N' where N = M-1.\n" 556 "\n" 557 " 3. Display the differences between OLD-TGT as it was seen in OLDREV and\n" 558 " NEW-TGT as it was seen in NEWREV. PATHs, if given, are relative to\n" 559 " OLD-TGT and NEW-TGT and restrict the output to differences for those\n" 560 " paths. OLD-TGT and NEW-TGT may be working copy paths or URL[@REV].\n" 561 " NEW-TGT defaults to OLD-TGT if not specified. -r N makes OLDREV default\n" 562 " to N, -r N:M makes OLDREV default to N and NEWREV default to M.\n" 563 " If OLDREV or NEWREV are not specified, they default to WORKING for\n" 564 " working copy targets and to HEAD for URL targets.\n" 565 "\n" 566 " Either or both OLD-TGT and NEW-TGT may also be paths to unversioned\n" 567 " targets. Revisions cannot be specified for unversioned targets.\n" 568 " Both targets must be of the same node kind (file or directory).\n" 569 " Diffing unversioned targets against URL targets is not supported.\n" 570 "\n" 571 " 4. Shorthand for 'svn diff --old=OLD-URL[@OLDREV] --new=NEW-URL[@NEWREV]'\n" 572 " 5. Shorthand for 'svn diff --old=OLD-URL[@OLDREV] --new=NEW-PATH[@NEWREV]'\n" 573 " 6. Shorthand for 'svn diff --old=OLD-PATH[@OLDREV] --new=NEW-URL[@NEWREV]'\n"), 574 {'r', 'c', opt_old_cmd, opt_new_cmd, 'N', opt_depth, opt_diff_cmd, 575 opt_internal_diff, 'x', opt_no_diff_added, opt_no_diff_deleted, 576 opt_ignore_properties, opt_properties_only, 577 opt_show_copies_as_adds, opt_notice_ancestry, opt_summarize, opt_changelist, 578 opt_force, opt_xml, opt_use_git_diff_format, opt_patch_compatible} }, 579 { "export", svn_cl__export, {0}, N_ 580 ("Create an unversioned copy of a tree.\n" 581 "usage: 1. export [-r REV] URL[@PEGREV] [PATH]\n" 582 " 2. export [-r REV] PATH1[@PEGREV] [PATH2]\n" 583 "\n" 584 " 1. Exports a clean directory tree from the repository specified by\n" 585 " URL, at revision REV if it is given, otherwise at HEAD, into\n" 586 " PATH. If PATH is omitted, the last component of the URL is used\n" 587 " for the local directory name.\n" 588 "\n" 589 " 2. Exports a clean directory tree from the working copy specified by\n" 590 " PATH1, at revision REV if it is given, otherwise at WORKING, into\n" 591 " PATH2. If PATH2 is omitted, the last component of the PATH1 is used\n" 592 " for the local directory name. If REV is not specified, all local\n" 593 " changes will be preserved. Files not under version control will\n" 594 " not be copied.\n" 595 "\n" 596 " If specified, PEGREV determines in which revision the target is first\n" 597 " looked up.\n"), 598 {'r', 'q', 'N', opt_depth, opt_force, opt_native_eol, opt_ignore_externals, 599 opt_ignore_keywords} }, 600 601 { "help", svn_cl__help, {"?", "h"}, N_ 602 ("Describe the usage of this program or its subcommands.\n" 603 "usage: help [SUBCOMMAND...]\n"), 604 {0} }, 605 /* This command is also invoked if we see option "--help", "-h" or "-?". */ 606 607 { "import", svn_cl__import, {0}, N_ 608 ("Commit an unversioned file or tree into the repository.\n" 609 "usage: import [PATH] URL\n" 610 "\n" 611 " Recursively commit a copy of PATH to URL.\n" 612 " If PATH is omitted '.' is assumed.\n" 613 " Parent directories are created as necessary in the repository.\n" 614 " If PATH is a directory, the contents of the directory are added\n" 615 " directly under URL.\n" 616 " Unversionable items such as device files and pipes are ignored\n" 617 " if --force is specified.\n"), 618 {'q', 'N', opt_depth, opt_autoprops, opt_force, opt_no_autoprops, 619 SVN_CL__LOG_MSG_OPTIONS, opt_no_ignore} }, 620 621 { "info", svn_cl__info, {0}, N_ 622 ("Display information about a local or remote item.\n" 623 "usage: info [TARGET[@REV]...]\n" 624 "\n" 625 " Print information about each TARGET (default: '.').\n" 626 " TARGET may be either a working-copy path or URL. If specified, REV\n" 627 " determines in which revision the target is first looked up.\n"), 628 {'r', 'R', opt_depth, opt_targets, opt_incremental, opt_xml, opt_changelist} 629 }, 630 631 { "list", svn_cl__list, {"ls"}, N_ 632 ("List directory entries in the repository.\n" 633 "usage: list [TARGET[@REV]...]\n" 634 "\n" 635 " List each TARGET file and the contents of each TARGET directory as\n" 636 " they exist in the repository. If TARGET is a working copy path, the\n" 637 " corresponding repository URL will be used. If specified, REV determines\n" 638 " in which revision the target is first looked up.\n" 639 "\n" 640 " The default TARGET is '.', meaning the repository URL of the current\n" 641 " working directory.\n" 642 "\n" 643 " With --verbose, the following fields will be shown for each item:\n" 644 "\n" 645 " Revision number of the last commit\n" 646 " Author of the last commit\n" 647 " If locked, the letter 'O'. (Use 'svn info URL' to see details)\n" 648 " Size (in bytes)\n" 649 " Date and time of the last commit\n"), 650 {'r', 'v', 'R', opt_depth, opt_incremental, opt_xml, 651 opt_include_externals }, 652 {{opt_include_externals, N_("include externals definitions")}} }, 653 654 { "lock", svn_cl__lock, {0}, N_ 655 ("Lock working copy paths or URLs in the repository, so that\n" 656 "no other user can commit changes to them.\n" 657 "usage: lock TARGET...\n" 658 "\n" 659 " Use --force to steal the lock from another user or working copy.\n"), 660 { opt_targets, 'm', 'F', opt_force_log, opt_encoding, opt_force }, 661 {{'F', N_("read lock comment from file ARG")}, 662 {'m', N_("specify lock comment ARG")}, 663 {opt_force_log, N_("force validity of lock comment source")}} }, 664 665 { "log", svn_cl__log, {0}, N_ 666 ("Show the log messages for a set of revision(s) and/or path(s).\n" 667 "usage: 1. log [PATH][@REV]\n" 668 " 2. log URL[@REV] [PATH...]\n" 669 "\n" 670 " 1. Print the log messages for the URL corresponding to PATH\n" 671 " (default: '.'). If specified, REV is the revision in which the\n" 672 " URL is first looked up, and the default revision range is REV:1.\n" 673 " If REV is not specified, the default revision range is BASE:1,\n" 674 " since the URL might not exist in the HEAD revision.\n" 675 "\n" 676 " 2. Print the log messages for the PATHs (default: '.') under URL.\n" 677 " If specified, REV is the revision in which the URL is first\n" 678 " looked up, and the default revision range is REV:1; otherwise,\n" 679 " the URL is looked up in HEAD, and the default revision range is\n" 680 " HEAD:1.\n" 681 "\n" 682 " Multiple '-c' or '-r' options may be specified (but not a\n" 683 " combination of '-c' and '-r' options), and mixing of forward and\n" 684 " reverse ranges is allowed.\n" 685 "\n" 686 " With -v, also print all affected paths with each log message.\n" 687 " With -q, don't print the log message body itself (note that this is\n" 688 " compatible with -v).\n" 689 "\n" 690 " Each log message is printed just once, even if more than one of the\n" 691 " affected paths for that revision were explicitly requested. Logs\n" 692 " follow copy history by default. Use --stop-on-copy to disable this\n" 693 " behavior, which can be useful for determining branchpoints.\n" 694 "\n" 695 " The --depth option is only valid in combination with the --diff option\n" 696 " and limits the scope of the displayed diff to the specified depth.\n" 697 "\n" 698 " If the --search option is used, log messages are displayed only if the\n" 699 " provided search pattern matches any of the author, date, log message\n" 700 " text (unless --quiet is used), or, if the --verbose option is also\n" 701 " provided, a changed path.\n" 702 " The search pattern may include \"glob syntax\" wildcards:\n" 703 " ? matches any single character\n" 704 " * matches a sequence of arbitrary characters\n" 705 " [abc] matches any of the characters listed inside the brackets\n" 706 " If multiple --search options are provided, a log message is shown if\n" 707 " it matches any of the provided search patterns. If the --search-and\n" 708 " option is used, that option's argument is combined with the pattern\n" 709 " from the previous --search or --search-and option, and a log message\n" 710 " is shown only if it matches the combined search pattern.\n" 711 " If --limit is used in combination with --search, --limit restricts the\n" 712 " number of log messages searched, rather than restricting the output\n" 713 " to a particular number of matching log messages.\n" 714 "\n" 715 " Examples:\n" 716 "\n" 717 " Show the latest 5 log messages for the current working copy\n" 718 " directory and display paths changed in each commit:\n" 719 " svn log -l 5 -v\n" 720 "\n" 721 " Show the log for bar.c as of revision 42:\n" 722 " svn log bar.c@42\n" 723 "\n" 724 " Show log messages and diffs for each commit to foo.c:\n" 725 " svn log --diff http://www.example.com/repo/project/foo.c\n" 726 " (Because the above command uses a full URL it does not require\n" 727 " a working copy.)\n" 728 "\n" 729 " Show log messages for the children foo.c and bar.c of the directory\n" 730 " '/trunk' as it appeared in revision 50, using the ^/ URL shortcut:\n" 731 " svn log ^/trunk@50 foo.c bar.c\n" 732 "\n" 733 " Show the log messages for any incoming changes to foo.c during the\n" 734 " next 'svn update':\n" 735 " svn log -r BASE:HEAD foo.c\n" 736 "\n" 737 " Show the log message for the revision in which /branches/foo\n" 738 " was created:\n" 739 " svn log --stop-on-copy --limit 1 -r0:HEAD ^/branches/foo\n"), 740 {'r', 'q', 'v', 'g', 'c', opt_targets, opt_stop_on_copy, opt_incremental, 741 opt_xml, 'l', opt_with_all_revprops, opt_with_no_revprops, opt_with_revprop, 742 opt_depth, opt_diff, opt_diff_cmd, opt_internal_diff, 'x', opt_search, 743 opt_search_and, }, 744 {{opt_with_revprop, N_("retrieve revision property ARG")}, 745 {'c', N_("the change made in revision ARG")}} }, 746 747 { "merge", svn_cl__merge, {0}, N_ 748 ( /* For this large section, let's keep it unindented for easier 749 * viewing/editing. It has been vim-treated with a textwidth=75 and 'gw' 750 * (with quotes and newlines removed). */ 751"Merge changes into a working copy.\n" 752"usage: 1. merge SOURCE[@REV] [TARGET_WCPATH]\n" 753" (the 'automatic' merge)\n" 754" 2. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n" 755" (the 'cherry-pick' merge)\n" 756" 3. merge SOURCE1[@REV1] SOURCE2[@REV2] [TARGET_WCPATH]\n" 757" (the '2-URL' merge)\n" 758"\n" 759" 1. This form, with one source path and no revision range, is called\n" 760" an 'automatic' merge:\n" 761"\n" 762" svn merge SOURCE[@REV] [TARGET_WCPATH]\n" 763"\n" 764" The automatic merge is used for the 'sync' and 'reintegrate' merges\n" 765" in the 'feature branch' pattern described below. It finds all the\n" 766" changes on the source branch that have not already been merged to the\n" 767" target branch, and merges them into the working copy. Merge tracking\n" 768" is used to know which changes have already been merged.\n" 769"\n" 770" SOURCE specifies the branch from where the changes will be pulled, and\n" 771" TARGET_WCPATH specifies a working copy of the target branch to which\n" 772" the changes will be applied. Normally SOURCE and TARGET_WCPATH should\n" 773" each correspond to the root of a branch. (If you want to merge only a\n" 774" subtree, then the subtree path must be included in both SOURCE and\n" 775" TARGET_WCPATH; this is discouraged, to avoid subtree mergeinfo.)\n" 776"\n" 777" SOURCE is usually a URL. The optional '@REV' specifies both the peg\n" 778" revision of the URL and the latest revision that will be considered\n" 779" for merging; if REV is not specified, the HEAD revision is assumed. If\n" 780" SOURCE is a working copy path, the corresponding URL of the path is\n" 781" used, and the default value of 'REV' is the base revision (usually the\n" 782" revision last updated to).\n" 783"\n" 784" TARGET_WCPATH is a working copy path; if omitted, '.' is generally\n" 785" assumed. There are some special cases:\n" 786"\n" 787" - If SOURCE is a URL:\n" 788"\n" 789" - If the basename of the URL and the basename of '.' are the\n" 790" same, then the differences are applied to '.'. Otherwise,\n" 791" if a file with the same basename as that of the URL is found\n" 792" within '.', then the differences are applied to that file.\n" 793" In all other cases, the target defaults to '.'.\n" 794"\n" 795" - If SOURCE is a working copy path:\n" 796"\n" 797" - If the source is a file, then differences are applied to that\n" 798" file (useful for reverse-merging earlier changes). Otherwise,\n" 799" if the source is a directory, then the target defaults to '.'.\n" 800"\n" 801" In normal usage the working copy should be up to date, at a single\n" 802" revision, with no local modifications and no switched subtrees.\n" 803"\n" 804" - The 'Feature Branch' Merging Pattern -\n" 805"\n" 806" In this commonly used work flow, known also as the 'development\n" 807" branch' pattern, a developer creates a branch and commits a series of\n" 808" changes that implement a new feature. The developer periodically\n" 809" merges all the latest changes from the parent branch so as to keep the\n" 810" development branch up to date with those changes. When the feature is\n" 811" complete, the developer performs a merge from the feature branch to\n" 812" the parent branch to re-integrate the changes.\n" 813"\n" 814" parent --+----------o------o-o-------------o--\n" 815" \\ \\ \\ /\n" 816" \\ merge merge merge\n" 817" \\ \\ \\ /\n" 818" feature +--o-o-------o----o-o----o-------\n" 819"\n" 820" A merge from the parent branch to the feature branch is called a\n" 821" 'sync' or 'catch-up' merge, and a merge from the feature branch to the\n" 822" parent branch is called a 'reintegrate' merge.\n" 823"\n" 824" - Sync Merge Example -\n" 825" ............\n" 826" . .\n" 827" trunk --+------------L--------------R------\n" 828" \\ \\\n" 829" \\ |\n" 830" \\ v\n" 831" feature +------------------------o-----\n" 832" r100 r200\n" 833"\n" 834" Subversion will locate all the changes on 'trunk' that have not yet\n" 835" been merged into the 'feature' branch. In this case that is a single\n" 836" range, r100:200. In the diagram above, L marks the left side (trunk@100)\n" 837" and R marks the right side (trunk@200) of the merge source. The\n" 838" difference between L and R will be applied to the target working copy\n" 839" path. In this case, the working copy is a clean checkout of the entire\n" 840" 'feature' branch.\n" 841"\n" 842" To perform this sync merge, have a clean working copy of the feature\n" 843" branch and run the following command in its top-level directory:\n" 844"\n" 845" svn merge ^/trunk\n" 846"\n" 847" Note that the merge is now only in your local working copy and still\n" 848" needs to be committed to the repository so that it can be seen by\n" 849" others. You can review the changes and you may have to resolve\n" 850" conflicts before you commit the merge.\n" 851"\n" 852" - Reintegrate Merge Example -\n" 853"\n" 854" The feature branch was last synced with trunk up to revision X. So the\n" 855" difference between trunk@X and feature@HEAD contains the complete set\n" 856" of changes that implement the feature, and no other changes. These\n" 857" changes are applied to trunk.\n" 858"\n" 859" rW rX\n" 860" trunk ------+--------------------L------------------o\n" 861" \\ . ^\n" 862" \\ ............. /\n" 863" \\ . /\n" 864" feature +--------------------------------R\n" 865"\n" 866" In the diagram above, L marks the left side (trunk@X) and R marks the\n" 867" right side (feature@HEAD) of the merge. The difference between the\n" 868" left and right side is merged into trunk, the target.\n" 869"\n" 870" To perform the merge, have a clean working copy of trunk and run the\n" 871" following command in its top-level directory:\n" 872"\n" 873" svn merge ^/feature\n" 874"\n" 875" To prevent unnecessary merge conflicts, a reintegrate merge requires\n" 876" that TARGET_WCPATH is not a mixed-revision working copy, has no local\n" 877" modifications, and has no switched subtrees.\n" 878"\n" 879" A reintegrate merge also requires that the source branch is coherently\n" 880" synced with the target -- in the above example, this means that all\n" 881" revisions between the branch point W and the last merged revision X\n" 882" are merged to the feature branch, so that there are no unmerged\n" 883" revisions in-between.\n" 884"\n" 885"\n" 886" 2. This form is called a 'cherry-pick' merge:\n" 887"\n" 888" svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n" 889"\n" 890" A cherry-pick merge is used to merge specific revisions (or revision\n" 891" ranges) from one branch to another. By default, this uses merge\n" 892" tracking to automatically skip any revisions that have already been\n" 893" merged to the target; you can use the --ignore-ancestry option to\n" 894" disable such skipping.\n" 895"\n" 896" SOURCE is usually a URL. The optional '@REV' specifies only the peg\n" 897" revision of the URL and does not affect the merge range; if REV is not\n" 898" specified, the HEAD revision is assumed. If SOURCE is a working copy\n" 899" path, the corresponding URL of the path is used, and the default value\n" 900" of 'REV' is the base revision (usually the revision last updated to).\n" 901"\n" 902" TARGET_WCPATH is a working copy path; if omitted, '.' is generally\n" 903" assumed. The special cases noted above in the 'automatic' merge form\n" 904" also apply here.\n" 905"\n" 906" The revision ranges to be merged are specified by the '-r' and/or '-c'\n" 907" options. '-r N:M' refers to the difference in the history of the\n" 908" source branch between revisions N and M. You can use '-c M' to merge\n" 909" single revisions: '-c M' is equivalent to '-r <M-1>:M'. Each such\n" 910" difference is applied to TARGET_WCPATH.\n" 911"\n" 912" If the mergeinfo in TARGET_WCPATH indicates that revisions within the\n" 913" range were already merged, changes made in those revisions are not\n" 914" merged again. If needed, the range is broken into multiple sub-ranges,\n" 915" and each sub-range is merged separately.\n" 916"\n" 917" A 'reverse range' can be used to undo changes. For example, when\n" 918" source and target refer to the same branch, a previously committed\n" 919" revision can be 'undone'. In a reverse range, N is greater than M in\n" 920" '-r N:M', or the '-c' option is used with a negative number: '-c -M'\n" 921" is equivalent to '-r M:<M-1>'. Undoing changes like this is also known\n" 922" as performing a 'reverse merge'.\n" 923"\n" 924" Multiple '-c' and/or '-r' options may be specified and mixing of\n" 925" forward and reverse ranges is allowed.\n" 926"\n" 927" - Cherry-pick Merge Example -\n" 928"\n" 929" A bug has been fixed on trunk in revision 50. This fix needs to\n" 930" be merged from trunk onto the release branch.\n" 931"\n" 932" 1.x-release +-----------------------o-----\n" 933" / ^\n" 934" / |\n" 935" / |\n" 936" trunk ------+--------------------------LR-----\n" 937" r50\n" 938"\n" 939" In the above diagram, L marks the left side (trunk@49) and R marks the\n" 940" right side (trunk@50) of the merge. The difference between the left\n" 941" and right side is applied to the target working copy path.\n" 942"\n" 943" Note that the difference between revision 49 and 50 is exactly those\n" 944" changes that were committed in revision 50, not including changes\n" 945" committed in revision 49.\n" 946"\n" 947" To perform the merge, have a clean working copy of the release branch\n" 948" and run the following command in its top-level directory; remember\n" 949" that the default target is '.':\n" 950"\n" 951" svn merge -c50 ^/trunk\n" 952"\n" 953" You can also cherry-pick several revisions and/or revision ranges:\n" 954"\n" 955" svn merge -c50,54,60 -r65:68 ^/trunk\n" 956"\n" 957"\n" 958" 3. This form is called a '2-URL merge':\n" 959"\n" 960" svn merge SOURCE1[@REV1] SOURCE2[@REV2] [TARGET_WCPATH]\n" 961"\n" 962" You should use this merge variant only if the other variants do not\n" 963" apply to your situation, as this variant can be quite complex to\n" 964" master.\n" 965"\n" 966" Two source URLs are specified, identifying two trees on the same\n" 967" branch or on different branches. The trees are compared and the\n" 968" difference from SOURCE1@REV1 to SOURCE2@REV2 is applied to the\n" 969" working copy of the target branch at TARGET_WCPATH. The target\n" 970" branch may be the same as one or both sources, or different again.\n" 971" The three branches involved can be completely unrelated.\n" 972"\n" 973" TARGET_WCPATH is a working copy path; if omitted, '.' is generally\n" 974" assumed. The special cases noted above in the 'automatic' merge form\n" 975" also apply here.\n" 976"\n" 977" SOURCE1 and/or SOURCE2 can also be specified as a working copy path,\n" 978" in which case the merge source URL is derived from the working copy.\n" 979"\n" 980" - 2-URL Merge Example -\n" 981"\n" 982" Two features have been developed on separate branches called 'foo' and\n" 983" 'bar'. It has since become clear that 'bar' should be combined with\n" 984" the 'foo' branch for further development before reintegration.\n" 985"\n" 986" Although both feature branches originate from trunk, they are not\n" 987" directly related -- one is not a direct copy of the other. A 2-URL\n" 988" merge is necessary.\n" 989"\n" 990" The 'bar' branch has been synced with trunk up to revision 500.\n" 991" (If this revision number is not known, it can be located using the\n" 992" 'svn log' and/or 'svn mergeinfo' commands.)\n" 993" The difference between trunk@500 and bar@HEAD contains the complete\n" 994" set of changes related to feature 'bar', and no other changes. These\n" 995" changes are applied to the 'foo' branch.\n" 996"\n" 997" foo +-----------------------------------o\n" 998" / ^\n" 999" / /\n" 1000" / r500 /\n" 1001" trunk ------+------+-----------------L---------> /\n" 1002" \\ . /\n" 1003" \\ ............ /\n" 1004" \\ . /\n" 1005" bar +-----------------------------------R\n" 1006"\n" 1007" In the diagram above, L marks the left side (trunk@500) and R marks\n" 1008" the right side (bar@HEAD) of the merge. The difference between the\n" 1009" left and right side is applied to the target working copy path, in\n" 1010" this case a working copy of the 'foo' branch.\n" 1011"\n" 1012" To perform the merge, have a clean working copy of the 'foo' branch\n" 1013" and run the following command in its top-level directory:\n" 1014"\n" 1015" svn merge ^/trunk@500 ^/bar\n" 1016"\n" 1017" The exact changes applied by a 2-URL merge can be previewed with svn's\n" 1018" diff command, which is a good idea to verify if you do not have the\n" 1019" luxury of a clean working copy to merge to. In this case:\n" 1020"\n" 1021" svn diff ^/trunk@500 ^/bar@HEAD\n" 1022"\n" 1023"\n" 1024" The following applies to all types of merges:\n" 1025"\n" 1026" To prevent unnecessary merge conflicts, svn merge requires that\n" 1027" TARGET_WCPATH is not a mixed-revision working copy. Running 'svn update'\n" 1028" before starting a merge ensures that all items in the working copy are\n" 1029" based on the same revision.\n" 1030"\n" 1031" If possible, you should have no local modifications in the merge's target\n" 1032" working copy prior to the merge, to keep things simpler. It will be\n" 1033" easier to revert the merge and to understand the branch's history.\n" 1034"\n" 1035" Switched sub-paths should also be avoided during merging, as they may\n" 1036" cause incomplete merges and create subtree mergeinfo.\n" 1037"\n" 1038" For each merged item a line will be printed with characters reporting the\n" 1039" action taken. These characters have the following meaning:\n" 1040"\n" 1041" A Added\n" 1042" D Deleted\n" 1043" U Updated\n" 1044" C Conflict\n" 1045" G Merged\n" 1046" E Existed\n" 1047" R Replaced\n" 1048"\n" 1049" Characters in the first column report about the item itself.\n" 1050" Characters in the second column report about properties of the item.\n" 1051" A 'C' in the third column indicates a tree conflict, while a 'C' in\n" 1052" the first and second columns indicate textual conflicts in files\n" 1053" and in property values, respectively.\n" 1054"\n" 1055" - Merge Tracking -\n" 1056"\n" 1057" Subversion uses the svn:mergeinfo property to track merge history. This\n" 1058" property is considered at the start of a merge to determine what to merge\n" 1059" and it is updated at the conclusion of the merge to describe the merge\n" 1060" that took place. Mergeinfo is used only if the two sources are on the\n" 1061" same line of history -- if the first source is an ancestor of the second,\n" 1062" or vice-versa (i.e. if one has originally been created by copying the\n" 1063" other). This is verified and enforced when using sync merges and\n" 1064" reintegrate merges.\n" 1065"\n" 1066" The --ignore-ancestry option prevents merge tracking and thus ignores\n" 1067" mergeinfo, neither considering it nor recording it.\n" 1068"\n" 1069" - Merging from foreign repositories -\n" 1070"\n" 1071" Subversion does support merging from foreign repositories.\n" 1072" While all merge source URLs must point to the same repository, the merge\n" 1073" target working copy may come from a different repository than the source.\n" 1074" However, there are some caveats. Most notably, copies made in the\n" 1075" merge source will be transformed into plain additions in the merge\n" 1076" target. Also, merge-tracking is not supported for merges from foreign\n" 1077" repositories.\n"), 1078 {'r', 'c', 'N', opt_depth, 'q', opt_force, opt_dry_run, opt_merge_cmd, 1079 opt_record_only, 'x', opt_ignore_ancestry, opt_accept, opt_reintegrate, 1080 opt_allow_mixed_revisions, 'v'} }, 1081 1082 { "mergeinfo", svn_cl__mergeinfo, {0}, N_ 1083 ("Display merge-related information.\n" 1084 "usage: 1. mergeinfo SOURCE[@REV] [TARGET[@REV]]\n" 1085 " 2. mergeinfo --show-revs=WHICH SOURCE[@REV] [TARGET[@REV]]\n" 1086 "\n" 1087 " 1. Summarize the history of merging between SOURCE and TARGET. The graph\n" 1088 " shows, from left to right:\n" 1089 " the youngest common ancestor of the branches;\n" 1090 " the latest full merge in either direction, and thus the common base\n" 1091 " that will be used for the next automatic merge;\n" 1092 " the repository path and revision number of the tip of each branch.\n" 1093 "\n" 1094 " 2. Print the revision numbers on SOURCE that have been merged to TARGET\n" 1095 " (with --show-revs=merged), or that have not been merged to TARGET\n" 1096 " (with --show-revs=eligible). Print only revisions in which there was\n" 1097 " at least one change in SOURCE.\n" 1098 "\n" 1099 " If --revision (-r) is provided, filter the displayed information to\n" 1100 " show only that which is associated with the revisions within the\n" 1101 " specified range. Revision numbers, dates, and the 'HEAD' keyword are\n" 1102 " valid range values.\n" 1103 "\n" 1104 " SOURCE and TARGET are the source and target branch URLs, respectively.\n" 1105 " (If a WC path is given, the corresponding base URL is used.) The default\n" 1106 " TARGET is the current working directory ('.'). REV specifies the revision\n" 1107 " to be considered the tip of the branch; the default for SOURCE is HEAD,\n" 1108 " and the default for TARGET is HEAD for a URL or BASE for a WC path.\n" 1109 "\n" 1110 " The depth can be 'empty' or 'infinity'; the default is 'empty'.\n"), 1111 {'r', 'R', opt_depth, opt_show_revs} }, 1112 1113 { "mkdir", svn_cl__mkdir, {0}, N_ 1114 ("Create a new directory under version control.\n" 1115 "usage: 1. mkdir PATH...\n" 1116 " 2. mkdir URL...\n" 1117 "\n" 1118 " Create version controlled directories.\n" 1119 "\n" 1120 " 1. Each directory specified by a working copy PATH is created locally\n" 1121 " and scheduled for addition upon the next commit.\n" 1122 "\n" 1123 " 2. Each directory specified by a URL is created in the repository via\n" 1124 " an immediate commit.\n" 1125 "\n" 1126 " In both cases, all the intermediate directories must already exist,\n" 1127 " unless the --parents option is given.\n"), 1128 {'q', opt_parents, SVN_CL__LOG_MSG_OPTIONS} }, 1129 1130 { "move", svn_cl__move, {"mv", "rename", "ren"}, N_ 1131 ("Move (rename) an item in a working copy or repository.\n" 1132 "usage: move SRC... DST\n" 1133 "\n" 1134 " SRC and DST can both be working copy (WC) paths or URLs:\n" 1135 " WC -> WC: move an item in a working copy, as a local change to\n" 1136 " be committed later (with or without further changes)\n" 1137 " URL -> URL: move an item in the repository directly, immediately\n" 1138 " creating a new revision in the repository\n" 1139 " All the SRCs must be of the same type. When moving multiple sources,\n" 1140 " they will be added as children of DST, which must be a directory.\n" 1141 "\n" 1142 " SRC and DST of WC -> WC moves must be committed in the same revision.\n" 1143 " Furthermore, WC -> WC moves will refuse to move a mixed-revision subtree.\n" 1144 " To avoid unnecessary conflicts, it is recommended to run 'svn update'\n" 1145 " to update the subtree to a single revision before moving it.\n" 1146 " The --allow-mixed-revisions option is provided for backward compatibility.\n" 1147 "\n" 1148 " The --revision option has no use and is deprecated.\n"), 1149 {'r', 'q', opt_force, opt_parents, opt_allow_mixed_revisions, 1150 SVN_CL__LOG_MSG_OPTIONS} }, 1151 1152 { "patch", svn_cl__patch, {0}, N_ 1153 ("Apply a patch to a working copy.\n" 1154 "usage: patch PATCHFILE [WCPATH]\n" 1155 "\n" 1156 " Apply a unidiff patch in PATCHFILE to the working copy WCPATH.\n" 1157 " If WCPATH is omitted, '.' is assumed.\n" 1158 "\n" 1159 " A unidiff patch suitable for application to a working copy can be\n" 1160 " produced with the 'svn diff' command or third-party diffing tools.\n" 1161 " Any non-unidiff content of PATCHFILE is ignored, except for Subversion\n" 1162 " property diffs as produced by 'svn diff'.\n" 1163 "\n" 1164 " Changes listed in the patch will either be applied or rejected.\n" 1165 " If a change does not match at its exact line offset, it may be applied\n" 1166 " earlier or later in the file if a match is found elsewhere for the\n" 1167 " surrounding lines of context provided by the patch.\n" 1168 " A change may also be applied with fuzz, which means that one\n" 1169 " or more lines of context are ignored when matching the change.\n" 1170 " If no matching context can be found for a change, the change conflicts\n" 1171 " and will be written to a reject file with the extension .svnpatch.rej.\n" 1172 "\n" 1173 " For each patched file a line will be printed with characters reporting\n" 1174 " the action taken. These characters have the following meaning:\n" 1175 "\n" 1176 " A Added\n" 1177 " D Deleted\n" 1178 " U Updated\n" 1179 " C Conflict\n" 1180 " G Merged (with local uncommitted changes)\n" 1181 "\n" 1182 " Changes applied with an offset or fuzz are reported on lines starting\n" 1183 " with the '>' symbol. You should review such changes carefully.\n" 1184 "\n" 1185 " If the patch removes all content from a file, that file is scheduled\n" 1186 " for deletion. If the patch creates a new file, that file is scheduled\n" 1187 " for addition. Use 'svn revert' to undo deletions and additions you\n" 1188 " do not agree with.\n" 1189 "\n" 1190 " Hint: If the patch file was created with Subversion, it will contain\n" 1191 " the number of a revision N the patch will cleanly apply to\n" 1192 " (look for lines like '--- foo/bar.txt (revision N)').\n" 1193 " To avoid rejects, first update to the revision N using\n" 1194 " 'svn update -r N', apply the patch, and then update back to the\n" 1195 " HEAD revision. This way, conflicts can be resolved interactively.\n" 1196 ), 1197 {'q', opt_dry_run, opt_strip, opt_reverse_diff, 1198 opt_ignore_whitespace} }, 1199 1200 { "propdel", svn_cl__propdel, {"pdel", "pd"}, N_ 1201 ("Remove a property from files, dirs, or revisions.\n" 1202 "usage: 1. propdel PROPNAME [PATH...]\n" 1203 " 2. propdel PROPNAME --revprop -r REV [TARGET]\n" 1204 "\n" 1205 " 1. Removes versioned props in working copy.\n" 1206 " 2. Removes unversioned remote prop on repos revision.\n" 1207 " TARGET only determines which repository to access.\n"), 1208 {'q', 'R', opt_depth, 'r', opt_revprop, opt_changelist} }, 1209 1210 { "propedit", svn_cl__propedit, {"pedit", "pe"}, N_ 1211 ("Edit a property with an external editor.\n" 1212 "usage: 1. propedit PROPNAME TARGET...\n" 1213 " 2. propedit PROPNAME --revprop -r REV [TARGET]\n" 1214 "\n" 1215 " 1. Edits versioned prop in working copy or repository.\n" 1216 " 2. Edits unversioned remote prop on repos revision.\n" 1217 " TARGET only determines which repository to access.\n" 1218 "\n" 1219 " See 'svn help propset' for more on setting properties.\n"), 1220 {'r', opt_revprop, SVN_CL__LOG_MSG_OPTIONS, opt_force} }, 1221 1222 { "propget", svn_cl__propget, {"pget", "pg"}, N_ 1223 ("Print the value of a property on files, dirs, or revisions.\n" 1224 "usage: 1. propget PROPNAME [TARGET[@REV]...]\n" 1225 " 2. propget PROPNAME --revprop -r REV [TARGET]\n" 1226 "\n" 1227 " 1. Prints versioned props. If specified, REV determines in which\n" 1228 " revision the target is first looked up.\n" 1229 " 2. Prints unversioned remote prop on repos revision.\n" 1230 " TARGET only determines which repository to access.\n" 1231 "\n" 1232 " With --verbose, the target path and the property name are printed on\n" 1233 " separate lines before each value, like 'svn proplist --verbose'.\n" 1234 " Otherwise, if there is more than one TARGET or a depth other than\n" 1235 " 'empty', the target path is printed on the same line before each value.\n" 1236 "\n" 1237 " By default, an extra newline is printed after the property value so that\n" 1238 " the output looks pretty. With a single TARGET and depth 'empty', you can\n" 1239 " use the --strict option to disable this (useful when redirecting a binary\n" 1240 " property value to a file, for example).\n"), 1241 {'v', 'R', opt_depth, 'r', opt_revprop, opt_strict, opt_xml, 1242 opt_changelist, opt_show_inherited_props }, 1243 {{'v', N_("print path, name and value on separate lines")}, 1244 {opt_strict, N_("don't print an extra newline")}} }, 1245 1246 { "proplist", svn_cl__proplist, {"plist", "pl"}, N_ 1247 ("List all properties on files, dirs, or revisions.\n" 1248 "usage: 1. proplist [TARGET[@REV]...]\n" 1249 " 2. proplist --revprop -r REV [TARGET]\n" 1250 "\n" 1251 " 1. Lists versioned props. If specified, REV determines in which\n" 1252 " revision the target is first looked up.\n" 1253 " 2. Lists unversioned remote props on repos revision.\n" 1254 " TARGET only determines which repository to access.\n" 1255 "\n" 1256 " With --verbose, the property values are printed as well, like 'svn propget\n" 1257 " --verbose'. With --quiet, the paths are not printed.\n"), 1258 {'v', 'R', opt_depth, 'r', 'q', opt_revprop, opt_xml, opt_changelist, 1259 opt_show_inherited_props }, 1260 {{'v', N_("print path, name and value on separate lines")}, 1261 {'q', N_("don't print the path")}} }, 1262 1263 { "propset", svn_cl__propset, {"pset", "ps"}, N_ 1264 ("Set the value of a property on files, dirs, or revisions.\n" 1265 "usage: 1. propset PROPNAME PROPVAL PATH...\n" 1266 " 2. propset PROPNAME --revprop -r REV PROPVAL [TARGET]\n" 1267 "\n" 1268 " 1. Changes a versioned file or directory property in a working copy.\n" 1269 " 2. Changes an unversioned property on a repository revision.\n" 1270 " (TARGET only determines which repository to access.)\n" 1271 "\n" 1272 " The value may be provided with the --file option instead of PROPVAL.\n" 1273 "\n" 1274 " Property names starting with 'svn:' are reserved. Subversion recognizes\n" 1275 " the following special versioned properties on a file:\n" 1276 " svn:keywords - Keywords to be expanded. Valid keywords are:\n" 1277 " URL, HeadURL - The URL for the head version of the file.\n" 1278 " Author, LastChangedBy - The last person to modify the file.\n" 1279 " Date, LastChangedDate - The date/time the file was last modified.\n" 1280 " Rev, Revision, - The last revision the file changed.\n" 1281 " LastChangedRevision\n" 1282 " Id - A compressed summary of the previous four.\n" 1283 " Header - Similar to Id but includes the full URL.\n" 1284 "\n" 1285 " Custom keywords can be defined with a format string separated from\n" 1286 " the keyword name with '='. Valid format substitutions are:\n" 1287 " %a - The author of the revision given by %r.\n" 1288 " %b - The basename of the URL of the file.\n" 1289 " %d - Short format of the date of the revision given by %r.\n" 1290 " %D - Long format of the date of the revision given by %r.\n" 1291 " %P - The file's path, relative to the repository root.\n" 1292 " %r - The number of the revision which last changed the file.\n" 1293 " %R - The URL to the root of the repository.\n" 1294 " %u - The URL of the file.\n" 1295 " %_ - A space (keyword definitions cannot contain a literal space).\n" 1296 " %% - A literal '%'.\n" 1297 " %H - Equivalent to %P%_%r%_%d%_%a.\n" 1298 " %I - Equivalent to %b%_%r%_%d%_%a.\n" 1299 " Example custom keyword definition: MyKeyword=%r%_%a%_%P\n" 1300 " Once a custom keyword has been defined for a file, it can be used\n" 1301 " within the file like any other keyword: $MyKeyword$\n" 1302 "\n" 1303 " svn:executable - If present, make the file executable. Use\n" 1304 " 'svn propdel svn:executable PATH...' to clear.\n" 1305 " svn:eol-style - One of 'native', 'LF', 'CR', 'CRLF'.\n" 1306 " svn:mime-type - The mimetype of the file. Used to determine\n" 1307 " whether to merge the file, and how to serve it from Apache.\n" 1308 " A mimetype beginning with 'text/' (or an absent mimetype) is\n" 1309 " treated as text. Anything else is treated as binary.\n" 1310 " svn:needs-lock - If present, indicates that the file should be locked\n" 1311 " before it is modified. Makes the working copy file read-only\n" 1312 " when it is not locked. Use 'svn propdel svn:needs-lock PATH...'\n" 1313 " to clear.\n" 1314 "\n" 1315 " Subversion recognizes the following special versioned properties on a\n" 1316 " directory:\n" 1317 " svn:ignore - A list of file glob patterns to ignore, one per line.\n" 1318 " svn:global-ignores - Like svn:ignore, but inheritable.\n" 1319 " svn:externals - A list of module specifiers, one per line, in the\n" 1320 " following format similar to the syntax of 'svn checkout':\n" 1321 " [-r REV] URL[@PEG] LOCALPATH\n" 1322 " Example:\n" 1323 " http://example.com/repos/zig foo/bar\n" 1324 " The LOCALPATH is relative to the directory having this property.\n" 1325 " To pin the external to a known revision, specify the optional REV:\n" 1326 " -r25 http://example.com/repos/zig foo/bar\n" 1327 " To unambiguously identify an element at a path which may have been\n" 1328 " subsequently deleted or renamed, specify the optional PEG revision:\n" 1329 " -r25 http://example.com/repos/zig@42 foo/bar\n" 1330 " The URL may be a full URL or a relative URL starting with one of:\n" 1331 " ../ to the parent directory of the extracted external\n" 1332 " ^/ to the repository root\n" 1333 " / to the server root\n" 1334 " // to the URL scheme\n" 1335 " Use of the following format is discouraged but is supported for\n" 1336 " interoperability with Subversion 1.4 and earlier clients:\n" 1337 " LOCALPATH [-r PEG] URL\n" 1338 " The ambiguous format 'relative_path relative_path' is taken as\n" 1339 " 'relative_url relative_path' with peg revision support.\n" 1340 " Lines starting with a '#' character are ignored.\n"), 1341 {'F', opt_encoding, 'q', 'r', opt_targets, 'R', opt_depth, opt_revprop, 1342 opt_force, opt_changelist }, 1343 {{'F', N_("read property value from file ARG")}} }, 1344 1345 { "relocate", svn_cl__relocate, {0}, N_ 1346 ("Relocate the working copy to point to a different repository root URL.\n" 1347 "usage: 1. relocate FROM-PREFIX TO-PREFIX [PATH...]\n" 1348 " 2. relocate TO-URL [PATH]\n" 1349 "\n" 1350 " Rewrite working copy URL metadata to reflect a syntactic change only.\n" 1351 " This is used when a repository's root URL changes (such as a scheme\n" 1352 " or hostname change) but your working copy still reflects the same\n" 1353 " directory within the same repository.\n" 1354 "\n" 1355 " 1. FROM-PREFIX and TO-PREFIX are initial substrings of the working\n" 1356 " copy's current and new URLs, respectively. (You may specify the\n" 1357 " complete old and new URLs if you wish.) Use 'svn info' to determine\n" 1358 " the current working copy URL.\n" 1359 "\n" 1360 " 2. TO-URL is the (complete) new repository URL to use for PATH.\n" 1361 "\n" 1362 " Examples:\n" 1363 " svn relocate http:// svn:// project1 project2\n" 1364 " svn relocate http://www.example.com/repo/project \\\n" 1365 " svn://svn.example.com/repo/project\n"), 1366 {opt_ignore_externals} }, 1367 1368 { "resolve", svn_cl__resolve, {0}, N_ 1369 ("Resolve conflicts on working copy files or directories.\n" 1370 "usage: resolve [PATH...]\n" 1371 "\n" 1372 " By default, perform interactive conflict resolution on PATH.\n" 1373 " In this mode, the command is recursive by default (depth 'infinity').\n" 1374 "\n" 1375 " The --accept=ARG option prevents interactive prompting and forces\n" 1376 " conflicts on PATH to be resolved in the manner specified by ARG.\n" 1377 " In this mode, the command is not recursive by default (depth 'empty').\n"), 1378 {opt_targets, 'R', opt_depth, 'q', opt_accept}, 1379 {{opt_accept, N_("specify automatic conflict resolution source\n" 1380 " " 1381 "('base', 'working', 'mine-conflict',\n" 1382 " " 1383 "'theirs-conflict', 'mine-full', 'theirs-full')")}} }, 1384 1385 { "resolved", svn_cl__resolved, {0}, N_ 1386 ("Remove 'conflicted' state on working copy files or directories.\n" 1387 "usage: resolved PATH...\n" 1388 "\n" 1389 " Note: this subcommand does not semantically resolve conflicts or\n" 1390 " remove conflict markers; it merely removes the conflict-related\n" 1391 " artifact files and allows PATH to be committed again. It has been\n" 1392 " deprecated in favor of running 'svn resolve --accept working'.\n"), 1393 {opt_targets, 'R', opt_depth, 'q'} }, 1394 1395 { "revert", svn_cl__revert, {0}, N_ 1396 ("Restore pristine working copy state (undo local changes).\n" 1397 "usage: revert PATH...\n" 1398 "\n" 1399 " Revert changes in the working copy at or within PATH, and remove\n" 1400 " conflict markers as well, if any.\n" 1401 "\n" 1402 " This subcommand does not revert already committed changes.\n" 1403 " For information about undoing already committed changes, search\n" 1404 " the output of 'svn help merge' for 'undo'.\n"), 1405 {opt_targets, 'R', opt_depth, 'q', opt_changelist} }, 1406 1407 { "status", svn_cl__status, {"stat", "st"}, N_ 1408 ("Print the status of working copy files and directories.\n" 1409 "usage: status [PATH...]\n" 1410 "\n" 1411 " With no args, print only locally modified items (no network access).\n" 1412 " With -q, print only summary information about locally modified items.\n" 1413 " With -u, add working revision and server out-of-date information.\n" 1414 " With -v, print full revision information on every item.\n" 1415 "\n" 1416 " The first seven columns in the output are each one character wide:\n" 1417 " First column: Says if item was added, deleted, or otherwise changed\n" 1418 " ' ' no modifications\n" 1419 " 'A' Added\n" 1420 " 'C' Conflicted\n" 1421 " 'D' Deleted\n" 1422 " 'I' Ignored\n" 1423 " 'M' Modified\n" 1424 " 'R' Replaced\n" 1425 " 'X' an unversioned directory created by an externals definition\n" 1426 " '?' item is not under version control\n" 1427 " '!' item is missing (removed by non-svn command) or incomplete\n" 1428 " '~' versioned item obstructed by some item of a different kind\n" 1429 " Second column: Modifications of a file's or directory's properties\n" 1430 " ' ' no modifications\n" 1431 " 'C' Conflicted\n" 1432 " 'M' Modified\n" 1433 " Third column: Whether the working copy directory is locked\n" 1434 " ' ' not locked\n" 1435 " 'L' locked\n" 1436 " Fourth column: Scheduled commit will contain addition-with-history\n" 1437 " ' ' no history scheduled with commit\n" 1438 " '+' history scheduled with commit\n" 1439 " Fifth column: Whether the item is switched or a file external\n" 1440 " ' ' normal\n" 1441 " 'S' the item has a Switched URL relative to the parent\n" 1442 " 'X' a versioned file created by an eXternals definition\n" 1443 " Sixth column: Repository lock token\n" 1444 " (without -u)\n" 1445 " ' ' no lock token\n" 1446 " 'K' lock token present\n" 1447 " (with -u)\n" 1448 " ' ' not locked in repository, no lock token\n" 1449 " 'K' locked in repository, lock toKen present\n" 1450 " 'O' locked in repository, lock token in some Other working copy\n" 1451 " 'T' locked in repository, lock token present but sTolen\n" 1452 " 'B' not locked in repository, lock token present but Broken\n" 1453 " Seventh column: Whether the item is the victim of a tree conflict\n" 1454 " ' ' normal\n" 1455 " 'C' tree-Conflicted\n" 1456 " If the item is a tree conflict victim, an additional line is printed\n" 1457 " after the item's status line, explaining the nature of the conflict.\n" 1458 "\n" 1459 " The out-of-date information appears in the ninth column (with -u):\n" 1460 " '*' a newer revision exists on the server\n" 1461 " ' ' the working copy is up to date\n" 1462 "\n" 1463 " Remaining fields are variable width and delimited by spaces:\n" 1464 " The working revision (with -u or -v; '-' if the item is copied)\n" 1465 " The last committed revision and last committed author (with -v)\n" 1466 " The working copy path is always the final field, so it can\n" 1467 " include spaces.\n" 1468 "\n" 1469 " The presence of a question mark ('?') where a working revision, last\n" 1470 " committed revision, or last committed author was expected indicates\n" 1471 " that the information is unknown or irrelevant given the state of the\n" 1472 " item (for example, when the item is the result of a copy operation).\n" 1473 " The question mark serves as a visual placeholder to facilitate parsing.\n" 1474 "\n" 1475 " Example output:\n" 1476 " svn status wc\n" 1477 " M wc/bar.c\n" 1478 " A + wc/qax.c\n" 1479 "\n" 1480 " svn status -u wc\n" 1481 " M 965 wc/bar.c\n" 1482 " * 965 wc/foo.c\n" 1483 " A + - wc/qax.c\n" 1484 " Status against revision: 981\n" 1485 "\n" 1486 " svn status --show-updates --verbose wc\n" 1487 " M 965 938 kfogel wc/bar.c\n" 1488 " * 965 922 sussman wc/foo.c\n" 1489 " A + - 687 joe wc/qax.c\n" 1490 " 965 687 joe wc/zig.c\n" 1491 " Status against revision: 981\n" 1492 "\n" 1493 " svn status\n" 1494 " M wc/bar.c\n" 1495 " ! C wc/qaz.c\n" 1496 " > local missing, incoming edit upon update\n" 1497 " D wc/qax.c\n"), 1498 { 'u', 'v', 'N', opt_depth, 'q', opt_no_ignore, opt_incremental, opt_xml, 1499 opt_ignore_externals, opt_changelist}, 1500 {{'q', N_("don't print unversioned items")}} }, 1501 1502 { "switch", svn_cl__switch, {"sw"}, N_ 1503 ("Update the working copy to a different URL within the same repository.\n" 1504 "usage: 1. switch URL[@PEGREV] [PATH]\n" 1505 " 2. switch --relocate FROM-PREFIX TO-PREFIX [PATH...]\n" 1506 "\n" 1507 " 1. Update the working copy to mirror a new URL within the repository.\n" 1508 " This behavior is similar to 'svn update', and is the way to\n" 1509 " move a working copy to a branch or tag within the same repository.\n" 1510 " If specified, PEGREV determines in which revision the target is first\n" 1511 " looked up.\n" 1512 "\n" 1513 " If --force is used, unversioned obstructing paths in the working\n" 1514 " copy do not automatically cause a failure if the switch attempts to\n" 1515 " add the same path. If the obstructing path is the same type (file\n" 1516 " or directory) as the corresponding path in the repository it becomes\n" 1517 " versioned but its contents are left 'as-is' in the working copy.\n" 1518 " This means that an obstructing directory's unversioned children may\n" 1519 " also obstruct and become versioned. For files, any content differences\n" 1520 " between the obstruction and the repository are treated like a local\n" 1521 " modification to the working copy. All properties from the repository\n" 1522 " are applied to the obstructing path.\n" 1523 "\n" 1524 " Use the --set-depth option to set a new working copy depth on the\n" 1525 " targets of this operation.\n" 1526 "\n" 1527 " By default, Subversion will refuse to switch a working copy path to\n" 1528 " a new URL with which it shares no common version control ancestry.\n" 1529 " Use the '--ignore-ancestry' option to override this sanity check.\n" 1530 "\n" 1531 " 2. The '--relocate' option is deprecated. This syntax is equivalent to\n" 1532 " 'svn relocate FROM-PREFIX TO-PREFIX [PATH]'.\n" 1533 "\n" 1534 " See also 'svn help update' for a list of possible characters\n" 1535 " reporting the action taken.\n" 1536 "\n" 1537 " Examples:\n" 1538 " svn switch ^/branches/1.x-release\n" 1539 " svn switch --relocate http:// svn://\n" 1540 " svn switch --relocate http://www.example.com/repo/project \\\n" 1541 " svn://svn.example.com/repo/project\n"), 1542 { 'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_relocate, 1543 opt_ignore_externals, opt_ignore_ancestry, opt_force, opt_accept}, 1544 {{opt_ignore_ancestry, 1545 N_("allow switching to a node with no common ancestor")}} 1546 }, 1547 1548 { "unlock", svn_cl__unlock, {0}, N_ 1549 ("Unlock working copy paths or URLs.\n" 1550 "usage: unlock TARGET...\n" 1551 "\n" 1552 " Use --force to break the lock.\n"), 1553 { opt_targets, opt_force } }, 1554 1555 { "update", svn_cl__update, {"up"}, N_ 1556 ("Bring changes from the repository into the working copy.\n" 1557 "usage: update [PATH...]\n" 1558 "\n" 1559 " If no revision is given, bring working copy up-to-date with HEAD rev.\n" 1560 " Else synchronize working copy to revision given by -r.\n" 1561 "\n" 1562 " For each updated item a line will be printed with characters reporting\n" 1563 " the action taken. These characters have the following meaning:\n" 1564 "\n" 1565 " A Added\n" 1566 " D Deleted\n" 1567 " U Updated\n" 1568 " C Conflict\n" 1569 " G Merged\n" 1570 " E Existed\n" 1571 " R Replaced\n" 1572 "\n" 1573 " Characters in the first column report about the item itself.\n" 1574 " Characters in the second column report about properties of the item.\n" 1575 " A 'B' in the third column signifies that the lock for the file has\n" 1576 " been broken or stolen.\n" 1577 " A 'C' in the fourth column indicates a tree conflict, while a 'C' in\n" 1578 " the first and second columns indicate textual conflicts in files\n" 1579 " and in property values, respectively.\n" 1580 "\n" 1581 " If --force is used, unversioned obstructing paths in the working\n" 1582 " copy do not automatically cause a failure if the update attempts to\n" 1583 " add the same path. If the obstructing path is the same type (file\n" 1584 " or directory) as the corresponding path in the repository it becomes\n" 1585 " versioned but its contents are left 'as-is' in the working copy.\n" 1586 " This means that an obstructing directory's unversioned children may\n" 1587 " also obstruct and become versioned. For files, any content differences\n" 1588 " between the obstruction and the repository are treated like a local\n" 1589 " modification to the working copy. All properties from the repository\n" 1590 " are applied to the obstructing path. Obstructing paths are reported\n" 1591 " in the first column with code 'E'.\n" 1592 "\n" 1593 " If the specified update target is missing from the working copy but its\n" 1594 " immediate parent directory is present, checkout the target into its\n" 1595 " parent directory at the specified depth. If --parents is specified,\n" 1596 " create any missing parent directories of the target by checking them\n" 1597 " out, too, at depth=empty.\n" 1598 "\n" 1599 " Use the --set-depth option to set a new working copy depth on the\n" 1600 " targets of this operation.\n"), 1601 {'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_force, 1602 opt_ignore_externals, opt_changelist, opt_editor_cmd, opt_accept, 1603 opt_parents} }, 1604 1605 { "upgrade", svn_cl__upgrade, {0}, N_ 1606 ("Upgrade the metadata storage format for a working copy.\n" 1607 "usage: upgrade [WCPATH...]\n" 1608 "\n" 1609 " Local modifications are preserved.\n"), 1610 { 'q' } }, 1611 1612 { NULL, NULL, {0}, NULL, {0} } 1613}; 1614 1615 1616/* Version compatibility check */ 1617static svn_error_t * 1618check_lib_versions(void) 1619{ 1620 static const svn_version_checklist_t checklist[] = 1621 { 1622 { "svn_subr", svn_subr_version }, 1623 { "svn_client", svn_client_version }, 1624 { "svn_wc", svn_wc_version }, 1625 { "svn_ra", svn_ra_version }, 1626 { "svn_delta", svn_delta_version }, 1627 { "svn_diff", svn_diff_version }, 1628 { NULL, NULL } 1629 }; 1630 SVN_VERSION_DEFINE(my_version); 1631 1632 return svn_ver_check_list(&my_version, checklist); 1633} 1634 1635 1636/* A flag to see if we've been cancelled by the client or not. */ 1637static volatile sig_atomic_t cancelled = FALSE; 1638 1639/* A signal handler to support cancellation. */ 1640static void 1641signal_handler(int signum) 1642{ 1643 apr_signal(signum, SIG_IGN); 1644 cancelled = TRUE; 1645} 1646 1647/* Our cancellation callback. */ 1648svn_error_t * 1649svn_cl__check_cancel(void *baton) 1650{ 1651 if (cancelled) 1652 return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal")); 1653 else 1654 return SVN_NO_ERROR; 1655} 1656 1657/* Add a --search argument to OPT_STATE. 1658 * These options start a new search pattern group. */ 1659static void 1660add_search_pattern_group(svn_cl__opt_state_t *opt_state, 1661 const char *pattern, 1662 apr_pool_t *result_pool) 1663{ 1664 apr_array_header_t *group = NULL; 1665 1666 if (opt_state->search_patterns == NULL) 1667 opt_state->search_patterns = apr_array_make(result_pool, 1, 1668 sizeof(apr_array_header_t *)); 1669 1670 group = apr_array_make(result_pool, 1, sizeof(const char *)); 1671 APR_ARRAY_PUSH(group, const char *) = pattern; 1672 APR_ARRAY_PUSH(opt_state->search_patterns, apr_array_header_t *) = group; 1673} 1674 1675/* Add a --search-and argument to OPT_STATE. 1676 * These patterns are added to an existing pattern group, if any. */ 1677static void 1678add_search_pattern_to_latest_group(svn_cl__opt_state_t *opt_state, 1679 const char *pattern, 1680 apr_pool_t *result_pool) 1681{ 1682 apr_array_header_t *group; 1683 1684 if (opt_state->search_patterns == NULL) 1685 { 1686 add_search_pattern_group(opt_state, pattern, result_pool); 1687 return; 1688 } 1689 1690 group = APR_ARRAY_IDX(opt_state->search_patterns, 1691 opt_state->search_patterns->nelts - 1, 1692 apr_array_header_t *); 1693 APR_ARRAY_PUSH(group, const char *) = pattern; 1694} 1695 1696 1697/*** Main. ***/ 1698 1699/* Report and clear the error ERR, and return EXIT_FAILURE. Suppress the 1700 * error message if it is SVN_ERR_IO_PIPE_WRITE_ERROR. */ 1701#define EXIT_ERROR(err) \ 1702 svn_cmdline_handle_exit_error(err, NULL, "svn: ") 1703 1704/* A redefinition of the public SVN_INT_ERR macro, that suppresses the 1705 * error message if it is SVN_ERR_IO_PIPE_WRITE_ERROR. */ 1706#undef SVN_INT_ERR 1707#define SVN_INT_ERR(expr) \ 1708 do { \ 1709 svn_error_t *svn_err__temp = (expr); \ 1710 if (svn_err__temp) \ 1711 return EXIT_ERROR(svn_err__temp); \ 1712 } while (0) 1713 1714static int 1715sub_main(int argc, const char *argv[], apr_pool_t *pool) 1716{ 1717 svn_error_t *err; 1718 int opt_id; 1719 apr_getopt_t *os; 1720 svn_cl__opt_state_t opt_state = { 0, { 0 } }; 1721 svn_client_ctx_t *ctx; 1722 apr_array_header_t *received_opts; 1723 int i; 1724 const svn_opt_subcommand_desc2_t *subcommand = NULL; 1725 const char *dash_m_arg = NULL, *dash_F_arg = NULL; 1726 svn_cl__cmd_baton_t command_baton; 1727 svn_auth_baton_t *ab; 1728 svn_config_t *cfg_config; 1729 svn_boolean_t descend = TRUE; 1730 svn_boolean_t interactive_conflicts = FALSE; 1731 svn_boolean_t force_interactive = FALSE; 1732 svn_cl__conflict_stats_t *conflict_stats 1733 = svn_cl__conflict_stats_create(pool); 1734 svn_boolean_t use_notifier = TRUE; 1735 svn_boolean_t reading_file_from_stdin = FALSE; 1736 apr_hash_t *changelists; 1737 apr_hash_t *cfg_hash; 1738 1739 received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int)); 1740 1741 /* Check library versions */ 1742 SVN_INT_ERR(check_lib_versions()); 1743 1744#if defined(WIN32) || defined(__CYGWIN__) 1745 /* Set the working copy administrative directory name. */ 1746 if (getenv("SVN_ASP_DOT_NET_HACK")) 1747 { 1748 SVN_INT_ERR(svn_wc_set_adm_dir("_svn", pool)); 1749 } 1750#endif 1751 1752 /* Initialize the RA library. */ 1753 SVN_INT_ERR(svn_ra_initialize(pool)); 1754 1755 /* Init our changelists hash. */ 1756 changelists = apr_hash_make(pool); 1757 1758 /* Begin processing arguments. */ 1759 opt_state.start_revision.kind = svn_opt_revision_unspecified; 1760 opt_state.end_revision.kind = svn_opt_revision_unspecified; 1761 opt_state.revision_ranges = 1762 apr_array_make(pool, 0, sizeof(svn_opt_revision_range_t *)); 1763 opt_state.depth = svn_depth_unknown; 1764 opt_state.set_depth = svn_depth_unknown; 1765 opt_state.accept_which = svn_cl__accept_unspecified; 1766 opt_state.show_revs = svn_cl__show_revs_invalid; 1767 1768 /* No args? Show usage. */ 1769 if (argc <= 1) 1770 { 1771 SVN_INT_ERR(svn_cl__help(NULL, NULL, pool)); 1772 return EXIT_FAILURE; 1773 } 1774 1775 /* Else, parse options. */ 1776 SVN_INT_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool)); 1777 1778 os->interleave = 1; 1779 while (1) 1780 { 1781 const char *opt_arg; 1782 const char *utf8_opt_arg; 1783 1784 /* Parse the next option. */ 1785 apr_status_t apr_err = apr_getopt_long(os, svn_cl__options, &opt_id, 1786 &opt_arg); 1787 if (APR_STATUS_IS_EOF(apr_err)) 1788 break; 1789 else if (apr_err) 1790 { 1791 SVN_INT_ERR(svn_cl__help(NULL, NULL, pool)); 1792 return EXIT_FAILURE; 1793 } 1794 1795 /* Stash the option code in an array before parsing it. */ 1796 APR_ARRAY_PUSH(received_opts, int) = opt_id; 1797 1798 switch (opt_id) { 1799 case 'l': 1800 { 1801 err = svn_cstring_atoi(&opt_state.limit, opt_arg); 1802 if (err) 1803 { 1804 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, err, 1805 _("Non-numeric limit argument given")); 1806 return EXIT_ERROR(err); 1807 } 1808 if (opt_state.limit <= 0) 1809 { 1810 err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 1811 _("Argument to --limit must be positive")); 1812 return EXIT_ERROR(err); 1813 } 1814 } 1815 break; 1816 case 'm': 1817 /* Note that there's no way here to detect if the log message 1818 contains a zero byte -- if it does, then opt_arg will just 1819 be shorter than the user intended. Oh well. */ 1820 opt_state.message = apr_pstrdup(pool, opt_arg); 1821 dash_m_arg = opt_arg; 1822 break; 1823 case 'c': 1824 { 1825 apr_array_header_t *change_revs = 1826 svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, pool); 1827 1828 if (opt_state.old_target) 1829 { 1830 err = svn_error_create 1831 (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 1832 _("Can't specify -c with --old")); 1833 return EXIT_ERROR(err); 1834 } 1835 1836 for (i = 0; i < change_revs->nelts; i++) 1837 { 1838 char *end; 1839 svn_revnum_t changeno, changeno_end; 1840 const char *change_str = 1841 APR_ARRAY_IDX(change_revs, i, const char *); 1842 const char *s = change_str; 1843 svn_boolean_t is_negative; 1844 1845 /* Check for a leading minus to allow "-c -r42". 1846 * The is_negative flag is used to handle "-c -42" and "-c -r42". 1847 * The "-c r-42" case is handled by strtol() returning a 1848 * negative number. */ 1849 is_negative = (*s == '-'); 1850 if (is_negative) 1851 s++; 1852 1853 /* Allow any number of 'r's to prefix a revision number. */ 1854 while (*s == 'r') 1855 s++; 1856 changeno = changeno_end = strtol(s, &end, 10); 1857 if (end != s && *end == '-') 1858 { 1859 if (changeno < 0 || is_negative) 1860 { 1861 err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, 1862 NULL, 1863 _("Negative number in range (%s)" 1864 " not supported with -c"), 1865 change_str); 1866 return EXIT_ERROR(err); 1867 } 1868 s = end + 1; 1869 while (*s == 'r') 1870 s++; 1871 changeno_end = strtol(s, &end, 10); 1872 } 1873 if (end == change_str || *end != '\0') 1874 { 1875 err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 1876 _("Non-numeric change argument (%s) " 1877 "given to -c"), change_str); 1878 return EXIT_ERROR(err); 1879 } 1880 1881 if (changeno == 0) 1882 { 1883 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 1884 _("There is no change 0")); 1885 return EXIT_ERROR(err); 1886 } 1887 1888 if (is_negative) 1889 changeno = -changeno; 1890 1891 /* Figure out the range: 1892 -c N -> -r N-1:N 1893 -c -N -> -r N:N-1 1894 -c M-N -> -r M-1:N for M < N 1895 -c M-N -> -r M:N-1 for M > N 1896 -c -M-N -> error (too confusing/no valid use case) 1897 */ 1898 if (changeno > 0) 1899 { 1900 if (changeno <= changeno_end) 1901 changeno--; 1902 else 1903 changeno_end--; 1904 } 1905 else 1906 { 1907 changeno = -changeno; 1908 changeno_end = changeno - 1; 1909 } 1910 1911 opt_state.used_change_arg = TRUE; 1912 APR_ARRAY_PUSH(opt_state.revision_ranges, 1913 svn_opt_revision_range_t *) 1914 = svn_opt__revision_range_from_revnums(changeno, changeno_end, 1915 pool); 1916 } 1917 } 1918 break; 1919 case 'r': 1920 opt_state.used_revision_arg = TRUE; 1921 if (svn_opt_parse_revision_to_range(opt_state.revision_ranges, 1922 opt_arg, pool) != 0) 1923 { 1924 SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); 1925 err = svn_error_createf 1926 (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 1927 _("Syntax error in revision argument '%s'"), 1928 utf8_opt_arg); 1929 return EXIT_ERROR(err); 1930 } 1931 break; 1932 case 'v': 1933 opt_state.verbose = TRUE; 1934 break; 1935 case 'u': 1936 opt_state.update = TRUE; 1937 break; 1938 case 'h': 1939 case '?': 1940 opt_state.help = TRUE; 1941 break; 1942 case 'q': 1943 opt_state.quiet = TRUE; 1944 break; 1945 case opt_incremental: 1946 opt_state.incremental = TRUE; 1947 break; 1948 case 'F': 1949 SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); 1950 SVN_INT_ERR(svn_stringbuf_from_file2(&(opt_state.filedata), 1951 utf8_opt_arg, pool)); 1952 reading_file_from_stdin = (strcmp(utf8_opt_arg, "-") == 0); 1953 dash_F_arg = opt_arg; 1954 break; 1955 case opt_targets: 1956 { 1957 svn_stringbuf_t *buffer, *buffer_utf8; 1958 1959 /* We need to convert to UTF-8 now, even before we divide 1960 the targets into an array, because otherwise we wouldn't 1961 know what delimiter to use for svn_cstring_split(). */ 1962 1963 SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); 1964 SVN_INT_ERR(svn_stringbuf_from_file2(&buffer, utf8_opt_arg, pool)); 1965 SVN_INT_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool)); 1966 opt_state.targets = svn_cstring_split(buffer_utf8->data, "\n\r", 1967 TRUE, pool); 1968 } 1969 break; 1970 case opt_force: 1971 opt_state.force = TRUE; 1972 break; 1973 case opt_force_log: 1974 opt_state.force_log = TRUE; 1975 break; 1976 case opt_dry_run: 1977 opt_state.dry_run = TRUE; 1978 break; 1979 case opt_revprop: 1980 opt_state.revprop = TRUE; 1981 break; 1982 case 'R': 1983 opt_state.depth = svn_depth_infinity; 1984 break; 1985 case 'N': 1986 descend = FALSE; 1987 break; 1988 case opt_depth: 1989 err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool); 1990 if (err) 1991 return EXIT_ERROR 1992 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err, 1993 _("Error converting depth " 1994 "from locale to UTF-8"))); 1995 opt_state.depth = svn_depth_from_word(utf8_opt_arg); 1996 if (opt_state.depth == svn_depth_unknown 1997 || opt_state.depth == svn_depth_exclude) 1998 { 1999 return EXIT_ERROR 2000 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2001 _("'%s' is not a valid depth; try " 2002 "'empty', 'files', 'immediates', " 2003 "or 'infinity'"), 2004 utf8_opt_arg)); 2005 } 2006 break; 2007 case opt_set_depth: 2008 err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool); 2009 if (err) 2010 return EXIT_ERROR 2011 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err, 2012 _("Error converting depth " 2013 "from locale to UTF-8"))); 2014 opt_state.set_depth = svn_depth_from_word(utf8_opt_arg); 2015 /* svn_depth_exclude is okay for --set-depth. */ 2016 if (opt_state.set_depth == svn_depth_unknown) 2017 { 2018 return EXIT_ERROR 2019 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2020 _("'%s' is not a valid depth; try " 2021 "'exclude', 'empty', 'files', " 2022 "'immediates', or 'infinity'"), 2023 utf8_opt_arg)); 2024 } 2025 break; 2026 case opt_version: 2027 opt_state.version = TRUE; 2028 break; 2029 case opt_auth_username: 2030 SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_username, 2031 opt_arg, pool)); 2032 break; 2033 case opt_auth_password: 2034 SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password, 2035 opt_arg, pool)); 2036 break; 2037 case opt_encoding: 2038 opt_state.encoding = apr_pstrdup(pool, opt_arg); 2039 break; 2040 case opt_xml: 2041 opt_state.xml = TRUE; 2042 break; 2043 case opt_stop_on_copy: 2044 opt_state.stop_on_copy = TRUE; 2045 break; 2046 case opt_strict: 2047 opt_state.strict = TRUE; 2048 break; 2049 case opt_no_ignore: 2050 opt_state.no_ignore = TRUE; 2051 break; 2052 case opt_no_auth_cache: 2053 opt_state.no_auth_cache = TRUE; 2054 break; 2055 case opt_non_interactive: 2056 opt_state.non_interactive = TRUE; 2057 break; 2058 case opt_force_interactive: 2059 force_interactive = TRUE; 2060 break; 2061 case opt_trust_server_cert: 2062 opt_state.trust_server_cert = TRUE; 2063 break; 2064 case opt_no_diff_added: 2065 opt_state.diff.no_diff_added = TRUE; 2066 break; 2067 case opt_no_diff_deleted: 2068 opt_state.diff.no_diff_deleted = TRUE; 2069 break; 2070 case opt_ignore_properties: 2071 opt_state.diff.ignore_properties = TRUE; 2072 break; 2073 case opt_show_copies_as_adds: 2074 opt_state.diff.show_copies_as_adds = TRUE; 2075 break; 2076 case opt_notice_ancestry: 2077 opt_state.diff.notice_ancestry = TRUE; 2078 break; 2079 case opt_ignore_ancestry: 2080 opt_state.ignore_ancestry = TRUE; 2081 break; 2082 case opt_ignore_externals: 2083 opt_state.ignore_externals = TRUE; 2084 break; 2085 case opt_relocate: 2086 opt_state.relocate = TRUE; 2087 break; 2088 case 'x': 2089 SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.extensions, 2090 opt_arg, pool)); 2091 break; 2092 case opt_diff_cmd: 2093 opt_state.diff.diff_cmd = apr_pstrdup(pool, opt_arg); 2094 break; 2095 case opt_merge_cmd: 2096 opt_state.merge_cmd = apr_pstrdup(pool, opt_arg); 2097 break; 2098 case opt_record_only: 2099 opt_state.record_only = TRUE; 2100 break; 2101 case opt_editor_cmd: 2102 opt_state.editor_cmd = apr_pstrdup(pool, opt_arg); 2103 break; 2104 case opt_old_cmd: 2105 if (opt_state.used_change_arg) 2106 { 2107 err = svn_error_create 2108 (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2109 _("Can't specify -c with --old")); 2110 return EXIT_ERROR(err); 2111 } 2112 opt_state.old_target = apr_pstrdup(pool, opt_arg); 2113 break; 2114 case opt_new_cmd: 2115 opt_state.new_target = apr_pstrdup(pool, opt_arg); 2116 break; 2117 case opt_config_dir: 2118 { 2119 const char *path_utf8; 2120 SVN_INT_ERR(svn_utf_cstring_to_utf8(&path_utf8, opt_arg, pool)); 2121 opt_state.config_dir = svn_dirent_internal_style(path_utf8, pool); 2122 } 2123 break; 2124 case opt_config_options: 2125 if (!opt_state.config_options) 2126 opt_state.config_options = 2127 apr_array_make(pool, 1, 2128 sizeof(svn_cmdline__config_argument_t*)); 2129 2130 SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool)); 2131 SVN_INT_ERR(svn_cmdline__parse_config_option(opt_state.config_options, 2132 opt_arg, pool)); 2133 break; 2134 case opt_autoprops: 2135 opt_state.autoprops = TRUE; 2136 break; 2137 case opt_no_autoprops: 2138 opt_state.no_autoprops = TRUE; 2139 break; 2140 case opt_native_eol: 2141 if ( !strcmp("LF", opt_arg) || !strcmp("CR", opt_arg) || 2142 !strcmp("CRLF", opt_arg)) 2143 opt_state.native_eol = apr_pstrdup(pool, opt_arg); 2144 else 2145 { 2146 SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); 2147 err = svn_error_createf 2148 (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2149 _("Syntax error in native-eol argument '%s'"), 2150 utf8_opt_arg); 2151 return EXIT_ERROR(err); 2152 } 2153 break; 2154 case opt_no_unlock: 2155 opt_state.no_unlock = TRUE; 2156 break; 2157 case opt_summarize: 2158 opt_state.diff.summarize = TRUE; 2159 break; 2160 case opt_remove: 2161 opt_state.remove = TRUE; 2162 break; 2163 case opt_changelist: 2164 SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); 2165 opt_state.changelist = utf8_opt_arg; 2166 if (opt_state.changelist[0] == '\0') 2167 { 2168 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2169 _("Changelist names must not be empty")); 2170 return EXIT_ERROR(err); 2171 } 2172 svn_hash_sets(changelists, opt_state.changelist, (void *)1); 2173 break; 2174 case opt_keep_changelists: 2175 opt_state.keep_changelists = TRUE; 2176 break; 2177 case opt_keep_local: 2178 opt_state.keep_local = TRUE; 2179 break; 2180 case opt_with_all_revprops: 2181 /* If --with-all-revprops is specified along with one or more 2182 * --with-revprops options, --with-all-revprops takes precedence. */ 2183 opt_state.all_revprops = TRUE; 2184 break; 2185 case opt_with_no_revprops: 2186 opt_state.no_revprops = TRUE; 2187 break; 2188 case opt_with_revprop: 2189 SVN_INT_ERR(svn_opt_parse_revprop(&opt_state.revprop_table, 2190 opt_arg, pool)); 2191 break; 2192 case opt_parents: 2193 opt_state.parents = TRUE; 2194 break; 2195 case 'g': 2196 opt_state.use_merge_history = TRUE; 2197 break; 2198 case opt_accept: 2199 opt_state.accept_which = svn_cl__accept_from_word(opt_arg); 2200 if (opt_state.accept_which == svn_cl__accept_invalid) 2201 return EXIT_ERROR 2202 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2203 _("'%s' is not a valid --accept value"), 2204 opt_arg)); 2205 break; 2206 case opt_show_revs: 2207 opt_state.show_revs = svn_cl__show_revs_from_word(opt_arg); 2208 if (opt_state.show_revs == svn_cl__show_revs_invalid) 2209 return EXIT_ERROR 2210 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2211 _("'%s' is not a valid --show-revs value"), 2212 opt_arg)); 2213 break; 2214 case opt_reintegrate: 2215 opt_state.reintegrate = TRUE; 2216 break; 2217 case opt_strip: 2218 { 2219 err = svn_cstring_atoi(&opt_state.strip, opt_arg); 2220 if (err) 2221 { 2222 err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err, 2223 _("Invalid strip count '%s'"), opt_arg); 2224 return EXIT_ERROR(err); 2225 } 2226 if (opt_state.strip < 0) 2227 { 2228 err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 2229 _("Argument to --strip must be positive")); 2230 return EXIT_ERROR(err); 2231 } 2232 } 2233 break; 2234 case opt_ignore_keywords: 2235 opt_state.ignore_keywords = TRUE; 2236 break; 2237 case opt_reverse_diff: 2238 opt_state.reverse_diff = TRUE; 2239 break; 2240 case opt_ignore_whitespace: 2241 opt_state.ignore_whitespace = TRUE; 2242 break; 2243 case opt_diff: 2244 opt_state.show_diff = TRUE; 2245 break; 2246 case opt_internal_diff: 2247 opt_state.diff.internal_diff = TRUE; 2248 break; 2249 case opt_patch_compatible: 2250 opt_state.diff.patch_compatible = TRUE; 2251 break; 2252 case opt_use_git_diff_format: 2253 opt_state.diff.use_git_diff_format = TRUE; 2254 break; 2255 case opt_allow_mixed_revisions: 2256 opt_state.allow_mixed_rev = TRUE; 2257 break; 2258 case opt_include_externals: 2259 opt_state.include_externals = TRUE; 2260 break; 2261 case opt_show_inherited_props: 2262 opt_state.show_inherited_props = TRUE; 2263 break; 2264 case opt_properties_only: 2265 opt_state.diff.properties_only = TRUE; 2266 break; 2267 case opt_search: 2268 add_search_pattern_group(&opt_state, opt_arg, pool); 2269 break; 2270 case opt_search_and: 2271 add_search_pattern_to_latest_group(&opt_state, opt_arg, pool); 2272 default: 2273 /* Hmmm. Perhaps this would be a good place to squirrel away 2274 opts that commands like svn diff might need. Hmmm indeed. */ 2275 break; 2276 } 2277 } 2278 2279 /* The --non-interactive and --force-interactive options are mutually 2280 * exclusive. */ 2281 if (opt_state.non_interactive && force_interactive) 2282 { 2283 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2284 _("--non-interactive and --force-interactive " 2285 "are mutually exclusive")); 2286 return EXIT_ERROR(err); 2287 } 2288 else 2289 opt_state.non_interactive = !svn_cmdline__be_interactive( 2290 opt_state.non_interactive, 2291 force_interactive); 2292 2293 /* Turn our hash of changelists into an array of unique ones. */ 2294 SVN_INT_ERR(svn_hash_keys(&(opt_state.changelists), changelists, pool)); 2295 2296 /* ### This really belongs in libsvn_client. The trouble is, 2297 there's no one place there to run it from, no 2298 svn_client_init(). We'd have to add it to all the public 2299 functions that a client might call. It's unmaintainable to do 2300 initialization from within libsvn_client itself, but it seems 2301 burdensome to demand that all clients call svn_client_init() 2302 before calling any other libsvn_client function... On the other 2303 hand, the alternative is effectively to demand that they call 2304 svn_config_ensure() instead, so maybe we should have a generic 2305 init function anyway. Thoughts? */ 2306 SVN_INT_ERR(svn_config_ensure(opt_state.config_dir, pool)); 2307 2308 /* If the user asked for help, then the rest of the arguments are 2309 the names of subcommands to get help on (if any), or else they're 2310 just typos/mistakes. Whatever the case, the subcommand to 2311 actually run is svn_cl__help(). */ 2312 if (opt_state.help) 2313 subcommand = svn_opt_get_canonical_subcommand2(svn_cl__cmd_table, "help"); 2314 2315 /* If we're not running the `help' subcommand, then look for a 2316 subcommand in the first argument. */ 2317 if (subcommand == NULL) 2318 { 2319 if (os->ind >= os->argc) 2320 { 2321 if (opt_state.version) 2322 { 2323 /* Use the "help" subcommand to handle the "--version" option. */ 2324 static const svn_opt_subcommand_desc2_t pseudo_cmd = 2325 { "--version", svn_cl__help, {0}, "", 2326 {opt_version, /* must accept its own option */ 2327 'q', /* brief output */ 2328 'v', /* verbose output */ 2329 opt_config_dir /* all commands accept this */ 2330 } }; 2331 2332 subcommand = &pseudo_cmd; 2333 } 2334 else 2335 { 2336 svn_error_clear 2337 (svn_cmdline_fprintf(stderr, pool, 2338 _("Subcommand argument required\n"))); 2339 svn_error_clear(svn_cl__help(NULL, NULL, pool)); 2340 return EXIT_FAILURE; 2341 } 2342 } 2343 else 2344 { 2345 const char *first_arg = os->argv[os->ind++]; 2346 subcommand = svn_opt_get_canonical_subcommand2(svn_cl__cmd_table, 2347 first_arg); 2348 if (subcommand == NULL) 2349 { 2350 const char *first_arg_utf8; 2351 SVN_INT_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8, 2352 first_arg, pool)); 2353 svn_error_clear 2354 (svn_cmdline_fprintf(stderr, pool, 2355 _("Unknown subcommand: '%s'\n"), 2356 first_arg_utf8)); 2357 svn_error_clear(svn_cl__help(NULL, NULL, pool)); 2358 2359 /* Be kind to people who try 'svn undo'. */ 2360 if (strcmp(first_arg_utf8, "undo") == 0) 2361 { 2362 svn_error_clear 2363 (svn_cmdline_fprintf(stderr, pool, 2364 _("Undo is done using either the " 2365 "'svn revert' or the 'svn merge' " 2366 "command.\n"))); 2367 } 2368 2369 return EXIT_FAILURE; 2370 } 2371 } 2372 } 2373 2374 /* Check that the subcommand wasn't passed any inappropriate options. */ 2375 for (i = 0; i < received_opts->nelts; i++) 2376 { 2377 opt_id = APR_ARRAY_IDX(received_opts, i, int); 2378 2379 /* All commands implicitly accept --help, so just skip over this 2380 when we see it. Note that we don't want to include this option 2381 in their "accepted options" list because it would be awfully 2382 redundant to display it in every commands' help text. */ 2383 if (opt_id == 'h' || opt_id == '?') 2384 continue; 2385 2386 if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, 2387 svn_cl__global_options)) 2388 { 2389 const char *optstr; 2390 const apr_getopt_option_t *badopt = 2391 svn_opt_get_option_from_code2(opt_id, svn_cl__options, 2392 subcommand, pool); 2393 svn_opt_format_option(&optstr, badopt, FALSE, pool); 2394 if (subcommand->name[0] == '-') 2395 svn_error_clear(svn_cl__help(NULL, NULL, pool)); 2396 else 2397 svn_error_clear 2398 (svn_cmdline_fprintf 2399 (stderr, pool, _("Subcommand '%s' doesn't accept option '%s'\n" 2400 "Type 'svn help %s' for usage.\n"), 2401 subcommand->name, optstr, subcommand->name)); 2402 return EXIT_FAILURE; 2403 } 2404 } 2405 2406 /* Only merge and log support multiple revisions/revision ranges. */ 2407 if (subcommand->cmd_func != svn_cl__merge 2408 && subcommand->cmd_func != svn_cl__log) 2409 { 2410 if (opt_state.revision_ranges->nelts > 1) 2411 { 2412 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2413 _("Multiple revision arguments " 2414 "encountered; can't specify -c twice, " 2415 "or both -c and -r")); 2416 return EXIT_ERROR(err); 2417 } 2418 } 2419 2420 /* Disallow simultaneous use of both --depth and --set-depth. */ 2421 if ((opt_state.depth != svn_depth_unknown) 2422 && (opt_state.set_depth != svn_depth_unknown)) 2423 { 2424 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2425 _("--depth and --set-depth are mutually " 2426 "exclusive")); 2427 return EXIT_ERROR(err); 2428 } 2429 2430 /* Disallow simultaneous use of both --with-all-revprops and 2431 --with-no-revprops. */ 2432 if (opt_state.all_revprops && opt_state.no_revprops) 2433 { 2434 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2435 _("--with-all-revprops and --with-no-revprops " 2436 "are mutually exclusive")); 2437 return EXIT_ERROR(err); 2438 } 2439 2440 /* Disallow simultaneous use of both --with-revprop and 2441 --with-no-revprops. */ 2442 if (opt_state.revprop_table && opt_state.no_revprops) 2443 { 2444 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2445 _("--with-revprop and --with-no-revprops " 2446 "are mutually exclusive")); 2447 return EXIT_ERROR(err); 2448 } 2449 2450 /* Disallow simultaneous use of both -m and -F, when they are 2451 both used to pass a commit message or lock comment. ('propset' 2452 takes the property value, not a commit message, from -F.) 2453 */ 2454 if (opt_state.filedata && opt_state.message 2455 && subcommand->cmd_func != svn_cl__propset) 2456 { 2457 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2458 _("--message (-m) and --file (-F) " 2459 "are mutually exclusive")); 2460 return EXIT_ERROR(err); 2461 } 2462 2463 /* --trust-server-cert can only be used with --non-interactive */ 2464 if (opt_state.trust_server_cert && !opt_state.non_interactive) 2465 { 2466 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2467 _("--trust-server-cert requires " 2468 "--non-interactive")); 2469 return EXIT_ERROR(err); 2470 } 2471 2472 /* Disallow simultaneous use of both --diff-cmd and 2473 --internal-diff. */ 2474 if (opt_state.diff.diff_cmd && opt_state.diff.internal_diff) 2475 { 2476 err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2477 _("--diff-cmd and --internal-diff " 2478 "are mutually exclusive")); 2479 return EXIT_ERROR(err); 2480 } 2481 2482 /* Ensure that 'revision_ranges' has at least one item, and make 2483 'start_revision' and 'end_revision' match that item. */ 2484 if (opt_state.revision_ranges->nelts == 0) 2485 { 2486 svn_opt_revision_range_t *range = apr_palloc(pool, sizeof(*range)); 2487 range->start.kind = svn_opt_revision_unspecified; 2488 range->end.kind = svn_opt_revision_unspecified; 2489 APR_ARRAY_PUSH(opt_state.revision_ranges, 2490 svn_opt_revision_range_t *) = range; 2491 } 2492 opt_state.start_revision = APR_ARRAY_IDX(opt_state.revision_ranges, 0, 2493 svn_opt_revision_range_t *)->start; 2494 opt_state.end_revision = APR_ARRAY_IDX(opt_state.revision_ranges, 0, 2495 svn_opt_revision_range_t *)->end; 2496 2497 err = svn_config_get_config(&cfg_hash, opt_state.config_dir, pool); 2498 if (err) 2499 { 2500 /* Fallback to default config if the config directory isn't readable 2501 or is not a directory. */ 2502 if (APR_STATUS_IS_EACCES(err->apr_err) 2503 || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)) 2504 { 2505 svn_handle_warning2(stderr, err, "svn: "); 2506 svn_error_clear(err); 2507 cfg_hash = NULL; 2508 } 2509 else 2510 return EXIT_ERROR(err); 2511 } 2512 2513 /* Relocation is infinite-depth only. */ 2514 if (opt_state.relocate) 2515 { 2516 if (opt_state.depth != svn_depth_unknown) 2517 { 2518 err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL, 2519 _("--relocate and --depth are mutually " 2520 "exclusive")); 2521 return EXIT_ERROR(err); 2522 } 2523 if (! descend) 2524 { 2525 err = svn_error_create( 2526 SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL, 2527 _("--relocate and --non-recursive (-N) are mutually " 2528 "exclusive")); 2529 return EXIT_ERROR(err); 2530 } 2531 } 2532 2533 /* Only a few commands can accept a revision range; the rest can take at 2534 most one revision number. */ 2535 if (subcommand->cmd_func != svn_cl__blame 2536 && subcommand->cmd_func != svn_cl__diff 2537 && subcommand->cmd_func != svn_cl__log 2538 && subcommand->cmd_func != svn_cl__mergeinfo 2539 && subcommand->cmd_func != svn_cl__merge) 2540 { 2541 if (opt_state.end_revision.kind != svn_opt_revision_unspecified) 2542 { 2543 err = svn_error_create(SVN_ERR_CLIENT_REVISION_RANGE, NULL, NULL); 2544 return EXIT_ERROR(err); 2545 } 2546 } 2547 2548 /* -N has a different meaning depending on the command */ 2549 if (!descend) 2550 { 2551 if (subcommand->cmd_func == svn_cl__status) 2552 { 2553 opt_state.depth = svn_depth_immediates; 2554 } 2555 else if (subcommand->cmd_func == svn_cl__revert 2556 || subcommand->cmd_func == svn_cl__add 2557 || subcommand->cmd_func == svn_cl__commit) 2558 { 2559 /* In pre-1.5 Subversion, some commands treated -N like 2560 --depth=empty, so force that mapping here. Anyway, with 2561 revert it makes sense to be especially conservative, 2562 since revert can lose data. */ 2563 opt_state.depth = svn_depth_empty; 2564 } 2565 else 2566 { 2567 opt_state.depth = svn_depth_files; 2568 } 2569 } 2570 2571 cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG); 2572 2573 /* Update the options in the config */ 2574 if (opt_state.config_options) 2575 { 2576 svn_error_clear( 2577 svn_cmdline__apply_config_options(cfg_hash, 2578 opt_state.config_options, 2579 "svn: ", "--config-option")); 2580 } 2581 2582#if !defined(SVN_CL_NO_EXCLUSIVE_LOCK) 2583 { 2584 const char *exclusive_clients_option; 2585 apr_array_header_t *exclusive_clients; 2586 2587 svn_config_get(cfg_config, &exclusive_clients_option, 2588 SVN_CONFIG_SECTION_WORKING_COPY, 2589 SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE_CLIENTS, 2590 NULL); 2591 exclusive_clients = svn_cstring_split(exclusive_clients_option, 2592 " ,", TRUE, pool); 2593 for (i = 0; i < exclusive_clients->nelts; ++i) 2594 { 2595 const char *exclusive_client = APR_ARRAY_IDX(exclusive_clients, i, 2596 const char *); 2597 2598 /* This blocks other clients from accessing the wc.db so it must 2599 be explicitly enabled.*/ 2600 if (!strcmp(exclusive_client, "svn")) 2601 svn_config_set(cfg_config, 2602 SVN_CONFIG_SECTION_WORKING_COPY, 2603 SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE, 2604 "true"); 2605 } 2606 } 2607#endif 2608 2609 /* Create a client context object. */ 2610 command_baton.opt_state = &opt_state; 2611 SVN_INT_ERR(svn_client_create_context2(&ctx, cfg_hash, pool)); 2612 command_baton.ctx = ctx; 2613 2614 /* If we're running a command that could result in a commit, verify 2615 that any log message we were given on the command line makes 2616 sense (unless we've also been instructed not to care). This may 2617 access the working copy so do it after setting the locking mode. */ 2618 if ((! opt_state.force_log) 2619 && (subcommand->cmd_func == svn_cl__commit 2620 || subcommand->cmd_func == svn_cl__copy 2621 || subcommand->cmd_func == svn_cl__delete 2622 || subcommand->cmd_func == svn_cl__import 2623 || subcommand->cmd_func == svn_cl__mkdir 2624 || subcommand->cmd_func == svn_cl__move 2625 || subcommand->cmd_func == svn_cl__lock 2626 || subcommand->cmd_func == svn_cl__propedit)) 2627 { 2628 /* If the -F argument is a file that's under revision control, 2629 that's probably not what the user intended. */ 2630 if (dash_F_arg) 2631 { 2632 svn_node_kind_t kind; 2633 const char *local_abspath; 2634 const char *fname_utf8 = svn_dirent_internal_style(dash_F_arg, pool); 2635 2636 err = svn_dirent_get_absolute(&local_abspath, fname_utf8, pool); 2637 2638 if (!err) 2639 { 2640 err = svn_wc_read_kind2(&kind, ctx->wc_ctx, local_abspath, TRUE, 2641 FALSE, pool); 2642 2643 if (!err && kind != svn_node_none && kind != svn_node_unknown) 2644 { 2645 if (subcommand->cmd_func != svn_cl__lock) 2646 { 2647 err = svn_error_create( 2648 SVN_ERR_CL_LOG_MESSAGE_IS_VERSIONED_FILE, NULL, 2649 _("Log message file is a versioned file; " 2650 "use '--force-log' to override")); 2651 } 2652 else 2653 { 2654 err = svn_error_create( 2655 SVN_ERR_CL_LOG_MESSAGE_IS_VERSIONED_FILE, NULL, 2656 _("Lock comment file is a versioned file; " 2657 "use '--force-log' to override")); 2658 } 2659 return EXIT_ERROR(err); 2660 } 2661 } 2662 svn_error_clear(err); 2663 } 2664 2665 /* If the -m argument is a file at all, that's probably not what 2666 the user intended. */ 2667 if (dash_m_arg) 2668 { 2669 apr_finfo_t finfo; 2670 if (apr_stat(&finfo, dash_m_arg, 2671 APR_FINFO_MIN, pool) == APR_SUCCESS) 2672 { 2673 if (subcommand->cmd_func != svn_cl__lock) 2674 { 2675 err = svn_error_create 2676 (SVN_ERR_CL_LOG_MESSAGE_IS_PATHNAME, NULL, 2677 _("The log message is a pathname " 2678 "(was -F intended?); use '--force-log' to override")); 2679 } 2680 else 2681 { 2682 err = svn_error_create 2683 (SVN_ERR_CL_LOG_MESSAGE_IS_PATHNAME, NULL, 2684 _("The lock comment is a pathname " 2685 "(was -F intended?); use '--force-log' to override")); 2686 } 2687 return EXIT_ERROR(err); 2688 } 2689 } 2690 } 2691 2692 /* XXX: Only diff_cmd for now, overlay rest later and stop passing 2693 opt_state altogether? */ 2694 if (opt_state.diff.diff_cmd) 2695 svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS, 2696 SVN_CONFIG_OPTION_DIFF_CMD, opt_state.diff.diff_cmd); 2697 if (opt_state.merge_cmd) 2698 svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS, 2699 SVN_CONFIG_OPTION_DIFF3_CMD, opt_state.merge_cmd); 2700 if (opt_state.diff.internal_diff) 2701 svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS, 2702 SVN_CONFIG_OPTION_DIFF_CMD, NULL); 2703 2704 /* Check for mutually exclusive args --auto-props and --no-auto-props */ 2705 if (opt_state.autoprops && opt_state.no_autoprops) 2706 { 2707 err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL, 2708 _("--auto-props and --no-auto-props are " 2709 "mutually exclusive")); 2710 return EXIT_ERROR(err); 2711 } 2712 2713 /* Update auto-props-enable option, and populate the MIME types map, 2714 for add/import commands */ 2715 if (subcommand->cmd_func == svn_cl__add 2716 || subcommand->cmd_func == svn_cl__import) 2717 { 2718 const char *mimetypes_file; 2719 svn_config_get(cfg_config, &mimetypes_file, 2720 SVN_CONFIG_SECTION_MISCELLANY, 2721 SVN_CONFIG_OPTION_MIMETYPES_FILE, FALSE); 2722 if (mimetypes_file && *mimetypes_file) 2723 { 2724 SVN_INT_ERR(svn_io_parse_mimetypes_file(&(ctx->mimetypes_map), 2725 mimetypes_file, pool)); 2726 } 2727 2728 if (opt_state.autoprops) 2729 { 2730 svn_config_set_bool(cfg_config, SVN_CONFIG_SECTION_MISCELLANY, 2731 SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, TRUE); 2732 } 2733 if (opt_state.no_autoprops) 2734 { 2735 svn_config_set_bool(cfg_config, SVN_CONFIG_SECTION_MISCELLANY, 2736 SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, FALSE); 2737 } 2738 } 2739 2740 /* Update the 'keep-locks' runtime option */ 2741 if (opt_state.no_unlock) 2742 svn_config_set_bool(cfg_config, SVN_CONFIG_SECTION_MISCELLANY, 2743 SVN_CONFIG_OPTION_NO_UNLOCK, TRUE); 2744 2745 /* Set the log message callback function. Note that individual 2746 subcommands will populate the ctx->log_msg_baton3. */ 2747 ctx->log_msg_func3 = svn_cl__get_log_message; 2748 2749 /* Set up the notifier. 2750 2751 In general, we use it any time we aren't in --quiet mode. 'svn 2752 status' is unique, though, in that we don't want it in --quiet mode 2753 unless we're also in --verbose mode. When in --xml mode, 2754 though, we never want it. */ 2755 if (opt_state.quiet) 2756 use_notifier = FALSE; 2757 if ((subcommand->cmd_func == svn_cl__status) && opt_state.verbose) 2758 use_notifier = TRUE; 2759 if (opt_state.xml) 2760 use_notifier = FALSE; 2761 if (use_notifier) 2762 { 2763 SVN_INT_ERR(svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, 2764 conflict_stats, pool)); 2765 } 2766 2767 /* Set up our cancellation support. */ 2768 ctx->cancel_func = svn_cl__check_cancel; 2769 apr_signal(SIGINT, signal_handler); 2770#ifdef SIGBREAK 2771 /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */ 2772 apr_signal(SIGBREAK, signal_handler); 2773#endif 2774#ifdef SIGHUP 2775 apr_signal(SIGHUP, signal_handler); 2776#endif 2777#ifdef SIGTERM 2778 apr_signal(SIGTERM, signal_handler); 2779#endif 2780 2781#ifdef SIGPIPE 2782 /* Disable SIGPIPE generation for the platforms that have it. */ 2783 apr_signal(SIGPIPE, SIG_IGN); 2784#endif 2785 2786#ifdef SIGXFSZ 2787 /* Disable SIGXFSZ generation for the platforms that have it, otherwise 2788 * working with large files when compiled against an APR that doesn't have 2789 * large file support will crash the program, which is uncool. */ 2790 apr_signal(SIGXFSZ, SIG_IGN); 2791#endif 2792 2793 /* Set up Authentication stuff. */ 2794 SVN_INT_ERR(svn_cmdline_create_auth_baton(&ab, 2795 opt_state.non_interactive, 2796 opt_state.auth_username, 2797 opt_state.auth_password, 2798 opt_state.config_dir, 2799 opt_state.no_auth_cache, 2800 opt_state.trust_server_cert, 2801 cfg_config, 2802 ctx->cancel_func, 2803 ctx->cancel_baton, 2804 pool)); 2805 2806 ctx->auth_baton = ab; 2807 2808 if (opt_state.non_interactive) 2809 { 2810 if (opt_state.accept_which == svn_cl__accept_edit) 2811 return EXIT_ERROR( 2812 svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2813 _("--accept=%s incompatible with" 2814 " --non-interactive"), 2815 SVN_CL__ACCEPT_EDIT)); 2816 2817 if (opt_state.accept_which == svn_cl__accept_launch) 2818 return EXIT_ERROR( 2819 svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, 2820 _("--accept=%s incompatible with" 2821 " --non-interactive"), 2822 SVN_CL__ACCEPT_LAUNCH)); 2823 2824 /* The default action when we're non-interactive is to postpone 2825 * conflict resolution. */ 2826 if (opt_state.accept_which == svn_cl__accept_unspecified) 2827 opt_state.accept_which = svn_cl__accept_postpone; 2828 } 2829 2830 /* Check whether interactive conflict resolution is disabled by 2831 * the configuration file. If no --accept option was specified 2832 * we postpone all conflicts in this case. */ 2833 SVN_INT_ERR(svn_config_get_bool(cfg_config, &interactive_conflicts, 2834 SVN_CONFIG_SECTION_MISCELLANY, 2835 SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS, 2836 TRUE)); 2837 if (!interactive_conflicts) 2838 { 2839 /* Make 'svn resolve' non-interactive. */ 2840 if (subcommand->cmd_func == svn_cl__resolve) 2841 opt_state.non_interactive = TRUE; 2842 2843 /* We're not resolving conflicts interactively. If no --accept option 2844 * was provided the default behaviour is to postpone all conflicts. */ 2845 if (opt_state.accept_which == svn_cl__accept_unspecified) 2846 opt_state.accept_which = svn_cl__accept_postpone; 2847 } 2848 2849 /* Install the default conflict handler. */ 2850 { 2851 svn_cl__interactive_conflict_baton_t *b; 2852 2853 ctx->conflict_func = NULL; 2854 ctx->conflict_baton = NULL; 2855 2856 ctx->conflict_func2 = svn_cl__conflict_func_interactive; 2857 SVN_INT_ERR(svn_cl__get_conflict_func_interactive_baton( 2858 &b, 2859 opt_state.accept_which, 2860 ctx->config, opt_state.editor_cmd, conflict_stats, 2861 ctx->cancel_func, ctx->cancel_baton, pool)); 2862 ctx->conflict_baton2 = b; 2863 } 2864 2865 /* And now we finally run the subcommand. */ 2866 err = (*subcommand->cmd_func)(os, &command_baton, pool); 2867 if (err) 2868 { 2869 /* For argument-related problems, suggest using the 'help' 2870 subcommand. */ 2871 if (err->apr_err == SVN_ERR_CL_INSUFFICIENT_ARGS 2872 || err->apr_err == SVN_ERR_CL_ARG_PARSING_ERROR) 2873 { 2874 err = svn_error_quick_wrap( 2875 err, apr_psprintf(pool, 2876 _("Try 'svn help %s' for more information"), 2877 subcommand->name)); 2878 } 2879 if (err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED) 2880 { 2881 err = svn_error_quick_wrap(err, 2882 _("Please see the 'svn upgrade' command")); 2883 } 2884 2885 if (err->apr_err == SVN_ERR_AUTHN_FAILED && opt_state.non_interactive) 2886 { 2887 err = svn_error_quick_wrap(err, 2888 _("Authentication failed and interactive" 2889 " prompting is disabled; see the" 2890 " --force-interactive option")); 2891 if (reading_file_from_stdin) 2892 err = svn_error_quick_wrap(err, 2893 _("Reading file from standard input " 2894 "because of -F option; this can " 2895 "interfere with interactive " 2896 "prompting")); 2897 } 2898 2899 /* Tell the user about 'svn cleanup' if any error on the stack 2900 was about locked working copies. */ 2901 if (svn_error_find_cause(err, SVN_ERR_WC_LOCKED)) 2902 { 2903 err = svn_error_quick_wrap( 2904 err, _("Run 'svn cleanup' to remove locks " 2905 "(type 'svn help cleanup' for details)")); 2906 } 2907 2908 if (err->apr_err == SVN_ERR_SQLITE_BUSY) 2909 { 2910 err = svn_error_quick_wrap(err, 2911 _("Another process is blocking the " 2912 "working copy database, or the " 2913 "underlying filesystem does not " 2914 "support file locking; if the working " 2915 "copy is on a network filesystem, make " 2916 "sure file locking has been enabled " 2917 "on the file server")); 2918 } 2919 2920 if (svn_error_find_cause(err, SVN_ERR_RA_CANNOT_CREATE_TUNNEL) && 2921 (opt_state.auth_username || opt_state.auth_password)) 2922 { 2923 err = svn_error_quick_wrap( 2924 err, _("When using svn+ssh:// URLs, keep in mind that the " 2925 "--username and --password options are ignored " 2926 "because authentication is performed by SSH, not " 2927 "Subversion")); 2928 } 2929 2930 return EXIT_ERROR(err); 2931 } 2932 else 2933 { 2934 /* Ensure that stdout is flushed, so the user will see any write errors. 2935 This makes sure that output is not silently lost. */ 2936 SVN_INT_ERR(svn_cmdline_fflush(stdout)); 2937 2938 return EXIT_SUCCESS; 2939 } 2940} 2941 2942int 2943main(int argc, const char *argv[]) 2944{ 2945 apr_pool_t *pool; 2946 int exit_code; 2947 2948 /* Initialize the app. */ 2949 if (svn_cmdline_init("svn", stderr) != EXIT_SUCCESS) 2950 return EXIT_FAILURE; 2951 2952 /* Create our top-level pool. Use a separate mutexless allocator, 2953 * given this application is single threaded. 2954 */ 2955 pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE)); 2956 2957 exit_code = sub_main(argc, argv, pool); 2958 2959 svn_pool_destroy(pool); 2960 return exit_code; 2961} 2962