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