diff options
421 files changed, 19485 insertions, 3592 deletions
diff --git a/.gitignore b/.gitignore index 1c2f832138..5087ce1eb7 100644 --- a/.gitignore +++ b/.gitignore @@ -187,6 +187,7 @@ /test-dump-cache-tree /test-dump-split-index /test-dump-untracked-cache +/test-fake-ssh /test-scrap-cache-tree /test-genrandom /test-hashmap diff --git a/.travis.yml b/.travis.yml index c3bf9c6d4d..f8b73ec3da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,11 @@ language: c +sudo: false + +cache: + directories: + - $HOME/travis-cache + os: - linux - osx @@ -18,7 +24,7 @@ env: - P4_VERSION="15.2" - GIT_LFS_VERSION="1.1.0" - DEFAULT_TEST_TARGET=prove - - GIT_PROVE_OPTS="--timer --jobs 3" + - GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save" - GIT_TEST_OPTS="--verbose --tee" - CFLAGS="-g -O2 -Wall -Werror" - GIT_TEST_CLONE_2GB=YesPlease @@ -67,6 +73,8 @@ before_install: p4 -V | grep Rev.; echo "$(tput setaf 6)Git-LFS Version$(tput sgr0)"; git-lfs version; + mkdir -p $HOME/travis-cache; + ln -s $HOME/travis-cache/.prove t/.prove; before_script: make --jobs=2 diff --git a/Documentation/RelNotes/2.7.1.txt b/Documentation/RelNotes/2.7.1.txt new file mode 100644 index 0000000000..6553d69e33 --- /dev/null +++ b/Documentation/RelNotes/2.7.1.txt @@ -0,0 +1,87 @@ +Git v2.7.1 Release Notes +======================== + +Fixes since v2.7 +---------------- + + * An earlier change in 2.5.x-era broke users' hooks and aliases by + exporting GIT_WORK_TREE to point at the root of the working tree, + interfering when they tried to use a different working tree without + setting GIT_WORK_TREE environment themselves. + + * The "exclude_list" structure has the usual "alloc, nr" pair of + fields to be used by ALLOC_GROW(), but clear_exclude_list() forgot + to reset 'alloc' to 0 when it cleared 'nr' to discard the managed + array. + + * "git send-email" was confused by escaped quotes stored in the alias + files saved by "mutt", which has been corrected. + + * A few unportable C construct have been spotted by clang compiler + and have been fixed. + + * The documentation has been updated to hint the connection between + the '--signoff' option and DCO. + + * "git reflog" incorrectly assumed that all objects that used to be + at the tip of a ref must be commits, which caused it to segfault. + + * The ignore mechanism saw a few regressions around untracked file + listing and sparse checkout selection areas in 2.7.0; the change + that is responsible for the regression has been reverted. + + * Some codepaths used fopen(3) when opening a fixed path in $GIT_DIR + (e.g. COMMIT_EDITMSG) that is meant to be left after the command is + done. This however did not work well if the repository is set to + be shared with core.sharedRepository and the umask of the previous + user is tighter. They have been made to work better by calling + unlink(2) and retrying after fopen(3) fails with EPERM. + + * Asking gitweb for a nonexistent commit left a warning in the server + log. + + * "git rebase", unlike all other callers of "gc --auto", did not + ignore the exit code from "gc --auto". + + * Many codepaths that run "gc --auto" before exiting kept packfiles + mapped and left the file descriptors to them open, which was not + friendly to systems that cannot remove files that are open. They + now close the packs before doing so. + + * A recent optimization to filter-branch in v2.7.0 introduced a + regression when --prune-empty filter is used, which has been + corrected. + + * The description for SANITY prerequisite the test suite uses has + been clarified both in the comment and in the implementation. + + * "git tag" started listing a tag "foo" as "tags/foo" when a branch + named "foo" exists in the same repository; remove this unnecessary + disambiguation, which is a regression introduced in v2.7.0. + + * The way "git svn" uses auth parameter was broken by Subversion + 1.9.0 and later. + + * The "split" subcommand of "git subtree" (in contrib/) incorrectly + skipped merges when it shouldn't, which was corrected. + + * A few options of "git diff" did not work well when the command was + run from a subdirectory. + + * dirname() emulation has been added, as Msys2 lacks it. + + * The underlying machinery used by "ls-files -o" and other commands + have been taught not to create empty submodule ref cache for a + directory that is not a submodule. This removes a ton of wasted + CPU cycles. + + * Drop a few old "todo" items by deciding that the change one of them + suggests is not such a good idea, and doing the change the other + one suggested to do. + + * Documentation for "git fetch --depth" has been updated for clarity. + + * The command line completion learned a handful of additional options + and command specific syntax. + +Also includes a handful of documentation and test updates. diff --git a/Documentation/RelNotes/2.7.2.txt b/Documentation/RelNotes/2.7.2.txt new file mode 100644 index 0000000000..4feef76704 --- /dev/null +++ b/Documentation/RelNotes/2.7.2.txt @@ -0,0 +1,41 @@ +Git v2.7.2 Release Notes +======================== + +Fixes since v2.7.1 +------------------ + + * The low-level merge machinery has been taught to use CRLF line + termination when inserting conflict markers to merged contents that + are themselves CRLF line-terminated. + + * "git worktree" had a broken code that attempted to auto-fix + possible inconsistency that results from end-users moving a + worktree to different places without telling Git (the original + repository needs to maintain backpointers to its worktrees, but + "mv" run by end-users who are not familiar with that fact will + obviously not adjust them), which actually made things worse + when triggered. + + * "git push --force-with-lease" has been taught to report if the push + needed to force (or fast-forwarded). + + * The emulated "yes" command used in our test scripts has been + tweaked not to spend too much time generating unnecessary output + that is not used, to help those who test on Windows where it would + not stop until it fills the pipe buffer due to lack of SIGPIPE. + + * The vimdiff backend for "git mergetool" has been tweaked to arrange + and number buffers in the order that would match the expectation of + majority of people who read left to right, then top down and assign + buffers 1 2 3 4 "mentally" to local base remote merge windows based + on that order. + + * The documentation for "git clean" has been corrected; it mentioned + that .git/modules/* are removed by giving two "-f", which has never + been the case. + + * Paths that have been told the index about with "add -N" are not + quite yet in the index, but a few commands behaved as if they + already are in a harmful way. + +Also includes tiny documentation and test updates. diff --git a/Documentation/RelNotes/2.8.0.txt b/Documentation/RelNotes/2.8.0.txt new file mode 100644 index 0000000000..3df3a98f70 --- /dev/null +++ b/Documentation/RelNotes/2.8.0.txt @@ -0,0 +1,323 @@ +Git 2.8 Release Notes +===================== + +Backward compatibility note +--------------------------- + +The rsync:// transport has been removed. + + +Updates since v2.7 +------------------ + +UI, Workflows & Features + + * It turns out "git clone" over rsync transport has been broken when + the source repository has packed references for a long time, and + nobody noticed nor complained about it. + + * "branch --delete" has "branch -d" but "push --delete" does not. + + * "git blame" learned to produce the progress eye-candy when it takes + too much time before emitting the first line of the result. + + * "git grep" can now be configured (or told from the command line) + how many threads to use when searching in the working tree files. + + * Some "git notes" operations, e.g. "git log --notes=<note>", should + be able to read notes from any tree-ish that is shaped like a notes + tree, but the notes infrastructure required that the argument must + be a ref under refs/notes/. Loosen it to require a valid ref only + when the operation would update the notes (in which case we must + have a place to store the updated notes tree, iow, a ref). + + * "git grep" by default does not fall back to its "--no-index" + behaviour outside a directory under Git's control (otherwise the + user may by mistake end up running a huge recursive search); with a + new configuration (set in $HOME/.gitconfig--by definition this + cannot be set in the config file per project), this safety can be + disabled. + + * "git pull --rebase" has been extended to allow invoking + "rebase -i". + + * "git p4" learned to cope with the type of a file getting changed. + + * "git format-patch" learned to notice format.outputDirectory + configuration variable. This allows "-o <dir>" option to be + omitted on the command line if you always use the same directory in + your workflow. + + * "interpret-trailers" has been taught to optionally update a file in + place, instead of always writing the result to the standard output. + + * Many commands that read files that are expected to contain text + that is generated (or can be edited) by the end user to control + their behaviour (e.g. "git grep -f <filename>") have been updated + to be more tolerant to lines that are terminated with CRLF (they + used to treat such a line to contain payload that ends with CR, + which is usually not what the users expect). + + * "git notes merge" used to limit the source of the merged notes tree + to somewhere under refs/notes/ hierarchy, which was too limiting + when inventing a workflow to exchange notes with remote + repositories using remote-tracking notes trees (located in e.g. + refs/remote-notes/ or somesuch). + + * "git ls-files" learned a new "--eol" option to help diagnose + end-of-line problems. + + * "ls-remote" learned an option to show which branch the remote + repository advertises as its primary by pointing its HEAD at. + + * New http.proxyAuthMethod configuration variable can be used to + specify what authentication method to use, as a way to work around + proxies that do not give error response expected by libcurl when + CURLAUTH_ANY is used. Also, the codepath for proxy authentication + has been taught to use credential API to store the authentication + material in user's keyrings. + + * Update the untracked cache subsystem and change its primary UI from + "git update-index" to "git config". + + * There were a few "now I am doing this thing" progress messages in + the TCP connection code that can be triggered by setting a verbose + option internally in the code, but "git fetch -v" and friends never + passed the verbose option down to that codepath. + + * Clean/smudge filters defined in a configuration file of lower + precedence can now be overridden to be a pass-through no-op by + setting the variable to an empty string. + + * A new "<branch>^{/!-<pattern>}" notation can be used to name a + commit that is reachable from <branch> that does not match the + given <pattern>. + + * The "user.useConfigOnly" configuration variable can be used to + force the user to always set user.email & user.name configuration + variables, serving as a reminder for those who work on multiple + projects and do not want to put these in their $HOME/.gitconfig. + + * "git fetch" and friends that make network connections can now be + told to only use ipv4 (or ipv6). + + * Some authentication methods do not need username or password, but + libcurl needs some hint that it needs to perform authentication. + Supplying an empty username and password string is a valid way to + do so, but you can set the http.[<url>.]emptyAuth configuration + variable to achieve the same, if you find it cleaner. + + * You can now set http.[<url>.]pinnedpubkey to specify the pinned + public key when building with recent enough versions of libcURL. + + +Performance, Internal Implementation, Development Support etc. + + * Add a framework to spawn a group of processes in parallel, and use + it to run "git fetch --recurse-submodules" in parallel. + + * A slight update to the Makefile to mark "phoney" targets + as such correctly. + + * In-core storage of the reverse index for .pack files (which lets + you go from a pack offset to an object name) has been streamlined. + + * d95138e6 (setup: set env $GIT_WORK_TREE when work tree is set, like + $GIT_DIR, 2015-06-26) attempted to work around a glitch in alias + handling by overwriting GIT_WORK_TREE environment variable to + affect subprocesses when set_git_work_tree() gets called, which + resulted in a rather unpleasant regression to "clone" and "init". + Try to address the same issue by always restoring the environment + and respawning the real underlying command when handling alias. + + * The low-level code that is used to create symbolic references has + been updated to share more code with the code that deals with + normal references. + + * strbuf_getline() and friends have been redefined to make it easier + to identify which callsite of (new) strbuf_getline_lf() should + allow and silently ignore carriage-return at the end of the line to + help users on DOSsy systems. + + * "git shortlog" used to accumulate various pieces of information + regardless of what was asked to be shown in the final output. It + has been optimized by noticing what need not to be collected + (e.g. there is no need to collect the log messages when showing + only the number of changes). + + * "git checkout $branch" (and other operations that share the same + underlying machinery) has been optimized. + + * Automated tests in Travis CI environment has been optimized by + persisting runtime statistics of previous "prove" run, executing + tests that take longer before other ones; this reduces the total + wallclock time. + + * Test scripts have been updated to remove assumptions that are not + portable between Git for POSIX and Git for Windows, or to skip ones + with expectations that are not satisfiable on Git for Windows. + + * Some calls to strcpy(3) triggers a false warning from static + analysers that are less intelligent than humans, and reducing the + number of these false hits helps us notice real issues. A few + calls to strcpy(3) in test-path-utils that are already safe has + been rewritten to avoid false wanings. + + * Some calls to strcpy(3) triggers a false warning from static + analysers that are less intelligent than humans, and reducing the + number of these false hits helps us notice real issues. A few + calls to strcpy(3) in "git rerere" that are already safe has been + rewritten to avoid false wanings. + + * The "name_path" API was an attempt to reduce the need to construct + the full path out of a series of path components while walking a + tree hierarchy, but over time made less efficient because the path + needs to be flattened, e.g. to be compared with another path that + is already flat. The API has been removed and its users have been + rewritten to simplify the overall code complexity. + + * Help those who debug http(s) part of the system. + (merge 0054045 sp/remote-curl-ssl-strerror later to maint). + +Also contains various documentation updates and code clean-ups. + + +Fixes since v2.7 +---------------- + +Unless otherwise noted, all the fixes since v2.7 in the maintenance +track are contained in this release (see the maintenance releases' +notes for details). + + * An earlier change in 2.5.x-era broke users' hooks and aliases by + exporting GIT_WORK_TREE to point at the root of the working tree, + interfering when they tried to use a different working tree without + setting GIT_WORK_TREE environment themselves. + + * The "exclude_list" structure has the usual "alloc, nr" pair of + fields to be used by ALLOC_GROW(), but clear_exclude_list() forgot + to reset 'alloc' to 0 when it cleared 'nr' to discard the managed + array. + + * Paths that have been told the index about with "add -N" are not + quite yet in the index, but a few commands behaved as if they + already are in a harmful way. + + * "git send-email" was confused by escaped quotes stored in the alias + files saved by "mutt", which has been corrected. + + * A few unportable C construct have been spotted by clang compiler + and have been fixed. + + * The documentation has been updated to hint the connection between + the '--signoff' option and DCO. + + * "git reflog" incorrectly assumed that all objects that used to be + at the tip of a ref must be commits, which caused it to segfault. + + * The ignore mechanism saw a few regressions around untracked file + listing and sparse checkout selection areas in 2.7.0; the change + that is responsible for the regression has been reverted. + + * Some codepaths used fopen(3) when opening a fixed path in $GIT_DIR + (e.g. COMMIT_EDITMSG) that is meant to be left after the command is + done. This however did not work well if the repository is set to + be shared with core.sharedRepository and the umask of the previous + user is tighter. They have been made to work better by calling + unlink(2) and retrying after fopen(3) fails with EPERM. + + * Asking gitweb for a nonexistent commit left a warning in the server + log. + + Somebody may want to follow this up with an additional test, perhaps? + IIRC, we do test that no Perl warnings are given to the server log, + so this should have been caught if our test coverage were good. + + * "git rebase", unlike all other callers of "gc --auto", did not + ignore the exit code from "gc --auto". + + * Many codepaths that run "gc --auto" before exiting kept packfiles + mapped and left the file descriptors to them open, which was not + friendly to systems that cannot remove files that are open. They + now close the packs before doing so. + + * A recent optimization to filter-branch in v2.7.0 introduced a + regression when --prune-empty filter is used, which has been + corrected. + + * The description for SANITY prerequisite the test suite uses has + been clarified both in the comment and in the implementation. + + * "git tag" started listing a tag "foo" as "tags/foo" when a branch + named "foo" exists in the same repository; remove this unnecessary + disambiguation, which is a regression introduced in v2.7.0. + + * The way "git svn" uses auth parameter was broken by Subversion + 1.9.0 and later. + + * The "split" subcommand of "git subtree" (in contrib/) incorrectly + skipped merges when it shouldn't, which was corrected. + + * A few options of "git diff" did not work well when the command was + run from a subdirectory. + + * The command line completion learned a handful of additional options + and command specific syntax. + + * dirname() emulation has been added, as Msys2 lacks it. + + * The underlying machinery used by "ls-files -o" and other commands + have been taught not to create empty submodule ref cache for a + directory that is not a submodule. This removes a ton of wasted + CPU cycles. + + * "git worktree" had a broken code that attempted to auto-fix + possible inconsistency that results from end-users moving a + worktree to different places without telling Git (the original + repository needs to maintain backpointers to its worktrees, but + "mv" run by end-users who are not familiar with that fact will + obviously not adjust them), which actually made things worse + when triggered. + + * The low-level merge machinery has been taught to use CRLF line + termination when inserting conflict markers to merged contents that + are themselves CRLF line-terminated. + + * "git push --force-with-lease" has been taught to report if the push + needed to force (or fast-forwarded). + + * The emulated "yes" command used in our test scripts has been + tweaked not to spend too much time generating unnecessary output + that is not used, to help those who test on Windows where it would + not stop until it fills the pipe buffer due to lack of SIGPIPE. + + * The documentation for "git clean" has been corrected; it mentioned + that .git/modules/* are removed by giving two "-f", which has never + been the case. + + * The vimdiff backend for "git mergetool" has been tweaked to arrange + and number buffers in the order that would match the expectation of + majority of people who read left to right, then top down and assign + buffers 1 2 3 4 "mentally" to local base remote merge windows based + on that order. + + * "git show 'HEAD:Foo[BAR]Baz'" did not interpret the argument as a + rev, i.e. the object named by the the pathname with wildcard + characters in a tree object. + (merge aac4fac nd/dwim-wildcards-as-pathspecs later to maint). + + * "git rev-parse --git-common-dir" used in the worktree feature + misbehaved when run from a subdirectory. + (merge 17f1365 nd/git-common-dir-fix later to maint). + + * Another try to add support to the ignore mechanism that lets you + say "this is excluded" and then later say "oh, no, this part (that + is a subset of the previous part) is not excluded". + + * "git worktree add -B <branchname>" did not work. + + * The "v(iew)" subcommand of the interactive "git am -i" command was + broken in 2.6.0 timeframe when the command was rewritten in C. + (merge 708b8cc jc/am-i-v-fix later to maint). + + * Other minor clean-ups and documentation updates diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index 760eab7428..02cb6845cd 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -69,6 +69,13 @@ include::line-range-format.txt[] iso format is used. For supported values, see the discussion of the --date option at linkgit:git-log[1]. +--[no-]progress:: + Progress status is reported on the standard error stream + by default when it is attached to a terminal. This flag + enables progress reporting even if not attached to a + terminal. Can't use `--progress` together with `--porcelain` + or `--incremental`. + -M|<num>|:: Detect moved or copied lines within a file. When a commit moves or copies a block of lines (e.g. the original file diff --git a/Documentation/config.txt b/Documentation/config.txt index f61788668e..2cd6bdd7d2 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -308,6 +308,15 @@ core.trustctime:: crawlers and some backup systems). See linkgit:git-update-index[1]. True by default. +core.untrackedCache:: + Determines what to do about the untracked cache feature of the + index. It will be kept, if this variable is unset or set to + `keep`. It will automatically be added if set to `true`. And + it will automatically be removed, if set to `false`. Before + setting it to `true`, you should check that mtime is working + properly on your system. + See linkgit:git-update-index[1]. `keep` by default. + core.checkStat:: Determines which stat fields to match between the index and work tree. The user can set this to 'default' or @@ -870,6 +879,8 @@ When preserve, also pass `--preserve-merges` along to 'git rebase' so that locally committed merge commits will not be flattened by running 'git pull'. + +When the value is `interactive`, the rebase is run in interactive mode. ++ *NOTE*: this is a possibly dangerous operation; do *not* use it unless you understand the implications (see linkgit:git-rebase[1] for details). @@ -1243,6 +1254,10 @@ format.coverLetter:: format-patch is invoked, but in addition can be set to "auto", to generate a cover-letter only when there's more than one patch. +format.outputDirectory:: + Set a custom directory to store the resulting files instead of the + current working directory. + filter.<driver>.clean:: The command which is used to convert the content of a worktree file to a blob upon checkin. See linkgit:gitattributes[5] for @@ -1450,6 +1465,14 @@ grep.extendedRegexp:: option is ignored when the 'grep.patternType' option is set to a value other than 'default'. +grep.threads:: + Number of grep worker threads to use. + See `grep.threads` in linkgit:git-grep[1] for more information. + +grep.fallbackToNoIndex:: + If set to true, fall back to git grep --no-index if git grep + is executed outside of a git repository. Defaults to false. + gpg.program:: Use this custom program instead of "gpg" found on $PATH when making or verifying a PGP signature. The program must support the @@ -1596,9 +1619,40 @@ help.htmlPath:: http.proxy:: Override the HTTP proxy, normally configured using the 'http_proxy', - 'https_proxy', and 'all_proxy' environment variables (see - `curl(1)`). This can be overridden on a per-remote basis; see - remote.<name>.proxy + 'https_proxy', and 'all_proxy' environment variables (see `curl(1)`). In + addition to the syntax understood by curl, it is possible to specify a + proxy string with a user name but no password, in which case git will + attempt to acquire one in the same way it does for other credentials. See + linkgit:gitcredentials[7] for more information. The syntax thus is + '[protocol://][user[:password]@]proxyhost[:port]'. This can be overridden + on a per-remote basis; see remote.<name>.proxy + +http.proxyAuthMethod:: + Set the method with which to authenticate against the HTTP proxy. This + only takes effect if the configured proxy string contains a user name part + (i.e. is of the form 'user@host' or 'user@host:port'). This can be + overridden on a per-remote basis; see `remote.<name>.proxyAuthMethod`. + Both can be overridden by the 'GIT_HTTP_PROXY_AUTHMETHOD' environment + variable. Possible values are: ++ +-- +* `anyauth` - Automatically pick a suitable authentication method. It is + assumed that the proxy answers an unauthenticated request with a 407 + status code and one or more Proxy-authenticate headers with supported + authentication methods. This is the default. +* `basic` - HTTP Basic authentication +* `digest` - HTTP Digest authentication; this prevents the password from being + transmitted to the proxy in clear text +* `negotiate` - GSS-Negotiate authentication (compare the --negotiate option + of `curl(1)`) +* `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`) +-- + +http.emptyAuth:: + Attempt authentication without seeking a username or password. This + can be used to attempt GSS-Negotiate authentication without specifying + a username in the URL, as libcurl normally requires a username for + authentication. http.cookieFile:: File containing previously stored cookie lines which should be used @@ -1679,6 +1733,14 @@ http.sslCAPath:: with when fetching or pushing over HTTPS. Can be overridden by the 'GIT_SSL_CAPATH' environment variable. +http.pinnedpubkey:: + Public key of the https service. It may either be the filename of + a PEM or DER encoded public key file or a string starting with + 'sha256//' followed by the base64 encoded sha256 hash of the + public key. See also libcurl 'CURLOPT_PINNEDPUBLICKEY'. git will + exit with an error if this option is set but not supported by + cURL. + http.sslTry:: Attempt to use AUTH SSL/TLS and encrypted data transfers when connecting via regular FTP protocol. This might be needed @@ -2074,7 +2136,7 @@ pack.indexVersion:: larger than 2 GB. + If you have an old Git that does not understand the version 2 `*.idx` file, -cloning or fetching over a non native protocol (e.g. "http" and "rsync") +cloning or fetching over a non native protocol (e.g. "http") that will copy both `*.pack` file and corresponding `*.idx` file from the other side may give you a repository that cannot be accessed with your older version of Git. If the `*.pack` file is smaller than 2 GB, however, @@ -2149,6 +2211,8 @@ When preserve, also pass `--preserve-merges` along to 'git rebase' so that locally committed merge commits will not be flattened by running 'git pull'. + +When the value is `interactive`, the rebase is run in interactive mode. ++ *NOTE*: this is a possibly dangerous operation; do *not* use it unless you understand the implications (see linkgit:git-rebase[1] for details). @@ -2407,6 +2471,11 @@ remote.<name>.proxy:: the proxy to use for that remote. Set to the empty string to disable proxying for that remote. +remote.<name>.proxyAuthMethod:: + For remotes that require curl (http, https and ftp), the method to use for + authenticating against the proxy in use (probably set in + `remote.<name>.proxy`). See `http.proxyAuthMethod`. + remote.<name>.fetch:: The default set of "refspec" for linkgit:git-fetch[1]. See linkgit:git-fetch[1]. @@ -2775,6 +2844,16 @@ user.name:: Can be overridden by the 'GIT_AUTHOR_NAME' and 'GIT_COMMITTER_NAME' environment variables. See linkgit:git-commit-tree[1]. +user.useConfigOnly:: + Instruct Git to avoid trying to guess defaults for 'user.email' + and 'user.name', and instead retrieve the values only from the + configuration. For example, if you have multiple email addresses + and would like to use a different one for each repository, then + with this configuration option set to `true` in the global config + along with a name, Git will prompt you to set up an email before + making new commits in a newly cloned repository. + Defaults to `false`. + user.signingKey:: If linkgit:git-tag[1] or linkgit:git-commit[1] is not selecting the key you want it to automatically when creating a signed tag or diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 45583d8454..036edfb099 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -8,10 +8,11 @@ option old data in `.git/FETCH_HEAD` will be overwritten. --depth=<depth>:: - Deepen or shorten the history of a 'shallow' repository created by - `git clone` with `--depth=<depth>` option (see linkgit:git-clone[1]) - to the specified number of commits from the tip of each remote - branch history. Tags for the deepened commits are not fetched. + Limit fetching to the specified number of commits from the tip of + each remote branch history. If fetching to a 'shallow' repository + created by `git clone` with `--depth=<depth>` option (see + linkgit:git-clone[1]), deepen or shorten the history to the specified + number of commits. Tags for the deepened commits are not fetched. --unshallow:: If the source repository is complete, convert a shallow @@ -100,6 +101,13 @@ ifndef::git-pull[] reference to a commit that isn't already in the local submodule clone. +-j:: +--jobs=<n>:: + Number of parallel children to be used for fetching submodules. + Each will fetch from different submodules, such that fetching many + submodules will be faster. By default submodules will be fetched + one at a time. + --no-recurse-submodules:: Disable recursive fetching of submodules (this has the same effect as using the '--recurse-submodules=no' option). @@ -150,3 +158,11 @@ endif::git-pull[] by default when it is attached to a terminal, unless -q is specified. This flag forces progress status even if the standard error stream is not directed to a terminal. + +-4:: +--ipv4:: + Use IPv4 addresses only, ignoring IPv6 addresses. + +-6:: +--ipv6:: + Use IPv6 addresses only, ignoring IPv4 addresses. diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index fe5282f130..6a96a669c2 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -24,7 +24,7 @@ remove paths that do not exist in the working tree anymore. The "index" holds a snapshot of the content of the working tree, and it is this snapshot that is taken as the contents of the next commit. Thus -after making any changes to the working directory, and before running +after making any changes to the working tree, and before running the commit command, you must use the `add` command to add any new or modified files to the index. diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 452c1feb23..13cdd7f3b6 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -35,6 +35,7 @@ OPTIONS --signoff:: Add a `Signed-off-by:` line to the commit message, using the committer identity of yourself. + See the signoff option in linkgit:git-commit[1] for more information. -k:: --keep:: diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt index e6e947c808..ba5417567c 100644 --- a/Documentation/git-blame.txt +++ b/Documentation/git-blame.txt @@ -10,7 +10,8 @@ SYNOPSIS [verse] 'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental] [-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>] - [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>] [--] <file> + [--progress] [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>] + [--] <file> DESCRIPTION ----------- diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt index 0417562eb7..3a8120c3b3 100644 --- a/Documentation/git-bundle.txt +++ b/Documentation/git-bundle.txt @@ -20,7 +20,7 @@ DESCRIPTION Some workflows require that one or more branches of development on one machine be replicated on another machine, but the two machines cannot be directly connected, and therefore the interactive Git protocols (git, -ssh, rsync, http) cannot be used. This command provides support for +ssh, http) cannot be used. This command provides support for 'git fetch' and 'git pull' to operate by packaging objects and references in an archive at the originating machine, then importing those into another repository using 'git fetch' and 'git pull' diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt index e94367a5ed..f60ee051f8 100644 --- a/Documentation/git-check-ignore.txt +++ b/Documentation/git-check-ignore.txt @@ -114,6 +114,7 @@ SEE ALSO linkgit:gitignore[5] linkgit:gitconfig[5] linkgit:git-ls-files[1] +GIT_TRACE_EXCLUDE in linkgit:git[1] GIT --- diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 77da29a474..6154e57238 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -100,6 +100,7 @@ effect to your index in a row. -s:: --signoff:: Add Signed-off-by line at the end of the commit message. + See the signoff option in linkgit:git-commit[1] for more information. -S[<keyid>]:: --gpg-sign[=<keyid>]:: diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index 641681f61a..51a7e26a8e 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -37,9 +37,7 @@ OPTIONS to false, 'git clean' will refuse to delete files or directories unless given -f, -n or -i. Git will refuse to delete directories with .git sub directory or file unless a second -f - is given. This affects also git submodules where the storage area - of the removed submodule under .git/modules/ is not removed until - -f is given twice. + is given. -i:: --interactive:: diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 6bf000dac3..b7c467a001 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -115,8 +115,7 @@ objects from the source repository into a pack in the cloned repository. --quiet:: -q:: Operate quietly. Progress is not reported to the standard - error stream. This flag is also passed to the `rsync' - command when given. + error stream. --verbose:: -v:: @@ -190,15 +189,14 @@ objects from the source repository into a pack in the cloned repository. --depth <depth>:: Create a 'shallow' clone with a history truncated to the - specified number of revisions. + specified number of commits. Implies `--single-branch` unless + `--no-single-branch` is given to fetch the histories near the + tips of all branches. --[no-]single-branch:: Clone only the history leading to the tip of a single branch, either specified by the `--branch` option or the primary - branch remote's `HEAD` points at. When creating a shallow - clone with the `--depth` option, this is the default, unless - `--no-single-branch` is given to fetch the histories near the - tips of all branches. + branch remote's `HEAD` points at. Further fetches into the resulting repository will only update the remote-tracking branch for the branch this option was used for the initial cloning. If the HEAD at the remote did not point at any diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 7f34a5b331..9ec6b3cc17 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -154,7 +154,11 @@ OPTIONS -s:: --signoff:: Add Signed-off-by line by the committer at the end of the commit - log message. + log message. The meaning of a signoff depends on the project, + but it typically certifies that committer has + the rights to submit this work under the same license and + agrees to a Developer Certificate of Origin + (see http://developercertificate.org/ for more information). -n:: --no-verify:: diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 2608ca74ac..153b2d89b5 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -9,18 +9,18 @@ git-config - Get and set repository or global options SYNOPSIS -------- [verse] -'git config' [<file-option>] [type] [-z|--null] name [value [value_regex]] +'git config' [<file-option>] [type] [--show-origin] [-z|--null] name [value [value_regex]] 'git config' [<file-option>] [type] --add name value 'git config' [<file-option>] [type] --replace-all name value [value_regex] -'git config' [<file-option>] [type] [-z|--null] --get name [value_regex] -'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex] -'git config' [<file-option>] [type] [-z|--null] [--name-only] --get-regexp name_regex [value_regex] +'git config' [<file-option>] [type] [--show-origin] [-z|--null] --get name [value_regex] +'git config' [<file-option>] [type] [--show-origin] [-z|--null] --get-all name [value_regex] +'git config' [<file-option>] [type] [--show-origin] [-z|--null] [--name-only] --get-regexp name_regex [value_regex] 'git config' [<file-option>] [type] [-z|--null] --get-urlmatch name URL 'git config' [<file-option>] --unset name [value_regex] 'git config' [<file-option>] --unset-all name [value_regex] 'git config' [<file-option>] --rename-section old_name new_name 'git config' [<file-option>] --remove-section name -'git config' [<file-option>] [-z|--null] [--name-only] -l | --list +'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list 'git config' [<file-option>] --get-color name [default] 'git config' [<file-option>] --get-colorbool name [stdout-is-tty] 'git config' [<file-option>] -e | --edit @@ -194,6 +194,12 @@ See also <<FILES>>. Output only the names of config variables for `--list` or `--get-regexp`. +--show-origin:: + Augment the output of all queried config options with the + origin type (file, standard input, blob, command line) and + the actual origin (config file path, ref, or blob id if + applicable). + --get-colorbool name [stdout-is-tty]:: Find the color setting for `name` (e.g. `color.diff`) and output @@ -219,7 +225,9 @@ See also <<FILES>>. --[no-]includes:: Respect `include.*` directives in config files when looking up - values. Defaults to on. + values. Defaults to `off` when a specific file is given (e.g., + using `--file`, `--global`, etc) and `on` when searching all + config files. [[FILES]] FILES diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt index 89b730632d..96208f822e 100644 --- a/Documentation/git-credential-cache.txt +++ b/Documentation/git-credential-cache.txt @@ -36,7 +36,7 @@ OPTIONS cache daemon if one is not started). Defaults to `~/.git-credential-cache/socket`. If your home directory is on a network-mounted filesystem, you may need to change this to a - local filesystem. + local filesystem. You must specify an absolute path. CONTROLLING THE DAEMON ---------------------- diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index c6f073cea4..012e8f9a08 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -92,7 +92,11 @@ refname:: The name of the ref (the part after $GIT_DIR/). For a non-ambiguous short name of the ref append `:short`. The option core.warnAmbiguousRefs is used to select the strict - abbreviation mode. + abbreviation mode. If `strip=<N>` is appended, strips `<N>` + slash-separated path components from the front of the refname + (e.g., `%(refname:strip=2)` turns `refs/tags/foo` into `foo`. + `<N>` must be a positive integer. If a displayed ref has fewer + components than `<N>`, the command aborts with an error. objecttype:: The type of the object (`blob`, `tree`, `commit`, `tag`). @@ -129,19 +133,28 @@ color:: align:: Left-, middle-, or right-align the content between - %(align:...) and %(end). The "align:" is followed by `<width>` - and `<position>` in any order separated by a comma, where the - `<position>` is either left, right or middle, default being - left and `<width>` is the total length of the content with - alignment. If the contents length is more than the width then - no alignment is performed. If used with '--quote' everything - in between %(align:...) and %(end) is quoted, but if nested - then only the topmost level performs quoting. + %(align:...) and %(end). The "align:" is followed by + `width=<width>` and `position=<position>` in any order + separated by a comma, where the `<position>` is either left, + right or middle, default being left and `<width>` is the total + length of the content with alignment. For brevity, the + "width=" and/or "position=" prefixes may be omitted, and bare + <width> and <position> used instead. For instance, + `%(align:<width>,<position>)`. If the contents length is more + than the width then no alignment is performed. If used with + '--quote' everything in between %(align:...) and %(end) is + quoted, but if nested then only the topmost level performs + quoting. In addition to the above, for commit and tag objects, the header field names (`tree`, `parent`, `object`, `type`, and `tag`) can be used to specify the value in the header field. +For commit and tag objects, the special `creatordate` and `creator` +fields will correspond to the appropriate date or name-email-date tuple +from the `committer` or `tagger` fields depending on the object type. +These are intended for working on a mix of annotated and lightweight tags. + Fields that have name-email-date tuple as its value (`author`, `committer`, and `tagger`) can be suffixed with `name`, `email`, and `date` to extract the named component. @@ -153,8 +166,8 @@ line is 'contents:body', where body is all of the lines after the first blank line. The optional GPG signature is `contents:signature`. The first `N` lines of the message is obtained using `contents:lines=N`. -For sorting purposes, fields with numeric values sort in numeric -order (`objectsize`, `authordate`, `committerdate`, `taggerdate`). +For sorting purposes, fields with numeric values sort in numeric order +(`objectsize`, `authordate`, `committerdate`, `creatordate`, `taggerdate`). All other fields are used to sort in their byte-value order. There is also an option to sort by versions, this can be done by using diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index e3cdaeb958..6821441d7d 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -57,7 +57,11 @@ The names of the output files are printed to standard output, unless the `--stdout` option is specified. If `-o` is specified, output files are created in <dir>. Otherwise -they are created in the current working directory. +they are created in the current working directory. The default path +can be set with the 'format.outputDirectory' configuration option. +The `-o` option takes precedence over `format.outputDirectory`. +To store patches in the current working directory even when +`format.outputDirectory` points elsewhere, use `-o .`. By default, the subject of a single patch is "[PATCH] " followed by the concatenation of lines from the commit message up to the first blank @@ -109,6 +113,7 @@ include::diff-options.txt[] --signoff:: Add `Signed-off-by:` line to the commit message, using the committer identity of yourself. + See the signoff option in linkgit:git-commit[1] for more information. --stdout:: Print all commits to the standard output in mbox format, diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4a44d6da13..cb0f6cf678 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -23,6 +23,7 @@ SYNOPSIS [--break] [--heading] [-p | --show-function] [-A <post-context>] [-B <pre-context>] [-C <context>] [-W | --function-context] + [--threads <num>] [-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...] [ [--[no-]exclude-standard] [--cached | --no-index | --untracked] | <tree>...] @@ -53,9 +54,17 @@ grep.extendedRegexp:: option is ignored when the 'grep.patternType' option is set to a value other than 'default'. +grep.threads:: + Number of grep worker threads to use. If unset (or set to 0), + 8 threads are used by default (for now). + grep.fullName:: If set to true, enable '--full-name' option by default. +grep.fallbackToNoIndex:: + If set to true, fall back to git grep --no-index if git grep + is executed outside of a git repository. Defaults to false. + OPTIONS ------- @@ -227,6 +236,10 @@ OPTIONS effectively showing the whole function in which the match was found. +--threads <num>:: + Number of grep worker threads to use. + See `grep.threads` in 'CONFIGURATION' for more information. + -f <file>:: Read patterns from <file>, one per line. diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt index 0ecd497c4d..a77b901f1d 100644 --- a/Documentation/git-interpret-trailers.txt +++ b/Documentation/git-interpret-trailers.txt @@ -8,7 +8,7 @@ git-interpret-trailers - help add structured information into commit messages SYNOPSIS -------- [verse] -'git interpret-trailers' [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...] +'git interpret-trailers' [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...] DESCRIPTION ----------- @@ -64,6 +64,9 @@ folding rules, the encoding rules and probably many other rules. OPTIONS ------- +--in-place:: + Edit the files in place. + --trim-empty:: If the <value> part of any trailer contains only whitespace, the whole trailer will be removed from the resulting message. @@ -216,6 +219,25 @@ Signed-off-by: Alice <alice@example.com> Signed-off-by: Bob <bob@example.com> ------------ +* Use the '--in-place' option to edit a message file in place: ++ +------------ +$ cat msg.txt +subject + +message + +Signed-off-by: Bob <bob@example.com> +$ git interpret-trailers --trailer 'Acked-by: Alice <alice@example.com>' --in-place msg.txt +$ cat msg.txt +subject + +message + +Signed-off-by: Bob <bob@example.com> +Acked-by: Alice <alice@example.com> +------------ + * Extract the last commit as a patch, and add a 'Cc' and a 'Reviewed-by' trailer to it: + diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index e26f01fb1d..0e08f567a1 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -12,6 +12,7 @@ SYNOPSIS 'git ls-files' [-z] [-t] [-v] (--[cached|deleted|others|ignored|stage|unmerged|killed|modified])* (-[c|d|o|i|s|u|k|m])* + [--eol] [-x <pattern>|--exclude=<pattern>] [-X <file>|--exclude-from=<file>] [--exclude-per-directory=<file>] @@ -147,6 +148,24 @@ a space) at the start of each line: possible for manual inspection; the exact format may change at any time. +--eol:: + Show <eolinfo> and <eolattr> of files. + <eolinfo> is the file content identification used by Git when + the "text" attribute is "auto" (or not set and core.autocrlf is not false). + <eolinfo> is either "-text", "none", "lf", "crlf", "mixed" or "". ++ +"" means the file is not a regular file, it is not in the index or +not accessable in the working tree. ++ +<eolattr> is the attribute that is used when checking out or committing, +it is either "", "-text", "text", "text=auto", "text eol=lf", "text eol=crlf". +Note: Currently Git does not support "text=auto eol=lf" or "text=auto eol=crlf", +that may change in the future. ++ +Both the <eolinfo> in the index ("i/<eolinfo>") +and in the working tree ("w/<eolinfo>") are shown for regular files, +followed by the ("attr/<eolattr>"). + \--:: Do not interpret any more arguments as options. @@ -161,6 +180,9 @@ which case it outputs: [<tag> ]<mode> <object> <stage> <file> +'git ls-files --eol' will show + i/<eolinfo><SPACES>w/<eolinfo><SPACES>attr/<eolattr><SPACE*><TAB><file> + 'git ls-files --unmerged' and 'git ls-files --stage' can be used to examine detailed information on unmerged paths. diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt index d510c05e11..5f2628c8f8 100644 --- a/Documentation/git-ls-remote.txt +++ b/Documentation/git-ls-remote.txt @@ -9,8 +9,9 @@ git-ls-remote - List references in a remote repository SYNOPSIS -------- [verse] -'git ls-remote' [--heads] [--tags] [--upload-pack=<exec>] - [--exit-code] <repository> [<refs>...] +'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>] + [-q | --quiet] [--exit-code] [--get-url] + [--symref] [<repository> [<refs>...]] DESCRIPTION ----------- @@ -29,6 +30,13 @@ OPTIONS both, references stored in refs/heads and refs/tags are displayed. +--refs:: + Do not show peeled tags or pseudorefs like HEAD in the output. + +-q:: +--quiet:: + Do not print remote URL to stderr. + --upload-pack=<exec>:: Specify the full path of 'git-upload-pack' on the remote host. This allows listing references from repositories accessed via @@ -46,6 +54,12 @@ OPTIONS "url.<base>.insteadOf" config setting (See linkgit:git-config[1]) and exit without talking to the remote. +--symref:: + In addition to the object pointed by it, show the underlying + ref pointed by it when showing a symbolic ref. Currently, + upload-pack only shows the symref HEAD, so it will be the only + one shown by ls-remote. + <repository>:: The "remote" repository to query. This parameter can be either a URL or the name of a remote (see the GIT URLS and diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 93c72a29ce..a62a2a615d 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -101,7 +101,7 @@ Options related to merging include::merge-options.txt[] -r:: ---rebase[=false|true|preserve]:: +--rebase[=false|true|preserve|interactive]:: When true, rebase the current branch on top of the upstream branch after fetching. If there is a remote-tracking branch corresponding to the upstream branch and the upstream branch @@ -113,6 +113,8 @@ to `git rebase` so that locally created merge commits will not be flattened. + When false, merge the current branch into the upstream branch. + +When `interactive`, enable the interactive mode of rebase. ++ See `pull.rebase`, `branch.<name>.rebase` and `branch.autoSetupRebase` in linkgit:git-config[1] if you want to make `git pull` always use `--rebase` instead of merging. diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 4c775bcec4..cf6ee4a4df 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>] - [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose] + [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose] [-u | --set-upstream] [--[no-]signed|--sign=(true|false|if-asked)] [--force-with-lease[=<refname>[:<expect>]]] @@ -37,6 +37,13 @@ the default `<refspec>` by consulting `remote.*.push` configuration, and if it is not found, honors `push.default` configuration to decide what to push (See linkgit:git-config[1] for the meaning of `push.default`). +When neither the command-line nor the configuration specify what to +push, the default behavior is used, which corresponds to the `simple` +value for `push.default`: the current branch is pushed to the +corresponding upstream branch, but as a safety measure, the push is +aborted if the upstream branch does not have the same name as the +local one. + OPTIONS[[OPTIONS]] ------------------ @@ -277,6 +284,13 @@ origin +master` to force a push to the `master` branch). See the default is --verify, giving the hook a chance to prevent the push. With --no-verify, the hook is bypassed completely. +-4:: +--ipv4:: + Use IPv4 addresses only, ignoring IPv6 addresses. + +-6:: +--ipv6:: + Use IPv6 addresses only, ignoring IPv4 addresses. include::urls-remotes.txt[] diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt index 0e0bd363d6..af230d0647 100644 --- a/Documentation/git-repack.txt +++ b/Documentation/git-repack.txt @@ -133,7 +133,7 @@ By default, the command passes `--delta-base-offset` option to 'git pack-objects'; this typically results in slightly smaller packs, but the generated packs are incompatible with versions of Git older than version 1.4.4. If you need to share your repository with such ancient Git -versions, either directly or via the dumb http or rsync protocol, then you +versions, either directly or via the dumb http protocol, then you need to set the configuration variable `repack.UseDeltaBaseOffset` to "false" and repack. Access from old Git versions over the native protocol is unaffected by this option as the conversion is performed on the fly diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt index b15139ffdc..573616a04a 100644 --- a/Documentation/git-revert.txt +++ b/Documentation/git-revert.txt @@ -89,6 +89,7 @@ effect to your index in a row. -s:: --signoff:: Add Signed-off-by line at the end of the commit message. + See the signoff option in linkgit:git-commit[1] for more information. --strategy=<strategy>:: Use the given merge strategy. Should only be used once. diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 7220e5eca1..abab4814ec 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -163,7 +163,7 @@ This option is only applicable when listing tags without annotation lines. A string that interpolates `%(fieldname)` from the object pointed at by a ref being shown. The format is the same as that of linkgit:git-for-each-ref[1]. When unspecified, - defaults to `%(refname:short)`. + defaults to `%(refname:strip=2)`. --[no-]merged [<commit>]:: Only list tags whose tips are reachable, or not reachable diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index f4e5a85351..c6cbed189c 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -18,7 +18,7 @@ SYNOPSIS [--[no-]skip-worktree] [--ignore-submodules] [--[no-]split-index] - [--[no-|force-]untracked-cache] + [--[no-|test-|force-]untracked-cache] [--really-refresh] [--unresolve] [--again | -g] [--info-only] [--index-info] [-z] [--stdin] [--index-version <n>] @@ -174,17 +174,30 @@ may not support it yet. --untracked-cache:: --no-untracked-cache:: - Enable or disable untracked cache extension. This could speed - up for commands that involve determining untracked files such - as `git status`. The underlying operating system and file - system must change `st_mtime` field of a directory if files - are added or deleted in that directory. + Enable or disable untracked cache feature. Please use + `--test-untracked-cache` before enabling it. ++ +These options take effect whatever the value of the `core.untrackedCache` +configuration variable (see linkgit:git-config[1]). But a warning is +emitted when the change goes against the configured value, as the +configured value will take effect next time the index is read and this +will remove the intended effect of the option. + +--test-untracked-cache:: + Only perform tests on the working directory to make sure + untracked cache can be used. You have to manually enable + untracked cache using `--untracked-cache` or + `--force-untracked-cache` or the `core.untrackedCache` + configuration variable afterwards if you really want to use + it. If a test fails the exit code is 1 and a message + explains what is not working as needed, otherwise the exit + code is 0 and OK is printed. --force-untracked-cache:: - For safety, `--untracked-cache` performs tests on the working - directory to make sure untracked cache can be used. These - tests can take a few seconds. `--force-untracked-cache` can be - used to skip the tests. + Same as `--untracked-cache`. Provided for backwards + compatibility with older versions of Git where + `--untracked-cache` used to imply `--test-untracked-cache` but + this option would enable the extension unconditionally. \--:: Do not interpret any more arguments as options. @@ -375,6 +388,37 @@ Although this bit looks similar to assume-unchanged bit, its goal is different from assume-unchanged bit's. Skip-worktree also takes precedence over assume-unchanged bit when both are set. +Untracked cache +--------------- + +This cache is meant to speed up commands that involve determining +untracked files such as `git status`. + +This feature works by recording the mtime of the working tree +directories and then omitting reading directories and stat calls +against files in those directories whose mtime hasn't changed. For +this to work the underlying operating system and file system must +change the `st_mtime` field of directories if files in the directory +are added, modified or deleted. + +You can test whether the filesystem supports that with the +`--test-untracked-cache` option. The `--untracked-cache` option used +to implicitly perform that test in older versions of Git, but that's +no longer the case. + +If you want to enable (or disable) this feature, it is easier to use +the `core.untrackedCache` configuration variable (see +linkgit:git-config[1]) than using the `--untracked-cache` option to +`git update-index` in each repository, especially if you want to do so +across all repositories you use, because you can set the configuration +variable to `true` (or `false`) in your `$HOME/.gitconfig` just once +and have it affect all repositories you touch. + +When the `core.untrackedCache` configuration variable is changed, the +untracked cache is added to or removed from the index the next time a +command reads the index; while when `--[no-|force-]untracked-cache` +are used, the untracked cache is immediately added to or removed from +the index. Configuration ------------- @@ -400,6 +444,9 @@ It can be useful when the inode change time is regularly modified by something outside Git (file system crawlers and backup systems use ctime for marking files processed) (see linkgit:git-config[1]). +The untracked cache extension can be enabled by the +`core.untrackedCache` configuration variable (see +linkgit:git-config[1]). SEE ALSO -------- diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 5b9ad0429c..62c76c1c89 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -32,11 +32,9 @@ The working tree's administrative files in the repository (see `git worktree prune` in the main or any linked working tree to clean up any stale administrative files. -If you move a linked working tree to another file system, or -within a file system that does not support hard links, you need to run -at least one git command inside the linked working tree -(e.g. `git status`) in order to update its administrative files in the -repository so that they do not get automatically pruned. +If you move a linked working tree, you need to manually update the +administrative files so that they do not get pruned automatically. See +section "DETAILS" for more information. If a linked working tree is stored on a portable device or network share which is not always mounted, you can prevent its administrative files from @@ -137,6 +135,13 @@ thumb is do not make any assumption about whether a path belongs to $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path. +If you move a linked working tree, you need to update the 'gitdir' file +in the entry's directory. For example, if a linked working tree is moved +to `/newpath/test-next` and its `.git` file points to +`/path/main/.git/worktrees/test-next`, then update +`/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next` +instead. + To prevent a $GIT_DIR/worktrees entry from being pruned (which can be useful in some situations, such as when the entry's working tree is stored on a portable device), add a file named diff --git a/Documentation/git.txt b/Documentation/git.txt index bff6302c0d..2754af8f77 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,11 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.7.0/git.html[documentation for release 2.7] +* link:v2.7.2/git.html[documentation for release 2.7.2] * release notes for + link:RelNotes/2.7.2.txt[2.7.2], + link:RelNotes/2.7.1.txt[2.7.1], link:RelNotes/2.7.0.txt[2.7]. * link:v2.6.5/git.html[documentation for release 2.6.5] @@ -1063,6 +1065,11 @@ of clones and fetches. cloning of shallow repositories. See 'GIT_TRACE' for available trace output options. +'GIT_TRACE_EXCLUDE':: + Enables trace messages that can help debugging .gitignore + processing. See 'GIT_TRACE' for available trace output + options. + 'GIT_LITERAL_PATHSPECS':: Setting this variable to `1` will cause Git to treat all pathspecs literally, rather than as glob patterns. For example, @@ -1123,8 +1130,6 @@ of clones and fetches. - `ssh`: git over ssh (including `host:path` syntax, `git+ssh://`, etc). - - `rsync`: git over rsync - - `http`: git over http, both "smart http" and "dumb http". Note that this does _not_ include `https`; if you want both, you should specify both as `http:https`. diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt index 36e9ab3e16..15b3bfa8db 100644 --- a/Documentation/gitcore-tutorial.txt +++ b/Documentation/gitcore-tutorial.txt @@ -710,7 +710,7 @@ files). Again, this can all be simplified with ---------------- -$ git clone rsync://rsync.kernel.org/pub/scm/git/git.git/ my-git +$ git clone git://git.kernel.org/pub/scm/git/git.git/ my-git $ cd my-git $ git checkout ---------------- @@ -1011,20 +1011,6 @@ $ git fetch <remote-repository> One of the following transports can be used to name the repository to download from: -Rsync:: - `rsync://remote.machine/path/to/repo.git/` -+ -Rsync transport is usable for both uploading and downloading, -but is completely unaware of what git does, and can produce -unexpected results when you download from the public repository -while the repository owner is uploading into it via `rsync` -transport. Most notably, it could update the files under -`refs/` which holds the object name of the topmost commits -before uploading the files in `objects/` -- the downloader would -obtain head commit object name while that object itself is still -not available in the repository. For this reason, it is -considered deprecated. - SSH:: `remote.machine:/path/to/repo.git/` or + @@ -1430,7 +1416,7 @@ while, depending on how active your project is. When a repository is synchronized via `git push` and `git pull` objects packed in the source repository are usually stored -unpacked in the destination, unless rsync transport is used. +unpacked in the destination. While this allows you to use different packing strategies on both ends, it also means you may need to repack both repositories every once in a while. diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index 79a1948a0b..3ded6fdc99 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -150,12 +150,6 @@ excluded, the following conditions must be met: - The directory part in the re-include rules must be literal (i.e. no wildcards) - - The rules to exclude the parent directory must not end with a - trailing slash. - - - The rules to exclude the parent directory must have at least one - slash. - EXAMPLES -------- diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt index b00c67df46..b3b58d324e 100644 --- a/Documentation/gittutorial.txt +++ b/Documentation/gittutorial.txt @@ -451,7 +451,7 @@ perform clones and pulls using the ssh protocol: bob$ git clone alice.org:/home/alice/project myrepo ------------------------------------- -Alternatively, Git has a native protocol, or can use rsync or http; +Alternatively, Git has a native protocol, or can use http; see linkgit:git-pull[1] for details. Git can also be used in a CVS-like mode, with a central repository diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index e225974253..cafc284359 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -531,6 +531,11 @@ The most notable example is `HEAD`. "Secure Hash Algorithm 1"; a cryptographic hash function. In the context of Git used as a synonym for <<def_object_name,object name>>. +[[def_shallow_clone]]shallow clone:: + Mostly a synonym to <<def_shallow_repository,shallow repository>> + but the phrase makes it more explicit that it was created by + running `git clone --depth=...` command. + [[def_shallow_repository]]shallow repository:: A shallow <<def_repository,repository>> has an incomplete history some of whose <<def_commit,commits>> have <<def_parent,parents>> cauterized away (in other diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt index 7bbd19b300..2eb92b9327 100644 --- a/Documentation/merge-strategies.txt +++ b/Documentation/merge-strategies.txt @@ -81,9 +81,17 @@ no-renormalize;; Disables the `renormalize` option. This overrides the `merge.renormalize` configuration variable. +no-renames;; + Turn off rename detection. + See also linkgit:git-diff[1] `--no-renames`. + +find-renames[=<n>];; + Turn on rename detection, optionally setting the similarity + threshold. This is the default. + See also linkgit:git-diff[1] `--find-renames`. + rename-threshold=<n>;; - Controls the similarity threshold used for rename detection. - See also linkgit:git-diff[1] `-M`. + Deprecated synonym for `find-renames=<n>`. subtree[=<path>];; This option is a more advanced form of 'subtree' strategy, where diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt index 4b659ac1a6..54b88b6dca 100644 --- a/Documentation/pretty-options.txt +++ b/Documentation/pretty-options.txt @@ -43,7 +43,7 @@ people using 80-column terminals. commit may be copied to the output. ifndef::git-rev-list[] ---notes[=<ref>]:: +--notes[=<treeish>]:: Show the notes (see linkgit:git-notes[1]) that annotate the commit, when showing the commit log message. This is the default for `git log`, `git show` and `git whatchanged` commands when @@ -54,8 +54,8 @@ By default, the notes shown are from the notes refs listed in the 'core.notesRef' and 'notes.displayRef' variables (or corresponding environment overrides). See linkgit:git-config[1] for more details. + -With an optional '<ref>' argument, show this notes ref instead of the -default notes ref(s). The ref specifies the full refname when it begins +With an optional '<treeish>' argument, use the treeish to find the notes +to display. The treeish can specify the full refname when it begins with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise `refs/notes/` is prefixed to form a full name of the ref. + @@ -71,7 +71,7 @@ being displayed. Examples: "--notes=foo" will show only notes from "--notes --notes=foo --no-notes --notes=bar" will only show notes from "refs/notes/bar". ---show-notes[=<ref>]:: +--show-notes[=<treeish>]:: --[no-]standard-notes:: These options are deprecated. Use the above --notes/--no-notes options instead. diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index d85e303364..19314e3b7f 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -61,11 +61,11 @@ some output processing may assume ref names in UTF-8. '@':: '@' alone is a shortcut for 'HEAD'. -'<refname>@\{<date>\}', e.g. 'master@\{yesterday\}', 'HEAD@\{5 minutes ago\}':: +'<refname>@{<date>}', e.g. 'master@\{yesterday\}', 'HEAD@{5 minutes ago}':: A ref followed by the suffix '@' with a date specification enclosed in a brace - pair (e.g. '\{yesterday\}', '\{1 month 2 weeks 3 days 1 hour 1 - second ago\}' or '\{1979-02-26 18:30:00\}') specifies the value + pair (e.g. '\{yesterday\}', '{1 month 2 weeks 3 days 1 hour 1 + second ago}' or '{1979-02-26 18:30:00}') specifies the value of the ref at a prior point in time. This suffix may only be used immediately following a ref name and the ref must have an existing log ('$GIT_DIR/logs/<ref>'). Note that this looks up the state @@ -73,7 +73,7 @@ some output processing may assume ref names in UTF-8. 'master' branch last week. If you want to look at commits made during certain times, see '--since' and '--until'. -'<refname>@\{<n>\}', e.g. 'master@\{1\}':: +'<refname>@{<n>}', e.g. 'master@\{1\}':: A ref followed by the suffix '@' with an ordinal specification enclosed in a brace pair (e.g. '\{1\}', '\{15\}') specifies the n-th prior value of that ref. For example 'master@\{1\}' @@ -82,13 +82,13 @@ some output processing may assume ref names in UTF-8. immediately following a ref name and the ref must have an existing log ('$GIT_DIR/logs/<refname>'). -'@\{<n>\}', e.g. '@\{1\}':: +'@{<n>}', e.g. '@\{1\}':: You can use the '@' construct with an empty ref part to get at a reflog entry of the current branch. For example, if you are on branch 'blabla' then '@\{1\}' means the same as 'blabla@\{1\}'. -'@\{-<n>\}', e.g. '@\{-1\}':: - The construct '@\{-<n>\}' means the <n>th branch/commit checked out +'@{-<n>}', e.g. '@{-1}':: + The construct '@{-<n>}' means the <n>th branch/commit checked out before the current one. '<branchname>@\{upstream\}', e.g. 'master@\{upstream\}', '@\{u\}':: @@ -139,7 +139,7 @@ from one location and push to another. In a non-triangular workflow, '<rev>{caret}1{caret}1{caret}1'. See below for an illustration of the usage of this form. -'<rev>{caret}\{<type>\}', e.g. 'v0.99.8{caret}\{commit\}':: +'<rev>{caret}{<type>}', e.g. 'v0.99.8{caret}\{commit\}':: A suffix '{caret}' followed by an object type name enclosed in brace pair means dereference the object at '<rev>' recursively until an object of type '<type>' is found or the object cannot be @@ -159,13 +159,13 @@ it does not have to be dereferenced even once to get to an object. 'rev{caret}\{tag\}' can be used to ensure that 'rev' identifies an existing tag object. -'<rev>{caret}\{\}', e.g. 'v0.99.8{caret}\{\}':: +'<rev>{caret}{}', e.g. 'v0.99.8{caret}{}':: A suffix '{caret}' followed by an empty brace pair means the object could be a tag, and dereference the tag recursively until a non-tag object is found. -'<rev>{caret}\{/<text>\}', e.g. 'HEAD^{/fix nasty bug}':: +'<rev>{caret}{/<text>}', e.g. 'HEAD^{/fix nasty bug}':: A suffix '{caret}' to a revision parameter, followed by a brace pair that contains a text led by a slash, is the same as the ':/fix nasty bug' syntax below except that @@ -176,11 +176,12 @@ existing tag object. A colon, followed by a slash, followed by a text, names a commit whose commit message matches the specified regular expression. This name returns the youngest matching commit which is - reachable from any ref. If the commit message starts with a - '!' you have to repeat that; the special sequence ':/!', - followed by something else than '!', is reserved for now. - The regular expression can match any part of the commit message. To - match messages starting with a string, one can use e.g. ':/^foo'. + reachable from any ref. The regular expression can match any part of the + commit message. To match messages starting with a string, one can use + e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what + is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a + literal '!' character, followed by 'foo'. Any other sequence beginning with + ':/!' is reserved for now. '<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README':: A suffix ':' followed by a path names the blob or tree diff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt index 8076172a08..cfc063018c 100644 --- a/Documentation/technical/api-argv-array.txt +++ b/Documentation/technical/api-argv-array.txt @@ -56,3 +56,10 @@ Functions `argv_array_clear`:: Free all memory associated with the array and return it to the initial, empty state. + +`argv_array_detach`:: + Disconnect the `argv` member from the `argv_array` struct and + return it. The caller is responsible for freeing the memory used + by the array, and by the strings it references. After detaching, + the `argv_array` is in a reinitialized state and can be pushed + into again. diff --git a/Documentation/technical/api-remote.txt b/Documentation/technical/api-remote.txt index 2cfdd224a8..f10941b2e8 100644 --- a/Documentation/technical/api-remote.txt +++ b/Documentation/technical/api-remote.txt @@ -51,6 +51,10 @@ struct remote The proxy to use for curl (http, https, ftp, etc.) URLs. +`http_proxy_authmethod`:: + + The method used for authenticating against `http_proxy`. + struct remotes can be found by name with remote_get(), and iterated through with for_each_remote(). remote_get(NULL) will return the default remote, given the current branch and configuration. diff --git a/Documentation/urls.txt b/Documentation/urls.txt index 9ccb24677e..b05da95788 100644 --- a/Documentation/urls.txt +++ b/Documentation/urls.txt @@ -7,9 +7,8 @@ Depending on the transport protocol, some of this information may be absent. Git supports ssh, git, http, and https protocols (in addition, ftp, -and ftps can be used for fetching and rsync can be used for fetching -and pushing, but these are inefficient and deprecated; do not use -them). +and ftps can be used for fetching, but this is inefficient and +deprecated; do not use it). The native transport (i.e. git:// URL) does no authentication and should be used with caution on unsecured networks. @@ -20,7 +19,6 @@ The following syntaxes may be used with them: - git://host.xz{startsb}:port{endsb}/path/to/repo.git/ - http{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/ - ftp{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/ -- rsync://host.xz/path/to/repo.git/ An alternative scp-like syntax may also be used with the ssh protocol: diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 1c790ac74a..ec6bacfcdf 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -2125,8 +2125,37 @@ Allowing web browsing of a repository ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The gitweb cgi script provides users an easy way to browse your -project's files and history without having to install Git; see the file -gitweb/INSTALL in the Git source tree for instructions on setting it up. +project's revisions, file contents and logs without having to install +Git. Features like RSS/Atom feeds and blame/annotation details may +optionally be enabled. + +The linkgit:git-instaweb[1] command provides a simple way to start +browsing the repository using gitweb. The default server when using +instaweb is lighttpd. + +See the file gitweb/INSTALL in the Git source tree and +linkgit:gitweb[1] for instructions on details setting up a permament +installation with a CGI or Perl capable server. + +[[how-to-get-a-git-repository-with-minimal-history]] +How to get a Git repository with minimal history +------------------------------------------------ + +A <<def_shallow_clone,shallow clone>>, with its truncated +history, is useful when one is interested only in recent history +of a project and getting full history from the upstream is +expensive. + +A <<def_shallow_clone,shallow clone>> is created by specifying +the linkgit:git-clone[1] `--depth` switch. The depth can later be +changed with the linkgit:git-fetch[1] `--depth` switch, or full +history restored with `--unshallow`. + +Merging inside a <<def_shallow_clone,shallow clone>> will work as long +as a merge base is in the recent history. +Otherwise, it will be like merging unrelated histories and may +have to result in huge conflicts. This limitation may make such +a repository unsuitable to be used in merge based workflows. [[sharing-development-examples]] Examples @@ -4636,23 +4665,15 @@ Scan email archives for other stuff left out Scan man pages to see if any assume more background than this manual provides. -Simplify beginning by suggesting disconnected head instead of -temporary branch creation? - Add more good examples. Entire sections of just cookbook examples might be a good idea; maybe make an "advanced examples" section a standard end-of-chapter section? Include cross-references to the glossary, where appropriate. -Document shallow clones? See draft 1.5.0 release notes for some -documentation. - Add a section on working with other version control systems, including CVS, Subversion, and just imports of series of release tarballs. -More details on gitweb? - Write a chapter on using plumbing and writing scripts. Alternates, clone -reference, etc. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 51aa9e6806..5873f163e5 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.7.0 +DEF_VER=v2.7.0.GIT LF=' ' @@ -583,6 +583,7 @@ TEST_PROGRAMS_NEED_X += test-delta TEST_PROGRAMS_NEED_X += test-dump-cache-tree TEST_PROGRAMS_NEED_X += test-dump-split-index TEST_PROGRAMS_NEED_X += test-dump-untracked-cache +TEST_PROGRAMS_NEED_X += test-fake-ssh TEST_PROGRAMS_NEED_X += test-genrandom TEST_PROGRAMS_NEED_X += test-hashmap TEST_PROGRAMS_NEED_X += test-index-version @@ -2025,6 +2026,7 @@ $(VCSSVN_LIB): $(VCSSVN_OBJS) export DEFAULT_EDITOR DEFAULT_PAGER +.PHONY: doc man html info pdf doc: $(MAKE) -C Documentation all @@ -2068,6 +2070,7 @@ po/git.pot: $(GENERATED_H) FORCE $(LOCALIZED_PERL) mv $@+ $@ +.PHONY: pot pot: po/git.pot POFILES := $(wildcard po/*.po) @@ -2277,6 +2280,7 @@ mergetools_instdir_SQ = $(subst ','\'',$(mergetools_instdir)) install_bindir_programs := $(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X)) $(BINDIR_PROGRAMS_NO_X) +.PHONY: profile-install profile-fast-install profile-install: profile $(MAKE) install @@ -2343,6 +2347,8 @@ endif done && \ ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" +.PHONY: install-gitweb install-doc install-man install-html install-info install-pdf +.PHONY: quick-install-doc quick-install-man quick-install-html install-gitweb: $(MAKE) -C gitweb install @@ -2402,6 +2408,7 @@ rpm: dist htmldocs = git-htmldocs-$(GIT_VERSION) manpages = git-manpages-$(GIT_VERSION) +.PHONY: dist-doc distclean dist-doc: $(RM) -r .doc-tmp-dir mkdir .doc-tmp-dir @@ -2470,6 +2477,8 @@ ALL_COMMANDS += git ALL_COMMANDS += gitk ALL_COMMANDS += gitweb ALL_COMMANDS += git-gui git-citool + +.PHONY: check-docs check-docs:: @(for v in $(ALL_COMMANDS); \ do \ @@ -2514,6 +2523,7 @@ check-builtins:: ### Test suite coverage testing # .PHONY: coverage coverage-clean coverage-compile coverage-test coverage-report +.PHONY: coverage-untested-functions cover_db cover_db_html .PHONY: coverage-clean-results coverage: @@ -1 +1 @@ -Documentation/RelNotes/2.7.0.txt
\ No newline at end of file +Documentation/RelNotes/2.8.0.txt
\ No newline at end of file @@ -23,7 +23,7 @@ int split_cmdline(char *cmdline, const char ***argv) int src, dst, count = 0, size = 16; char quoted = 0; - *argv = xmalloc(sizeof(**argv) * size); + ALLOC_ARRAY(*argv, size); /* split alias_string */ (*argv)[count++] = cmdline; @@ -171,8 +171,8 @@ static void queue_directory(const unsigned char *sha1, unsigned mode, int stage, struct archiver_context *c) { struct directory *d; - size_t len = base->len + 1 + strlen(filename) + 1; - d = xmalloc(sizeof(*d) + len); + size_t len = st_add4(base->len, 1, strlen(filename), 1); + d = xmalloc(st_add(sizeof(*d), len)); d->up = c->bottom; d->baselen = base->len; d->mode = mode; diff --git a/argv-array.c b/argv-array.c index eaed47712b..5d370fa336 100644 --- a/argv-array.c +++ b/argv-array.c @@ -74,3 +74,14 @@ void argv_array_clear(struct argv_array *array) } argv_array_init(array); } + +const char **argv_array_detach(struct argv_array *array) +{ + if (array->argv == empty_argv) + return xcalloc(1, sizeof(const char *)); + else { + const char **ret = array->argv; + argv_array_init(array); + return ret; + } +} diff --git a/argv-array.h b/argv-array.h index a2fa0aa606..29056e49a1 100644 --- a/argv-array.h +++ b/argv-array.h @@ -20,5 +20,6 @@ void argv_array_pushl(struct argv_array *, ...); void argv_array_pushv(struct argv_array *, const char **); void argv_array_pop(struct argv_array *); void argv_array_clear(struct argv_array *); +const char **argv_array_detach(struct argv_array *); #endif /* ARGV_ARRAY_H */ @@ -93,9 +93,7 @@ static struct git_attr *git_attr_internal(const char *name, int len) if (invalid_attr_name(name, len)) return NULL; - a = xmalloc(sizeof(*a) + len + 1); - memcpy(a->name, name, len); - a->name[len] = 0; + FLEX_ALLOC_MEM(a, name, name, len); a->h = hval; a->next = git_attr_hash[pos]; a->attr_nr = attr_nr++; @@ -799,7 +797,7 @@ int git_all_attrs(const char *path, int *num, struct git_attr_check **check) ++count; } *num = count; - *check = xmalloc(sizeof(**check) * count); + ALLOC_ARRAY(*check, count); j = 0; for (i = 0; i < attr_nr; i++) { const char *value = check_all_attr[i].value; @@ -440,7 +440,7 @@ static void read_bisect_paths(struct argv_array *array) if (!fp) die_errno("Could not open file '%s'", filename); - while (strbuf_getline(&str, fp, '\n') != EOF) { + while (strbuf_getline_lf(&str, fp) != EOF) { strbuf_trim(&str); if (sq_dequote_to_argv_array(str.buf, array)) die("Badly quoted content in file '%s': %s", @@ -668,7 +668,7 @@ static int is_expected_rev(const struct object_id *oid) if (!fp) return 0; - if (strbuf_getline(&str, fp, '\n') != EOF) + if (strbuf_getline_lf(&str, fp) != EOF) res = !strcmp(str.buf, oid_to_hex(oid)); strbuf_release(&str); @@ -708,10 +708,10 @@ static struct commit *get_commit_reference(const unsigned char *sha1) static struct commit **get_bad_and_good_commits(int *rev_nr) { - int len = 1 + good_revs.nr; - struct commit **rev = xmalloc(len * sizeof(*rev)); + struct commit **rev; int i, n = 0; + ALLOC_ARRAY(rev, 1 + good_revs.nr); rev[n++] = get_commit_reference(current_bad_oid->hash); for (i = 0; i < good_revs.nr; i++) rev[n++] = get_commit_reference(good_revs.sha1[i]); @@ -914,9 +914,9 @@ void read_bisect_terms(const char **read_bad, const char **read_good) strerror(errno)); } } else { - strbuf_getline(&str, fp, '\n'); + strbuf_getline_lf(&str, fp); *read_bad = strbuf_detach(&str, NULL); - strbuf_getline(&str, fp, '\n'); + strbuf_getline_lf(&str, fp); *read_good = strbuf_detach(&str, NULL); } strbuf_release(&str); @@ -49,7 +49,13 @@ static int should_setup_rebase(const char *origin) return 0; } -void install_branch_config(int flag, const char *local, const char *origin, const char *remote) +static const char tracking_advice[] = +N_("\n" +"After fixing the error cause you may try to fix up\n" +"the remote tracking information by invoking\n" +"\"git branch --set-upstream-to=%s%s%s\"."); + +int install_branch_config(int flag, const char *local, const char *origin, const char *remote) { const char *shortname = NULL; struct strbuf key = STRBUF_INIT; @@ -60,20 +66,23 @@ void install_branch_config(int flag, const char *local, const char *origin, cons && !origin) { warning(_("Not setting branch %s as its own upstream."), local); - return; + return 0; } strbuf_addf(&key, "branch.%s.remote", local); - git_config_set(key.buf, origin ? origin : "."); + if (git_config_set_gently(key.buf, origin ? origin : ".") < 0) + goto out_err; strbuf_reset(&key); strbuf_addf(&key, "branch.%s.merge", local); - git_config_set(key.buf, remote); + if (git_config_set_gently(key.buf, remote) < 0) + goto out_err; if (rebasing) { strbuf_reset(&key); strbuf_addf(&key, "branch.%s.rebase", local); - git_config_set(key.buf, "true"); + if (git_config_set_gently(key.buf, "true") < 0) + goto out_err; } strbuf_release(&key); @@ -102,6 +111,19 @@ void install_branch_config(int flag, const char *local, const char *origin, cons local, remote); } } + + return 0; + +out_err: + strbuf_release(&key); + error(_("Unable to write upstream branch configuration")); + + advise(_(tracking_advice), + origin ? origin : "", + origin ? "/" : "", + shortname ? shortname : remote); + + return -1; } /* @@ -109,8 +131,8 @@ void install_branch_config(int flag, const char *local, const char *origin, cons * to infer the settings for branch.<new_ref>.{remote,merge} from the * config. */ -static int setup_tracking(const char *new_ref, const char *orig_ref, - enum branch_track track, int quiet) +static void setup_tracking(const char *new_ref, const char *orig_ref, + enum branch_track track, int quiet) { struct tracking tracking; int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE; @@ -118,7 +140,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref, memset(&tracking, 0, sizeof(tracking)); tracking.spec.dst = (char *)orig_ref; if (for_each_remote(find_tracked_branch, &tracking)) - return 1; + return; if (!tracking.matches) switch (track) { @@ -127,18 +149,18 @@ static int setup_tracking(const char *new_ref, const char *orig_ref, case BRANCH_TRACK_OVERRIDE: break; default: - return 1; + return; } if (tracking.matches > 1) - return error(_("Not tracking: ambiguous information for ref %s"), - orig_ref); + die(_("Not tracking: ambiguous information for ref %s"), + orig_ref); - install_branch_config(config_flags, new_ref, tracking.remote, - tracking.src ? tracking.src : orig_ref); + if (install_branch_config(config_flags, new_ref, tracking.remote, + tracking.src ? tracking.src : orig_ref) < 0) + exit(-1); free(tracking.src); - return 0; } int read_branch_desc(struct strbuf *buf, const char *branch_name) @@ -43,9 +43,10 @@ void remove_branch_state(void); /* * Configure local branch "local" as downstream to branch "remote" * from remote "origin". Used by git branch --set-upstream. + * Returns 0 on success. */ #define BRANCH_CONFIG_VERBOSE 01 -extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote); +extern int install_branch_config(int flag, const char *local, const char *origin, const char *remote); /* * Read branch description diff --git a/builtin/am.c b/builtin/am.c index 9fb42fdd71..d003939bc5 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -46,21 +46,6 @@ static int is_empty_file(const char *filename) } /** - * Like strbuf_getline(), but treats both '\n' and "\r\n" as line terminators. - */ -static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp) -{ - if (strbuf_getwholeline(sb, fp, '\n')) - return EOF; - if (sb->buf[sb->len - 1] == '\n') { - strbuf_setlen(sb, sb->len - 1); - if (sb->len > 0 && sb->buf[sb->len - 1] == '\r') - strbuf_setlen(sb, sb->len - 1); - } - return 0; -} - -/** * Returns the length of the first line of msg. */ static int linelen(const char *msg) @@ -284,7 +269,7 @@ static char *read_shell_var(FILE *fp, const char *key) struct strbuf sb = STRBUF_INIT; const char *str; - if (strbuf_getline(&sb, fp, '\n')) + if (strbuf_getline_lf(&sb, fp)) goto fail; if (!skip_prefix(sb.buf, key, &str)) @@ -573,7 +558,7 @@ static int copy_notes_for_rebase(const struct am_state *state) fp = xfopen(am_path(state, "rewritten"), "r"); - while (!strbuf_getline(&sb, fp, '\n')) { + while (!strbuf_getline_lf(&sb, fp)) { unsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ]; if (sb.len != GIT_SHA1_HEXSZ * 2 + 1) { @@ -628,7 +613,7 @@ static int is_mail(FILE *fp) if (regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED)) die("invalid pattern: %s", header_regex); - while (!strbuf_getline_crlf(&sb, fp)) { + while (!strbuf_getline(&sb, fp)) { if (!sb.len) break; /* End of header */ @@ -675,7 +660,7 @@ static int detect_patch_format(const char **paths) fp = xfopen(*paths, "r"); - while (!strbuf_getline_crlf(&l1, fp)) { + while (!strbuf_getline(&l1, fp)) { if (l1.len) break; } @@ -696,9 +681,9 @@ static int detect_patch_format(const char **paths) } strbuf_reset(&l2); - strbuf_getline_crlf(&l2, fp); + strbuf_getline(&l2, fp); strbuf_reset(&l3); - strbuf_getline_crlf(&l3, fp); + strbuf_getline(&l3, fp); /* * If the second line is empty and the third is a From, Author or Date @@ -817,7 +802,7 @@ static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr) struct strbuf sb = STRBUF_INIT; int subject_printed = 0; - while (!strbuf_getline(&sb, in, '\n')) { + while (!strbuf_getline_lf(&sb, in)) { const char *str; if (str_isspace(sb.buf)) @@ -875,7 +860,7 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths, return error(_("could not open '%s' for reading: %s"), *paths, strerror(errno)); - while (!strbuf_getline(&sb, fp, '\n')) { + while (!strbuf_getline_lf(&sb, fp)) { if (*sb.buf == '#') continue; /* skip comment lines */ @@ -900,7 +885,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr) { struct strbuf sb = STRBUF_INIT; - while (!strbuf_getline(&sb, in, '\n')) { + while (!strbuf_getline_lf(&sb, in)) { const char *str; if (skip_prefix(sb.buf, "# User ", &str)) @@ -1317,7 +1302,7 @@ static int parse_mail(struct am_state *state, const char *mail) /* Extract message and author information */ fp = xfopen(am_path(state, "info"), "r"); - while (!strbuf_getline(&sb, fp, '\n')) { + while (!strbuf_getline_lf(&sb, fp)) { const char *x; if (skip_prefix(sb.buf, "Subject: ", &x)) { @@ -1383,7 +1368,7 @@ static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail) FILE *fp = xfopen(mail, "r"); const char *x; - if (strbuf_getline(&sb, fp, '\n')) + if (strbuf_getline_lf(&sb, fp)) return -1; if (!skip_prefix(sb.buf, "From ", &x)) @@ -1657,7 +1642,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa init_revisions(&rev_info, NULL); rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS; - diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1); + diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix); add_pending_sha1(&rev_info, "HEAD", our_tree, 0); diff_setup_done(&rev_info.diffopt); run_diff_index(&rev_info, 1); @@ -1821,7 +1806,7 @@ static int do_interactive(struct am_state *state) if (!pager) pager = "cat"; - argv_array_push(&cp.args, pager); + prepare_pager_args(&cp, pager); argv_array_push(&cp.args, am_path(state, "patch")); run_command(&cp); } @@ -1939,6 +1924,7 @@ next: */ if (!state->rebasing) { am_destroy(state); + close_all_packs(); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); } } diff --git a/builtin/apply.c b/builtin/apply.c index deb1364fa8..42c610e2ec 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -2632,7 +2632,7 @@ static void update_image(struct image *img, insert_count = postimage->len; /* Adjust the contents */ - result = xmalloc(img->len + insert_count - remove_count + 1); + result = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1)); memcpy(result, img->buf, applied_at); memcpy(result + applied_at, postimage->buf, postimage->len); memcpy(result + applied_at + postimage->len, @@ -4464,16 +4464,6 @@ static int option_parse_p(const struct option *opt, return 0; } -static int option_parse_z(const struct option *opt, - const char *arg, int unset) -{ - if (unset) - line_termination = '\n'; - else - line_termination = 0; - return 0; -} - static int option_parse_space_change(const struct option *opt, const char *arg, int unset) { @@ -4546,9 +4536,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix_) N_( "attempt three-way merge if a patch does not apply")), OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor, N_("build a temporary index based on embedded index information")), - { OPTION_CALLBACK, 'z', NULL, NULL, NULL, - N_("paths are separated with NUL character"), - PARSE_OPT_NOARG, option_parse_z }, + /* Think twice before adding "--nul" synonym to this */ + OPT_SET_INT('z', NULL, &line_termination, + N_("paths are separated with NUL character"), '\0'), OPT_INTEGER('C', NULL, &p_context, N_("ensure at least <n> lines of context match")), { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, N_("action"), diff --git a/builtin/blame.c b/builtin/blame.c index 1df13cf7f4..e982fb8137 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -28,6 +28,7 @@ #include "line-range.h" #include "line-log.h" #include "dir.h" +#include "progress.h" static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"); @@ -50,6 +51,7 @@ static int incremental; static int xdl_opts; static int abbrev = -1; static int no_whole_file_rename; +static int show_progress; static struct date_mode blame_date_mode = { DATE_ISO8601 }; static size_t blame_date_width; @@ -127,6 +129,11 @@ struct origin { char path[FLEX_ARRAY]; }; +struct progress_info { + struct progress *progress; + int blamed_lines; +}; + static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen, xdl_emit_hunk_consume_func_t hunk_func, void *cb_data) { @@ -459,13 +466,11 @@ static void queue_blames(struct scoreboard *sb, struct origin *porigin, static struct origin *make_origin(struct commit *commit, const char *path) { struct origin *o; - size_t pathlen = strlen(path) + 1; - o = xcalloc(1, sizeof(*o) + pathlen); + FLEX_ALLOC_STR(o, path, path); o->commit = commit; o->refcnt = 1; o->next = commit->util; commit->util = o; - memcpy(o->path, path, pathlen); /* includes NUL */ return o; } @@ -1746,7 +1751,8 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat) * The blame_entry is found to be guilty for the range. * Show it in incremental output. */ -static void found_guilty_entry(struct blame_entry *ent) +static void found_guilty_entry(struct blame_entry *ent, + struct progress_info *pi) { if (incremental) { struct origin *suspect = ent->suspect; @@ -1758,6 +1764,8 @@ static void found_guilty_entry(struct blame_entry *ent) write_filename_info(suspect->path); maybe_flush_or_die(stdout, "stdout"); } + pi->blamed_lines += ent->num_lines; + display_progress(pi->progress, pi->blamed_lines); } /* @@ -1768,6 +1776,11 @@ static void assign_blame(struct scoreboard *sb, int opt) { struct rev_info *revs = sb->revs; struct commit *commit = prio_queue_get(&sb->commits); + struct progress_info pi = { NULL, 0 }; + + if (show_progress) + pi.progress = start_progress_delay(_("Blaming lines"), + sb->num_lines, 50, 1); while (commit) { struct blame_entry *ent; @@ -1809,7 +1822,7 @@ static void assign_blame(struct scoreboard *sb, int opt) suspect->guilty = 1; for (;;) { struct blame_entry *next = ent->next; - found_guilty_entry(ent); + found_guilty_entry(ent, &pi); if (next) { ent = next; continue; @@ -1825,6 +1838,8 @@ static void assign_blame(struct scoreboard *sb, int opt) if (DEBUG) /* sanity */ sanity_check_refcnt(sb); } + + stop_progress(&pi.progress); } static const char *format_time(unsigned long time, const char *tz_str, @@ -2042,7 +2057,8 @@ static int prepare_lines(struct scoreboard *sb) for (p = buf; p < end; p = get_next_line(p, end)) num++; - sb->lineno = lineno = xmalloc(sizeof(*sb->lineno) * (num + 1)); + ALLOC_ARRAY(sb->lineno, num + 1); + lineno = sb->lineno; for (p = buf; p < end; p = get_next_line(p, end)) *lineno++ = p - buf; @@ -2392,11 +2408,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ce->ce_mode = create_ce_mode(mode); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); - /* - * We are not going to write this out, so this does not matter - * right now, but someday we might optimize diff-index --cached - * with cache-tree information. - */ cache_tree_invalidate_path(&the_index, path); return commit; @@ -2520,6 +2531,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")), OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")), OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")), + OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")), OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE), OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME), OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER), @@ -2555,6 +2567,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) save_commit_buffer = 0; dashdash_pos = 0; + show_progress = -1; parse_options_start(&ctx, argc, argv, prefix, options, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0); @@ -2579,6 +2592,13 @@ parse_done: DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES); argc = parse_options_end(&ctx); + if (incremental || (output_option & OUTPUT_PORCELAIN)) { + if (show_progress > 0) + die("--progress can't be used with --incremental or porcelain formats"); + show_progress = 0; + } else if (show_progress < 0) + show_progress = isatty(2); + if (0 < abbrev) /* one more abbrev length is needed for the boundary commit */ abbrev++; @@ -2828,11 +2848,11 @@ parse_done: read_mailmap(&mailmap, NULL); + assign_blame(&sb, opt); + if (!incremental) setup_pager(); - assign_blame(&sb, opt); - free(final_commit_name); if (incremental) diff --git a/builtin/branch.c b/builtin/branch.c index 3f6c825db1..7b45b6bd6b 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -570,7 +570,6 @@ static const char edit_description[] = "BRANCH_DESCRIPTION"; static int edit_branch_description(const char *branch_name) { - int status; struct strbuf buf = STRBUF_INIT; struct strbuf name = STRBUF_INIT; @@ -595,11 +594,11 @@ static int edit_branch_description(const char *branch_name) strbuf_stripspace(&buf, 1); strbuf_addf(&name, "branch.%s.description", branch_name); - status = git_config_set(name.buf, buf.len ? buf.buf : NULL); + git_config_set(name.buf, buf.len ? buf.buf : NULL); strbuf_release(&name); strbuf_release(&buf); - return status; + return 0; } int cmd_branch(int argc, const char **argv, const char *prefix) diff --git a/builtin/cat-file.c b/builtin/cat-file.c index c0fd8dbb1c..54db1184a0 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -401,7 +401,7 @@ static int batch_objects(struct batch_options *opt) save_warning = warn_on_object_refname_ambiguity; warn_on_object_refname_ambiguity = 0; - while (strbuf_getline(&buf, stdin, '\n') != EOF) { + while (strbuf_getline(&buf, stdin) != EOF) { if (data.split_on_whitespace) { /* * Split at first whitespace, tying off the beginning diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 265c9ba022..53a5a18c16 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -72,23 +72,23 @@ static void check_attr(const char *prefix, int cnt, static void check_attr_stdin_paths(const char *prefix, int cnt, struct git_attr_check *check) { - struct strbuf buf, nbuf; - int line_termination = nul_term_line ? 0 : '\n'; - - strbuf_init(&buf, 0); - strbuf_init(&nbuf, 0); - while (strbuf_getline(&buf, stdin, line_termination) != EOF) { - if (line_termination && buf.buf[0] == '"') { - strbuf_reset(&nbuf); - if (unquote_c_style(&nbuf, buf.buf, NULL)) + struct strbuf buf = STRBUF_INIT; + struct strbuf unquoted = STRBUF_INIT; + strbuf_getline_fn getline_fn; + + getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; + while (getline_fn(&buf, stdin) != EOF) { + if (!nul_term_line && buf.buf[0] == '"') { + strbuf_reset(&unquoted); + if (unquote_c_style(&unquoted, buf.buf, NULL)) die("line is badly quoted"); - strbuf_swap(&buf, &nbuf); + strbuf_swap(&buf, &unquoted); } check_attr(prefix, cnt, check, buf.buf); maybe_flush_or_die(stdout, "attribute to stdout"); } strbuf_release(&buf); - strbuf_release(&nbuf); + strbuf_release(&unquoted); } static NORETURN void error_with_usage(const char *msg) diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c index 43f361797a..1d73d3ca3d 100644 --- a/builtin/check-ignore.c +++ b/builtin/check-ignore.c @@ -115,19 +115,19 @@ static int check_ignore(struct dir_struct *dir, static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix) { - struct strbuf buf, nbuf; + struct strbuf buf = STRBUF_INIT; + struct strbuf unquoted = STRBUF_INIT; char *pathspec[2] = { NULL, NULL }; - int line_termination = nul_term_line ? 0 : '\n'; + strbuf_getline_fn getline_fn; int num_ignored = 0; - strbuf_init(&buf, 0); - strbuf_init(&nbuf, 0); - while (strbuf_getline(&buf, stdin, line_termination) != EOF) { - if (line_termination && buf.buf[0] == '"') { - strbuf_reset(&nbuf); - if (unquote_c_style(&nbuf, buf.buf, NULL)) + getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; + while (getline_fn(&buf, stdin) != EOF) { + if (!nul_term_line && buf.buf[0] == '"') { + strbuf_reset(&unquoted); + if (unquote_c_style(&unquoted, buf.buf, NULL)) die("line is badly quoted"); - strbuf_swap(&buf, &nbuf); + strbuf_swap(&buf, &unquoted); } pathspec[0] = buf.buf; num_ignored += check_ignore(dir, prefix, @@ -135,7 +135,7 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix) maybe_flush_or_die(stdout, "check-ignore to stdout"); } strbuf_release(&buf); - strbuf_release(&nbuf); + strbuf_release(&unquoted); return num_ignored; } diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c index eaaea546d3..cf0f54f6b9 100644 --- a/builtin/check-mailmap.c +++ b/builtin/check-mailmap.c @@ -54,7 +54,7 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix) if (use_stdin) { struct strbuf buf = STRBUF_INIT; - while (strbuf_getline(&buf, stdin, '\n') != EOF) { + while (strbuf_getline_lf(&buf, stdin) != EOF) { check_mailmap(&mailmap, buf.buf); maybe_flush_or_die(stdout, "stdout"); } diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c index fd915d5984..eac499450f 100644 --- a/builtin/check-ref-format.c +++ b/builtin/check-ref-format.c @@ -20,7 +20,7 @@ static const char builtin_check_ref_format_usage[] = */ static char *collapse_slashes(const char *refname) { - char *ret = xmalloc(strlen(refname) + 1); + char *ret = xmallocz(strlen(refname)); char ch; char prev = '/'; char *cp = ret; diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 8028c3768f..92c69672e9 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -11,7 +11,7 @@ #include "parse-options.h" #define CHECKOUT_ALL 4 -static int line_termination = '\n'; +static int nul_term_line; static int checkout_stage; /* default to checkout stage0 */ static int to_tempfile; static char topath[4][TEMPORARY_FILENAME_LENGTH + 1]; @@ -35,7 +35,8 @@ static void write_tempfile_record(const char *name, const char *prefix) fputs(topath[checkout_stage], stdout); putchar('\t'); - write_name_quoted_relative(name, prefix, stdout, line_termination); + write_name_quoted_relative(name, prefix, stdout, + nul_term_line ? '\0' : '\n'); for (i = 0; i < 4; i++) { topath[i][0] = 0; @@ -129,36 +130,6 @@ static const char * const builtin_checkout_index_usage[] = { static struct lock_file lock_file; -static int option_parse_u(const struct option *opt, - const char *arg, int unset) -{ - int *newfd = opt->value; - - state.refresh_cache = 1; - state.istate = &the_index; - if (*newfd < 0) - *newfd = hold_locked_index(&lock_file, 1); - return 0; -} - -static int option_parse_z(const struct option *opt, - const char *arg, int unset) -{ - if (unset) - line_termination = '\n'; - else - line_termination = 0; - return 0; -} - -static int option_parse_prefix(const struct option *opt, - const char *arg, int unset) -{ - state.base_dir = arg; - state.base_dir_len = strlen(arg); - return 0; -} - static int option_parse_stage(const struct option *opt, const char *arg, int unset) { @@ -170,7 +141,7 @@ static int option_parse_stage(const struct option *opt, if ('1' <= ch && ch <= '3') checkout_stage = arg[0] - '0'; else - die("stage should be between 1 and 3 or all"); + die(_("stage should be between 1 and 3 or all")); } return 0; } @@ -183,6 +154,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) int read_from_stdin = 0; int prefix_length; int force = 0, quiet = 0, not_new = 0; + int index_opt = 0; struct option builtin_checkout_index_options[] = { OPT_BOOL('a', "all", &all, N_("check out all files in the index")), @@ -191,22 +163,19 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) N_("no warning for existing files and files not in index")), OPT_BOOL('n', "no-create", ¬_new, N_("don't checkout new files")), - { OPTION_CALLBACK, 'u', "index", &newfd, NULL, - N_("update stat information in the index file"), - PARSE_OPT_NOARG, option_parse_u }, - { OPTION_CALLBACK, 'z', NULL, NULL, NULL, - N_("paths are separated with NUL character"), - PARSE_OPT_NOARG, option_parse_z }, + OPT_BOOL('u', "index", &index_opt, + N_("update stat information in the index file")), + OPT_BOOL('z', NULL, &nul_term_line, + N_("paths are separated with NUL character")), OPT_BOOL(0, "stdin", &read_from_stdin, N_("read list of paths from the standard input")), OPT_BOOL(0, "temp", &to_tempfile, N_("write the content to temporary files")), - OPT_CALLBACK(0, "prefix", NULL, N_("string"), - N_("when creating files, prepend <string>"), - option_parse_prefix), - OPT_CALLBACK(0, "stage", NULL, NULL, + OPT_STRING(0, "prefix", &state.base_dir, N_("string"), + N_("when creating files, prepend <string>")), + { OPTION_CALLBACK, 0, "stage", NULL, "1-3|all", N_("copy out the files from named stage"), - option_parse_stage), + PARSE_OPT_NONEG, option_parse_stage }, OPT_END() }; @@ -214,7 +183,6 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) usage_with_options(builtin_checkout_index_usage, builtin_checkout_index_options); git_config(git_default_config, NULL); - state.base_dir = ""; prefix_length = prefix ? strlen(prefix) : 0; if (read_cache() < 0) { @@ -227,15 +195,17 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) state.quiet = quiet; state.not_new = not_new; - if (state.base_dir_len || to_tempfile) { - /* when --prefix is specified we do not - * want to update cache. - */ - if (state.refresh_cache) { - rollback_lock_file(&lock_file); - newfd = -1; - } - state.refresh_cache = 0; + if (!state.base_dir) + state.base_dir = ""; + state.base_dir_len = strlen(state.base_dir); + + /* + * when --prefix is specified we do not want to update cache. + */ + if (index_opt && !state.base_dir_len && !to_tempfile) { + state.refresh_cache = 1; + state.istate = &the_index; + newfd = hold_locked_index(&lock_file, 1); } /* Check out named files first */ @@ -253,24 +223,27 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) } if (read_from_stdin) { - struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; + struct strbuf buf = STRBUF_INIT; + struct strbuf unquoted = STRBUF_INIT; + strbuf_getline_fn getline_fn; if (all) die("git checkout-index: don't mix '--all' and '--stdin'"); - while (strbuf_getline(&buf, stdin, line_termination) != EOF) { + getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; + while (getline_fn(&buf, stdin) != EOF) { char *p; - if (line_termination && buf.buf[0] == '"') { - strbuf_reset(&nbuf); - if (unquote_c_style(&nbuf, buf.buf, NULL)) + if (!nul_term_line && buf.buf[0] == '"') { + strbuf_reset(&unquoted); + if (unquote_c_style(&unquoted, buf.buf, NULL)) die("line is badly quoted"); - strbuf_swap(&buf, &nbuf); + strbuf_swap(&buf, &unquoted); } p = prefix_path(prefix, prefix_length, buf.buf); checkout_file(p, prefix); free(p); } - strbuf_release(&nbuf); + strbuf_release(&unquoted); strbuf_release(&buf); } diff --git a/builtin/checkout.c b/builtin/checkout.c index e8110a9243..cfa66e25eb 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -661,7 +661,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts, describe_detached_head(_("HEAD is now at"), new->commit); } } else if (new->path) { /* Switch branches. */ - create_symref("HEAD", new->path, msg.buf); + if (create_symref("HEAD", new->path, msg.buf) < 0) + die("unable to update HEAD"); if (!opts->quiet) { if (old->path && !strcmp(new->path, old->path)) { if (opts->new_branch_force) @@ -981,7 +982,8 @@ static int parse_branchname_arg(int argc, const char **argv, */ int recover_with_dwim = dwim_new_local_branch_ok; - if (check_filename(NULL, arg) && !has_dash_dash) + if (!has_dash_dash && + (check_filename(NULL, arg) || !no_wildcard(arg))) recover_with_dwim = 0; /* * Accept "git checkout foo" and "git checkout foo --" diff --git a/builtin/clean.c b/builtin/clean.c index d7acb94a95..0371010afb 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -147,30 +147,6 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset) return 0; } -/* - * Return 1 if the given path is the root of a git repository or - * submodule else 0. Will not return 1 for bare repositories with the - * exception of creating a bare repository in "foo/.git" and calling - * is_git_repository("foo"). - */ -static int is_git_repository(struct strbuf *path) -{ - int ret = 0; - int gitfile_error; - size_t orig_path_len = path->len; - assert(orig_path_len != 0); - strbuf_complete(path, '/'); - strbuf_addstr(path, ".git"); - if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf)) - ret = 1; - if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED || - gitfile_error == READ_GITFILE_ERR_READ_FAILED) - ret = 1; /* This could be a real .git file, take the - * safe option and avoid cleaning */ - strbuf_setlen(path, orig_path_len); - return ret; -} - static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag, int dry_run, int quiet, int *dir_gone) { @@ -182,7 +158,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag, *dir_gone = 1; - if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_git_repository(path)) { + if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_nonbare_repository_dir(path)) { if (!quiet) { quote_path_relative(path->buf, prefix, "ed); printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir), @@ -567,7 +543,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff) int eof = 0; int i; - chosen = xmalloc(sizeof(int) * stuff->nr); + ALLOC_ARRAY(chosen, stuff->nr); /* set chosen as uninitialized */ for (i = 0; i < stuff->nr; i++) chosen[i] = -1; @@ -594,7 +570,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff) clean_get_color(CLEAN_COLOR_RESET)); } - if (strbuf_getline(&choice, stdin, '\n') != EOF) { + if (strbuf_getline_lf(&choice, stdin) != EOF) { strbuf_trim(&choice); } else { eof = 1; @@ -639,7 +615,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff) nr += chosen[i]; } - result = xcalloc(nr + 1, sizeof(int)); + result = xcalloc(st_add(nr, 1), sizeof(int)); for (i = 0; i < stuff->nr && j < nr; i++) { if (chosen[i]) result[j++] = i; @@ -676,7 +652,7 @@ static int filter_by_patterns_cmd(void) clean_print_color(CLEAN_COLOR_PROMPT); printf(_("Input ignore patterns>> ")); clean_print_color(CLEAN_COLOR_RESET); - if (strbuf_getline(&confirm, stdin, '\n') != EOF) + if (strbuf_getline_lf(&confirm, stdin) != EOF) strbuf_trim(&confirm); else putchar('\n'); @@ -774,7 +750,7 @@ static int ask_each_cmd(void) qname = quote_path_relative(item->string, NULL, &buf); /* TRANSLATORS: Make sure to keep [y/N] as is */ printf(_("Remove %s [y/N]? "), qname); - if (strbuf_getline(&confirm, stdin, '\n') != EOF) { + if (strbuf_getline_lf(&confirm, stdin) != EOF) { strbuf_trim(&confirm); } else { putchar('\n'); diff --git a/builtin/clone.c b/builtin/clone.c index a0b3cd9e56..9ac6c01442 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -47,6 +47,7 @@ static const char *real_git_dir; static char *option_upload_pack = "git-upload-pack"; static int option_verbosity; static int option_progress = -1; +static enum transport_family family; static struct string_list option_config; static struct string_list option_reference; static int option_dissociate; @@ -92,6 +93,10 @@ static struct option builtin_clone_options[] = { N_("separate git dir from working tree")), OPT_STRING_LIST('c', "config", &option_config, N_("key=value"), N_("set config inside the new repository")), + OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), + TRANSPORT_FAMILY_IPV4), + OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), + TRANSPORT_FAMILY_IPV6), OPT_END() }; @@ -339,7 +344,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst, FILE *in = fopen(src->buf, "r"); struct strbuf line = STRBUF_INIT; - while (strbuf_getline(&line, in, '\n') != EOF) { + while (strbuf_getline(&line, in) != EOF) { char *abs_path; if (!line.len || line.buf[0] == '#') continue; @@ -636,9 +641,11 @@ static void update_remote_refs(const struct ref *refs, struct strbuf head_ref = STRBUF_INIT; strbuf_addstr(&head_ref, branch_top); strbuf_addstr(&head_ref, "HEAD"); - create_symref(head_ref.buf, - remote_head_points_at->peer_ref->name, - msg); + if (create_symref(head_ref.buf, + remote_head_points_at->peer_ref->name, + msg) < 0) + die("unable to update %s", head_ref.buf); + strbuf_release(&head_ref); } } @@ -648,7 +655,8 @@ static void update_head(const struct ref *our, const struct ref *remote, const char *head; if (our && skip_prefix(our->name, "refs/heads/", &head)) { /* Local default branch link */ - create_symref("HEAD", our->name, NULL); + if (create_symref("HEAD", our->name, NULL) < 0) + die("unable to update HEAD"); if (!option_bare) { update_ref(msg, "HEAD", our->old_oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); @@ -732,7 +740,7 @@ static int checkout(void) static int write_one_config(const char *key, const char *value, void *data) { - return git_config_set_multivar(key, value ? value : "true", "^$", 0); + return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0); } static void write_config(struct string_list *config) @@ -967,6 +975,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) remote = remote_get(option_origin); transport = transport_get(remote, remote->url[0]); transport_set_verbosity(transport, option_verbosity, option_progress); + transport->family = family; path = get_repo_path(remote->url[0], &is_bundle); is_local = option_local != 0 && path && !is_bundle; diff --git a/builtin/column.c b/builtin/column.c index 449413c8a8..33314b4d71 100644 --- a/builtin/column.c +++ b/builtin/column.c @@ -51,7 +51,7 @@ int cmd_column(int argc, const char **argv, const char *prefix) die(_("--command must be the first argument")); } finalize_colopts(&colopts, -1); - while (!strbuf_getline(&sb, stdin, '\n')) + while (!strbuf_getline(&sb, stdin)) string_list_append(&list, sb.buf); print_columns(&list, colopts, &copts); diff --git a/builtin/commit.c b/builtin/commit.c index d054f84960..b3bd2d4181 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -761,7 +761,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, hook_arg2 = ""; } - s->fp = fopen(git_path(commit_editmsg), "w"); + s->fp = fopen_for_writing(git_path(commit_editmsg)); if (s->fp == NULL) die_errno(_("could not open '%s'"), git_path(commit_editmsg)); @@ -1690,7 +1690,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (fp == NULL) die_errno(_("could not open '%s' for reading"), git_path_merge_head()); - while (strbuf_getline(&m, fp, '\n') != EOF) { + while (strbuf_getline_lf(&m, fp) != EOF) { struct commit *parent; parent = get_merge_parent(m.buf); diff --git a/builtin/config.c b/builtin/config.c index adc772786a..ca9f834ae6 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -3,6 +3,7 @@ #include "color.h" #include "parse-options.h" #include "urlmatch.h" +#include "quote.h" static const char *const builtin_config_usage[] = { N_("git config [<options>]"), @@ -27,6 +28,7 @@ static int actions, types; static const char *get_color_slot, *get_colorbool_slot; static int end_null; static int respect_includes = -1; +static int show_origin; #define ACTION_GET (1<<0) #define ACTION_GET_ALL (1<<1) @@ -81,6 +83,7 @@ static struct option builtin_config_options[] = { OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")), OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")), OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")), + OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")), OPT_END(), }; @@ -91,8 +94,28 @@ static void check_argc(int argc, int min, int max) { usage_with_options(builtin_config_usage, builtin_config_options); } +static void show_config_origin(struct strbuf *buf) +{ + const char term = end_null ? '\0' : '\t'; + + strbuf_addstr(buf, current_config_origin_type()); + strbuf_addch(buf, ':'); + if (end_null) + strbuf_addstr(buf, current_config_name()); + else + quote_c_style(current_config_name(), buf, NULL, 0); + strbuf_addch(buf, term); +} + static int show_all_config(const char *key_, const char *value_, void *cb) { + if (show_origin) { + struct strbuf buf = STRBUF_INIT; + show_config_origin(&buf); + /* Use fwrite as "buf" can contain \0's if "end_null" is set. */ + fwrite(buf.buf, 1, buf.len, stdout); + strbuf_release(&buf); + } if (!omit_values && value_) printf("%s%c%s%c", key_, delim, value_, term); else @@ -108,6 +131,8 @@ struct strbuf_list { static int format_config(struct strbuf *buf, const char *key_, const char *value_) { + if (show_origin) + show_config_origin(buf); if (show_keys) strbuf_addstr(buf, key_); if (!omit_values) { @@ -352,6 +377,9 @@ static int get_colorbool(const char *var, int print) static void check_write(void) { + if (!given_config_source.file && !startup_info->have_repository) + die("not in a git directory"); + if (given_config_source.use_stdin) die("writing to stdin is not supported"); @@ -538,6 +566,14 @@ int cmd_config(int argc, const char **argv, const char *prefix) error("--name-only is only applicable to --list or --get-regexp"); usage_with_options(builtin_config_usage, builtin_config_options); } + + if (show_origin && !(actions & + (ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) { + error("--show-origin is only applicable to --get, --get-all, " + "--get-regexp, and --list."); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (actions == ACTION_LIST) { check_argc(argc, 0, 0); if (git_config_with_options(show_all_config, NULL, @@ -582,7 +618,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) check_write(); check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); - ret = git_config_set_in_file(given_config_source.file, argv[0], value); + ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value); if (ret == CONFIG_NOTHING_SET) error("cannot overwrite multiple values with a single value\n" " Use a regexp, --add or --replace-all to change %s.", argv[0]); @@ -592,23 +628,23 @@ int cmd_config(int argc, const char **argv, const char *prefix) check_write(); check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1]); - return git_config_set_multivar_in_file(given_config_source.file, - argv[0], value, argv[2], 0); + return git_config_set_multivar_in_file_gently(given_config_source.file, + argv[0], value, argv[2], 0); } else if (actions == ACTION_ADD) { check_write(); check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); - return git_config_set_multivar_in_file(given_config_source.file, - argv[0], value, - CONFIG_REGEX_NONE, 0); + return git_config_set_multivar_in_file_gently(given_config_source.file, + argv[0], value, + CONFIG_REGEX_NONE, 0); } else if (actions == ACTION_REPLACE_ALL) { check_write(); check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1]); - return git_config_set_multivar_in_file(given_config_source.file, - argv[0], value, argv[2], 1); + return git_config_set_multivar_in_file_gently(given_config_source.file, + argv[0], value, argv[2], 1); } else if (actions == ACTION_GET) { check_argc(argc, 1, 2); @@ -634,17 +670,17 @@ int cmd_config(int argc, const char **argv, const char *prefix) check_write(); check_argc(argc, 1, 2); if (argc == 2) - return git_config_set_multivar_in_file(given_config_source.file, - argv[0], NULL, argv[1], 0); + return git_config_set_multivar_in_file_gently(given_config_source.file, + argv[0], NULL, argv[1], 0); else - return git_config_set_in_file(given_config_source.file, - argv[0], NULL); + return git_config_set_in_file_gently(given_config_source.file, + argv[0], NULL); } else if (actions == ACTION_UNSET_ALL) { check_write(); check_argc(argc, 1, 2); - return git_config_set_multivar_in_file(given_config_source.file, - argv[0], NULL, argv[1], 1); + return git_config_set_multivar_in_file_gently(given_config_source.file, + argv[0], NULL, argv[1], 1); } else if (actions == ACTION_RENAME_SECTION) { int ret; diff --git a/builtin/diff.c b/builtin/diff.c index ed0acca91f..52c98a9217 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -341,7 +341,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } if (no_index) /* If this is a no-index diff, just run it and exit there. */ - diff_no_index(&rev, argc, argv, prefix); + diff_no_index(&rev, argc, argv); /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; diff --git a/builtin/fast-export.c b/builtin/fast-export.c index d9ac5d8410..8164b581a6 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -880,7 +880,7 @@ static void export_marks(char *file) FILE *f; int e = 0; - f = fopen(file, "w"); + f = fopen_for_writing(file); if (!f) die_errno("Unable to open marks file %s for writing.", file); @@ -1021,7 +1021,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) const char **refspecs_str; int i; - refspecs_str = xmalloc(sizeof(*refspecs_str) * refspecs_list.nr); + ALLOC_ARRAY(refspecs_str, refspecs_list.nr); for (i = 0; i < refspecs_list.nr; i++) refspecs_str[i] = refspecs_list.items[i].string; diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index cf3019e05b..79a611fda1 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -10,33 +10,24 @@ static const char fetch_pack_usage[] = "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] " "[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]"; -static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc, - const char *name, int namelen) +static void add_sought_entry(struct ref ***sought, int *nr, int *alloc, + const char *name) { - struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1); + struct ref *ref; struct object_id oid; - const int chunksz = GIT_SHA1_HEXSZ + 1; - if (namelen > chunksz && name[chunksz - 1] == ' ' && - !get_oid_hex(name, &oid)) { - oidcpy(&ref->old_oid, &oid); - name += chunksz; - namelen -= chunksz; - } + if (!get_oid_hex(name, &oid) && name[GIT_SHA1_HEXSZ] == ' ') + name += GIT_SHA1_HEXSZ + 1; + else + oidclr(&oid); - memcpy(ref->name, name, namelen); - ref->name[namelen] = '\0'; + ref = alloc_ref(name); + oidcpy(&ref->old_oid, &oid); (*nr)++; ALLOC_GROW(*sought, *nr, *alloc); (*sought)[*nr - 1] = ref; } -static void add_sought_entry(struct ref ***sought, int *nr, int *alloc, - const char *string) -{ - add_sought_entry_mem(sought, nr, alloc, string, strlen(string)); -} - int cmd_fetch_pack(int argc, const char **argv, const char *prefix) { int i, ret; @@ -158,7 +149,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) else { /* read from stdin one ref per line, until EOF */ struct strbuf line = STRBUF_INIT; - while (strbuf_getline(&line, stdin, '\n') != EOF) + while (strbuf_getline_lf(&line, stdin) != EOF) add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf); strbuf_release(&line); } diff --git a/builtin/fetch.c b/builtin/fetch.c index c85f3471d4..e4639d8eb1 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -37,6 +37,8 @@ static int prune = -1; /* unspecified */ static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity; static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int tags = TAGS_DEFAULT, unshallow, update_shallow; +static int max_children = 1; +static enum transport_family family; static const char *depth; static const char *upload_pack; static struct strbuf default_rla = STRBUF_INIT; @@ -99,6 +101,8 @@ static struct option builtin_fetch_options[] = { N_("fetch all tags and associated objects"), TAGS_SET), OPT_SET_INT('n', NULL, &tags, N_("do not fetch all tags (--no-tags)"), TAGS_UNSET), + OPT_INTEGER('j', "jobs", &max_children, + N_("number of submodules fetched in parallel")), OPT_BOOL('p', "prune", &prune, N_("prune remote-tracking branches no longer on remote")), { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"), @@ -124,6 +128,10 @@ static struct option builtin_fetch_options[] = { N_("accept refs that update .git/shallow")), { OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"), N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg }, + OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), + TRANSPORT_FAMILY_IPV4), + OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), + TRANSPORT_FAMILY_IPV6), OPT_END() }; @@ -837,7 +845,7 @@ static void check_not_current_branch(struct ref *ref_map) static int truncate_fetch_head(void) { const char *filename = git_path_fetch_head(); - FILE *fp = fopen(filename, "w"); + FILE *fp = fopen_for_writing(filename); if (!fp) return error(_("cannot open %s: %s\n"), filename, strerror(errno)); @@ -861,6 +869,7 @@ static struct transport *prepare_transport(struct remote *remote) struct transport *transport; transport = transport_get(remote, NULL); transport_set_verbosity(transport, verbosity, progress); + transport->family = family; if (upload_pack) set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack); if (keep) @@ -1013,10 +1022,9 @@ static int add_remote_or_group(const char *name, struct string_list *list) git_config(get_remote_group, &g); if (list->nr == prev_nr) { - struct remote *remote; - if (!remote_is_configured(name)) + struct remote *remote = remote_get(name); + if (!remote_is_configured(remote)) return 0; - remote = remote_get(name); string_list_append(list, remote->name); } return 1; @@ -1107,7 +1115,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv) if (argc > 0) { int j = 0; int i; - refs = xcalloc(argc + 1, sizeof(const char *)); + refs = xcalloc(st_add(argc, 1), sizeof(const char *)); for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "tag")) { i++; @@ -1213,7 +1221,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) result = fetch_populated_submodules(&options, submodule_prefix, recurse_submodules, - verbosity < 0); + verbosity < 0, + max_children); argv_array_clear(&options); } @@ -1221,6 +1230,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) list.strdup_strings = 1; string_list_clear(&list, 0); + close_all_packs(); + argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL); if (verbosity < 0) argv_array_push(&argv_gc_auto, "--quiet"); diff --git a/builtin/grep.c b/builtin/grep.c index 4229cae390..aa7435f380 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -24,11 +24,11 @@ static char const * const grep_usage[] = { NULL }; -static int use_threads = 1; +#define GREP_NUM_THREADS_DEFAULT 8 +static int num_threads; #ifndef NO_PTHREADS -#define THREADS 8 -static pthread_t threads[THREADS]; +static pthread_t *threads; /* We use one producer thread and THREADS consumer * threads. The producer adds struct work_items to 'todo' and the @@ -63,13 +63,13 @@ static pthread_mutex_t grep_mutex; static inline void grep_lock(void) { - if (use_threads) + if (num_threads) pthread_mutex_lock(&grep_mutex); } static inline void grep_unlock(void) { - if (use_threads) + if (num_threads) pthread_mutex_unlock(&grep_mutex); } @@ -206,7 +206,8 @@ static void start_threads(struct grep_opt *opt) strbuf_init(&todo[i].out, 0); } - for (i = 0; i < ARRAY_SIZE(threads); i++) { + threads = xcalloc(num_threads, sizeof(*threads)); + for (i = 0; i < num_threads; i++) { int err; struct grep_opt *o = grep_opt_dup(opt); o->output = strbuf_out; @@ -238,12 +239,14 @@ static int wait_all(void) pthread_cond_broadcast(&cond_add); grep_unlock(); - for (i = 0; i < ARRAY_SIZE(threads); i++) { + for (i = 0; i < num_threads; i++) { void *h; pthread_join(threads[i], &h); hit |= (int) (intptr_t) h; } + free(threads); + pthread_mutex_destroy(&grep_mutex); pthread_mutex_destroy(&grep_read_mutex); pthread_mutex_destroy(&grep_attr_mutex); @@ -267,6 +270,14 @@ static int grep_cmd_config(const char *var, const char *value, void *cb) int st = grep_config(var, value, cb); if (git_color_default_config(var, value, cb) < 0) st = -1; + + if (!strcmp(var, "grep.threads")) { + num_threads = git_config_int(var, value); + if (num_threads < 0) + die(_("invalid number of threads specified (%d) for %s"), + num_threads, var); + } + return st; } @@ -294,7 +305,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, } #ifndef NO_PTHREADS - if (use_threads) { + if (num_threads) { add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1); strbuf_release(&pathbuf); return 0; @@ -323,7 +334,7 @@ static int grep_file(struct grep_opt *opt, const char *filename) strbuf_addstr(&buf, filename); #ifndef NO_PTHREADS - if (use_threads) { + if (num_threads) { add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename); strbuf_release(&buf); return 0; @@ -354,17 +365,17 @@ static void append_path(struct grep_opt *opt, const void *data, size_t len) static void run_pager(struct grep_opt *opt, const char *prefix) { struct string_list *path_list = opt->output_priv; - const char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + struct child_process child = CHILD_PROCESS_INIT; int i, status; for (i = 0; i < path_list->nr; i++) - argv[i] = path_list->items[i].string; - argv[path_list->nr] = NULL; + argv_array_push(&child.args, path_list->items[i].string); + child.dir = prefix; + child.use_shell = 1; - status = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, prefix, NULL); + status = run_command(&child); if (status) exit(status); - free(argv); } static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached) @@ -375,7 +386,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int for (nr = 0; nr < active_nr; nr++) { const struct cache_entry *ce = active_cache[nr]; - if (!S_ISREG(ce->ce_mode)) + if (!S_ISREG(ce->ce_mode) || ce_intent_to_add(ce)) continue; if (!ce_path_match(ce, pathspec, NULL)) continue; @@ -562,7 +573,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset) patterns = from_stdin ? stdin : fopen(arg, "r"); if (!patterns) die_errno(_("cannot open '%s'"), arg); - while (strbuf_getline(&sb, patterns, '\n') == 0) { + while (strbuf_getline(&sb, patterns) == 0) { /* ignore empty line like grep does */ if (sb.len == 0) continue; @@ -697,6 +708,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) N_("show <n> context lines before matches")), OPT_INTEGER('A', "after-context", &opt.post_context, N_("show <n> context lines after matches")), + OPT_INTEGER(0, "threads", &num_threads, + N_("use <n> worker threads")), OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"), context_callback), OPT_BOOL('p', "show-function", &opt.funcname, @@ -755,9 +768,15 @@ int cmd_grep(int argc, const char **argv, const char *prefix) PARSE_OPT_STOP_AT_NON_OPTION); grep_commit_pattern_type(pattern_type_arg, &opt); - if (use_index && !startup_info->have_repository) - /* die the same way as if we did it at the beginning */ - setup_git_directory(); + if (use_index && !startup_info->have_repository) { + int fallback = 0; + git_config_get_bool("grep.fallbacktonoindex", &fallback); + if (fallback) + use_index = 0; + else + /* die the same way as if we did it at the beginning */ + setup_git_directory(); + } /* * skip a -- separator; we know it cannot be @@ -786,7 +805,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix) opt.output_priv = &path_list; opt.output = append_path; string_list_append(&path_list, show_in_pager); - use_threads = 0; } if (!opt.pattern_list) @@ -817,14 +835,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } #ifndef NO_PTHREADS - if (list.nr || cached || online_cpus() == 1) - use_threads = 0; + if (list.nr || cached || show_in_pager) + num_threads = 0; + else if (num_threads == 0) + num_threads = GREP_NUM_THREADS_DEFAULT; + else if (num_threads < 0) + die(_("invalid number of threads specified (%d)"), num_threads); #else - use_threads = 0; + num_threads = 0; #endif #ifndef NO_PTHREADS - if (use_threads) { + if (num_threads) { if (!(opt.name_only || opt.unmatch_name_only || opt.count) && (opt.pre_context || opt.post_context || opt.file_break || opt.funcbody)) @@ -894,7 +916,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) hit = grep_objects(&opt, &pathspec, &list); } - if (use_threads) + if (num_threads) hit |= wait_all(); if (hit && show_in_pager) run_pager(&opt, prefix); diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 43b098b76c..f7d3567dd0 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -58,20 +58,21 @@ static void hash_object(const char *path, const char *type, const char *vpath, static void hash_stdin_paths(const char *type, int no_filters, unsigned flags, int literally) { - struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; + struct strbuf buf = STRBUF_INIT; + struct strbuf unquoted = STRBUF_INIT; - while (strbuf_getline(&buf, stdin, '\n') != EOF) { + while (strbuf_getline(&buf, stdin) != EOF) { if (buf.buf[0] == '"') { - strbuf_reset(&nbuf); - if (unquote_c_style(&nbuf, buf.buf, NULL)) + strbuf_reset(&unquoted); + if (unquote_c_style(&unquoted, buf.buf, NULL)) die("line is badly quoted"); - strbuf_swap(&buf, &nbuf); + strbuf_swap(&buf, &unquoted); } hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags, literally); } strbuf_release(&buf); - strbuf_release(&nbuf); + strbuf_release(&unquoted); } int cmd_hash_object(int argc, const char **argv, const char *prefix) diff --git a/builtin/help.c b/builtin/help.c index 1cd0c1ee44..3c55ce4563 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -171,12 +171,10 @@ static void exec_man_cmd(const char *cmd, const char *page) static void add_man_viewer(const char *name) { struct man_viewer_list **p = &man_viewer_list; - size_t len = strlen(name); while (*p) p = &((*p)->next); - *p = xcalloc(1, (sizeof(**p) + len + 1)); - memcpy((*p)->name, name, len); /* NUL-terminated by xcalloc */ + FLEX_ALLOC_STR(*p, name, name); } static int supported_man_viewer(const char *name, size_t len) @@ -190,9 +188,8 @@ static void do_add_man_viewer_info(const char *name, size_t len, const char *value) { - struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1); - - memcpy(new->name, name, len); /* NUL-terminated by xcalloc */ + struct man_viewer_info_list *new; + FLEX_ALLOC_MEM(new, name, name, len); new->info = xstrdup(value); new->next = man_viewer_info_list; man_viewer_info_list = new; diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 6a01509587..193908a619 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1346,7 +1346,7 @@ static void fix_unresolved_deltas(struct sha1file *f) * before deltas depending on them, a good heuristic is to start * resolving deltas in the same order as their position in the pack. */ - sorted_by_pos = xmalloc(nr_ref_deltas * sizeof(*sorted_by_pos)); + ALLOC_ARRAY(sorted_by_pos, nr_ref_deltas); for (i = 0; i < nr_ref_deltas; i++) sorted_by_pos[i] = &ref_deltas[i]; qsort(sorted_by_pos, nr_ref_deltas, sizeof(*sorted_by_pos), delta_pos_compare); @@ -1744,9 +1744,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) curr_pack = open_pack_file(pack_name); parse_pack_header(); - objects = xcalloc(nr_objects + 1, sizeof(struct object_entry)); + objects = xcalloc(st_add(nr_objects, 1), sizeof(struct object_entry)); if (show_stat) - obj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat)); + obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat)); ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry)); parse_pack_objects(pack_sha1); resolve_deltas(); @@ -1759,7 +1759,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) if (show_stat) show_pack_info(stat_only); - idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *)); + ALLOC_ARRAY(idx_objects, nr_objects); for (i = 0; i < nr_objects; i++) idx_objects[i] = &objects[i].idx; curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1); diff --git a/builtin/init-db.c b/builtin/init-db.c index 07229d60f1..6223b7d46a 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -250,7 +250,7 @@ static int create_default_files(const char *template_path) git_config_set("core.bare", "false"); /* allow template config file to override the default */ if (log_all_ref_updates == -1) - git_config_set("core.logallrefupdates", "true"); + git_config_set("core.logallrefupdates", "true"); if (needs_work_tree_config(get_git_dir(), work_tree)) git_config_set("core.worktree", work_tree); } diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c index 46838d24a9..b99ae4be88 100644 --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@ -12,16 +12,18 @@ #include "trailer.h" static const char * const git_interpret_trailers_usage[] = { - N_("git interpret-trailers [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"), + N_("git interpret-trailers [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"), NULL }; int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) { + int in_place = 0; int trim_empty = 0; struct string_list trailers = STRING_LIST_INIT_DUP; struct option options[] = { + OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")), OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")), OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"), N_("trailer(s) to add")), @@ -34,9 +36,12 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) if (argc) { int i; for (i = 0; i < argc; i++) - process_trailers(argv[i], trim_empty, &trailers); - } else - process_trailers(NULL, trim_empty, &trailers); + process_trailers(argv[i], in_place, trim_empty, &trailers); + } else { + if (in_place) + die(_("no input file given for in-place editing")); + process_trailers(NULL, in_place, trim_empty, &trailers); + } string_list_clear(&trailers, 0); diff --git a/builtin/log.c b/builtin/log.c index e00cea75cc..0d738d6ddc 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -699,6 +699,7 @@ static int do_signoff; static const char *signature = git_version_string; static const char *signature_file; static int config_cover_letter; +static const char *config_output_directory; enum { COVER_UNSET, @@ -777,6 +778,8 @@ static int git_format_config(const char *var, const char *value, void *cb) config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF; return 0; } + if (!strcmp(var, "format.outputdirectory")) + return git_config_string(&config_output_directory, var, value); return git_log_config(var, value, cb); } @@ -1391,6 +1394,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (rev.show_notes) init_display_notes(&rev.notes_opt); + if (!output_directory && !use_stdout) + output_directory = config_output_directory; + if (!use_stdout) output_directory = set_outdir(prefix, output_directory); else diff --git a/builtin/ls-files.c b/builtin/ls-files.c index b6a7cb0c7c..f02e3d23bb 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -27,6 +27,7 @@ static int show_killed; static int show_valid_bit; static int line_terminator = '\n'; static int debug_mode; +static int show_eol; static const char *prefix; static int max_prefix_len; @@ -47,6 +48,23 @@ static const char *tag_modified = ""; static const char *tag_skip_worktree = ""; static const char *tag_resolve_undo = ""; +static void write_eolinfo(const struct cache_entry *ce, const char *path) +{ + if (!show_eol) + return; + else { + struct stat st; + const char *i_txt = ""; + const char *w_txt = ""; + const char *a_txt = get_convert_attr_ascii(path); + if (ce && S_ISREG(ce->ce_mode)) + i_txt = get_cached_convert_stats_ascii(ce->name); + if (!lstat(path, &st) && S_ISREG(st.st_mode)) + w_txt = get_wt_convert_stats_ascii(path); + printf("i/%-5s w/%-5s attr/%-17s\t", i_txt, w_txt, a_txt); + } +} + static void write_name(const char *name) { /* @@ -68,6 +86,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent) return; fputs(tag, stdout); + write_eolinfo(NULL, ent->name); write_name(ent->name); } @@ -170,6 +189,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce) find_unique_abbrev(ce->sha1,abbrev), ce_stage(ce)); } + write_eolinfo(ce, ce->name); write_name(ce->name); if (debug_mode) { const struct stat_data *sd = &ce->ce_stat_data; @@ -359,14 +379,6 @@ static const char * const ls_files_usage[] = { NULL }; -static int option_parse_z(const struct option *opt, - const char *arg, int unset) -{ - line_terminator = unset ? '\n' : '\0'; - - return 0; -} - static int option_parse_exclude(const struct option *opt, const char *arg, int unset) { @@ -408,9 +420,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) struct exclude_list *el; struct string_list exclude_list = STRING_LIST_INIT_NODUP; struct option builtin_ls_files_options[] = { - { OPTION_CALLBACK, 'z', NULL, NULL, NULL, - N_("paths are separated with NUL character"), - PARSE_OPT_NOARG, option_parse_z }, + /* Think twice before adding "--nul" synonym to this */ + OPT_SET_INT('z', NULL, &line_terminator, + N_("paths are separated with NUL character"), '\0'), OPT_BOOL('t', NULL, &show_tag, N_("identify the file status with tags")), OPT_BOOL('v', NULL, &show_valid_bit, @@ -433,6 +445,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) OPT_BIT(0, "directory", &dir.flags, N_("show 'other' directories' names only"), DIR_SHOW_OTHER_DIRECTORIES), + OPT_BOOL(0, "eol", &show_eol, N_("show line endings of files")), OPT_NEGBIT(0, "empty-directory", &dir.flags, N_("don't show empty directories"), DIR_HIDE_EMPTY_DIRECTORIES), diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index fa65a8448a..66cdd45cc1 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -3,9 +3,12 @@ #include "transport.h" #include "remote.h" -static const char ls_remote_usage[] = -"git ls-remote [--heads] [--tags] [--upload-pack=<exec>]\n" -" [-q | --quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]"; +static const char * const ls_remote_usage[] = { + N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" + " [-q | --quiet] [--exit-code] [--get-url]\n" + " [--symref] [<repository> [<refs>...]]"), + NULL +}; /* * Is there one among the list of patterns that match the tail part @@ -30,12 +33,12 @@ static int tail_match(const char **pattern, const char *path) int cmd_ls_remote(int argc, const char **argv, const char *prefix) { - int i; const char *dest = NULL; unsigned flags = 0; int get_url = 0; int quiet = 0; int status = 0; + int show_symref_target = 0; const char *uploadpack = NULL; const char **pattern = NULL; @@ -43,59 +46,36 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) struct transport *transport; const struct ref *ref; - if (argc == 2 && !strcmp("-h", argv[1])) - usage(ls_remote_usage); + struct option options[] = { + OPT__QUIET(&quiet, N_("do not print remote URL")), + OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"), + N_("path of git-upload-pack on the remote host")), + { OPTION_STRING, 0, "exec", &uploadpack, N_("exec"), + N_("path of git-upload-pack on the remote host"), + PARSE_OPT_HIDDEN }, + OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS), + OPT_BIT('h', "heads", &flags, N_("limit to heads"), REF_HEADS), + OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL), + OPT_BOOL(0, "get-url", &get_url, + N_("take url.<base>.insteadOf into account")), + OPT_SET_INT(0, "exit-code", &status, + N_("exit with exit code 2 if no matching refs are found"), 2), + OPT_BOOL(0, "symref", &show_symref_target, + N_("show underlying ref in addition to the object pointed by it")), + OPT_END() + }; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + argc = parse_options(argc, argv, prefix, options, ls_remote_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + dest = argv[0]; - if (*arg == '-') { - if (starts_with(arg, "--upload-pack=")) { - uploadpack = arg + 14; - continue; - } - if (starts_with(arg, "--exec=")) { - uploadpack = arg + 7; - continue; - } - if (!strcmp("--tags", arg) || !strcmp("-t", arg)) { - flags |= REF_TAGS; - continue; - } - if (!strcmp("--heads", arg) || !strcmp("-h", arg)) { - flags |= REF_HEADS; - continue; - } - if (!strcmp("--refs", arg)) { - flags |= REF_NORMAL; - continue; - } - if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) { - quiet = 1; - continue; - } - if (!strcmp("--get-url", arg)) { - get_url = 1; - continue; - } - if (!strcmp("--exit-code", arg)) { - /* return this code if no refs are reported */ - status = 2; - continue; - } - usage(ls_remote_usage); - } - dest = arg; - i++; - break; + if (argc > 1) { + int i; + pattern = xcalloc(argc, sizeof(const char *)); + for (i = 1; i < argc; i++) + pattern[i - 1] = xstrfmt("*/%s", argv[i]); } - if (argv[i]) { - int j; - pattern = xcalloc(argc - i + 1, sizeof(const char *)); - for (j = i; j < argc; j++) - pattern[j - i] = xstrfmt("*/%s", argv[j]); - } remote = remote_get(dest); if (!remote) { if (dest) @@ -125,7 +105,9 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) continue; if (!tail_match(pattern, ref->name)) continue; - printf("%s %s\n", oid_to_hex(&ref->old_oid), ref->name); + if (show_symref_target && ref->symref) + printf("ref: %s\t%s\n", ref->symref, ref->name); + printf("%s\t%s\n", oid_to_hex(&ref->old_oid), ref->name); status = 0; /* we found something */ } return status; diff --git a/builtin/merge-base.c b/builtin/merge-base.c index a8911626c2..c0d1822eb3 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -252,7 +252,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix) if (argc < 2) usage_with_options(merge_base_usage, options); - rev = xmalloc(argc * sizeof(*rev)); + ALLOC_ARRAY(rev, argc); while (argc-- > 0) rev[rev_nr++] = get_commit_reference(*argv++); return show_merge_base(rev, rev_nr, show_all); diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index d4f0cbd451..ca570041df 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -174,7 +174,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsi static char *traverse_path(const struct traverse_info *info, const struct name_entry *n) { - char *path = xmalloc(traverse_path_len(info, n) + 1); + char *path = xmallocz(traverse_path_len(info, n)); return make_traverse_path(path, info, n); } diff --git a/builtin/merge.c b/builtin/merge.c index 15bf95b3ac..101ffeff4c 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -404,6 +404,7 @@ static void finish(struct commit *head_commit, * We ignore errors in 'gc --auto', since the * user should see them. */ + close_all_packs(); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); } } @@ -938,7 +939,7 @@ static int setup_with_upstream(const char ***argv) if (!branch->merge_nr) die(_("No default upstream defined for the current branch.")); - args = xcalloc(branch->merge_nr + 1, sizeof(char *)); + args = xcalloc(st_add(branch->merge_nr, 1), sizeof(char *)); for (i = 0; i < branch->merge_nr; i++) { if (!branch->merge[i]->dst) die(_("No remote-tracking branch for %s from %s"), diff --git a/builtin/mktree.c b/builtin/mktree.c index a964d6be52..4282b62c59 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -19,16 +19,17 @@ static int alloc, used; static void append_to_tree(unsigned mode, unsigned char *sha1, char *path) { struct treeent *ent; - int len = strlen(path); + size_t len = strlen(path); if (strchr(path, '/')) die("path %s contains slash", path); - ALLOC_GROW(entries, used + 1, alloc); - ent = entries[used++] = xmalloc(sizeof(**entries) + len + 1); + FLEX_ALLOC_MEM(ent, name, path, len); ent->mode = mode; ent->len = len; hashcpy(ent->sha1, sha1); - memcpy(ent->name, path, len+1); + + ALLOC_GROW(entries, used + 1, alloc); + entries[used++] = ent; } static int ent_compare(const void *a_, const void *b_) @@ -65,7 +66,7 @@ static const char *mktree_usage[] = { NULL }; -static void mktree_line(char *buf, size_t len, int line_termination, int allow_missing) +static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_missing) { char *ptr, *ntr; unsigned mode; @@ -97,7 +98,7 @@ static void mktree_line(char *buf, size_t len, int line_termination, int allow_m *ntr++ = 0; /* now at the beginning of SHA1 */ path = ntr + 41; /* at the beginning of name */ - if (line_termination && path[0] == '"') { + if (!nul_term_line && path[0] == '"') { struct strbuf p_uq = STRBUF_INIT; if (unquote_c_style(&p_uq, path, NULL)) die("invalid quoting"); @@ -141,23 +142,25 @@ int cmd_mktree(int ac, const char **av, const char *prefix) { struct strbuf sb = STRBUF_INIT; unsigned char sha1[20]; - int line_termination = '\n'; + int nul_term_line = 0; int allow_missing = 0; int is_batch_mode = 0; int got_eof = 0; + strbuf_getline_fn getline_fn; const struct option option[] = { - OPT_SET_INT('z', NULL, &line_termination, N_("input is NUL terminated"), '\0'), + OPT_BOOL('z', NULL, &nul_term_line, N_("input is NUL terminated")), OPT_SET_INT( 0 , "missing", &allow_missing, N_("allow missing objects"), 1), OPT_SET_INT( 0 , "batch", &is_batch_mode, N_("allow creation of more than one tree"), 1), OPT_END() }; ac = parse_options(ac, av, prefix, option, mktree_usage, 0); + getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; while (!got_eof) { while (1) { - if (strbuf_getline(&sb, stdin, line_termination) == EOF) { + if (getline_fn(&sb, stdin) == EOF) { got_eof = 1; break; } @@ -167,7 +170,7 @@ int cmd_mktree(int ac, const char **av, const char *prefix) break; die("input format error: (blank line only valid in batch mode)"); } - mktree_line(sb.buf, sb.len, line_termination, allow_missing); + mktree_line(sb.buf, sb.len, nul_term_line, allow_missing); } if (is_batch_mode && got_eof && used < 1) { /* diff --git a/builtin/mv.c b/builtin/mv.c index d1d43168ae..aeae855e2b 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -24,7 +24,8 @@ static const char **internal_copy_pathspec(const char *prefix, int count, unsigned flags) { int i; - const char **result = xmalloc((count + 1) * sizeof(const char *)); + const char **result; + ALLOC_ARRAY(result, count + 1); memcpy(result, pathspec, count * sizeof(const char *)); result[count] = NULL; for (i = 0; i < count; i++) { @@ -47,9 +48,9 @@ static const char **internal_copy_pathspec(const char *prefix, static const char *add_slash(const char *path) { - int len = strlen(path); + size_t len = strlen(path); if (path[len - 1] != '/') { - char *with_slash = xmalloc(len + 2); + char *with_slash = xmalloc(st_add(len, 2)); memcpy(with_slash, path, len); with_slash[len++] = '/'; with_slash[len] = 0; diff --git a/builtin/notes.c b/builtin/notes.c index 52aa9af74b..ed6f2222f4 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -286,11 +286,11 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd) if (!c) return 0; } else { - init_notes(NULL, NULL, NULL, 0); + init_notes(NULL, NULL, NULL, NOTES_INIT_WRITABLE); t = &default_notes_tree; } - while (strbuf_getline(&buf, stdin, '\n') != EOF) { + while (strbuf_getline_lf(&buf, stdin) != EOF) { unsigned char from_obj[20], to_obj[20]; struct strbuf **split; int err; @@ -329,15 +329,18 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd) return ret; } -static struct notes_tree *init_notes_check(const char *subcommand) +static struct notes_tree *init_notes_check(const char *subcommand, + int flags) { struct notes_tree *t; - init_notes(NULL, NULL, NULL, 0); + const char *ref; + init_notes(NULL, NULL, NULL, flags); t = &default_notes_tree; - if (!starts_with(t->ref, "refs/notes/")) + ref = (flags & NOTES_INIT_WRITABLE) ? t->update_ref : t->ref; + if (!starts_with(ref, "refs/notes/")) die("Refusing to %s notes in %s (outside of refs/notes/)", - subcommand, t->ref); + subcommand, ref); return t; } @@ -360,7 +363,7 @@ static int list(int argc, const char **argv, const char *prefix) usage_with_options(git_notes_list_usage, options); } - t = init_notes_check("list"); + t = init_notes_check("list", 0); if (argc) { if (get_sha1(argv[0], object)) die(_("Failed to resolve '%s' as a valid ref."), argv[0]); @@ -420,7 +423,7 @@ static int add(int argc, const char **argv, const char *prefix) if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check("add"); + t = init_notes_check("add", NOTES_INIT_WRITABLE); note = get_note(t, object); if (note) { @@ -511,7 +514,7 @@ static int copy(int argc, const char **argv, const char *prefix) if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check("copy"); + t = init_notes_check("copy", NOTES_INIT_WRITABLE); note = get_note(t, object); if (note) { @@ -589,7 +592,7 @@ static int append_edit(int argc, const char **argv, const char *prefix) if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check(argv[0]); + t = init_notes_check(argv[0], NOTES_INIT_WRITABLE); note = get_note(t, object); prepare_note_data(object, &d, edit ? note : NULL); @@ -652,7 +655,7 @@ static int show(int argc, const char **argv, const char *prefix) if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check("show"); + t = init_notes_check("show", 0); note = get_note(t, object); if (!note) @@ -806,10 +809,10 @@ static int merge(int argc, const char **argv, const char *prefix) o.local_ref = default_notes_ref(); strbuf_addstr(&remote_ref, argv[0]); - expand_notes_ref(&remote_ref); + expand_loose_notes_ref(&remote_ref); o.remote_ref = remote_ref.buf; - t = init_notes_check("merge"); + t = init_notes_check("merge", NOTES_INIT_WRITABLE); if (strategy) { if (parse_notes_merge_strategy(strategy, &o.strategy)) { @@ -901,7 +904,7 @@ static int remove_cmd(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, git_notes_remove_usage, 0); - t = init_notes_check("remove"); + t = init_notes_check("remove", NOTES_INIT_WRITABLE); if (!argc && !from_stdin) { retval = remove_one_note(t, "HEAD", flag); @@ -943,7 +946,7 @@ static int prune(int argc, const char **argv, const char *prefix) usage_with_options(git_notes_prune_usage, options); } - t = init_notes_check("prune"); + t = init_notes_check("prune", NOTES_INIT_WRITABLE); prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) | (show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) ); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 4dae5b11c2..a27de5b323 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -624,7 +624,7 @@ static struct object_entry **compute_write_order(void) { unsigned int i, wo_end, last_untagged; - struct object_entry **wo = xmalloc(to_pack.nr_objects * sizeof(*wo)); + struct object_entry **wo; struct object_entry *objects = to_pack.objects; for (i = 0; i < to_pack.nr_objects; i++) { @@ -657,6 +657,7 @@ static struct object_entry **compute_write_order(void) * Give the objects in the original recency order until * we see a tagged tip. */ + ALLOC_ARRAY(wo, to_pack.nr_objects); for (i = wo_end = 0; i < to_pack.nr_objects; i++) { if (objects[i].tagged) break; @@ -769,7 +770,7 @@ static void write_pack_file(void) if (progress > pack_to_stdout) progress_state = start_progress(_("Writing objects"), nr_result); - written_list = xmalloc(to_pack.nr_objects * sizeof(*written_list)); + ALLOC_ARRAY(written_list, to_pack.nr_objects); write_order = compute_write_order(); do { @@ -2129,7 +2130,7 @@ static void prepare_pack(int window, int depth) if (!to_pack.nr_objects || !window || !depth) return; - delta_list = xmalloc(to_pack.nr_objects * sizeof(*delta_list)); + ALLOC_ARRAY(delta_list, to_pack.nr_objects); nr_deltas = n = 0; for (i = 0; i < to_pack.nr_objects; i++) { @@ -2284,21 +2285,11 @@ static void show_commit(struct commit *commit, void *data) index_commit_for_bitmap(commit); } -static void show_object(struct object *obj, - const struct name_path *path, const char *last, - void *data) +static void show_object(struct object *obj, const char *name, void *data) { - char *name = path_name(path, last); - add_preferred_base_object(name); add_object_entry(obj->oid.hash, obj->type, name, 0); obj->flags |= OBJECT_ADDED; - - /* - * We will have generated the hash from the name, - * but not saved a pointer to it - we can free it - */ - free((char *)name); } static void show_edge(struct commit *commit) @@ -2480,8 +2471,7 @@ static int get_object_list_from_bitmap(struct rev_info *revs) } static void record_recent_object(struct object *obj, - const struct name_path *path, - const char *last, + const char *name, void *data) { sha1_array_append(&recent_objects, obj->oid.hash); diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index d0532f66b1..72c815844d 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -53,7 +53,7 @@ static inline struct llist_item *llist_item_get(void) free_nodes = free_nodes->next; } else { int i = 1; - new = xmalloc(sizeof(struct llist_item) * BLKSIZE); + ALLOC_ARRAY(new, BLKSIZE); for (; i < BLKSIZE; i++) llist_item_put(&new[i]); } diff --git a/builtin/pull.c b/builtin/pull.c index 5145fc60a0..10eff03967 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -22,7 +22,8 @@ enum rebase_type { REBASE_INVALID = -1, REBASE_FALSE = 0, REBASE_TRUE, - REBASE_PRESERVE + REBASE_PRESERVE, + REBASE_INTERACTIVE }; /** @@ -42,6 +43,8 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value, return REBASE_TRUE; else if (!strcmp(value, "preserve")) return REBASE_PRESERVE; + else if (!strcmp(value, "interactive")) + return REBASE_INTERACTIVE; if (fatal) die(_("Invalid value for %s: %s"), key, value); @@ -95,6 +98,7 @@ static int opt_force; static char *opt_tags; static char *opt_prune; static char *opt_recurse_submodules; +static char *max_children; static int opt_dry_run; static char *opt_keep; static char *opt_depth; @@ -112,7 +116,7 @@ static struct option pull_options[] = { /* Options passed to git-merge or git-rebase */ OPT_GROUP(N_("Options related to merging")), { OPTION_CALLBACK, 'r', "rebase", &opt_rebase, - "false|true|preserve", + "false|true|preserve|interactive", N_("incorporate changes by rebasing rather than merging"), PARSE_OPT_OPTARG, parse_opt_rebase }, OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL, @@ -178,6 +182,9 @@ static struct option pull_options[] = { N_("on-demand"), N_("control recursive fetching of submodules"), PARSE_OPT_OPTARG), + OPT_PASSTHRU('j', "jobs", &max_children, N_("n"), + N_("number of submodules pulled in parallel"), + PARSE_OPT_OPTARG), OPT_BOOL(0, "dry-run", &opt_dry_run, N_("dry run")), OPT_PASSTHRU('k', "keep", &opt_keep, NULL, @@ -378,7 +385,7 @@ static void get_merge_heads(struct sha1_array *merge_heads) if (!(fp = fopen(filename, "r"))) die_errno(_("could not open '%s' for reading"), filename); - while (strbuf_getline(&sb, fp, '\n') != EOF) { + while (strbuf_getline_lf(&sb, fp) != EOF) { if (get_sha1_hex(sb.buf, sha1)) continue; /* invalid line: does not start with SHA1 */ if (starts_with(sb.buf + GIT_SHA1_HEXSZ, "\tnot-for-merge\t")) @@ -525,6 +532,8 @@ static int run_fetch(const char *repo, const char **refspecs) argv_array_push(&args, opt_prune); if (opt_recurse_submodules) argv_array_push(&args, opt_recurse_submodules); + if (max_children) + argv_array_push(&args, max_children); if (opt_dry_run) argv_array_push(&args, "--dry-run"); if (opt_keep) @@ -772,6 +781,8 @@ static int run_rebase(const unsigned char *curr_head, /* Options passed to git-rebase */ if (opt_rebase == REBASE_PRESERVE) argv_array_push(&args, "--preserve-merges"); + else if (opt_rebase == REBASE_INTERACTIVE) + argv_array_push(&args, "--interactive"); if (opt_diffstat) argv_array_push(&args, opt_diffstat); argv_array_pushv(&args, opt_strategies.argv); diff --git a/builtin/push.c b/builtin/push.c index 8963dbdf3d..4e9e4dbab2 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -23,6 +23,7 @@ static const char *receivepack; static int verbosity; static int progress = -1; static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; +static enum transport_family family; static struct push_cas_option cas; @@ -204,37 +205,6 @@ static void setup_push_current(struct remote *remote, struct branch *branch) add_refspec(branch->name); } -static char warn_unspecified_push_default_msg[] = -N_("push.default is unset; its implicit value has changed in\n" - "Git 2.0 from 'matching' to 'simple'. To squelch this message\n" - "and maintain the traditional behavior, use:\n" - "\n" - " git config --global push.default matching\n" - "\n" - "To squelch this message and adopt the new behavior now, use:\n" - "\n" - " git config --global push.default simple\n" - "\n" - "When push.default is set to 'matching', git will push local branches\n" - "to the remote branches that already exist with the same name.\n" - "\n" - "Since Git 2.0, Git defaults to the more conservative 'simple'\n" - "behavior, which only pushes the current branch to the corresponding\n" - "remote branch that 'git pull' uses to update the current branch.\n" - "\n" - "See 'git help config' and search for 'push.default' for further information.\n" - "(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" - "'current' instead of 'simple' if you sometimes use older versions of Git)"); - -static void warn_unspecified_push_default_configuration(void) -{ - static int warn_once; - - if (warn_once++) - return; - warning("%s\n", _(warn_unspecified_push_default_msg)); -} - static int is_workflow_triangular(struct remote *remote) { struct remote *fetch_remote = remote_get(NULL); @@ -253,9 +223,6 @@ static void setup_default_push_refspecs(struct remote *remote) break; case PUSH_DEFAULT_UNSPECIFIED: - warn_unspecified_push_default_configuration(); - /* fallthru */ - case PUSH_DEFAULT_SIMPLE: if (triangular) setup_push_current(remote, branch); @@ -346,6 +313,7 @@ static int push_with_options(struct transport *transport, int flags) unsigned int reject_reasons; transport_set_verbosity(transport, verbosity, progress); + transport->family = family; if (receivepack) transport_set_option(transport, @@ -538,7 +506,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL), OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"), (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)), - OPT_BOOL( 0, "delete", &deleterefs, N_("delete refs")), + OPT_BOOL('d', "delete", &deleterefs, N_("delete refs")), OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")), OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN), OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN), @@ -565,6 +533,10 @@ int cmd_push(int argc, const char **argv, const char *prefix) 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"), PARSE_OPT_OPTARG, option_parse_push_signed }, OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC), + OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), + TRANSPORT_FAMILY_IPV4), + OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), + TRANSPORT_FAMILY_IPV6), OPT_END() }; diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index ca38131873..c8e32b297c 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1031,7 +1031,6 @@ static void run_update_post_hook(struct command *commands) { struct command *cmd; int argc; - const char **argv; struct child_process proc = CHILD_PROCESS_INIT; const char *hook; @@ -1044,21 +1043,16 @@ static void run_update_post_hook(struct command *commands) if (!argc || !hook) return; - argv = xmalloc(sizeof(*argv) * (2 + argc)); - argv[0] = hook; - - for (argc = 1, cmd = commands; cmd; cmd = cmd->next) { + argv_array_push(&proc.args, hook); + for (cmd = commands; cmd; cmd = cmd->next) { if (cmd->error_string || cmd->did_not_exist) continue; - argv[argc] = xstrdup(cmd->ref_name); - argc++; + argv_array_push(&proc.args, cmd->ref_name); } - argv[argc] = NULL; proc.no_stdin = 1; proc.stdout_to_stderr = 1; proc.err = use_sideband ? -1 : 0; - proc.argv = argv; if (!start_command(&proc)) { if (use_sideband) @@ -1378,7 +1372,7 @@ static struct command **queue_command(struct command **tail, refname = line + 82; reflen = linelen - 82; - cmd = xcalloc(1, sizeof(struct command) + reflen + 1); + cmd = xcalloc(1, st_add3(sizeof(struct command), reflen, 1)); hashcpy(cmd->old_sha1, old_sha1); hashcpy(cmd->new_sha1, new_sha1); memcpy(cmd->ref_name, refname, reflen); @@ -1597,8 +1591,7 @@ static void prepare_shallow_update(struct command *commands, { int i, j, k, bitmap_size = (si->ref->nr + 31) / 32; - si->used_shallow = xmalloc(sizeof(*si->used_shallow) * - si->shallow->nr); + ALLOC_ARRAY(si->used_shallow, si->shallow->nr); assign_shallow_commits_to_refs(si, si->used_shallow, NULL); si->need_reachability_test = @@ -1618,7 +1611,7 @@ static void prepare_shallow_update(struct command *commands, continue; si->need_reachability_test[i]++; for (k = 0; k < 32; k++) - if (si->used_shallow[i][j] & (1 << k)) + if (si->used_shallow[i][j] & (1U << k)) si->shallow_ref[j * 32 + k]++; } @@ -1664,7 +1657,7 @@ static void update_shallow_info(struct command *commands, return; } - ref_status = xmalloc(sizeof(*ref_status) * ref->nr); + ALLOC_ARRAY(ref_status, ref->nr); assign_shallow_commits_to_refs(si, NULL, ref_status); for (cmd = commands; cmd; cmd = cmd->next) { if (is_null_sha1(cmd->new_sha1)) @@ -1796,6 +1789,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) "gc", "--auto", "--quiet", NULL, }; int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR; + close_all_packs(); run_command_v_opt(argv_gc_auto, opt); } if (auto_update_server_info) diff --git a/builtin/reflog.c b/builtin/reflog.c index f39960e5e4..2d46b6482a 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -382,11 +382,9 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus { struct collected_reflog *e; struct collect_reflog_cb *cb = cb_data; - size_t namelen = strlen(ref); - e = xmalloc(sizeof(*e) + namelen + 1); + FLEX_ALLOC_STR(e, reflog, ref); hashcpy(e->sha1, oid->hash); - memcpy(e->reflog, ref, namelen + 1); ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc); cb->e[cb->nr++] = e; return 0; @@ -396,7 +394,6 @@ static struct reflog_expire_cfg { struct reflog_expire_cfg *next; unsigned long expire_total; unsigned long expire_unreachable; - size_t len; char pattern[FLEX_ARRAY]; } *reflog_expire_cfg, **reflog_expire_cfg_tail; @@ -408,13 +405,11 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len) reflog_expire_cfg_tail = &reflog_expire_cfg; for (ent = reflog_expire_cfg; ent; ent = ent->next) - if (ent->len == len && - !memcmp(ent->pattern, pattern, len)) + if (!strncmp(ent->pattern, pattern, len) && + ent->pattern[len] == '\0') return ent; - ent = xcalloc(1, (sizeof(*ent) + len)); - memcpy(ent->pattern, pattern, len); - ent->len = len; + FLEX_ALLOC_MEM(ent, pattern, pattern, len); *reflog_expire_cfg_tail = ent; reflog_expire_cfg_tail = &(ent->next); return ent; diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index e3cd25d580..7457c743e8 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -114,30 +114,14 @@ static char *strip_escapes(const char *str, const char *service, } } -/* Should be enough... */ -#define MAXARGUMENTS 256 - -static const char **parse_argv(const char *arg, const char *service) +static void parse_argv(struct argv_array *out, const char *arg, const char *service) { - int arguments = 0; - int i; - const char **ret; - char *temparray[MAXARGUMENTS + 1]; - while (*arg) { - char *expanded; - if (arguments == MAXARGUMENTS) - die("remote-ext command has too many arguments"); - expanded = strip_escapes(arg, service, &arg); + char *expanded = strip_escapes(arg, service, &arg); if (expanded) - temparray[arguments++] = expanded; + argv_array_push(out, expanded); + free(expanded); } - - ret = xmalloc((arguments + 1) * sizeof(char *)); - for (i = 0; i < arguments; i++) - ret[i] = temparray[i]; - ret[arguments] = NULL; - return ret; } static void send_git_request(int stdin_fd, const char *serv, const char *repo, @@ -158,7 +142,7 @@ static int run_child(const char *arg, const char *service) child.in = -1; child.out = -1; child.err = 0; - child.argv = parse_argv(arg, service); + parse_argv(&child.args, arg, service); if (start_command(&child) < 0) die("Can't run specified command"); diff --git a/builtin/remote.c b/builtin/remote.c index 6694cf20ef..fda5c2e53d 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -108,8 +108,8 @@ enum { #define MIRROR_PUSH 2 #define MIRROR_BOTH (MIRROR_FETCH|MIRROR_PUSH) -static int add_branch(const char *key, const char *branchname, - const char *remotename, int mirror, struct strbuf *tmp) +static void add_branch(const char *key, const char *branchname, + const char *remotename, int mirror, struct strbuf *tmp) { strbuf_reset(tmp); strbuf_addch(tmp, '+'); @@ -119,7 +119,7 @@ static int add_branch(const char *key, const char *branchname, else strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s", branchname, remotename, branchname); - return git_config_set_multivar(key, tmp->buf, "^$", 0); + git_config_set_multivar(key, tmp->buf, "^$", 0); } static const char mirror_advice[] = @@ -186,10 +186,7 @@ static int add(int argc, const char **argv) url = argv[1]; remote = remote_get(name); - if (remote && (remote->url_nr > 1 || - (strcmp(name, remote->url[0]) && - strcmp(url, remote->url[0])) || - remote->fetch_refspec_nr)) + if (remote_is_configured(remote)) die(_("remote %s already exists."), name); strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name); @@ -197,8 +194,7 @@ static int add(int argc, const char **argv) die(_("'%s' is not a valid remote name"), name); strbuf_addf(&buf, "remote.%s.url", name); - if (git_config_set(buf.buf, url)) - return 1; + git_config_set(buf.buf, url); if (!mirror || mirror & MIRROR_FETCH) { strbuf_reset(&buf); @@ -206,25 +202,22 @@ static int add(int argc, const char **argv) if (track.nr == 0) string_list_append(&track, "*"); for (i = 0; i < track.nr; i++) { - if (add_branch(buf.buf, track.items[i].string, - name, mirror, &buf2)) - return 1; + add_branch(buf.buf, track.items[i].string, + name, mirror, &buf2); } } if (mirror & MIRROR_PUSH) { strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.mirror", name); - if (git_config_set(buf.buf, "true")) - return 1; + git_config_set(buf.buf, "true"); } if (fetch_tags != TAGS_DEFAULT) { strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.tagopt", name); - if (git_config_set(buf.buf, - fetch_tags == TAGS_SET ? "--tags" : "--no-tags")) - return 1; + git_config_set(buf.buf, + fetch_tags == TAGS_SET ? "--tags" : "--no-tags"); } if (fetch && fetch_remote(name)) @@ -251,7 +244,7 @@ static int add(int argc, const char **argv) struct branch_info { char *remote_name; struct string_list merge; - int rebase; + enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase; }; static struct string_list branch_list; @@ -311,7 +304,9 @@ static int config_read_branches(const char *key, const char *value, void *cb) if (v >= 0) info->rebase = v; else if (!strcmp(value, "preserve")) - info->rebase = 1; + info->rebase = NORMAL_REBASE; + else if (!strcmp(value, "interactive")) + info->rebase = INTERACTIVE_REBASE; } } return 0; @@ -590,25 +585,20 @@ static int migrate_file(struct remote *remote) strbuf_addf(&buf, "remote.%s.url", remote->name); for (i = 0; i < remote->url_nr; i++) - if (git_config_set_multivar(buf.buf, remote->url[i], "^$", 0)) - return error(_("Could not append '%s' to '%s'"), - remote->url[i], buf.buf); + git_config_set_multivar(buf.buf, remote->url[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.push", remote->name); for (i = 0; i < remote->push_refspec_nr; i++) - if (git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0)) - return error(_("Could not append '%s' to '%s'"), - remote->push_refspec[i], buf.buf); + git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", remote->name); for (i = 0; i < remote->fetch_refspec_nr; i++) - if (git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0)) - return error(_("Could not append '%s' to '%s'"), - remote->fetch_refspec[i], buf.buf); + git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0); if (remote->origin == REMOTE_REMOTES) unlink_or_warn(git_path("remotes/%s", remote->name)); else if (remote->origin == REMOTE_BRANCHES) unlink_or_warn(git_path("branches/%s", remote->name)); + return 0; } @@ -632,14 +622,14 @@ static int mv(int argc, const char **argv) rename.remote_branches = &remote_branches; oldremote = remote_get(rename.old); - if (!oldremote) + if (!remote_is_configured(oldremote)) die(_("No such remote: %s"), rename.old); if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG) return migrate_file(oldremote); newremote = remote_get(rename.new); - if (newremote && (newremote->url_nr > 1 || newremote->fetch_refspec_nr)) + if (remote_is_configured(newremote)) die(_("remote %s already exists."), rename.new); strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new); @@ -655,8 +645,7 @@ static int mv(int argc, const char **argv) strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", rename.new); - if (git_config_set_multivar(buf.buf, NULL, NULL, 1)) - return error(_("Could not remove config section '%s'"), buf.buf); + git_config_set_multivar(buf.buf, NULL, NULL, 1); strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old); for (i = 0; i < oldremote->fetch_refspec_nr; i++) { char *ptr; @@ -676,8 +665,7 @@ static int mv(int argc, const char **argv) "\tPlease update the configuration manually if necessary."), buf2.buf); - if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0)) - return error(_("Could not append '%s'"), buf.buf); + git_config_set_multivar(buf.buf, buf2.buf, "^$", 0); } read_branches(); @@ -687,9 +675,7 @@ static int mv(int argc, const char **argv) if (info->remote_name && !strcmp(info->remote_name, rename.old)) { strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.remote", item->string); - if (git_config_set(buf.buf, rename.new)) { - return error(_("Could not set '%s'"), buf.buf); - } + git_config_set(buf.buf, rename.new); } } @@ -771,7 +757,7 @@ static int rm(int argc, const char **argv) usage_with_options(builtin_remote_rm_usage, options); remote = remote_get(argv[1]); - if (!remote) + if (!remote_is_configured(remote)) die(_("No such remote: %s"), argv[1]); known_remotes.to_delete = remote; @@ -787,10 +773,7 @@ static int rm(int argc, const char **argv) strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.%s", item->string, *k); - if (git_config_set(buf.buf, NULL)) { - strbuf_release(&buf); - return -1; - } + git_config_set(buf.buf, NULL); } } } @@ -980,7 +963,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data) printf(" %-*s ", show_info->width, item->string); if (branch_info->rebase) { - printf_ln(_("rebases onto remote %s"), merge->items[0].string); + printf_ln(_(branch_info->rebase == INTERACTIVE_REBASE ? + "rebases interactively onto remote %s" : + "rebases onto remote %s"), merge->items[0].string); return 0; } else if (show_info->any_rebase) { printf_ln(_(" merges with remote %s"), merge->items[0].string); @@ -1409,24 +1394,20 @@ static int update(int argc, const char **argv) static int remove_all_fetch_refspecs(const char *remote, const char *key) { - return git_config_set_multivar(key, NULL, NULL, 1); + return git_config_set_multivar_gently(key, NULL, NULL, 1); } -static int add_branches(struct remote *remote, const char **branches, - const char *key) +static void add_branches(struct remote *remote, const char **branches, + const char *key) { const char *remotename = remote->name; int mirror = remote->mirror; struct strbuf refspec = STRBUF_INIT; for (; *branches; branches++) - if (add_branch(key, *branches, remotename, mirror, &refspec)) { - strbuf_release(&refspec); - return 1; - } + add_branch(key, *branches, remotename, mirror, &refspec); strbuf_release(&refspec); - return 0; } static int set_remote_branches(const char *remotename, const char **branches, @@ -1437,18 +1418,15 @@ static int set_remote_branches(const char *remotename, const char **branches, strbuf_addf(&key, "remote.%s.fetch", remotename); - if (!remote_is_configured(remotename)) - die(_("No such remote '%s'"), remotename); remote = remote_get(remotename); + if (!remote_is_configured(remote)) + die(_("No such remote '%s'"), remotename); if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) { strbuf_release(&key); return 1; } - if (add_branches(remote, branches, key.buf)) { - strbuf_release(&key); - return 1; - } + add_branches(remote, branches, key.buf); strbuf_release(&key); return 0; @@ -1494,9 +1472,9 @@ static int get_url(int argc, const char **argv) remotename = argv[0]; - if (!remote_is_configured(remotename)) - die(_("No such remote '%s'"), remotename); remote = remote_get(remotename); + if (!remote_is_configured(remote)) + die(_("No such remote '%s'"), remotename); url_nr = 0; if (push_mode) { @@ -1562,9 +1540,9 @@ static int set_url(int argc, const char **argv) if (delete_mode) oldurl = newurl; - if (!remote_is_configured(remotename)) - die(_("No such remote '%s'"), remotename); remote = remote_get(remotename); + if (!remote_is_configured(remote)) + die(_("No such remote '%s'"), remotename); if (push_mode) { strbuf_addf(&name_buf, "remote.%s.pushurl", remotename); @@ -1580,10 +1558,11 @@ static int set_url(int argc, const char **argv) if ((!oldurl && !delete_mode) || add_mode) { if (add_mode) git_config_set_multivar(name_buf.buf, newurl, - "^$", 0); + "^$", 0); else git_config_set(name_buf.buf, newurl); strbuf_release(&name_buf); + return 0; } diff --git a/builtin/repack.c b/builtin/repack.c index 945611006a..858db38f52 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -266,7 +266,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) return ret; out = xfdopen(cmd.out, "r"); - while (strbuf_getline(&line, out, '\n') != EOF) { + while (strbuf_getline_lf(&line, out) != EOF) { if (line.len != 40) die("repack: Expecting 40 character sha1 lines only from pack-objects."); string_list_append(&names, line.buf); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 3aa89a1a3c..275da0d647 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -177,9 +177,7 @@ static void finish_commit(struct commit *commit, void *data) free_commit_buffer(commit); } -static void finish_object(struct object *obj, - const struct name_path *path, const char *name, - void *cb_data) +static void finish_object(struct object *obj, const char *name, void *cb_data) { struct rev_list_info *info = cb_data; if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid)) @@ -188,15 +186,13 @@ static void finish_object(struct object *obj, parse_object(obj->oid.hash); } -static void show_object(struct object *obj, - const struct name_path *path, const char *component, - void *cb_data) +static void show_object(struct object *obj, const char *name, void *cb_data) { struct rev_list_info *info = cb_data; - finish_object(obj, path, component, cb_data); + finish_object(obj, name, cb_data); if (info->flags & REV_LIST_QUIET) return; - show_object_with_name(stdout, obj, path, component); + show_object_with_name(stdout, obj, name); } static void show_edge(struct commit *commit) diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 7e074aad40..cf8487b3b9 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -383,7 +383,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) /* get the usage up to the first line with a -- on it */ for (;;) { - if (strbuf_getline(&sb, stdin, '\n') == EOF) + if (strbuf_getline(&sb, stdin) == EOF) die("premature end of input"); ALLOC_GROW(usage, unb + 1, usz); if (!strcmp("--", sb.buf)) { @@ -396,7 +396,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) } /* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */ - while (strbuf_getline(&sb, stdin, '\n') != EOF) { + while (strbuf_getline(&sb, stdin) != EOF) { const char *s; const char *help; struct option *o; @@ -763,7 +763,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--git-common-dir")) { - puts(get_git_common_dir()); + const char *pfx = prefix ? prefix : ""; + puts(prefix_filename(pfx, strlen(pfx), get_git_common_dir())); continue; } if (!strcmp(arg, "--resolve-git-dir")) { diff --git a/builtin/rm.c b/builtin/rm.c index 80b972f92f..8829b09d0b 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -211,7 +211,7 @@ static int check_local_mod(unsigned char *head, int index_only) * "intent to add" entry. */ if (local_changes && staged_changes) { - if (!index_only || !(ce->ce_flags & CE_INTENT_TO_ADD)) + if (!index_only || !ce_intent_to_add(ce)) string_list_append(&files_staged, name); } else if (!index_only) { diff --git a/builtin/send-pack.c b/builtin/send-pack.c index f6e5d643c1..5b9dd6a9d8 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -212,7 +212,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) argv_array_push(&all_refspecs, buf); } else { struct strbuf line = STRBUF_INIT; - while (strbuf_getline(&line, stdin, '\n') != EOF) + while (strbuf_getline(&line, stdin) != EOF) argv_array_push(&all_refspecs, line.buf); strbuf_release(&line); } diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 35ebd17f80..bfc082e584 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -14,7 +14,26 @@ static char const * const shortlog_usage[] = { NULL }; -static int compare_by_number(const void *a1, const void *a2) +/* + * The util field of our string_list_items will contain one of two things: + * + * - if --summary is not in use, it will point to a string list of the + * oneline subjects assigned to this author + * + * - if --summary is in use, we don't need that list; we only need to know + * its size. So we abuse the pointer slot to store our integer counter. + * + * This macro accesses the latter. + */ +#define UTIL_TO_INT(x) ((intptr_t)(x)->util) + +static int compare_by_counter(const void *a1, const void *a2) +{ + const struct string_list_item *i1 = a1, *i2 = a2; + return UTIL_TO_INT(i2) - UTIL_TO_INT(i1); +} + +static int compare_by_list(const void *a1, const void *a2) { const struct string_list_item *i1 = a1, *i2 = a2; const struct string_list *l1 = i1->util, *l2 = i2->util; @@ -31,13 +50,9 @@ static void insert_one_record(struct shortlog *log, const char *author, const char *oneline) { - const char *dot3 = log->common_repo_prefix; - char *buffer, *p; struct string_list_item *item; const char *mailbuf, *namebuf; size_t namelen, maillen; - const char *eol; - struct strbuf subject = STRBUF_INIT; struct strbuf namemailbuf = STRBUF_INIT; struct ident_split ident; @@ -56,98 +71,95 @@ static void insert_one_record(struct shortlog *log, strbuf_addf(&namemailbuf, " <%.*s>", (int)maillen, mailbuf); item = string_list_insert(&log->list, namemailbuf.buf); - if (item->util == NULL) - item->util = xcalloc(1, sizeof(struct string_list)); - - /* Skip any leading whitespace, including any blank lines. */ - while (*oneline && isspace(*oneline)) - oneline++; - eol = strchr(oneline, '\n'); - if (!eol) - eol = oneline + strlen(oneline); - if (starts_with(oneline, "[PATCH")) { - char *eob = strchr(oneline, ']'); - if (eob && (!eol || eob < eol)) - oneline = eob + 1; - } - while (*oneline && isspace(*oneline) && *oneline != '\n') - oneline++; - format_subject(&subject, oneline, " "); - buffer = strbuf_detach(&subject, NULL); - - if (dot3) { - int dot3len = strlen(dot3); - if (dot3len > 5) { - while ((p = strstr(buffer, dot3)) != NULL) { - int taillen = strlen(p) - dot3len; - memcpy(p, "/.../", 5); - memmove(p + 5, p + dot3len, taillen + 1); + + if (log->summary) + item->util = (void *)(UTIL_TO_INT(item) + 1); + else { + const char *dot3 = log->common_repo_prefix; + char *buffer, *p; + struct strbuf subject = STRBUF_INIT; + const char *eol; + + /* Skip any leading whitespace, including any blank lines. */ + while (*oneline && isspace(*oneline)) + oneline++; + eol = strchr(oneline, '\n'); + if (!eol) + eol = oneline + strlen(oneline); + if (starts_with(oneline, "[PATCH")) { + char *eob = strchr(oneline, ']'); + if (eob && (!eol || eob < eol)) + oneline = eob + 1; + } + while (*oneline && isspace(*oneline) && *oneline != '\n') + oneline++; + format_subject(&subject, oneline, " "); + buffer = strbuf_detach(&subject, NULL); + + if (dot3) { + int dot3len = strlen(dot3); + if (dot3len > 5) { + while ((p = strstr(buffer, dot3)) != NULL) { + int taillen = strlen(p) - dot3len; + memcpy(p, "/.../", 5); + memmove(p + 5, p + dot3len, taillen + 1); + } } } - } - string_list_append(item->util, buffer); + if (item->util == NULL) + item->util = xcalloc(1, sizeof(struct string_list)); + string_list_append(item->util, buffer); + } } static void read_from_stdin(struct shortlog *log) { - char author[1024], oneline[1024]; + struct strbuf author = STRBUF_INIT; + struct strbuf oneline = STRBUF_INIT; - while (fgets(author, sizeof(author), stdin) != NULL) { - if (!(author[0] == 'A' || author[0] == 'a') || - !starts_with(author + 1, "uthor: ")) + while (strbuf_getline_lf(&author, stdin) != EOF) { + const char *v; + if (!skip_prefix(author.buf, "Author: ", &v) && + !skip_prefix(author.buf, "author ", &v)) continue; - while (fgets(oneline, sizeof(oneline), stdin) && - oneline[0] != '\n') + while (strbuf_getline_lf(&oneline, stdin) != EOF && + oneline.len) ; /* discard headers */ - while (fgets(oneline, sizeof(oneline), stdin) && - oneline[0] == '\n') + while (strbuf_getline_lf(&oneline, stdin) != EOF && + !oneline.len) ; /* discard blanks */ - insert_one_record(log, author + 8, oneline); + insert_one_record(log, v, oneline.buf); } + strbuf_release(&author); + strbuf_release(&oneline); } void shortlog_add_commit(struct shortlog *log, struct commit *commit) { - const char *author = NULL, *buffer; - struct strbuf buf = STRBUF_INIT; - struct strbuf ufbuf = STRBUF_INIT; - - pp_commit_easy(CMIT_FMT_RAW, commit, &buf); - buffer = buf.buf; - while (*buffer && *buffer != '\n') { - const char *eol = strchr(buffer, '\n'); - - if (eol == NULL) - eol = buffer + strlen(buffer); + struct strbuf author = STRBUF_INIT; + struct strbuf oneline = STRBUF_INIT; + struct pretty_print_context ctx = {0}; + + ctx.fmt = CMIT_FMT_USERFORMAT; + ctx.abbrev = log->abbrev; + ctx.subject = ""; + ctx.after_subject = ""; + ctx.date_mode.type = DATE_NORMAL; + ctx.output_encoding = get_log_output_encoding(); + + format_commit_message(commit, "%an <%ae>", &author, &ctx); + if (!log->summary) { + if (log->user_format) + pretty_print_commit(&ctx, commit, &oneline); else - eol++; - - if (starts_with(buffer, "author ")) - author = buffer + 7; - buffer = eol; - } - if (!author) { - warning(_("Missing author: %s"), - oid_to_hex(&commit->object.oid)); - return; + format_commit_message(commit, "%s", &oneline, &ctx); } - if (log->user_format) { - struct pretty_print_context ctx = {0}; - ctx.fmt = CMIT_FMT_USERFORMAT; - ctx.abbrev = log->abbrev; - ctx.subject = ""; - ctx.after_subject = ""; - ctx.date_mode.type = DATE_NORMAL; - ctx.output_encoding = get_log_output_encoding(); - pretty_print_commit(&ctx, commit, &ufbuf); - buffer = ufbuf.buf; - } else if (*buffer) { - buffer++; - } - insert_one_record(log, author, !*buffer ? "<none>" : buffer); - strbuf_release(&ufbuf); - strbuf_release(&buf); + + insert_one_record(log, author.buf, oneline.len ? oneline.buf : "<none>"); + + strbuf_release(&author); + strbuf_release(&oneline); } static void get_from_rev(struct rev_info *rev, struct shortlog *log) @@ -294,14 +306,14 @@ void shortlog_output(struct shortlog *log) if (log->sort_by_number) qsort(log->list.items, log->list.nr, sizeof(struct string_list_item), - compare_by_number); + log->summary ? compare_by_counter : compare_by_list); for (i = 0; i < log->list.nr; i++) { - struct string_list *onelines = log->list.items[i].util; - + const struct string_list_item *item = &log->list.items[i]; if (log->summary) { - printf("%6d\t%s\n", onelines->nr, log->list.items[i].string); + printf("%6d\t%s\n", (int)UTIL_TO_INT(item), item->string); } else { - printf("%s (%d):\n", log->list.items[i].string, onelines->nr); + struct string_list *onelines = item->util; + printf("%s (%d):\n", item->string, onelines->nr); for (j = onelines->nr - 1; j >= 0; j--) { const char *msg = onelines->items[j].string; @@ -314,11 +326,11 @@ void shortlog_output(struct shortlog *log) printf(" %s\n", msg); } putchar('\n'); + onelines->strdup_strings = 1; + string_list_clear(onelines, 0); + free(onelines); } - onelines->strdup_strings = 1; - string_list_clear(onelines, 0); - free(onelines); log->list.items[i].util = NULL; } diff --git a/builtin/stripspace.c b/builtin/stripspace.c index 7ff8434f7c..15e716ef43 100644 --- a/builtin/stripspace.c +++ b/builtin/stripspace.c @@ -35,7 +35,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix) N_("skip and remove all lines starting with comment character"), STRIP_COMMENTS), OPT_CMDMODE('c', "comment-lines", &mode, - N_("prepend comment character and blank to each line"), + N_("prepend comment character and space to each line"), COMMENT_LINES), OPT_END() }; diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index f4c3eff179..ed764c9f0e 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -22,17 +22,12 @@ static int module_list_compute(int argc, const char **argv, struct module_list *list) { int i, result = 0; - char *max_prefix, *ps_matched = NULL; - int max_prefix_len; + char *ps_matched = NULL; parse_pathspec(pathspec, 0, PATHSPEC_PREFER_FULL | PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, prefix, argv); - /* Find common prefix for all pathspec's */ - max_prefix = common_prefix(pathspec); - max_prefix_len = max_prefix ? strlen(max_prefix) : 0; - if (pathspec->nr) ps_matched = xcalloc(pathspec->nr, 1); @@ -44,7 +39,7 @@ static int module_list_compute(int argc, const char **argv, if (!S_ISGITLINK(ce->ce_mode) || !match_pathspec(pathspec, ce->name, ce_namelen(ce), - max_prefix_len, ps_matched, 1)) + 0, ps_matched, 1)) continue; ALLOC_GROW(list->entries, list->nr + 1, list->alloc); @@ -57,7 +52,6 @@ static int module_list_compute(int argc, const char **argv, */ i++; } - free(max_prefix); if (ps_matched && report_path_error(ps_matched, pathspec, prefix)) result = -1; diff --git a/builtin/tag.c b/builtin/tag.c index 8db8c87e57..1705c94665 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -44,11 +44,11 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con if (!format) { if (filter->lines) { to_free = xstrfmt("%s %%(contents:lines=%d)", - "%(align:15)%(refname:short)%(end)", + "%(align:15)%(refname:strip=2)%(end)", filter->lines); format = to_free; } else - format = "%(refname:short)"; + format = "%(refname:strip=2)"; } verify_ref_format(format); diff --git a/builtin/update-index.c b/builtin/update-index.c index 7431938fa6..1c94ca59bf 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -35,6 +35,15 @@ static int mark_skip_worktree_only; #define UNMARK_FLAG 2 static struct strbuf mtime_dir = STRBUF_INIT; +/* Untracked cache mode */ +enum uc_mode { + UC_UNSPECIFIED = -1, + UC_DISABLE = 0, + UC_ENABLE, + UC_TEST, + UC_FORCE +}; + __attribute__((format (printf, 1, 2))) static void report(const char *fmt, ...) { @@ -121,7 +130,7 @@ static int test_if_untracked_cache_is_supported(void) if (!mkdtemp(mtime_dir.buf)) die_errno("Could not make temporary directory"); - fprintf(stderr, _("Testing ")); + fprintf(stderr, _("Testing mtime in '%s' "), xgetcwd()); atexit(remove_test_directory); xstat_mtime_dir(&st); fill_stat_data(&base, &st); @@ -468,12 +477,14 @@ static void update_one(const char *path) report("add '%s'", path); } -static void read_index_info(int line_termination) +static void read_index_info(int nul_term_line) { struct strbuf buf = STRBUF_INIT; struct strbuf uq = STRBUF_INIT; + strbuf_getline_fn getline_fn; - while (strbuf_getline(&buf, stdin, line_termination) != EOF) { + getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; + while (getline_fn(&buf, stdin) != EOF) { char *ptr, *tab; char *path_name; unsigned char sha1[20]; @@ -522,7 +533,7 @@ static void read_index_info(int line_termination) goto bad_line; path_name = ptr; - if (line_termination && path_name[0] == '"') { + if (!nul_term_line && path_name[0] == '"') { strbuf_reset(&uq); if (unquote_c_style(&uq, path_name, NULL)) { die("git update-index: bad quoting of path name"); @@ -844,12 +855,12 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx, static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx, const struct option *opt, int unset) { - int *line_termination = opt->value; + int *nul_term_line = opt->value; if (ctx->argc != 1) return error("option '%s' must be the last argument", opt->long_name); allow_add = allow_replace = allow_remove = 1; - read_index_info(*line_termination); + read_index_info(*nul_term_line); return 0; } @@ -901,8 +912,8 @@ static int reupdate_callback(struct parse_opt_ctx_t *ctx, int cmd_update_index(int argc, const char **argv, const char *prefix) { - int newfd, entries, has_errors = 0, line_termination = '\n'; - int untracked_cache = -1; + int newfd, entries, has_errors = 0, nul_term_line = 0; + enum uc_mode untracked_cache = UC_UNSPECIFIED; int read_from_stdin = 0; int prefix_length = prefix ? strlen(prefix) : 0; int preferred_index_format = 0; @@ -912,6 +923,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) int split_index = -1; struct lock_file *lock_file; struct parse_opt_ctx_t ctx; + strbuf_getline_fn getline_fn; int parseopt_state = PARSE_OPT_UNKNOWN; struct option options[] = { OPT_BIT('q', NULL, &refresh_args.flags, @@ -963,13 +975,13 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) N_("add to index only; do not add content to object database"), 1), OPT_SET_INT(0, "force-remove", &force_remove, N_("remove named paths even if present in worktree"), 1), - OPT_SET_INT('z', NULL, &line_termination, - N_("with --stdin: input lines are terminated by null bytes"), '\0'), + OPT_BOOL('z', NULL, &nul_term_line, + N_("with --stdin: input lines are terminated by null bytes")), {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, N_("read list of paths to be updated from standard input"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_callback}, - {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL, + {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL, N_("add entries from standard input to the index"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_cacheinfo_callback}, @@ -996,8 +1008,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) N_("enable or disable split index")), OPT_BOOL(0, "untracked-cache", &untracked_cache, N_("enable/disable untracked cache")), + OPT_SET_INT(0, "test-untracked-cache", &untracked_cache, + N_("test if the filesystem supports untracked cache"), UC_TEST), OPT_SET_INT(0, "force-untracked-cache", &untracked_cache, - N_("enable untracked cache without testing the filesystem"), 2), + N_("enable untracked cache without testing the filesystem"), UC_FORCE), OPT_END() }; @@ -1057,6 +1071,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) } } argc = parse_options_end(&ctx); + + getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; if (preferred_index_format) { if (preferred_index_format < INDEX_FORMAT_LB || INDEX_FORMAT_UB < preferred_index_format) @@ -1070,16 +1086,17 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) } if (read_from_stdin) { - struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; + struct strbuf buf = STRBUF_INIT; + struct strbuf unquoted = STRBUF_INIT; setup_work_tree(); - while (strbuf_getline(&buf, stdin, line_termination) != EOF) { + while (getline_fn(&buf, stdin) != EOF) { char *p; - if (line_termination && buf.buf[0] == '"') { - strbuf_reset(&nbuf); - if (unquote_c_style(&nbuf, buf.buf, NULL)) + if (!nul_term_line && buf.buf[0] == '"') { + strbuf_reset(&unquoted); + if (unquote_c_style(&unquoted, buf.buf, NULL)) die("line is badly quoted"); - strbuf_swap(&buf, &nbuf); + strbuf_swap(&buf, &unquoted); } p = prefix_path(prefix, prefix_length, buf.buf); update_one(p); @@ -1087,7 +1104,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) chmod_path(set_executable_bit, p); free(p); } - strbuf_release(&nbuf); + strbuf_release(&unquoted); strbuf_release(&buf); } @@ -1104,27 +1121,32 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) the_index.split_index = NULL; the_index.cache_changed |= SOMETHING_CHANGED; } - if (untracked_cache > 0) { - struct untracked_cache *uc; - if (untracked_cache < 2) { - setup_work_tree(); - if (!test_if_untracked_cache_is_supported()) - return 1; - } - if (!the_index.untracked) { - uc = xcalloc(1, sizeof(*uc)); - strbuf_init(&uc->ident, 100); - uc->exclude_per_dir = ".gitignore"; - /* should be the same flags used by git-status */ - uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; - the_index.untracked = uc; - } - add_untracked_ident(the_index.untracked); - the_index.cache_changed |= UNTRACKED_CHANGED; - } else if (!untracked_cache && the_index.untracked) { - the_index.untracked = NULL; - the_index.cache_changed |= UNTRACKED_CHANGED; + switch (untracked_cache) { + case UC_UNSPECIFIED: + break; + case UC_DISABLE: + if (git_config_get_untracked_cache() == 1) + warning("core.untrackedCache is set to true; " + "remove or change it, if you really want to " + "disable the untracked cache"); + remove_untracked_cache(&the_index); + report(_("Untracked cache disabled")); + break; + case UC_TEST: + setup_work_tree(); + return !test_if_untracked_cache_is_supported(); + case UC_ENABLE: + case UC_FORCE: + if (git_config_get_untracked_cache() == 0) + warning("core.untrackedCache is set to false; " + "remove or change it, if you really want to " + "enable the untracked cache"); + add_untracked_cache(&the_index); + report(_("Untracked cache enabled for '%s'"), get_git_work_tree()); + break; + default: + die("Bug: bad untracked_cache value: %d", untracked_cache); } if (active_cache_changed) { diff --git a/builtin/worktree.c b/builtin/worktree.c index 475b9581a5..38b56096bd 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -52,7 +52,7 @@ static int prune_worktree(const char *id, struct strbuf *reason) return 1; } len = st.st_size; - path = xmalloc(len + 1); + path = xmallocz(len); read_in_full(fd, path, len); close(fd); while (len && (path[len - 1] == '\n' || path[len - 1] == '\r')) @@ -201,9 +201,7 @@ static int add_worktree(const char *path, const char *refname, die(_("'%s' already exists"), path); /* is 'refname' a branch or commit? */ - if (opts->force_new_branch) /* definitely a branch */ - ; - else if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) && + if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) && ref_exists(symref.buf)) { /* it's a branch */ if (!opts->force) die_if_checked_out(symref.buf); @@ -336,9 +334,18 @@ static int add(int ac, const char **av, const char *prefix) branch = ac < 2 ? "HEAD" : av[1]; opts.force_new_branch = !!new_branch_force; - if (opts.force_new_branch) + if (opts.force_new_branch) { + struct strbuf symref = STRBUF_INIT; + opts.new_branch = new_branch_force; + if (!opts.force && + !strbuf_check_branch_ref(&symref, opts.new_branch) && + ref_exists(symref.buf)) + die_if_checked_out(symref.buf); + strbuf_release(&symref); + } + if (ac < 2 && !opts.new_branch && !opts.detach) { int n; const char *s = worktree_basename(path, &n); diff --git a/cache-tree.c b/cache-tree.c index a59e6f1e1f..3ebf9c3aa4 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -79,11 +79,9 @@ static struct cache_tree_sub *find_subtree(struct cache_tree *it, ALLOC_GROW(it->down, it->subtree_nr + 1, it->subtree_alloc); it->subtree_nr++; - down = xmalloc(sizeof(*down) + pathlen + 1); + FLEX_ALLOC_MEM(down, name, path, pathlen); down->cache_tree = NULL; down->namelen = pathlen; - memcpy(down->name, path, pathlen); - down->name[pathlen] = 0; if (pos < it->subtree_nr) memmove(it->down + pos + 1, @@ -377,7 +375,7 @@ static int update_one(struct cache_tree *it, * they are not part of generated trees. Invalidate up * to root to force cache-tree users to read elsewhere. */ - if (ce->ce_flags & CE_INTENT_TO_ADD) { + if (ce_intent_to_add(ce)) { to_invalidate = 1; continue; } @@ -9,6 +9,7 @@ #include "convert.h" #include "trace.h" #include "string-list.h" +#include "pack-revindex.h" #include SHA1_HEADER #ifndef platform_SHA_CTX @@ -214,7 +215,7 @@ struct cache_entry { #define CE_INTENT_TO_ADD (1 << 29) #define CE_SKIP_WORKTREE (1 << 30) /* CE_EXTENDED2 is for future extension */ -#define CE_EXTENDED2 (1 << 31) +#define CE_EXTENDED2 (1U << 31) #define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE) @@ -228,7 +229,9 @@ struct cache_entry { #error "CE_EXTENDED_FLAGS out of range" #endif +/* Forward structure decls */ struct pathspec; +struct child_process; /* * Copy the sha1 and stat state of a cache entry from one to @@ -259,6 +262,7 @@ static inline unsigned create_ce_flags(unsigned stage) #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE) #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE) #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE) +#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD) #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644) static inline unsigned int create_ce_mode(unsigned int mode) @@ -456,7 +460,6 @@ extern char *git_work_tree_cfg; extern int is_inside_work_tree(void); extern const char *get_git_dir(void); extern const char *get_git_common_dir(void); -extern int is_git_directory(const char *path); extern char *get_object_directory(void); extern char *get_index_file(void); extern char *get_graft_file(void); @@ -467,6 +470,25 @@ extern const char *get_git_namespace(void); extern const char *strip_namespace(const char *namespaced_ref); extern const char *get_git_work_tree(void); +/* + * Return true if the given path is a git directory; note that this _just_ + * looks at the directory itself. If you want to know whether "foo/.git" + * is a repository, you must feed that path, not just "foo". + */ +extern int is_git_directory(const char *path); + +/* + * Return 1 if the given path is the root of a git repository or + * submodule, else 0. Will not return 1 for bare repositories with the + * exception of creating a bare repository in "foo/.git" and calling + * is_git_repository("foo"). + * + * If we run into read errors, we err on the side of saying "yes, it is", + * as we usually consider sub-repos precious, and would prefer to err on the + * side of not disrupting or deleting them. + */ +extern int is_nonbare_repository_dir(struct strbuf *path); + #define READ_GITFILE_ERR_STAT_FAILED 1 #define READ_GITFILE_ERR_NOT_A_FILE 2 #define READ_GITFILE_ERR_OPEN_FAILED 3 @@ -1299,6 +1321,7 @@ extern struct packed_git { freshened:1, do_not_close:1; unsigned char sha1[20]; + struct revindex_entry *revindex; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ } *packed_git; @@ -1466,7 +1489,7 @@ extern int update_server_info(int); /* git_config_parse_key() returns these negated: */ #define CONFIG_INVALID_KEY 1 #define CONFIG_NO_SECTION_OR_NAME 2 -/* git_config_set(), git_config_set_multivar() return the above or these: */ +/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */ #define CONFIG_NO_LOCK -1 #define CONFIG_INVALID_FILE 3 #define CONFIG_NO_WRITE 4 @@ -1485,8 +1508,8 @@ struct git_config_source { typedef int (*config_fn_t)(const char *, const char *, void *); extern int git_default_config(const char *, const char *, void *); extern int git_config_from_file(config_fn_t fn, const char *, void *); -extern int git_config_from_buf(config_fn_t fn, const char *name, - const char *buf, size_t len, void *data); +extern int git_config_from_mem(config_fn_t fn, const char *origin_type, + const char *name, const char *buf, size_t len, void *data); extern void git_config_push_parameter(const char *text); extern int git_config_from_parameters(config_fn_t fn, void *data); extern void git_config(config_fn_t fn, void *); @@ -1504,12 +1527,16 @@ extern int git_config_bool(const char *, const char *); extern int git_config_maybe_bool(const char *, const char *); extern int git_config_string(const char **, const char *, const char *); extern int git_config_pathname(const char **, const char *, const char *); -extern int git_config_set_in_file(const char *, const char *, const char *); -extern int git_config_set(const char *, const char *); +extern int git_config_set_in_file_gently(const char *, const char *, const char *); +extern void git_config_set_in_file(const char *, const char *, const char *); +extern int git_config_set_gently(const char *, const char *); +extern void git_config_set(const char *, const char *); extern int git_config_parse_key(const char *, char **, int *); extern int git_config_key_is_valid(const char *key); -extern int git_config_set_multivar(const char *, const char *, const char *, int); -extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int); +extern int git_config_set_multivar_gently(const char *, const char *, const char *, int); +extern void git_config_set_multivar(const char *, const char *, const char *, int); +extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int); +extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int); extern int git_config_rename_section(const char *, const char *); extern int git_config_rename_section_in_file(const char *, const char *, const char *); extern const char *git_etc_gitconfig(void); @@ -1525,6 +1552,8 @@ extern const char *get_log_output_encoding(void); extern const char *get_commit_output_encoding(void); extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data); +extern const char *current_config_origin_type(void); +extern const char *current_config_name(void); struct config_include_data { int depth; @@ -1603,6 +1632,14 @@ extern int git_config_get_bool(const char *key, int *dest); extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest); extern int git_config_get_maybe_bool(const char *key, int *dest); extern int git_config_get_pathname(const char *key, const char **dest); +extern int git_config_get_untracked_cache(void); + +/* + * This is a hack for test programs like test-dump-untracked-cache to + * ensure that they do not modify the untracked cache when reading it. + * Do not use it otherwise! + */ +extern int ignore_untracked_cache_config; struct key_value_info { const char *filename; @@ -1656,6 +1693,7 @@ extern int pager_use_color; extern int term_columns(void); extern int decimal_width(uintmax_t); extern int check_pager_config(const char *cmd); +extern void prepare_pager_args(struct child_process *, const char *pager); extern const char *editor_program; extern const char *askpass_program; @@ -164,7 +164,7 @@ static void display_table(const struct string_list *list, data.colopts = colopts; data.opts = *opts; - data.len = xmalloc(sizeof(*data.len) * list->nr); + ALLOC_ARRAY(data.len, list->nr); for (i = 0; i < list->nr; i++) data.len[i] = item_length(colopts, list->items[i].string); @@ -173,9 +173,8 @@ static void display_table(const struct string_list *list, if (colopts & COL_DENSE) shrink_columns(&data); - empty_cell = xmalloc(initial_width + 1); + empty_cell = xmallocz(initial_width); memset(empty_cell, ' ', initial_width); - empty_cell[initial_width] = '\0'; for (y = 0; y < data.rows; y++) { for (x = 0; x < data.cols; x++) if (display_cell(&data, initial_width, empty_cell, x, y)) diff --git a/combine-diff.c b/combine-diff.c index 55713049a4..0e1d4b0893 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -189,11 +189,11 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase, * - Else if we have NEW, insert newend lline into base and * consume newend */ - lcs = xcalloc(origbaselen + 1, sizeof(int*)); - directions = xcalloc(origbaselen + 1, sizeof(enum coalesce_direction*)); + lcs = xcalloc(st_add(origbaselen, 1), sizeof(int*)); + directions = xcalloc(st_add(origbaselen, 1), sizeof(enum coalesce_direction*)); for (i = 0; i < origbaselen + 1; i++) { - lcs[i] = xcalloc(lennew + 1, sizeof(int)); - directions[i] = xcalloc(lennew + 1, sizeof(enum coalesce_direction)); + lcs[i] = xcalloc(st_add(lennew, 1), sizeof(int)); + directions[i] = xcalloc(st_add(lennew, 1), sizeof(enum coalesce_direction)); directions[i][0] = BASE; } for (j = 1; j < lennew + 1; j++) @@ -319,7 +319,7 @@ static void append_lost(struct sline *sline, int n, const char *line, int len) if (line[len-1] == '\n') len--; - lline = xmalloc(sizeof(*lline) + len + 1); + FLEX_ALLOC_MEM(lline, line, line, len); lline->len = len; lline->next = NULL; lline->prev = sline->plost.lost_tail; @@ -330,8 +330,6 @@ static void append_lost(struct sline *sline, int n, const char *line, int len) sline->plost.lost_tail = lline; sline->plost.len++; lline->parent_map = this_mask; - memcpy(lline->line, line, len); - lline->line[len] = 0; } struct combine_diff_state { @@ -1043,7 +1041,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, elem->mode = canon_mode(S_IFLNK); result_size = len; - result = xmalloc(len + 1); + result = xmallocz(len); done = read_in_full(fd, result, len); if (done < 0) @@ -1051,8 +1049,6 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, else if (done < len) die("early EOF '%s'", elem->path); - result[len] = 0; - /* If not a fake symlink, apply filters, e.g. autocrlf */ if (is_file) { struct strbuf buf = STRBUF_INIT; @@ -1115,7 +1111,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, if (result_size && result[result_size-1] != '\n') cnt++; /* incomplete line */ - sline = xcalloc(cnt+2, sizeof(*sline)); + sline = xcalloc(st_add(cnt, 2), sizeof(*sline)); sline[0].bol = result; for (lno = 0, cp = result; cp < result + result_size; cp++) { if (*cp == '\n') { @@ -1134,7 +1130,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, /* Even p_lno[cnt+1] is valid -- that is for the end line number * for deletion hunk at the end. */ - sline[0].p_lno = xcalloc((cnt+2) * num_parent, sizeof(unsigned long)); + sline[0].p_lno = xcalloc(st_mult(st_add(cnt, 2), num_parent), sizeof(unsigned long)); for (lno = 0; lno <= cnt; lno++) sline[lno+1].p_lno = sline[lno].p_lno + num_parent; @@ -1266,7 +1262,7 @@ static struct diff_filepair *combined_pair(struct combine_diff_path *p, struct diff_filespec *pool; pair = xmalloc(sizeof(*pair)); - pool = xcalloc(num_parent + 1, sizeof(struct diff_filespec)); + pool = xcalloc(st_add(num_parent, 1), sizeof(struct diff_filespec)); pair->one = pool + 1; pair->two = pool; @@ -1372,7 +1368,7 @@ static struct combine_diff_path *find_paths_multitree( struct combine_diff_path paths_head; struct strbuf base; - parents_sha1 = xmalloc(nparent * sizeof(parents_sha1[0])); + ALLOC_ARRAY(parents_sha1, nparent); for (i = 0; i < nparent; i++) parents_sha1[i] = parents->sha1[i]; @@ -1483,7 +1479,7 @@ void diff_tree_combined(const unsigned char *sha1, if (opt->orderfile && num_paths) { struct obj_order *o; - o = xmalloc(sizeof(*o) * num_paths); + ALLOC_ARRAY(o, num_paths); for (i = 0, p = paths; p; p = p->next, i++) o[i].obj = p; order_objects(opt->orderfile, path_path, o, num_paths); @@ -147,7 +147,7 @@ struct commit_graft *read_graft_line(char *buf, int len) if ((len + 1) % entry_size) goto bad_graft_data; i = (len + 1) / entry_size - 1; - graft = xmalloc(sizeof(*graft) + GIT_SHA1_RAWSZ * i); + graft = xmalloc(st_add(sizeof(*graft), st_mult(GIT_SHA1_RAWSZ, i))); graft->nr_parent = i; if (get_oid_hex(buf, &graft->oid)) goto bad_graft_data; @@ -903,7 +903,7 @@ static int remove_redundant(struct commit **array, int cnt) work = xcalloc(cnt, sizeof(*work)); redundant = xcalloc(cnt, 1); - filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1)); + ALLOC_ARRAY(filled_index, cnt - 1); for (i = 0; i < cnt; i++) parse_commit(array[i]); diff --git a/compat/basename.c b/compat/basename.c index d8f8a3c6dc..96bd9533b4 100644 --- a/compat/basename.c +++ b/compat/basename.c @@ -1,15 +1,71 @@ #include "../git-compat-util.h" +#include "../strbuf.h" /* Adapted from libiberty's basename.c. */ char *gitbasename (char *path) { const char *base; - /* Skip over the disk name in MSDOS pathnames. */ - if (has_dos_drive_prefix(path)) - path += 2; + + if (path) + skip_dos_drive_prefix(&path); + + if (!path || !*path) + return "."; + for (base = path; *path; path++) { - if (is_dir_sep(*path)) - base = path + 1; + if (!is_dir_sep(*path)) + continue; + do { + path++; + } while (is_dir_sep(*path)); + if (*path) + base = path; + else + while (--path != base && is_dir_sep(*path)) + *path = '\0'; } return (char *)base; } + +char *gitdirname(char *path) +{ + static struct strbuf buf = STRBUF_INIT; + char *p = path, *slash = NULL, c; + int dos_drive_prefix; + + if (!p) + return "."; + + if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p) + goto dot; + + /* + * POSIX.1-2001 says dirname("/") should return "/", and dirname("//") + * should return "//", but dirname("///") should return "/" again. + */ + if (is_dir_sep(*p)) { + if (!p[1] || (is_dir_sep(p[1]) && !p[2])) + return path; + slash = ++p; + } + while ((c = *(p++))) + if (is_dir_sep(c)) { + char *tentative = p - 1; + + /* POSIX.1-2001 says to ignore trailing slashes */ + while (is_dir_sep(*p)) + p++; + if (*p) + slash = tentative; + } + + if (slash) { + *slash = '\0'; + return path; + } + +dot: + strbuf_reset(&buf); + strbuf_addf(&buf, "%.*s.", dos_drive_prefix, path); + return buf.buf; +} diff --git a/compat/bswap.h b/compat/bswap.h index 7fed637ed0..d47c003544 100644 --- a/compat/bswap.h +++ b/compat/bswap.h @@ -149,11 +149,12 @@ static inline uint64_t git_bswap64(uint64_t x) * and is faster on architectures with memory alignment issues. */ -#if defined(__i386__) || defined(__x86_64__) || \ +#if !defined(NO_UNALIGNED_LOADS) && ( \ + defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64) || \ defined(__ppc__) || defined(__ppc64__) || \ defined(__powerpc__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__s390x__) + defined(__s390__) || defined(__s390x__)) #define get_be16(p) ntohs(*(unsigned short *)(p)) #define get_be32(p) ntohl(*(unsigned int *)(p)) diff --git a/compat/mingw.c b/compat/mingw.c index 5edea29508..cfedcf9656 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -6,6 +6,8 @@ #include "../run-command.h" #include "../cache.h" +#define HCAST(type, handle) ((type)(intptr_t)handle) + static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) @@ -452,6 +454,39 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)(filetime_to_hnsec(ft) / 10000000); } +/** + * Verifies that safe_create_leading_directories() would succeed. + */ +static int has_valid_directory_prefix(wchar_t *wfilename) +{ + int n = wcslen(wfilename); + + while (n > 0) { + wchar_t c = wfilename[--n]; + DWORD attributes; + + if (!is_dir_sep(c)) + continue; + + wfilename[n] = L'\0'; + attributes = GetFileAttributesW(wfilename); + wfilename[n] = c; + if (attributes == FILE_ATTRIBUTE_DIRECTORY || + attributes == FILE_ATTRIBUTE_DEVICE) + return 1; + if (attributes == INVALID_FILE_ATTRIBUTES) + switch (GetLastError()) { + case ERROR_PATH_NOT_FOUND: + continue; + case ERROR_FILE_NOT_FOUND: + /* This implies parent directory exists. */ + return 1; + } + return 0; + } + return 1; +} + /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. @@ -512,6 +547,12 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; + case ERROR_PATH_NOT_FOUND: + if (!has_valid_directory_prefix(wfilename)) { + errno = ENOTDIR; + break; + } + /* fallthru */ default: errno = ENOENT; break; @@ -691,13 +732,13 @@ int pipe(int filedes[2]) errno = err_win_to_posix(GetLastError()); return -1; } - filedes[0] = _open_osfhandle((int)h[0], O_NOINHERIT); + filedes[0] = _open_osfhandle(HCAST(int, h[0]), O_NOINHERIT); if (filedes[0] < 0) { CloseHandle(h[0]); CloseHandle(h[1]); return -1; } - filedes[1] = _open_osfhandle((int)h[1], O_NOINHERIT); + filedes[1] = _open_osfhandle(HCAST(int, h[1]), O_NOINHERIT); if (filedes[1] < 0) { close(filedes[0]); CloseHandle(h[1]); @@ -769,7 +810,7 @@ static const char *quote_arg(const char *arg) return arg; /* insert \ where necessary */ - d = q = xmalloc(len+n+3); + d = q = xmalloc(st_add3(len, n, 3)); *d++ = '"'; while (*arg) { if (*arg == '"') @@ -852,7 +893,7 @@ static char **get_path_split(void) if (!n) return NULL; - path = xmalloc((n+1)*sizeof(char *)); + ALLOC_ARRAY(path, n + 1); p = envpath; i = 0; do { @@ -937,7 +978,7 @@ static wchar_t *make_environment_block(char **deltaenv) i++; /* copy the environment, leaving space for changes */ - tmpenv = xmalloc((size + i) * sizeof(char*)); + ALLOC_ARRAY(tmpenv, size + i); memcpy(tmpenv, environ, size * sizeof(char*)); /* merge supplied environment changes into the temporary environment */ @@ -1028,7 +1069,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen free(quoted); } - wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t)); + wargs = xmalloc_array(st_add(st_mult(2, args.len), 1), sizeof(wchar_t)); xutftowcs(wargs, args.buf, 2 * args.len + 1); strbuf_release(&args); @@ -1127,7 +1168,7 @@ static int try_shell_exec(const char *cmd, char *const *argv) int argc = 0; const char **argv2; while (argv[argc]) argc++; - argv2 = xmalloc(sizeof(*argv) * (argc+1)); + ALLOC_ARRAY(argv2, argc + 1); argv2[0] = (char *)cmd; /* full path to the script file */ memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc); pid = mingw_spawnv(prog, argv2, 1); @@ -1601,7 +1642,12 @@ repeat: if (gle == ERROR_ACCESS_DENIED && (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) { - errno = EISDIR; + DWORD attrsold = GetFileAttributesW(wpold); + if (attrsold == INVALID_FILE_ATTRIBUTES || + !(attrsold & FILE_ATTRIBUTE_DIRECTORY)) + errno = EISDIR; + else if (!_wrmdir(wpnew)) + goto repeat; return -1; } if ((attrs & FILE_ATTRIBUTE_READONLY) && @@ -1846,7 +1892,8 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); + r = HCAST(int, ShellExecute(NULL, "open", htmlpath, + NULL, "\\", SW_SHOWNORMAL)); FreeLibrary(shell32); /* see the MSDN documentation referring to the result codes here */ if (r <= 32) { @@ -1932,28 +1979,31 @@ pid_t waitpid(pid_t pid, int *status, int options) return -1; } +int mingw_skip_dos_drive_prefix(char **path) +{ + int ret = has_dos_drive_prefix(*path); + *path += ret; + return ret; +} + int mingw_offset_1st_component(const char *path) { - int offset = 0; - if (has_dos_drive_prefix(path)) - offset = 2; + char *pos = (char *)path; /* unc paths */ - else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { - + if (!skip_dos_drive_prefix(&pos) && + is_dir_sep(pos[0]) && is_dir_sep(pos[1])) { /* skip server name */ - char *pos = strpbrk(path + 2, "\\/"); + pos = strpbrk(pos + 2, "\\/"); if (!pos) return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - - offset = pos - path; } - return offset + is_dir_sep(path[offset]); + return pos + is_dir_sep(*pos) - path; } int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen) @@ -2041,6 +2091,37 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen) return -1; } +static void setup_windows_environment() +{ + char *tmp = getenv("TMPDIR"); + + /* on Windows it is TMP and TEMP */ + if (!tmp) { + if (!(tmp = getenv("TMP"))) + tmp = getenv("TEMP"); + if (tmp) { + setenv("TMPDIR", tmp, 1); + tmp = getenv("TMPDIR"); + } + } + + if (tmp) { + /* + * Convert all dir separators to forward slashes, + * to help shell commands called from the Git + * executable (by not mistaking the dir separators + * for escape characters). + */ + for (; *tmp; tmp++) + if (*tmp == '\\') + *tmp = '/'; + } + + /* simulate TERM to enable auto-color (see color.c) */ + if (!getenv("TERM")) + setenv("TERM", "cygwin", 1); +} + /* * Disable MSVCRT command line wildcard expansion (__getmainargs called from * mingw startup code, see init.c in mingw runtime). @@ -2119,19 +2200,7 @@ void mingw_startup() qsort(environ, i, sizeof(char*), compareenv); /* fix Windows specific environment settings */ - - /* on Windows it is TMP and TEMP */ - if (!mingw_getenv("TMPDIR")) { - const char *tmp = mingw_getenv("TMP"); - if (!tmp) - tmp = mingw_getenv("TEMP"); - if (tmp) - setenv("TMPDIR", tmp, 1); - } - - /* simulate TERM to enable auto-color (see color.c) */ - if (!getenv("TERM")) - setenv("TERM", "cygwin", 1); + setup_windows_environment(); /* initialize critical section for waitpid pinfo_t list */ InitializeCriticalSection(&pinfo_cs); diff --git a/compat/mingw.h b/compat/mingw.h index 57ca477d1f..8c5bf5076b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -1,27 +1,43 @@ +#ifdef __MINGW64_VERSION_MAJOR +#include <stdint.h> +#include <wchar.h> +typedef _sigset_t sigset_t; +#endif #include <winsock2.h> #include <ws2tcpip.h> +/* MinGW-w64 reports to have flockfile, but it does not actually have it. */ +#ifdef __MINGW64_VERSION_MAJOR +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#endif + /* * things that are not available in header files */ -typedef int pid_t; typedef int uid_t; typedef int socklen_t; +#ifndef __MINGW64_VERSION_MAJOR +typedef int pid_t; #define hstrerror strerror +#endif #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef S_IRWXG #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 #define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#endif +#ifndef S_IRWXO #define S_IROTH 0 #define S_IWOTH 0 #define S_IXOTH 0 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif #define S_ISUID 0004000 #define S_ISGID 0002000 @@ -100,8 +116,10 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } +#ifndef __MINGW64_VERSION_MAJOR static inline pid_t fork(void) { errno = ENOSYS; return -1; } +#endif static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) @@ -176,8 +194,10 @@ int pipe(int filedes[2]); unsigned int sleep (unsigned int seconds); int mkstemp(char *template); int gettimeofday(struct timeval *tv, void *tz); +#ifndef __MINGW64_VERSION_MAJOR struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); +#endif int getpagesize(void); /* defined in MinGW's libgcc.a */ struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); @@ -301,8 +321,10 @@ static inline int getrlimit(int resource, struct rlimit *rlp) /* * Use mingw specific stat()/lstat()/fstat() implementations on Windows. */ +#ifndef __MINGW64_VERSION_MAJOR #define off_t off64_t #define lseek _lseeki64 +#endif /* use struct stat with 64 bit st_size */ #ifdef stat @@ -361,7 +383,10 @@ HANDLE winansi_get_osfhandle(int fd); * git specific compatibility */ -#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') +#define has_dos_drive_prefix(path) \ + (isalpha(*(path)) && (path)[1] == ':' ? 2 : 0) +int mingw_skip_dos_drive_prefix(char **path); +#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix #define is_dir_sep(c) ((c) == '/' || (c) == '\\') static inline char *mingw_find_last_dir_sep(const char *path) { @@ -375,8 +400,12 @@ static inline char *mingw_find_last_dir_sep(const char *path) int mingw_offset_1st_component(const char *path); #define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' +#ifndef __MINGW64_VERSION_MAJOR #define PRIuMAX "I64u" #define PRId64 "I64d" +#else +#include <inttypes.h> +#endif void mingw_open_html(const char *path); #define open_html mingw_open_html diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index f216a2a7d3..b833ff9225 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -720,6 +720,9 @@ struct mallinfo { inlining are defined as macros, so these aren't used for them. */ +#ifdef __MINGW64_VERSION_MAJOR +#undef FORCEINLINE +#endif #ifndef FORCEINLINE #if defined(__GNUC__) #define FORCEINLINE __inline __attribute__ ((always_inline)) @@ -1382,6 +1385,7 @@ LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); /*** Atomic operations ***/ #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 + #undef _ReadWriteBarrier #define _ReadWriteBarrier() __sync_synchronize() #else static __inline__ __attribute__((always_inline)) long __sync_lock_test_and_set(volatile long * const Target, const long Value) @@ -1798,9 +1802,10 @@ struct win32_mlock_t volatile long threadid; }; +static inline int return_0(int i) { return 0; } #define MLOCK_T struct win32_mlock_t #define CURRENT_THREAD win32_getcurrentthreadid() -#define INITIAL_LOCK(sl) (memset(sl, 0, sizeof(MLOCK_T)), 0) +#define INITIAL_LOCK(sl) (memset(sl, 0, sizeof(MLOCK_T)), return_0(0)) #define ACQUIRE_LOCK(sl) win32_acquire_lock(sl) #define RELEASE_LOCK(sl) win32_release_lock(sl) #define TRY_LOCK(sl) win32_try_lock(sl) diff --git a/compat/poll/poll.c b/compat/poll/poll.c index db4e03ed79..b10adc780f 100644 --- a/compat/poll/poll.c +++ b/compat/poll/poll.c @@ -76,7 +76,7 @@ #ifdef WIN32_NATIVE -#define IsConsoleHandle(h) (((long) (h) & 3) == 3) +#define IsConsoleHandle(h) (((long) (intptr_t) (h) & 3) == 3) static BOOL IsSocketHandle (HANDLE h) diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c index 079070ff1d..dfbe6d8408 100644 --- a/compat/precompose_utf8.c +++ b/compat/precompose_utf8.c @@ -50,7 +50,8 @@ void probe_utf8_pathname_composition(void) close(output_fd); git_path_buf(&path, "%s", auml_nfd); precomposed_unicode = access(path.buf, R_OK) ? 0 : 1; - git_config_set("core.precomposeunicode", precomposed_unicode ? "true" : "false"); + git_config_set("core.precomposeunicode", + precomposed_unicode ? "true" : "false"); git_path_buf(&path, "%s", auml_nfc); if (unlink(path.buf)) die_errno(_("failed to unlink '%s'"), path.buf); diff --git a/compat/qsort.c b/compat/qsort.c index 9574d537bd..7d071afb70 100644 --- a/compat/qsort.c +++ b/compat/qsort.c @@ -47,7 +47,7 @@ static void msort_with_tmp(void *b, size_t n, size_t s, void git_qsort(void *b, size_t n, size_t s, int (*cmp)(const void *, const void *)) { - const size_t size = n * s; + const size_t size = st_mult(n, s); char buf[1024]; if (size < sizeof(buf)) { diff --git a/compat/setenv.c b/compat/setenv.c index fc1439a643..7849f258d2 100644 --- a/compat/setenv.c +++ b/compat/setenv.c @@ -18,7 +18,7 @@ int gitsetenv(const char *name, const char *value, int replace) namelen = strlen(name); valuelen = strlen(value); - envstr = malloc((namelen + valuelen + 2)); + envstr = malloc(st_add3(namelen, valuelen, 2)); if (!envstr) { errno = ENOMEM; return -1; diff --git a/compat/terminal.c b/compat/terminal.c index 313897d581..fa13ee672d 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -122,7 +122,7 @@ char *git_terminal_prompt(const char *prompt, int echo) fputs(prompt, output_fh); fflush(output_fh); - r = strbuf_getline(&buf, input_fh, '\n'); + r = strbuf_getline_lf(&buf, input_fh); if (!echo) { putc('\n', output_fh); fflush(output_fh); diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h index 8ad187344f..20b35a283c 100644 --- a/compat/win32/pthread.h +++ b/compat/win32/pthread.h @@ -18,7 +18,10 @@ */ #define pthread_mutex_t CRITICAL_SECTION -#define pthread_mutex_init(a,b) (InitializeCriticalSection((a)), 0) +static inline int return_0(int i) { + return 0; +} +#define pthread_mutex_init(a,b) return_0((InitializeCriticalSection((a)), 0)) #define pthread_mutex_destroy(a) DeleteCriticalSection((a)) #define pthread_mutex_lock EnterCriticalSection #define pthread_mutex_unlock LeaveCriticalSection @@ -77,7 +80,7 @@ extern pthread_t pthread_self(void); static inline int pthread_exit(void *ret) { - ExitThread((DWORD)ret); + ExitThread((DWORD)(intptr_t)ret); } typedef DWORD pthread_key_t; diff --git a/compat/win32/syslog.c b/compat/win32/syslog.c index d015e436d5..b905aea31b 100644 --- a/compat/win32/syslog.c +++ b/compat/win32/syslog.c @@ -32,7 +32,7 @@ void syslog(int priority, const char *fmt, ...) return; } - str = malloc(str_len + 1); + str = malloc(st_add(str_len, 1)); if (!str) { warning("malloc failed: '%s'", strerror(errno)); return; @@ -43,7 +43,7 @@ void syslog(int priority, const char *fmt, ...) va_end(ap); while ((pos = strstr(str, "%1")) != NULL) { - str = realloc(str, ++str_len + 1); + str = realloc(str, st_add(++str_len, 1)); if (!str) { warning("realloc failed: '%s'", strerror(errno)); return; diff --git a/compat/winansi.c b/compat/winansi.c index ceff55bd67..5dfa5ed61f 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -23,6 +23,7 @@ static HANDLE hthread, hread, hwrite; static HANDLE hconsole1, hconsole2; #ifdef __MINGW32__ +#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 5 typedef struct _CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; @@ -32,6 +33,7 @@ typedef struct _CONSOLE_FONT_INFOEX { WCHAR FaceName[LF_FACESIZE]; } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; #endif +#endif typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX); @@ -452,7 +454,8 @@ static HANDLE duplicate_handle(HANDLE hnd) HANDLE hresult, hproc = GetCurrentProcess(); if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE, DUPLICATE_SAME_ACCESS)) - die_lasterr("DuplicateHandle(%li) failed", (long) hnd); + die_lasterr("DuplicateHandle(%li) failed", + (long) (intptr_t) hnd); return hresult; } @@ -24,6 +24,7 @@ struct config_source { size_t pos; } buf; } u; + const char *origin_type; const char *name; const char *path; int die_on_error; @@ -471,9 +472,9 @@ static int git_parse_source(config_fn_t fn, void *data) break; } if (cf->die_on_error) - die(_("bad config file line %d in %s"), cf->linenr, cf->name); + die(_("bad config line %d in %s %s"), cf->linenr, cf->origin_type, cf->name); else - return error(_("bad config file line %d in %s"), cf->linenr, cf->name); + return error(_("bad config line %d in %s %s"), cf->linenr, cf->origin_type, cf->name); } static int parse_unit_factor(const char *end, uintmax_t *val) @@ -588,9 +589,9 @@ static void die_bad_number(const char *name, const char *value) if (!value) value = ""; - if (cf && cf->name) - die(_("bad numeric config value '%s' for '%s' in %s: %s"), - value, name, cf->name, reason); + if (cf && cf->origin_type && cf->name) + die(_("bad numeric config value '%s' for '%s' in %s %s: %s"), + value, name, cf->origin_type, cf->name, reason); die(_("bad numeric config value '%s' for '%s': %s"), value, name, reason); } @@ -1061,11 +1062,13 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data) } static int do_config_from_file(config_fn_t fn, - const char *name, const char *path, FILE *f, void *data) + const char *origin_type, const char *name, const char *path, FILE *f, + void *data) { struct config_source top; top.u.file = f; + top.origin_type = origin_type; top.name = name; top.path = path; top.die_on_error = 1; @@ -1078,7 +1081,7 @@ static int do_config_from_file(config_fn_t fn, static int git_config_from_stdin(config_fn_t fn, void *data) { - return do_config_from_file(fn, "<stdin>", NULL, stdin, data); + return do_config_from_file(fn, "standard input", "", NULL, stdin, data); } int git_config_from_file(config_fn_t fn, const char *filename, void *data) @@ -1089,21 +1092,22 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data) f = fopen(filename, "r"); if (f) { flockfile(f); - ret = do_config_from_file(fn, filename, filename, f, data); + ret = do_config_from_file(fn, "file", filename, filename, f, data); funlockfile(f); fclose(f); } return ret; } -int git_config_from_buf(config_fn_t fn, const char *name, const char *buf, - size_t len, void *data) +int git_config_from_mem(config_fn_t fn, const char *origin_type, + const char *name, const char *buf, size_t len, void *data) { struct config_source top; top.u.buf.buf = buf; top.u.buf.len = len; top.u.buf.pos = 0; + top.origin_type = origin_type; top.name = name; top.path = NULL; top.die_on_error = 0; @@ -1132,7 +1136,7 @@ static int git_config_from_blob_sha1(config_fn_t fn, return error("reference '%s' does not point to a blob", name); } - ret = git_config_from_buf(fn, name, buf, size, data); + ret = git_config_from_mem(fn, "blob", name, buf, size, data); free(buf); return ret; @@ -1594,6 +1598,30 @@ int git_config_get_pathname(const char *key, const char **dest) return ret; } +int git_config_get_untracked_cache(void) +{ + int val = -1; + const char *v; + + /* Hack for test programs like test-dump-untracked-cache */ + if (ignore_untracked_cache_config) + return -1; + + if (!git_config_get_maybe_bool("core.untrackedcache", &val)) + return val; + + if (!git_config_get_value("core.untrackedcache", &v)) { + if (!strcasecmp(v, "keep")) + return -1; + + error("unknown core.untrackedCache value '%s'; " + "using 'keep' default value", v); + return -1; + } + + return -1; /* default value */ +} + NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr) { @@ -1825,15 +1853,26 @@ contline: return offset; } -int git_config_set_in_file(const char *config_filename, - const char *key, const char *value) +int git_config_set_in_file_gently(const char *config_filename, + const char *key, const char *value) { - return git_config_set_multivar_in_file(config_filename, key, value, NULL, 0); + return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0); } -int git_config_set(const char *key, const char *value) +void git_config_set_in_file(const char *config_filename, + const char *key, const char *value) { - return git_config_set_multivar(key, value, NULL, 0); + git_config_set_multivar_in_file(config_filename, key, value, NULL, 0); +} + +int git_config_set_gently(const char *key, const char *value) +{ + return git_config_set_multivar_gently(key, value, NULL, 0); +} + +void git_config_set(const char *key, const char *value) +{ + git_config_set_multivar(key, value, NULL, 0); } /* @@ -1878,7 +1917,7 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele * Validate the key and while at it, lower case it for matching. */ if (store_key) - *store_key = xmalloc(strlen(key) + 1); + *store_key = xmallocz(strlen(key)); dot = 0; for (i = 0; key[i]; i++) { @@ -1902,8 +1941,6 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele if (store_key) (*store_key)[i] = c; } - if (store_key) - (*store_key)[i] = 0; return 0; @@ -1950,9 +1987,10 @@ int git_config_key_is_valid(const char *key) * - the config file is removed and the lock file rename()d to it. * */ -int git_config_set_multivar_in_file(const char *config_filename, - const char *key, const char *value, - const char *value_regex, int multi_replace) +int git_config_set_multivar_in_file_gently(const char *config_filename, + const char *key, const char *value, + const char *value_regex, + int multi_replace) { int fd = -1, in_fd = -1; int ret; @@ -2179,11 +2217,27 @@ write_err_out: } -int git_config_set_multivar(const char *key, const char *value, - const char *value_regex, int multi_replace) +void git_config_set_multivar_in_file(const char *config_filename, + const char *key, const char *value, + const char *value_regex, int multi_replace) +{ + if (git_config_set_multivar_in_file_gently(config_filename, key, value, + value_regex, multi_replace) < 0) + die(_("Could not set '%s' to '%s'"), key, value); +} + +int git_config_set_multivar_gently(const char *key, const char *value, + const char *value_regex, int multi_replace) { - return git_config_set_multivar_in_file(NULL, key, value, value_regex, - multi_replace); + return git_config_set_multivar_in_file_gently(NULL, key, value, value_regex, + multi_replace); +} + +void git_config_set_multivar(const char *key, const char *value, + const char *value_regex, int multi_replace) +{ + git_config_set_multivar_in_file(NULL, key, value, value_regex, + multi_replace); } static int section_name_match (const char *buf, const char *name) @@ -2385,3 +2439,13 @@ int parse_config_key(const char *var, return 0; } + +const char *current_config_origin_type(void) +{ + return cf && cf->origin_type ? cf->origin_type : "command line"; +} + +const char *current_config_name(void) +{ + return cf && cf->name ? cf->name : ""; +} diff --git a/config.mak.uname b/config.mak.uname index f34dcaad20..d6f7980bb9 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -518,13 +518,12 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_INET_NTOP = YesPlease NO_POSIX_GOODIES = UnfortunatelyYes DEFAULT_HELP_FORMAT = html - COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -D_USE_32BIT_TIME_T -DNOGDI -Icompat -Icompat/win32 + COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/winansi.o \ compat/win32/pthread.o compat/win32/syslog.o \ compat/win32/dirent.o BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1 - BASIC_LDFLAGS += -Wl,--large-address-aware EXTLIBS += -lws2_32 GITLIBS += git.res PTHREAD_LIBS = @@ -541,8 +540,35 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) INTERNAL_QSORT = YesPlease HAVE_LIBCHARSET_H = YesPlease NO_GETTEXT = YesPlease + COMPAT_CLFAGS += -D__USE_MINGW_ACCESS else - NO_CURL = YesPlease + ifeq ($(shell expr "$(uname_R)" : '2\.'),2) + # MSys2 + prefix = /usr/ + ifeq (MINGW32,$(MSYSTEM)) + prefix = /mingw32 + endif + ifeq (MINGW64,$(MSYSTEM)) + prefix = /mingw64 + else + COMPAT_CFLAGS += -D_USE_32BIT_TIME_T + BASIC_LDFLAGS += -Wl,--large-address-aware + endif + CC = gcc + COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 + INSTALL = /bin/install + NO_R_TO_GCC_LINKER = YesPlease + INTERNAL_QSORT = YesPlease + HAVE_LIBCHARSET_H = YesPlease + NO_GETTEXT = + USE_GETTEXT_SCHEME = fallthrough + USE_LIBPCRE= YesPlease + NO_CURL = + USE_NED_ALLOCATOR = YesPlease + else + COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO + NO_CURL = YesPlease + endif endif endif ifeq ($(uname_S),QNX) @@ -357,6 +357,10 @@ static int git_tcp_connect_sock(char *host, int flags) port = "<none>"; memset(&hints, 0, sizeof(hints)); + if (flags & CONNECT_IPV4) + hints.ai_family = AF_INET; + else if (flags & CONNECT_IPV6) + hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; @@ -783,6 +787,10 @@ struct child_process *git_connect(int fd[2], const char *url, } argv_array_push(&conn->args, ssh); + if (flags & CONNECT_IPV4) + argv_array_push(&conn->args, "-4"); + else if (flags & CONNECT_IPV6) + argv_array_push(&conn->args, "-6"); if (tortoiseplink) argv_array_push(&conn->args, "-batch"); if (port) { @@ -3,6 +3,8 @@ #define CONNECT_VERBOSE (1u << 0) #define CONNECT_DIAG_URL (1u << 1) +#define CONNECT_IPV4 (1u << 2) +#define CONNECT_IPV6 (1u << 3) extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); extern int finish_connect(struct child_process *conn); extern int git_connection_is_socket(struct child_process *conn); diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 6956807519..e3918c87e3 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1169,7 +1169,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary --no-prefix --src-prefix= --dst-prefix= --inter-hunk-context= --patience --histogram --minimal - --raw --word-diff + --raw --word-diff --word-diff-regex= --dirstat --dirstat= --dirstat-by-file --dirstat-by-file= --cumulative --diff-algorithm= @@ -1312,6 +1312,7 @@ _git_grep () --full-name --line-number --extended-regexp --basic-regexp --fixed-strings --perl-regexp + --threads --files-with-matches --name-only --files-without-match --max-depth @@ -1687,8 +1688,12 @@ _git_rebase () --preserve-merges --stat --no-stat --committer-date-is-author-date --ignore-date --ignore-whitespace --whitespace= - --autosquash --fork-point --no-fork-point - --autostash + --autosquash --no-autosquash + --fork-point --no-fork-point + --autostash --no-autostash + --verify --no-verify + --keep-empty --root --force-rebase --no-ff + --exec " return @@ -1808,7 +1813,7 @@ _git_config () return ;; branch.*.rebase) - __gitcomp "false true" + __gitcomp "false true preserve interactive" return ;; remote.pushdefault) @@ -2055,6 +2060,7 @@ _git_config () core.sparseCheckout core.symlinks core.trustctime + core.untrackedCache core.warnAmbiguousRefs core.whitespace core.worktree @@ -2368,7 +2374,7 @@ _git_show_branch () case "$cur" in --*) __gitcomp " - --all --remotes --topo-order --current --more= + --all --remotes --topo-order --date-order --current --more= --list --independent --merge-base --no-name --color --no-color --sha1-name --sparse --topics --reflog @@ -2381,7 +2387,7 @@ _git_show_branch () _git_stash () { - local save_opts='--keep-index --no-keep-index --quiet --patch' + local save_opts='--all --keep-index --no-keep-index --quiet --patch --include-untracked' local subcommands='save list show apply clear drop pop create branch' local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then @@ -2403,9 +2409,20 @@ _git_stash () apply,--*|pop,--*) __gitcomp "--index --quiet" ;; - show,--*|drop,--*|branch,--*) + drop,--*) + __gitcomp "--quiet" + ;; + show,--*|branch,--*) + ;; + branch,*) + if [ $cword -eq 3 ]; then + __gitcomp_nl "$(__git_refs)"; + else + __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ + | sed -n -e 's/:.*//p')" + fi ;; - show,*|apply,*|drop,*|pop,*|branch,*) + show,*|apply,*|drop,*|pop,*) __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ | sed -n -e 's/:.*//p')" ;; diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh index 934505bab9..86c9cfa0c7 100755 --- a/contrib/examples/git-commit.sh +++ b/contrib/examples/git-commit.sh @@ -574,10 +574,10 @@ then if test "$templatefile" != "" then # Test whether this is just the unaltered template. - if cnt=`sed -e '/^#/d' < "$templatefile" | + if cnt=$(sed -e '/^#/d' < "$templatefile" | git stripspace | diff "$GIT_DIR"/COMMIT_BAREMSG - | - wc -l` && + wc -l) && test 0 -lt $cnt then have_commitmsg=t @@ -630,8 +630,8 @@ then fi if test -z "$quiet" then - commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\ - --abbrev --summary --root HEAD --` + commit=$(git diff-tree --always --shortstat --pretty="format:%h: %s"\ + --abbrev --summary --root HEAD --) echo "Created${initial_commit:+ initial} commit $commit" fi fi diff --git a/contrib/examples/git-fetch.sh b/contrib/examples/git-fetch.sh index 554070909c..57d2e5616f 100755 --- a/contrib/examples/git-fetch.sh +++ b/contrib/examples/git-fetch.sh @@ -146,13 +146,13 @@ esac reflist=$(get_remote_refs_for_fetch "$@") if test "$tags" then - taglist=`IFS=' ' && + taglist=$(IFS=' ' && echo "$ls_remote_result" | git show-ref --exclude-existing=refs/tags/ | while read sha1 name do echo ".${name}:${name}" - done` || exit + done) || exit if test "$#" -gt 1 then # remote URL plus explicit refspecs; we need to merge them. diff --git a/contrib/examples/git-merge.sh b/contrib/examples/git-merge.sh index 52f2aafb9d..ee99f1a4ee 100755 --- a/contrib/examples/git-merge.sh +++ b/contrib/examples/git-merge.sh @@ -523,10 +523,10 @@ do if test "$exit" -eq 1 then - cnt=`{ + cnt=$({ git diff-files --name-only git ls-files --unmerged - } | wc -l` + } | wc -l) if test $best_cnt -le 0 || test $cnt -le $best_cnt then best_strategy=$strategy diff --git a/contrib/examples/git-repack.sh b/contrib/examples/git-repack.sh index 96e3fed326..672af93443 100755 --- a/contrib/examples/git-repack.sh +++ b/contrib/examples/git-repack.sh @@ -67,8 +67,8 @@ case ",$all_into_one," in ,t,) args= existing= if [ -d "$PACKDIR" ]; then - for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \ - | sed -e 's/^\.\///' -e 's/\.pack$//'` + for e in $(cd "$PACKDIR" && find . -type f -name '*.pack' \ + | sed -e 's/^\.\///' -e 's/\.pack$//') do if [ -e "$PACKDIR/$e.keep" ]; then : keep diff --git a/contrib/examples/git-revert.sh b/contrib/examples/git-revert.sh index 7e2aad5491..197838d10b 100755 --- a/contrib/examples/git-revert.sh +++ b/contrib/examples/git-revert.sh @@ -138,8 +138,8 @@ cherry-pick) }' logmsg=$(git show -s --pretty=raw --encoding="$encoding" "$commit") - set_author_env=`echo "$logmsg" | - LANG=C LC_ALL=C sed -ne "$pick_author_script"` + set_author_env=$(echo "$logmsg" | + LANG=C LC_ALL=C sed -ne "$pick_author_script") eval "$set_author_env" export GIT_AUTHOR_NAME export GIT_AUTHOR_EMAIL @@ -160,9 +160,9 @@ cherry-pick) esac >.msg eval GITHEAD_$head=HEAD -eval GITHEAD_$next='`git show -s \ +eval GITHEAD_$next='$(git show -s \ --pretty=oneline --encoding="$encoding" "$commit" | - sed -e "s/^[^ ]* //"`' + sed -e "s/^[^ ]* //")' export GITHEAD_$head GITHEAD_$next # This three way merge is an interesting one. We are at diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile index 3071baf493..6afa9aafdf 100644 --- a/contrib/subtree/Makefile +++ b/contrib/subtree/Makefile @@ -37,6 +37,7 @@ GIT_SUBTREE_DOC := git-subtree.1 GIT_SUBTREE_XML := git-subtree.xml GIT_SUBTREE_TXT := git-subtree.txt GIT_SUBTREE_HTML := git-subtree.html +GIT_SUBTREE_TEST := ../../git-subtree all:: $(GIT_SUBTREE) @@ -71,7 +72,10 @@ $(GIT_SUBTREE_HTML): $(GIT_SUBTREE_TXT) $(ASCIIDOC) -b xhtml11 -d manpage -f $(ASCIIDOC_CONF) \ -agit_version=$(GIT_VERSION) $^ -test: +$(GIT_SUBTREE_TEST): $(GIT_SUBTREE) + cp $< $@ + +test: $(GIT_SUBTREE_TEST) $(MAKE) -C t/ test clean: diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index edf36f8c36..7a39b30ad0 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -245,7 +245,10 @@ find_latest_squash() case "$a" in START) sq="$b" ;; git-subtree-mainline:) main="$b" ;; - git-subtree-split:) sub="$b" ;; + git-subtree-split:) + sub="$(git rev-parse "$b^0")" || + die "could not rev-parse split hash $b from commit $sq" + ;; END) if [ -n "$sub" ]; then if [ -n "$main" ]; then @@ -278,7 +281,10 @@ find_existing_splits() case "$a" in START) sq="$b" ;; git-subtree-mainline:) main="$b" ;; - git-subtree-split:) sub="$b" ;; + git-subtree-split:) + sub="$(git rev-parse "$b^0")" || + die "could not rev-parse split hash $b from commit $sq" + ;; END) debug " Main is: '$main'" if [ -z "$main" -a -n "$sub" ]; then @@ -479,8 +485,16 @@ copy_or_skip() p="$p -p $parent" fi done - - if [ -n "$identical" ]; then + + copycommit= + if [ -n "$identical" ] && [ -n "$nonidentical" ]; then + extras=$(git rev-list --count $identical..$nonidentical) + if [ "$extras" -ne 0 ]; then + # we need to preserve history along the other branch + copycommit=1 + fi + fi + if [ -n "$identical" ] && [ -z "$copycommit" ]; then echo $identical else copy_commit $rev $tree "$p" || exit $? diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index 751aee3a0c..3bf96a9bb6 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -1014,4 +1014,64 @@ test_expect_success 'push split to subproj' ' ) ' +# +# This test covers 2 cases in subtree split copy_or_skip code +# 1) Merges where one parent is a superset of the changes of the other +# parent regarding changes to the subtree, in this case the merge +# commit should be copied +# 2) Merges where only one parent operate on the subtree, and the merge +# commit should be skipped +# +# (1) is checked by ensuring subtree_tip is a descendent of subtree_branch +# (2) should have a check added (not_a_subtree_change shouldn't be present +# on the produced subtree) +# +# Other related cases which are not tested (or currently handled correctly) +# - Case (1) where there are more than 2 parents, it will sometimes correctly copy +# the merge, and sometimes not +# - Merge commit where both parents have same tree as the merge, currently +# will always be skipped, even if they reached that state via different +# set of commits. +# + +next_test +test_expect_success 'subtree descendant check' ' + subtree_test_create_repo "$subtree_test_count" && + test_create_commit "$subtree_test_count" folder_subtree/a && + ( + cd "$subtree_test_count" && + git branch branch + ) && + test_create_commit "$subtree_test_count" folder_subtree/0 && + test_create_commit "$subtree_test_count" folder_subtree/b && + cherry=$(cd "$subtree_test_count"; git rev-parse HEAD) && + ( + cd "$subtree_test_count" && + git checkout branch + ) && + test_create_commit "$subtree_test_count" commit_on_branch && + ( + cd "$subtree_test_count" && + git cherry-pick $cherry && + git checkout master && + git merge -m "merge should be kept on subtree" branch && + git branch no_subtree_work_branch + ) && + test_create_commit "$subtree_test_count" folder_subtree/d && + ( + cd "$subtree_test_count" && + git checkout no_subtree_work_branch + ) && + test_create_commit "$subtree_test_count" not_a_subtree_change && + ( + cd "$subtree_test_count" && + git checkout master && + git merge -m "merge should be skipped on subtree" no_subtree_work_branch && + + git subtree split --prefix folder_subtree/ --branch subtree_tip master && + git subtree split --prefix folder_subtree/ --branch subtree_branch branch && + check_equal $(git rev-list --count subtree_tip..subtree_branch) 0 + ) +' + test_done diff --git a/contrib/thunderbird-patch-inline/appp.sh b/contrib/thunderbird-patch-inline/appp.sh index 8dc73ece15..1053872eea 100755 --- a/contrib/thunderbird-patch-inline/appp.sh +++ b/contrib/thunderbird-patch-inline/appp.sh @@ -31,8 +31,8 @@ BODY=$(sed -e "1,/${SEP}/d" $1) CMT_MSG=$(sed -e '1,/^$/d' -e '/^---$/,$d' "${PATCH}") DIFF=$(sed -e '1,/^---$/d' "${PATCH}") -CCS=`echo -e "$CMT_MSG\n$HEADERS" | sed -n -e 's/^Cc: \(.*\)$/\1,/gp' \ - -e 's/^Signed-off-by: \(.*\)/\1,/gp'` +CCS=$(echo -e "$CMT_MSG\n$HEADERS" | sed -n -e 's/^Cc: \(.*\)$/\1,/gp' \ + -e 's/^Signed-off-by: \(.*\)/\1,/gp') echo "$SUBJECT" > $1 echo "Cc: $CCS" >> $1 @@ -13,18 +13,25 @@ * translation when the "text" attribute or "auto_crlf" option is set. */ +/* Stat bits: When BIN is set, the txt bits are unset */ +#define CONVERT_STAT_BITS_TXT_LF 0x1 +#define CONVERT_STAT_BITS_TXT_CRLF 0x2 +#define CONVERT_STAT_BITS_BIN 0x4 + enum crlf_action { - CRLF_GUESS = -1, - CRLF_BINARY = 0, + CRLF_UNDEFINED, + CRLF_BINARY, CRLF_TEXT, - CRLF_INPUT, - CRLF_CRLF, - CRLF_AUTO + CRLF_TEXT_INPUT, + CRLF_TEXT_CRLF, + CRLF_AUTO, + CRLF_AUTO_INPUT, + CRLF_AUTO_CRLF }; struct text_stat { /* NUL, CR, LF and CRLF counts */ - unsigned nul, cr, lf, crlf; + unsigned nul, lonecr, lonelf, crlf; /* These are just approximations! */ unsigned printable, nonprintable; @@ -39,13 +46,15 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat * for (i = 0; i < size; i++) { unsigned char c = buf[i]; if (c == '\r') { - stats->cr++; - if (i+1 < size && buf[i+1] == '\n') + if (i+1 < size && buf[i+1] == '\n') { stats->crlf++; + i++; + } else + stats->lonecr++; continue; } if (c == '\n') { - stats->lf++; + stats->lonelf++; continue; } if (c == 127) @@ -75,23 +84,84 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat * /* * The same heuristics as diff.c::mmfile_is_binary() + * We treat files with bare CR as binary */ -static int is_binary(unsigned long size, struct text_stat *stats) +static int convert_is_binary(unsigned long size, const struct text_stat *stats) { - + if (stats->lonecr) + return 1; if (stats->nul) return 1; if ((stats->printable >> 7) < stats->nonprintable) return 1; - /* - * Other heuristics? Average line length might be relevant, - * as might LF vs CR vs CRLF counts.. - * - * NOTE! It might be normal to have a low ratio of CRLF to LF - * (somebody starts with a LF-only file and edits it with an editor - * that adds CRLF only to lines that are added..). But do we - * want to support CR-only? Probably not. - */ + return 0; +} + +static unsigned int gather_convert_stats(const char *data, unsigned long size) +{ + struct text_stat stats; + int ret = 0; + if (!data || !size) + return 0; + gather_stats(data, size, &stats); + if (convert_is_binary(size, &stats)) + ret |= CONVERT_STAT_BITS_BIN; + if (stats.crlf) + ret |= CONVERT_STAT_BITS_TXT_CRLF; + if (stats.lonelf) + ret |= CONVERT_STAT_BITS_TXT_LF; + + return ret; +} + +static const char *gather_convert_stats_ascii(const char *data, unsigned long size) +{ + unsigned int convert_stats = gather_convert_stats(data, size); + + if (convert_stats & CONVERT_STAT_BITS_BIN) + return "-text"; + switch (convert_stats) { + case CONVERT_STAT_BITS_TXT_LF: + return "lf"; + case CONVERT_STAT_BITS_TXT_CRLF: + return "crlf"; + case CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF: + return "mixed"; + default: + return "none"; + } +} + +const char *get_cached_convert_stats_ascii(const char *path) +{ + const char *ret; + unsigned long sz; + void *data = read_blob_data_from_cache(path, &sz); + ret = gather_convert_stats_ascii(data, sz); + free(data); + return ret; +} + +const char *get_wt_convert_stats_ascii(const char *path) +{ + const char *ret = ""; + struct strbuf sb = STRBUF_INIT; + if (strbuf_read_file(&sb, path, 0) >= 0) + ret = gather_convert_stats_ascii(sb.buf, sb.len); + strbuf_release(&sb); + return ret; +} + +static int text_eol_is_crlf(void) +{ + if (auto_crlf == AUTO_CRLF_TRUE) + return 1; + else if (auto_crlf == AUTO_CRLF_INPUT) + return 0; + if (core_eol == EOL_CRLF) + return 1; + if (core_eol == EOL_UNSET && EOL_NATIVE == EOL_CRLF) + return 1; return 0; } @@ -100,23 +170,19 @@ static enum eol output_eol(enum crlf_action crlf_action) switch (crlf_action) { case CRLF_BINARY: return EOL_UNSET; - case CRLF_CRLF: + case CRLF_TEXT_CRLF: return EOL_CRLF; - case CRLF_INPUT: + case CRLF_TEXT_INPUT: return EOL_LF; - case CRLF_GUESS: - if (!auto_crlf) - return EOL_UNSET; - /* fall through */ + case CRLF_UNDEFINED: + case CRLF_AUTO_CRLF: + case CRLF_AUTO_INPUT: case CRLF_TEXT: case CRLF_AUTO: - if (auto_crlf == AUTO_CRLF_TRUE) - return EOL_CRLF; - else if (auto_crlf == AUTO_CRLF_INPUT) - return EOL_LF; - else if (core_eol == EOL_UNSET) - return EOL_NATIVE; + /* fall through */ + return text_eol_is_crlf() ? EOL_CRLF : EOL_LF; } + warning("Illegal crlf_action %d\n", (int)crlf_action); return core_eol; } @@ -142,7 +208,7 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action, * CRLFs would be added by checkout: * check if we have "naked" LFs */ - if (stats->lf != stats->crlf) { + if (stats->lonelf) { if (checksafe == SAFE_CRLF_WARN) warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.", path); else /* i.e. SAFE_CRLF_FAIL */ @@ -173,7 +239,6 @@ static int crlf_to_git(const char *path, const char *src, size_t len, char *dst; if (crlf_action == CRLF_BINARY || - (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || (src && !len)) return 0; @@ -186,22 +251,11 @@ static int crlf_to_git(const char *path, const char *src, size_t len, gather_stats(src, len, &stats); - if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) { - /* - * We're currently not going to even try to convert stuff - * that has bare CR characters. Does anybody do that crazy - * stuff? - */ - if (stats.cr != stats.crlf) - return 0; - - /* - * And add some heuristics for binary vs text, of course... - */ - if (is_binary(len, &stats)) + if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) { + if (convert_is_binary(len, &stats)) return 0; - if (crlf_action == CRLF_GUESS) { + if (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) { /* * If the file in the index has any CR in it, do not convert. * This is the new safer autocrlf handling. @@ -213,8 +267,8 @@ static int crlf_to_git(const char *path, const char *src, size_t len, check_safe_crlf(path, crlf_action, &stats, checksafe); - /* Optimization: No CR? Nothing to convert, regardless. */ - if (!stats.cr) + /* Optimization: No CRLF? Nothing to convert, regardless. */ + if (!stats.crlf) return 0; /* @@ -228,7 +282,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len, if (strbuf_avail(buf) + buf->len < len) strbuf_grow(buf, len - buf->len); dst = buf->buf; - if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) { + if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) { /* * If we guessed, we already know we rejected a file with * lone CR, and we can strip a CR without looking at what @@ -261,27 +315,19 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len, gather_stats(src, len, &stats); - /* No LF? Nothing to convert, regardless. */ - if (!stats.lf) + /* No "naked" LF? Nothing to convert, regardless. */ + if (!stats.lonelf) return 0; - /* Was it already in CRLF format? */ - if (stats.lf == stats.crlf) - return 0; - - if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) { - if (crlf_action == CRLF_GUESS) { + if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) { + if (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) { /* If we have any CR or CRLF line endings, we do not touch it */ /* This is the new safer autocrlf-handling */ - if (stats.cr > 0 || stats.crlf > 0) + if (stats.lonecr || stats.crlf ) return 0; } - /* If we have any bare CR characters, we're not going to touch it */ - if (stats.cr != stats.crlf) - return 0; - - if (is_binary(len, &stats)) + if (convert_is_binary(len, &stats)) return 0; } @@ -289,7 +335,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len, if (src == buf->buf) to_free = strbuf_detach(buf, NULL); - strbuf_grow(buf, len + stats.lf - stats.crlf); + strbuf_grow(buf, len + stats.lonelf); for (;;) { const char *nl = memchr(src, '\n', len); if (!nl) @@ -395,7 +441,7 @@ static int apply_filter(const char *path, const char *src, size_t len, int fd, struct async async; struct filter_params params; - if (!cmd) + if (!cmd || !*cmd) return 0; if (!dst) @@ -657,7 +703,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len, return 1; } -static enum crlf_action git_path_check_crlf(const char *path, struct git_attr_check *check) +static enum crlf_action git_path_check_crlf(struct git_attr_check *check) { const char *value = check->value; @@ -668,13 +714,13 @@ static enum crlf_action git_path_check_crlf(const char *path, struct git_attr_ch else if (ATTR_UNSET(value)) ; else if (!strcmp(value, "input")) - return CRLF_INPUT; + return CRLF_TEXT_INPUT; else if (!strcmp(value, "auto")) return CRLF_AUTO; - return CRLF_GUESS; + return CRLF_UNDEFINED; } -static enum eol git_path_check_eol(const char *path, struct git_attr_check *check) +static enum eol git_path_check_eol(struct git_attr_check *check) { const char *value = check->value; @@ -687,8 +733,7 @@ static enum eol git_path_check_eol(const char *path, struct git_attr_check *chec return EOL_UNSET; } -static struct convert_driver *git_path_check_convert(const char *path, - struct git_attr_check *check) +static struct convert_driver *git_path_check_convert(struct git_attr_check *check) { const char *value = check->value; struct convert_driver *drv; @@ -701,28 +746,17 @@ static struct convert_driver *git_path_check_convert(const char *path, return NULL; } -static int git_path_check_ident(const char *path, struct git_attr_check *check) +static int git_path_check_ident(struct git_attr_check *check) { const char *value = check->value; return !!ATTR_TRUE(value); } -static enum crlf_action input_crlf_action(enum crlf_action text_attr, enum eol eol_attr) -{ - if (text_attr == CRLF_BINARY) - return CRLF_BINARY; - if (eol_attr == EOL_LF) - return CRLF_INPUT; - if (eol_attr == EOL_CRLF) - return CRLF_CRLF; - return text_attr; -} - struct conv_attrs { struct convert_driver *drv; - enum crlf_action crlf_action; - enum eol eol_attr; + enum crlf_action attr_action; /* What attr says */ + enum crlf_action crlf_action; /* When no attr is set, use core.autocrlf */ int ident; }; @@ -744,18 +778,33 @@ static void convert_attrs(struct conv_attrs *ca, const char *path) } if (!git_check_attr(path, NUM_CONV_ATTRS, ccheck)) { - ca->crlf_action = git_path_check_crlf(path, ccheck + 4); - if (ca->crlf_action == CRLF_GUESS) - ca->crlf_action = git_path_check_crlf(path, ccheck + 0); - ca->ident = git_path_check_ident(path, ccheck + 1); - ca->drv = git_path_check_convert(path, ccheck + 2); - ca->eol_attr = git_path_check_eol(path, ccheck + 3); + ca->crlf_action = git_path_check_crlf(ccheck + 4); + if (ca->crlf_action == CRLF_UNDEFINED) + ca->crlf_action = git_path_check_crlf(ccheck + 0); + ca->attr_action = ca->crlf_action; + ca->ident = git_path_check_ident(ccheck + 1); + ca->drv = git_path_check_convert(ccheck + 2); + if (ca->crlf_action != CRLF_BINARY) { + enum eol eol_attr = git_path_check_eol(ccheck + 3); + if (eol_attr == EOL_LF) + ca->crlf_action = CRLF_TEXT_INPUT; + else if (eol_attr == EOL_CRLF) + ca->crlf_action = CRLF_TEXT_CRLF; + } + ca->attr_action = ca->crlf_action; } else { ca->drv = NULL; - ca->crlf_action = CRLF_GUESS; - ca->eol_attr = EOL_UNSET; + ca->crlf_action = CRLF_UNDEFINED; ca->ident = 0; } + if (ca->crlf_action == CRLF_TEXT) + ca->crlf_action = text_eol_is_crlf() ? CRLF_TEXT_CRLF : CRLF_TEXT_INPUT; + if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_FALSE) + ca->crlf_action = CRLF_BINARY; + if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_TRUE) + ca->crlf_action = CRLF_AUTO_CRLF; + if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_INPUT) + ca->crlf_action = CRLF_AUTO_INPUT; } int would_convert_to_git_filter_fd(const char *path) @@ -777,6 +826,32 @@ int would_convert_to_git_filter_fd(const char *path) return apply_filter(path, NULL, 0, -1, NULL, ca.drv->clean); } +const char *get_convert_attr_ascii(const char *path) +{ + struct conv_attrs ca; + + convert_attrs(&ca, path); + switch (ca.attr_action) { + case CRLF_UNDEFINED: + return ""; + case CRLF_BINARY: + return "-text"; + case CRLF_TEXT: + return "text"; + case CRLF_TEXT_INPUT: + return "text eol=lf"; + case CRLF_TEXT_CRLF: + return "text eol=crlf"; + case CRLF_AUTO: + return "text=auto"; + case CRLF_AUTO_CRLF: + return "text=auto eol=crlf"; /* This is not supported yet */ + case CRLF_AUTO_INPUT: + return "text=auto eol=lf"; /* This is not supported yet */ + } + return ""; +} + int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst, enum safe_crlf checksafe) { @@ -799,7 +874,6 @@ int convert_to_git(const char *path, const char *src, size_t len, src = dst->buf; len = dst->len; } - ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr); ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe); if (ret && dst) { src = dst->buf; @@ -820,7 +894,6 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst, if (!apply_filter(path, NULL, 0, fd, dst, ca.drv->clean)) die("%s: clean filter '%s' failed", path, ca.drv->name); - ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr); crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe); ident_to_git(path, dst->buf, dst->len, dst, ca.ident); } @@ -850,7 +923,6 @@ static int convert_to_working_tree_internal(const char *path, const char *src, * is a smudge filter. The filter might expect CRLFs. */ if (filter || !normalizing) { - ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr); ret |= crlf_to_worktree(path, src, len, dst, ca.crlf_action); if (ret) { src = dst->buf; @@ -1319,14 +1391,15 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s if (ca.ident) filter = ident_filter(sha1); - crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr); + crlf_action = ca.crlf_action; - if ((crlf_action == CRLF_BINARY) || (crlf_action == CRLF_INPUT) || - (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE)) + if ((crlf_action == CRLF_BINARY) || + crlf_action == CRLF_AUTO_INPUT || + (crlf_action == CRLF_TEXT_INPUT)) filter = cascade_filter(filter, &null_filter_singleton); else if (output_eol(crlf_action) == EOL_CRLF && - !(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS)) + !(crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_CRLF)) filter = cascade_filter(filter, lf_to_crlf_filter()); return filter; @@ -32,6 +32,9 @@ enum eol { }; extern enum eol core_eol; +extern const char *get_cached_convert_stats_ascii(const char *path); +extern const char *get_wt_convert_stats_ascii(const char *path); +extern const char *get_convert_attr_ascii(const char *path); /* returns 1 if *dst was used */ extern int convert_to_git(const char *path, const char *src, size_t len, diff --git a/credential-cache--daemon.c b/credential-cache--daemon.c index 9365f2ce5c..caef21e4fc 100644 --- a/credential-cache--daemon.c +++ b/credential-cache--daemon.c @@ -96,12 +96,12 @@ static int read_request(FILE *fh, struct credential *c, static struct strbuf item = STRBUF_INIT; const char *p; - strbuf_getline(&item, fh, '\n'); + strbuf_getline_lf(&item, fh); if (!skip_prefix(item.buf, "action=", &p)) return error("client sent bogus action line: %s", item.buf); strbuf_addstr(action, p); - strbuf_getline(&item, fh, '\n'); + strbuf_getline_lf(&item, fh); if (!skip_prefix(item.buf, "timeout=", &p)) return error("client sent bogus timeout line: %s", item.buf); *timeout = atoi(p); @@ -215,7 +215,7 @@ static const char permissions_advice[] = "users may be able to read your cached credentials. Consider running:\n" "\n" " chmod 0700 %s"; -static void check_socket_directory(const char *path) +static void init_socket_directory(const char *path) { struct stat st; char *path_copy = xstrdup(path); @@ -224,20 +224,27 @@ static void check_socket_directory(const char *path) if (!stat(dir, &st)) { if (st.st_mode & 077) die(permissions_advice, dir); - free(path_copy); - return; + } else { + /* + * We must be sure to create the directory with the correct mode, + * not just chmod it after the fact; otherwise, there is a race + * condition in which somebody can chdir to it, sleep, then try to open + * our protected socket. + */ + if (safe_create_leading_directories_const(dir) < 0) + die_errno("unable to create directories for '%s'", dir); + if (mkdir(dir, 0700) < 0) + die_errno("unable to mkdir '%s'", dir); } - /* - * We must be sure to create the directory with the correct mode, - * not just chmod it after the fact; otherwise, there is a race - * condition in which somebody can chdir to it, sleep, then try to open - * our protected socket. - */ - if (safe_create_leading_directories_const(dir) < 0) - die_errno("unable to create directories for '%s'", dir); - if (mkdir(dir, 0700) < 0) - die_errno("unable to mkdir '%s'", dir); + if (chdir(dir)) + /* + * We don't actually care what our cwd is; we chdir here just to + * be a friendly daemon and avoid tying up our original cwd. + * If this fails, it's OK to just continue without that benefit. + */ + ; + free(path_copy); } @@ -264,7 +271,10 @@ int main(int argc, const char **argv) if (!socket_path) usage_with_options(usage, options); - check_socket_directory(socket_path); + if (!is_absolute_path(socket_path)) + die("socket directory must be an absolute path"); + + init_socket_directory(socket_path); register_tempfile(&socket_file, socket_path); if (ignore_sighup) diff --git a/credential-store.c b/credential-store.c index 54c4e04737..57141679ab 100644 --- a/credential-store.c +++ b/credential-store.c @@ -23,7 +23,7 @@ static int parse_credential_file(const char *fn, return found_credential; } - while (strbuf_getline(&line, fh, '\n') != EOF) { + while (strbuf_getline_lf(&line, fh) != EOF) { credential_from_url(&entry, line.buf); if (entry.username && entry.password && credential_match(c, &entry)) { diff --git a/credential.c b/credential.c index b146ad8481..7d6501d190 100644 --- a/credential.c +++ b/credential.c @@ -142,7 +142,7 @@ int credential_read(struct credential *c, FILE *fp) { struct strbuf line = STRBUF_INIT; - while (strbuf_getline(&line, fp, '\n') != EOF) { + while (strbuf_getline_lf(&line, fp) != EOF) { char *key = line.buf; char *value = strchr(key, '='); @@ -424,7 +424,7 @@ static void copy_to_log(int fd) return; } - while (strbuf_getline(&line, fp, '\n') != EOF) { + while (strbuf_getline_lf(&line, fp) != EOF) { logerror("%s", line.buf); strbuf_setlen(&line, 0); } @@ -808,7 +808,7 @@ static void check_dead_children(void) cradle = &blanket->next; } -static char **cld_argv; +static struct argv_array cld_argv = ARGV_ARRAY_INIT; static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen) { struct child_process cld = CHILD_PROCESS_INIT; @@ -842,7 +842,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen) #endif } - cld.argv = (const char **)cld_argv; + cld.argv = cld_argv.argv; cld.in = incoming; cld.out = dup(incoming); @@ -1374,12 +1374,10 @@ int main(int argc, char **argv) write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid()); /* prepare argv for serving-processes */ - cld_argv = xmalloc(sizeof (char *) * (argc + 2)); - cld_argv[0] = argv[0]; /* git-daemon */ - cld_argv[1] = "--serve"; + argv_array_push(&cld_argv, argv[0]); /* git-daemon */ + argv_array_push(&cld_argv, "--serve"); for (i = 1; i < argc; ++i) - cld_argv[i+1] = argv[i]; - cld_argv[argc+1] = NULL; + argv_array_push(&cld_argv, argv[i]); return serve(&listen_addr, listen_port, cred); } diff --git a/diff-no-index.c b/diff-no-index.c index 8e0fd270b5..03daadb25a 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -237,12 +237,12 @@ static void fixup_paths(const char **path, struct strbuf *replacement) } void diff_no_index(struct rev_info *revs, - int argc, const char **argv, - const char *prefix) + int argc, const char **argv) { int i, prefixlen; const char *paths[2]; struct strbuf replacement = STRBUF_INIT; + const char *prefix = revs->prefix; diff_setup(&revs->diffopt); for (i = 1; i < argc - 2; ) { @@ -252,7 +252,8 @@ void diff_no_index(struct rev_info *revs, else if (!strcmp(argv[i], "--")) i++; else { - j = diff_opt_parse(&revs->diffopt, argv + i, argc - i); + j = diff_opt_parse(&revs->diffopt, argv + i, argc - i, + revs->prefix); if (j <= 0) die("invalid diff option/value: %s", argv[i]); i += j; @@ -2607,12 +2607,9 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, struct diff_filespec *alloc_filespec(const char *path) { - int namelen = strlen(path); - struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1); + struct diff_filespec *spec; - memset(spec, 0, sizeof(*spec)); - spec->path = (char *)(spec + 1); - memcpy(spec->path, path, namelen+1); + FLEXPTR_ALLOC_STR(spec, path, path); spec->count = 1; spec->is_binary = -1; return spec; @@ -2707,21 +2704,21 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int static int diff_populate_gitlink(struct diff_filespec *s, int size_only) { - int len; - char *data = xmalloc(100), *dirty = ""; + struct strbuf buf = STRBUF_INIT; + char *dirty = ""; /* Are we looking at the work tree? */ if (s->dirty_submodule) dirty = "-dirty"; - len = snprintf(data, 100, - "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty); - s->data = data; - s->size = len; - s->should_free = 1; + strbuf_addf(&buf, "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty); + s->size = buf.len; if (size_only) { s->data = NULL; - free(data); + strbuf_release(&buf); + } else { + s->data = strbuf_detach(&buf, NULL); + s->should_free = 1; } return 0; } @@ -3693,12 +3690,16 @@ static int parse_ws_error_highlight(struct diff_options *opt, const char *arg) return 1; } -int diff_opt_parse(struct diff_options *options, const char **av, int ac) +int diff_opt_parse(struct diff_options *options, + const char **av, int ac, const char *prefix) { const char *arg = av[0]; const char *optarg; int argcount; + if (!prefix) + prefix = ""; + /* Output format options */ if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch") || opt_arg(arg, 'U', "unified", &options->context)) @@ -3915,7 +3916,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (!strcmp(arg, "--pickaxe-regex")) options->pickaxe_opts |= DIFF_PICKAXE_REGEX; else if ((argcount = short_opt('O', av, &optarg))) { - options->orderfile = optarg; + const char *path = prefix_filename(prefix, strlen(prefix), optarg); + options->orderfile = xstrdup(path); return argcount; } else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) { @@ -3954,9 +3956,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (!strcmp(arg, "--no-function-context")) DIFF_OPT_CLR(options, FUNCCONTEXT); else if ((argcount = parse_long_opt("output", av, &optarg))) { - options->file = fopen(optarg, "w"); + const char *path = prefix_filename(prefix, strlen(prefix), optarg); + options->file = fopen(path, "w"); if (!options->file) - die_errno("Could not open '%s'", optarg); + die_errno("Could not open '%s'", path); options->close_file = 1; return argcount; } else @@ -5079,7 +5082,7 @@ size_t fill_textconv(struct userdiff_driver *driver, { size_t size; - if (!driver || !driver->textconv) { + if (!driver) { if (!DIFF_FILE_VALID(df)) { *outbuf = ""; return 0; @@ -5090,6 +5093,9 @@ size_t fill_textconv(struct userdiff_driver *driver, return df->size; } + if (!driver->textconv) + die("BUG: fill_textconv called with non-textconv driver"); + if (driver->textconv_cache && df->sha1_valid) { *outbuf = notes_cache_get(driver->textconv_cache, df->sha1, &size); @@ -91,7 +91,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data) #define DIFF_OPT_DIRSTAT_BY_LINE (1 << 28) #define DIFF_OPT_FUNCCONTEXT (1 << 29) #define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30) -#define DIFF_OPT_DEFAULT_FOLLOW_RENAMES (1 << 31) +#define DIFF_OPT_DEFAULT_FOLLOW_RENAMES (1U << 31) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_TOUCHED(opts, flag) ((opts)->touched_flags & DIFF_OPT_##flag) @@ -222,8 +222,8 @@ struct combine_diff_path { } parent[FLEX_ARRAY]; }; #define combine_diff_path_size(n, l) \ - (sizeof(struct combine_diff_path) + \ - sizeof(struct combine_diff_parent) * (n) + (l) + 1) + st_add4(sizeof(struct combine_diff_path), (l), 1, \ + st_mult(sizeof(struct combine_diff_parent), (n))) extern void show_combined_diff(struct combine_diff_path *elem, int num_parent, int dense, struct rev_info *); @@ -268,7 +268,7 @@ extern int parse_long_opt(const char *opt, const char **argv, extern int git_diff_basic_config(const char *var, const char *value, void *cb); extern int git_diff_ui_config(const char *var, const char *value, void *cb); extern void diff_setup(struct diff_options *); -extern int diff_opt_parse(struct diff_options *, const char **, int); +extern int diff_opt_parse(struct diff_options *, const char **, int, const char *); extern void diff_setup_done(struct diff_options *); #define DIFF_DETECT_RENAME 1 @@ -345,14 +345,30 @@ extern int diff_flush_patch_id(struct diff_options *, unsigned char *); extern int diff_result_code(struct diff_options *, int); -extern void diff_no_index(struct rev_info *, int, const char **, const char *); +extern void diff_no_index(struct rev_info *, int, const char **); extern int index_differs_from(const char *def, int diff_flags); +/* + * Fill the contents of the filespec "df", respecting any textconv defined by + * its userdiff driver. The "driver" parameter must come from a + * previous call to get_textconv(), and therefore should either be NULL or have + * textconv enabled. + * + * Note that the memory ownership of the resulting buffer depends on whether + * the driver field is NULL. If it is, then the memory belongs to the filespec + * struct. If it is non-NULL, then "outbuf" points to a newly allocated buffer + * that should be freed by the caller. + */ extern size_t fill_textconv(struct userdiff_driver *driver, struct diff_filespec *df, char **outbuf); +/* + * Look up the userdiff driver for the given filespec, and return it if + * and only if it has textconv enabled (otherwise return NULL). The result + * can be passed to fill_textconv(). + */ extern struct userdiff_driver *get_textconv(struct diff_filespec *one); extern int parse_rename_score(const char **cp_p); diff --git a/diffcore-delta.c b/diffcore-delta.c index 7cf431d261..4159748a70 100644 --- a/diffcore-delta.c +++ b/diffcore-delta.c @@ -53,7 +53,8 @@ static struct spanhash_top *spanhash_rehash(struct spanhash_top *orig) int osz = 1 << orig->alloc_log2; int sz = osz << 1; - new = xmalloc(sizeof(*orig) + sizeof(struct spanhash) * sz); + new = xmalloc(st_add(sizeof(*orig), + st_mult(sizeof(struct spanhash), sz))); new->alloc_log2 = orig->alloc_log2 + 1; new->free = INITIAL_FREE(new->alloc_log2); memset(new->data, 0, sizeof(struct spanhash) * sz); @@ -130,7 +131,8 @@ static struct spanhash_top *hash_chars(struct diff_filespec *one) int is_text = !diff_filespec_is_binary(one); i = INITIAL_HASH_SIZE; - hash = xmalloc(sizeof(*hash) + sizeof(struct spanhash) * (1<<i)); + hash = xmalloc(st_add(sizeof(*hash), + st_mult(sizeof(struct spanhash), 1<<i))); hash->alloc_log2 = i; hash->free = INITIAL_FREE(i); memset(hash->data, 0, sizeof(struct spanhash) * (1<<i)); diff --git a/diffcore-order.c b/diffcore-order.c index 97dd3d0095..69d41f7a57 100644 --- a/diffcore-order.c +++ b/diffcore-order.c @@ -52,7 +52,7 @@ static void prepare_order(const char *orderfile) } if (pass == 0) { order_cnt = cnt; - order = xmalloc(sizeof(*order) * cnt); + ALLOC_ARRAY(order, cnt); } } } @@ -120,7 +120,7 @@ void diffcore_order(const char *orderfile) if (!q->nr) return; - o = xmalloc(sizeof(*o) * q->nr); + ALLOC_ARRAY(o, q->nr); for (i = 0; i < q->nr; i++) o[i].obj = q->queue[i]; order_objects(orderfile, pair_pathtwo, o, q->nr); diff --git a/diffcore-rename.c b/diffcore-rename.c index af1fe08861..3b3c1ed535 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -537,7 +537,7 @@ void diffcore_rename(struct diff_options *options) rename_dst_nr * rename_src_nr, 50, 1); } - mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx)); + mx = xcalloc(st_mult(num_create, NUM_CANDIDATE_PER_DST), sizeof(*mx)); for (dst_cnt = i = 0; i < rename_dst_nr; i++) { struct diff_filespec *two = rename_dst[i].two; struct diff_score *m; @@ -53,6 +53,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, int check_only, const struct path_simplify *simplify); static int get_dtype(struct dirent *de, const char *path, int len); +static struct trace_key trace_exclude = TRACE_KEY_INIT(EXCLUDE); + /* helper string functions with support for the ignore_case flag */ int strcmp_icase(const char *a, const char *b) { @@ -503,12 +505,7 @@ void add_exclude(const char *string, const char *base, parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen); if (flags & EXC_FLAG_MUSTBEDIR) { - char *s; - x = xmalloc(sizeof(*x) + patternlen + 1); - s = (char *)(x+1); - memcpy(s, string, patternlen); - s[patternlen] = '\0'; - x->pattern = s; + FLEXPTR_ALLOC_MEM(x, pattern, string, patternlen); } else { x = xmalloc(sizeof(*x)); x->pattern = string; @@ -519,6 +516,7 @@ void add_exclude(const char *string, const char *base, x->baselen = baselen; x->flags = flags; x->srcpos = srcpos; + string_list_init(&x->sticky_paths, 1); ALLOC_GROW(el->excludes, el->nr + 1, el->alloc); el->excludes[el->nr++] = x; x->el = el; @@ -559,14 +557,14 @@ void clear_exclude_list(struct exclude_list *el) { int i; - for (i = 0; i < el->nr; i++) + for (i = 0; i < el->nr; i++) { + string_list_clear(&el->excludes[i]->sticky_paths, 0); free(el->excludes[i]); + } free(el->excludes); free(el->filebuf); - el->nr = 0; - el->excludes = NULL; - el->filebuf = NULL; + memset(el, 0, sizeof(*el)); } static void trim_trailing_spaces(char *buf) @@ -627,10 +625,7 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc, } uc->dir_created++; - d = xmalloc(sizeof(*d) + len + 1); - memset(d, 0, sizeof(*d)); - memcpy(d->name, name, len); - d->name[len] = '\0'; + FLEX_ALLOC_MEM(d, name, name, len); ALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc); memmove(dir->dirs + first + 1, dir->dirs + first, @@ -699,7 +694,7 @@ static int add_excludes(const char *fname, const char *base, int baselen, return 0; } if (buf[size-1] != '\n') { - buf = xrealloc(buf, size+1); + buf = xrealloc(buf, st_add(size, 1)); buf[size++] = '\n'; } } else { @@ -713,7 +708,7 @@ static int add_excludes(const char *fname, const char *base, int baselen, close(fd); return 0; } - buf = xmalloc(size+1); + buf = xmallocz(size); if (read_in_full(fd, buf, size) != size) { free(buf); close(fd); @@ -880,26 +875,7 @@ int match_pathname(const char *pathname, int pathlen, * then our prefix match is all we need; we * do not need to call fnmatch at all. */ - if (!patternlen && !namelen) - return 1; - /* - * This can happen when we ignore some exclude rules - * on directories in other to see if negative rules - * may match. E.g. - * - * /abc - * !/abc/def/ghi - * - * The pattern of interest is "/abc". On the first - * try, we should match path "abc" with this pattern - * in the "if" statement right above, but the caller - * ignores it. - * - * On the second try with paths within "abc", - * e.g. "abc/xyz", we come here and try to match it - * with "/abc". - */ - if (!patternlen && namelen && *name == '/') + if (!patternlen && (!namelen || *name == '/')) return 1; } @@ -908,18 +884,62 @@ int match_pathname(const char *pathname, int pathlen, WM_PATHNAME) == 0; } +static void add_sticky(struct exclude *exc, const char *pathname, int pathlen) +{ + struct strbuf sb = STRBUF_INIT; + int i; + + for (i = exc->sticky_paths.nr - 1; i >= 0; i--) { + const char *sticky = exc->sticky_paths.items[i].string; + int len = strlen(sticky); + + if (pathlen < len && sticky[pathlen] == '/' && + !strncmp(pathname, sticky, pathlen)) + return; + } + + strbuf_add(&sb, pathname, pathlen); + string_list_append_nodup(&exc->sticky_paths, strbuf_detach(&sb, NULL)); +} + +static int match_sticky(struct exclude *exc, const char *pathname, int pathlen, int dtype) +{ + int i; + + for (i = exc->sticky_paths.nr - 1; i >= 0; i--) { + const char *sticky = exc->sticky_paths.items[i].string; + int len = strlen(sticky); + + if (pathlen == len && dtype == DT_DIR && + !strncmp(pathname, sticky, len)) + return 1; + + if (pathlen > len && pathname[len] == '/' && + !strncmp(pathname, sticky, len)) + return 1; + } + + return 0; +} + +static inline int different_decisions(const struct exclude *a, + const struct exclude *b) +{ + return (a->flags & EXC_FLAG_NEGATIVE) != (b->flags & EXC_FLAG_NEGATIVE); +} + /* * Return non-zero if pathname is a directory and an ancestor of the - * literal path in a (negative) pattern. This is used to keep - * descending in "foo" and "foo/bar" when the pattern is - * "!foo/bar/.gitignore". "foo/notbar" will not be descended however. + * literal path in a pattern. */ -static int match_neg_path(const char *pathname, int pathlen, int *dtype, - const char *base, int baselen, - const char *pattern, int prefix, int patternlen, - int flags) +static int match_directory_part(const char *pathname, int pathlen, + int *dtype, struct exclude *x) { - assert((flags & EXC_FLAG_NEGATIVE) && !(flags & EXC_FLAG_NODIR)); + const char *base = x->base; + int baselen = x->baselen ? x->baselen - 1 : 0; + const char *pattern = x->pattern; + int prefix = x->nowildcardlen; + int patternlen = x->patternlen; if (*dtype == DT_UNKNOWN) *dtype = get_dtype(NULL, pathname, pathlen); @@ -943,13 +963,34 @@ static int match_neg_path(const char *pathname, int pathlen, int *dtype, if (prefix && - ((pathlen < prefix && pattern[pathlen] == '/') && + (((pathlen < prefix && pattern[pathlen] == '/') || + pathlen == prefix) && !strncmp_icase(pathname, pattern, pathlen))) return 1; return 0; } +static struct exclude *should_descend(const char *pathname, int pathlen, + int *dtype, struct exclude_list *el, + struct exclude *exc) +{ + int i; + + for (i = el->nr - 1; 0 <= i; i--) { + struct exclude *x = el->excludes[i]; + + if (x == exc) + break; + + if (!(x->flags & EXC_FLAG_NODIR) && + different_decisions(x, exc) && + match_directory_part(pathname, pathlen, dtype, x)) + return x; + } + return NULL; +} + /* * Scan the given exclude list in reverse to see whether pathname * should be ignored. The first match (i.e. the last on the list), if @@ -963,16 +1004,32 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname, struct exclude_list *el) { struct exclude *exc = NULL; /* undecided */ - int i, matched_negative_path = 0; + int i, maybe_descend = 0; if (!el->nr) return NULL; /* undefined */ + trace_printf_key(&trace_exclude, "exclude: from %s\n", el->src); + for (i = el->nr - 1; 0 <= i; i--) { struct exclude *x = el->excludes[i]; const char *exclude = x->pattern; int prefix = x->nowildcardlen; + if (!maybe_descend && i < el->nr - 1 && + different_decisions(x, el->excludes[i+1])) + maybe_descend = 1; + + if (x->sticky_paths.nr) { + if (*dtype == DT_UNKNOWN) + *dtype = get_dtype(NULL, pathname, pathlen); + if (match_sticky(x, pathname, pathlen, *dtype)) { + exc = x; + break; + } + continue; + } + if (x->flags & EXC_FLAG_MUSTBEDIR) { if (*dtype == DT_UNKNOWN) *dtype = get_dtype(NULL, pathname, pathlen); @@ -998,18 +1055,46 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname, exc = x; break; } + } - if ((x->flags & EXC_FLAG_NEGATIVE) && !matched_negative_path && - match_neg_path(pathname, pathlen, dtype, x->base, - x->baselen ? x->baselen - 1 : 0, - exclude, prefix, x->patternlen, x->flags)) - matched_negative_path = 1; - } - if (exc && - !(exc->flags & EXC_FLAG_NEGATIVE) && - !(exc->flags & EXC_FLAG_NODIR) && - matched_negative_path) - exc = NULL; + if (!exc) { + trace_printf_key(&trace_exclude, "exclude: %.*s => n/a\n", + pathlen, pathname); + return NULL; + } + + /* + * We have found a matching pattern "exc" that may exclude whole + * directory. We also found that there may be a pattern that matches + * something inside the directory and reincludes stuff. + * + * Go through the patterns again, find that pattern and double check. + * If it's true, return "undecided" and keep descending in. "exc" is + * marked sticky so that it continues to match inside the directory. + */ + if (!(exc->flags & EXC_FLAG_NEGATIVE) && maybe_descend) { + struct exclude *x; + + if (*dtype == DT_UNKNOWN) + *dtype = get_dtype(NULL, pathname, pathlen); + + if (*dtype == DT_DIR && + (x = should_descend(pathname, pathlen, dtype, el, exc))) { + add_sticky(exc, pathname, pathlen); + trace_printf_key(&trace_exclude, + "exclude: %.*s vs %s at line %d => %s," + " forced open by %s at line %d => n/a\n", + pathlen, pathname, exc->pattern, exc->srcpos, + exc->flags & EXC_FLAG_NEGATIVE ? "no" : "yes", + x->pattern, x->srcpos); + return NULL; + } + } + + trace_printf_key(&trace_exclude, "exclude: %.*s vs %s at line %d => %s%s\n", + pathlen, pathname, exc->pattern, exc->srcpos, + exc->flags & EXC_FLAG_NEGATIVE ? "no" : "yes", + exc->sticky_paths.nr ? " (stuck)" : ""); return exc; } @@ -1241,10 +1326,8 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len) { struct dir_entry *ent; - ent = xmalloc(sizeof(*ent) + len + 1); + FLEX_ALLOC_MEM(ent, name, pathname, len); ent->len = len; - memcpy(ent->name, pathname, len); - ent->name[len] = 0; return ent; } @@ -1757,9 +1840,13 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, struct cached_dir cdir; enum path_treatment state, subdir_state, dir_state = path_none; struct strbuf path = STRBUF_INIT; + static int level = 0; strbuf_add(&path, base, baselen); + trace_printf_key(&trace_exclude, "exclude: [%d] enter '%.*s'\n", + level++, baselen, base); + if (open_cached_dir(&cdir, dir, untracked, &path, check_only)) goto out; @@ -1823,6 +1910,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, } close_cached_dir(&cdir); out: + trace_printf_key(&trace_exclude, "exclude: [%d] leave '%.*s'\n", + --level, baselen, base); strbuf_release(&path); return dir_state; @@ -1913,31 +2002,67 @@ static const char *get_ident_string(void) return sb.buf; if (uname(&uts) < 0) die_errno(_("failed to get kernel name and information")); - strbuf_addf(&sb, "Location %s, system %s %s %s", get_git_work_tree(), - uts.sysname, uts.release, uts.version); + strbuf_addf(&sb, "Location %s, system %s", get_git_work_tree(), + uts.sysname); return sb.buf; } static int ident_in_untracked(const struct untracked_cache *uc) { - const char *end = uc->ident.buf + uc->ident.len; - const char *p = uc->ident.buf; + /* + * Previous git versions may have saved many NUL separated + * strings in the "ident" field, but it is insane to manage + * many locations, so just take care of the first one. + */ - for (p = uc->ident.buf; p < end; p += strlen(p) + 1) - if (!strcmp(p, get_ident_string())) - return 1; - return 0; + return !strcmp(uc->ident.buf, get_ident_string()); } -void add_untracked_ident(struct untracked_cache *uc) +static void set_untracked_ident(struct untracked_cache *uc) { - if (ident_in_untracked(uc)) - return; + strbuf_reset(&uc->ident); strbuf_addstr(&uc->ident, get_ident_string()); - /* this strbuf contains a list of strings, save NUL too */ + + /* + * This strbuf used to contain a list of NUL separated + * strings, so save NUL too for backward compatibility. + */ strbuf_addch(&uc->ident, 0); } +static void new_untracked_cache(struct index_state *istate) +{ + struct untracked_cache *uc = xcalloc(1, sizeof(*uc)); + strbuf_init(&uc->ident, 100); + uc->exclude_per_dir = ".gitignore"; + /* should be the same flags used by git-status */ + uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; + set_untracked_ident(uc); + istate->untracked = uc; + istate->cache_changed |= UNTRACKED_CHANGED; +} + +void add_untracked_cache(struct index_state *istate) +{ + if (!istate->untracked) { + new_untracked_cache(istate); + } else { + if (!ident_in_untracked(istate->untracked)) { + free_untracked_cache(istate->untracked); + new_untracked_cache(istate); + } + } +} + +void remove_untracked_cache(struct index_state *istate) +{ + if (istate->untracked) { + free_untracked_cache(istate->untracked); + istate->untracked = NULL; + istate->cache_changed |= UNTRACKED_CHANGED; + } +} + static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir, int base_len, const struct pathspec *pathspec) @@ -1995,7 +2120,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d return NULL; if (!ident_in_untracked(dir->untracked)) { - warning(_("Untracked cache is disabled on this system.")); + warning(_("Untracked cache is disabled on this system or location.")); return NULL; } @@ -2023,6 +2148,25 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d return root; } +static void clear_sticky(struct dir_struct *dir) +{ + struct exclude_list_group *g; + struct exclude_list *el; + struct exclude *x; + int i, j, k; + + for (i = EXC_CMDL; i <= EXC_FILE; i++) { + g = &dir->exclude_list_group[i]; + for (j = g->nr - 1; j >= 0; j--) { + el = &g->el[j]; + for (k = el->nr - 1; 0 <= k; k--) { + x = el->excludes[k]; + string_list_clear(&x->sticky_paths, 0); + } + } + } +} + int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec) { struct path_simplify *simplify; @@ -2044,6 +2188,12 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru return dir->nr; /* + * Stay on the safe side. if read_directory() has run once on + * "dir", some sticky flag may have been left. Clear them all. + */ + clear_sticky(dir); + + /* * exclude patterns are treated like positive ones in * create_simplify. Usually exclude patterns should be a * subset of positive ones, which has no impacts on @@ -2408,16 +2558,15 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra struct ondisk_untracked_cache *ouc; struct write_data wd; unsigned char varbuf[16]; - int len = 0, varint_len; - if (untracked->exclude_per_dir) - len = strlen(untracked->exclude_per_dir); - ouc = xmalloc(sizeof(*ouc) + len + 1); + int varint_len; + size_t len = strlen(untracked->exclude_per_dir); + + FLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len); stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat); stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat); hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1); hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1); ouc->dir_flags = htonl(untracked->dir_flags); - memcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1); varint_len = encode_varint(untracked->ident.len, varbuf); strbuf_add(out, varbuf, varint_len); @@ -2522,21 +2671,21 @@ static int read_one_dir(struct untracked_cache_dir **untracked_, ud.untracked_alloc = value; ud.untracked_nr = value; if (ud.untracked_nr) - ud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr); + ALLOC_ARRAY(ud.untracked, ud.untracked_nr); data = next; next = data; ud.dirs_alloc = ud.dirs_nr = decode_varint(&next); if (next > end) return -1; - ud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr); + ALLOC_ARRAY(ud.dirs, ud.dirs_nr); data = next; len = strlen((const char *)data); next = data + len + 1; if (next > rd->end) return -1; - *untracked_ = untracked = xmalloc(sizeof(*untracked) + len); + *untracked_ = untracked = xmalloc(st_add(sizeof(*untracked), len)); memcpy(untracked, &ud, sizeof(ud)); memcpy(untracked->name, data, len + 1); data = next; @@ -2649,7 +2798,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long rd.data = next; rd.end = end; rd.index = 0; - rd.ucd = xmalloc(sizeof(*rd.ucd) * len); + ALLOC_ARRAY(rd.ucd, len); if (read_one_dir(&uc->root, &rd) || rd.index != len) goto done; @@ -4,6 +4,7 @@ /* See Documentation/technical/api-directory-listing.txt */ #include "strbuf.h" +#include "string-list.h" struct dir_entry { unsigned int len; @@ -34,6 +35,8 @@ struct exclude { * and from -1 decrementing for patterns from CLI args. */ int srcpos; + + struct string_list sticky_paths; }; /* @@ -307,5 +310,6 @@ void untracked_cache_add_to_index(struct index_state *, const char *); void free_untracked_cache(struct untracked_cache *); struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz); void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked); -void add_untracked_ident(struct untracked_cache *); +void add_untracked_cache(struct index_state *istate); +void remove_untracked_cache(struct index_state *istate); #endif @@ -6,7 +6,7 @@ static void create_directories(const char *path, int path_len, const struct checkout *state) { - char *buf = xmalloc(path_len + 1); + char *buf = xmallocz(path_len); int len = 0; while (len < path_len) { diff --git a/environment.c b/environment.c index 2da7fe2e06..6dec9d0403 100644 --- a/environment.c +++ b/environment.c @@ -87,6 +87,13 @@ int auto_comment_line_char; /* Parallel index stat data preload? */ int core_preload_index = 1; +/* + * This is a hack for test programs like test-dump-untracked-cache to + * ensure that they do not modify the untracked cache when reading it. + * Do not use it otherwise! + */ +int ignore_untracked_cache_config; + /* This is set by setup_git_dir_gently() and/or git_default_config() */ char *git_work_tree_cfg; static char *work_tree; @@ -235,8 +242,6 @@ void set_git_work_tree(const char *new_work_tree) } git_work_tree_initialized = 1; work_tree = xstrdup(real_path(new_work_tree)); - if (setenv(GIT_WORK_TREE_ENVIRONMENT, work_tree, 1)) - die("could not set GIT_WORK_TREE to '%s'", work_tree); } const char *get_git_work_tree(void) diff --git a/ewah/bitmap.c b/ewah/bitmap.c index 47ad6747c4..7103ceefbf 100644 --- a/ewah/bitmap.c +++ b/ewah/bitmap.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "git-compat-util.h" +#include "cache.h" #include "ewok.h" #define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD)) @@ -25,8 +25,8 @@ struct bitmap *bitmap_new(void) { - struct bitmap *bitmap = ewah_malloc(sizeof(struct bitmap)); - bitmap->words = ewah_calloc(32, sizeof(eword_t)); + struct bitmap *bitmap = xmalloc(sizeof(struct bitmap)); + bitmap->words = xcalloc(32, sizeof(eword_t)); bitmap->word_alloc = 32; return bitmap; } @@ -38,9 +38,7 @@ void bitmap_set(struct bitmap *self, size_t pos) if (block >= self->word_alloc) { size_t old_size = self->word_alloc; self->word_alloc = block * 2; - self->words = ewah_realloc(self->words, - self->word_alloc * sizeof(eword_t)); - + REALLOC_ARRAY(self->words, self->word_alloc); memset(self->words + old_size, 0x0, (self->word_alloc - old_size) * sizeof(eword_t)); } @@ -100,12 +98,7 @@ struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah) ewah_iterator_init(&it, ewah); while (ewah_iterator_next(&blowup, &it)) { - if (i >= bitmap->word_alloc) { - bitmap->word_alloc *= 1.5; - bitmap->words = ewah_realloc( - bitmap->words, bitmap->word_alloc * sizeof(eword_t)); - } - + ALLOC_GROW(bitmap->words, i + 1, bitmap->word_alloc); bitmap->words[i++] = blowup; } @@ -134,8 +127,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other) if (self->word_alloc < other_final) { self->word_alloc = other_final; - self->words = ewah_realloc(self->words, - self->word_alloc * sizeof(eword_t)); + REALLOC_ARRAY(self->words, self->word_alloc); memset(self->words + original_size, 0x0, (self->word_alloc - original_size) * sizeof(eword_t)); } diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c index b522437c0a..2dc9c82ecf 100644 --- a/ewah/ewah_bitmap.c +++ b/ewah/ewah_bitmap.c @@ -39,8 +39,7 @@ static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size) return; self->alloc_size = new_size; - self->buffer = ewah_realloc(self->buffer, - self->alloc_size * sizeof(eword_t)); + REALLOC_ARRAY(self->buffer, self->alloc_size); self->rlw = self->buffer + (rlw_offset / sizeof(eword_t)); } @@ -282,12 +281,9 @@ struct ewah_bitmap *ewah_new(void) { struct ewah_bitmap *self; - self = ewah_malloc(sizeof(struct ewah_bitmap)); - if (self == NULL) - return NULL; - - self->buffer = ewah_malloc(32 * sizeof(eword_t)); + self = xmalloc(sizeof(struct ewah_bitmap)); self->alloc_size = 32; + ALLOC_ARRAY(self->buffer, self->alloc_size); ewah_clear(self); return self; diff --git a/ewah/ewah_io.c b/ewah/ewah_io.c index 43481b9c60..61f6a43579 100644 --- a/ewah/ewah_io.c +++ b/ewah/ewah_io.c @@ -134,11 +134,7 @@ int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len) self->buffer_size = self->alloc_size = get_be32(ptr); ptr += sizeof(uint32_t); - self->buffer = ewah_realloc(self->buffer, - self->alloc_size * sizeof(eword_t)); - - if (!self->buffer) - return -1; + REALLOC_ARRAY(self->buffer, self->alloc_size); /* * Copy the raw data for the bitmap as a whole chunk; @@ -180,11 +176,7 @@ int ewah_deserialize(struct ewah_bitmap *self, int fd) return -1; self->buffer_size = self->alloc_size = (size_t)ntohl(word_count); - self->buffer = ewah_realloc(self->buffer, - self->alloc_size * sizeof(eword_t)); - - if (!self->buffer) - return -1; + REALLOC_ARRAY(self->buffer, self->alloc_size); /** 64 bit x N -- compressed words */ buffer = self->buffer; diff --git a/ewah/ewok.h b/ewah/ewok.h index 6e2c5e1e3d..269a1a8706 100644 --- a/ewah/ewok.h +++ b/ewah/ewok.h @@ -20,16 +20,6 @@ #ifndef __EWOK_BITMAP_H__ #define __EWOK_BITMAP_H__ -#ifndef ewah_malloc -# define ewah_malloc xmalloc -#endif -#ifndef ewah_realloc -# define ewah_realloc xrealloc -#endif -#ifndef ewah_calloc -# define ewah_calloc xcalloc -#endif - struct strbuf; typedef uint64_t eword_t; #define BITS_IN_EWORD (sizeof(eword_t) * 8) diff --git a/exec_cmd.c b/exec_cmd.c index e85f0fd8d8..9d5703a157 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,6 +1,7 @@ #include "cache.h" #include "exec_cmd.h" #include "quote.h" +#include "argv-array.h" #define MAX_ARGS 32 static const char *argv_exec_path; @@ -43,12 +44,10 @@ const char *git_extract_argv0_path(const char *argv0) if (!argv0 || !*argv0) return NULL; - slash = argv0 + strlen(argv0); - while (argv0 <= slash && !is_dir_sep(*slash)) - slash--; + slash = find_last_dir_sep(argv0); - if (slash >= argv0) { + if (slash) { argv0_path = xstrndup(argv0, slash - argv0); return slash + 1; } @@ -107,32 +106,25 @@ void setup_path(void) strbuf_release(&new_path); } -const char **prepare_git_cmd(const char **argv) +const char **prepare_git_cmd(struct argv_array *out, const char **argv) { - int argc; - const char **nargv; - - for (argc = 0; argv[argc]; argc++) - ; /* just counting */ - nargv = xmalloc(sizeof(*nargv) * (argc + 2)); - - nargv[0] = "git"; - for (argc = 0; argv[argc]; argc++) - nargv[argc + 1] = argv[argc]; - nargv[argc + 1] = NULL; - return nargv; + argv_array_push(out, "git"); + argv_array_pushv(out, argv); + return out->argv; } int execv_git_cmd(const char **argv) { - const char **nargv = prepare_git_cmd(argv); - trace_argv_printf(nargv, "trace: exec:"); + struct argv_array nargv = ARGV_ARRAY_INIT; + + prepare_git_cmd(&nargv, argv); + trace_argv_printf(nargv.argv, "trace: exec:"); /* execvp() can only ever return if it fails */ - sane_execvp("git", (char **)nargv); + sane_execvp("git", (char **)nargv.argv); trace_printf("trace: exec failed: %s\n", strerror(errno)); - free(nargv); + argv_array_clear(&nargv); return -1; } diff --git a/exec_cmd.h b/exec_cmd.h index 93b0c02529..1f6b43378b 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -1,11 +1,13 @@ #ifndef GIT_EXEC_CMD_H #define GIT_EXEC_CMD_H +struct argv_array; + extern void git_set_argv_exec_path(const char *exec_path); extern const char *git_extract_argv0_path(const char *path); extern const char *git_exec_path(void); extern void setup_path(void); -extern const char **prepare_git_cmd(const char **argv); +extern const char **prepare_git_cmd(struct argv_array *out, const char **argv); extern int execv_git_cmd(const char **argv); /* NULL terminated */ LAST_ARG_MUST_BE_NULL extern int execl_git_cmd(const char *cmd, ...); diff --git a/fast-import.c b/fast-import.c index 3c65edb5c4..9fc7093406 100644 --- a/fast-import.c +++ b/fast-import.c @@ -622,7 +622,7 @@ static void *pool_alloc(size_t len) return xmalloc(len); } total_allocd += sizeof(struct mem_pool) + mem_pool_alloc; - p = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc); + p = xmalloc(st_add(sizeof(struct mem_pool), mem_pool_alloc)); p->next_pool = mem_pool; p->next_free = (char *) p->space; p->end = p->next_free + mem_pool_alloc; @@ -814,7 +814,8 @@ static struct tree_entry *new_tree_entry(void) if (!avail_tree_entry) { unsigned int n = tree_entry_alloc; total_allocd += n * sizeof(struct tree_entry); - avail_tree_entry = e = xmalloc(n * sizeof(struct tree_entry)); + ALLOC_ARRAY(e, n); + avail_tree_entry = e; while (n-- > 1) { *((void**)e) = e + 1; e++; @@ -864,15 +865,12 @@ static void start_packfile(void) { static char tmp_file[PATH_MAX]; struct packed_git *p; - int namelen; struct pack_header hdr; int pack_fd; pack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file), "pack/tmp_pack_XXXXXX"); - namelen = strlen(tmp_file) + 2; - p = xcalloc(1, sizeof(*p) + namelen); - xsnprintf(p->pack_name, namelen, "%s", tmp_file); + FLEX_ALLOC_STR(p, pack_name, tmp_file); p->pack_fd = pack_fd; p->do_not_close = 1; pack_file = sha1fd(pack_fd, p->pack_name); @@ -898,7 +896,7 @@ static const char *create_index(void) struct object_entry_pool *o; /* Build the table of object IDs. */ - idx = xmalloc(object_count * sizeof(*idx)); + ALLOC_ARRAY(idx, object_count); c = idx; for (o = blocks; o; o = o->next_pool) for (e = o->next_free; e-- != o->entries;) @@ -1888,7 +1886,7 @@ static int read_next_command(void) struct recent_command *rc; strbuf_detach(&command_buf, NULL); - stdin_eof = strbuf_getline(&command_buf, stdin, '\n'); + stdin_eof = strbuf_getline_lf(&command_buf, stdin); if (stdin_eof) return EOF; @@ -1960,7 +1958,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res) strbuf_detach(&command_buf, NULL); for (;;) { - if (strbuf_getline(&command_buf, stdin, '\n') == EOF) + if (strbuf_getline_lf(&command_buf, stdin) == EOF) die("EOF in data (terminator '%s' not found)", term); if (term_len == command_buf.len && !strcmp(term, command_buf.buf)) diff --git a/fetch-pack.c b/fetch-pack.c index 01e34b689b..f96f6dfb35 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -15,6 +15,7 @@ #include "version.h" #include "prio-queue.h" #include "sha1-array.h" +#include "sigchain.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; @@ -671,9 +672,12 @@ static int everything_local(struct fetch_pack_args *args, static int sideband_demux(int in, int out, void *data) { int *xd = data; + int ret; - int ret = recv_sideband("fetch-pack", xd[0], out); + sigchain_push(SIGPIPE, SIG_IGN); + ret = recv_sideband("fetch-pack", xd[0], out); close(out); + sigchain_pop(SIGPIPE); return ret; } @@ -199,7 +199,8 @@ void fsck_set_msg_type(struct fsck_options *options, if (!options->msg_type) { int i; - int *msg_type = xmalloc(sizeof(int) * FSCK_MSG_MAX); + int *msg_type; + ALLOC_ARRAY(msg_type, FSCK_MSG_MAX); for (i = 0; i < FSCK_MSG_MAX; i++) msg_type[i] = fsck_msg_type(i, options); options->msg_type = msg_type; diff --git a/git-compat-util.h b/git-compat-util.h index 2da0a75a38..c07e0c1778 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -96,6 +96,14 @@ #define unsigned_add_overflows(a, b) \ ((b) > maximum_unsigned_value_of_type(a) - (a)) +/* + * Returns true if the multiplication of "a" and "b" will + * overflow. The types of "a" and "b" must match and must be unsigned. + * Note that this macro evaluates "a" twice! + */ +#define unsigned_mult_overflows(a, b) \ + ((a) && (b) > maximum_unsigned_value_of_type(a) / (a)) + #ifdef __GNUC__ #define TYPEOF(x) (__typeof__(x)) #else @@ -253,6 +261,8 @@ struct itimerval { #else #define basename gitbasename extern char *gitbasename(char *); +#define dirname gitdirname +extern char *gitdirname(char *); #endif #ifndef NO_ICONV @@ -323,10 +333,6 @@ extern char *gitbasename(char *); #define _PATH_DEFPATH "/usr/local/bin:/usr/bin:/bin" #endif -#ifndef STRIP_EXTENSION -#define STRIP_EXTENSION "" -#endif - #ifndef has_dos_drive_prefix static inline int git_has_dos_drive_prefix(const char *path) { @@ -335,6 +341,14 @@ static inline int git_has_dos_drive_prefix(const char *path) #define has_dos_drive_prefix git_has_dos_drive_prefix #endif +#ifndef skip_dos_drive_prefix +static inline int git_skip_dos_drive_prefix(char **path) +{ + return 0; +} +#define skip_dos_drive_prefix git_skip_dos_drive_prefix +#endif + #ifndef is_dir_sep static inline int git_is_dir_sep(int c) { @@ -663,7 +677,6 @@ extern int git_vsnprintf(char *str, size_t maxsize, #ifdef __GLIBC_PREREQ #if __GLIBC_PREREQ(2, 1) #define HAVE_STRCHRNUL -#define HAVE_MEMPCPY #endif #endif @@ -677,14 +690,6 @@ static inline char *gitstrchrnul(const char *s, int c) } #endif -#ifndef HAVE_MEMPCPY -#define mempcpy gitmempcpy -static inline void *gitmempcpy(void *dest, const void *src, size_t n) -{ - return (char *)memcpy(dest, src, n) + n; -} -#endif - #ifdef NO_INET_PTON int inet_pton(int af, const char *src, void *dst); #endif @@ -703,6 +708,32 @@ extern void release_pack_memory(size_t); typedef void (*try_to_free_t)(size_t); extern try_to_free_t set_try_to_free_routine(try_to_free_t); +static inline size_t st_add(size_t a, size_t b) +{ + if (unsigned_add_overflows(a, b)) + die("size_t overflow: %"PRIuMAX" + %"PRIuMAX, + (uintmax_t)a, (uintmax_t)b); + return a + b; +} +#define st_add3(a,b,c) st_add((a),st_add((b),(c))) +#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d))) + +static inline size_t st_mult(size_t a, size_t b) +{ + if (unsigned_mult_overflows(a, b)) + die("size_t overflow: %"PRIuMAX" * %"PRIuMAX, + (uintmax_t)a, (uintmax_t)b); + return a * b; +} + +static inline size_t st_sub(size_t a, size_t b) +{ + if (a < b) + die("size_t underflow: %"PRIuMAX" - %"PRIuMAX, + (uintmax_t)a, (uintmax_t)b); + return a - b; +} + #ifdef HAVE_ALLOCA_H # include <alloca.h> # define xalloca(size) (alloca(size)) @@ -733,8 +764,72 @@ extern int xmkstemp_mode(char *template, int mode); extern int odb_mkstemp(char *template, size_t limit, const char *pattern); extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1); extern char *xgetcwd(void); +extern FILE *fopen_for_writing(const char *path); -#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x))) +#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc))) +#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc))) + +/* + * These functions help you allocate structs with flex arrays, and copy + * the data directly into the array. For example, if you had: + * + * struct foo { + * int bar; + * char name[FLEX_ARRAY]; + * }; + * + * you can do: + * + * struct foo *f; + * FLEX_ALLOC_MEM(f, name, src, len); + * + * to allocate a "foo" with the contents of "src" in the "name" field. + * The resulting struct is automatically zero'd, and the flex-array field + * is NUL-terminated (whether the incoming src buffer was or not). + * + * The FLEXPTR_* variants operate on structs that don't use flex-arrays, + * but do want to store a pointer to some extra data in the same allocated + * block. For example, if you have: + * + * struct foo { + * char *name; + * int bar; + * }; + * + * you can do: + * + * struct foo *f; + * FLEX_ALLOC_STR(f, name, src); + * + * and "name" will point to a block of memory after the struct, which will be + * freed along with the struct (but the pointer can be repointed anywhere). + * + * The *_STR variants accept a string parameter rather than a ptr/len + * combination. + * + * Note that these macros will evaluate the first parameter multiple + * times, and it must be assignable as an lvalue. + */ +#define FLEX_ALLOC_MEM(x, flexname, buf, len) do { \ + (x) = NULL; /* silence -Wuninitialized for offset calculation */ \ + (x) = xalloc_flex(sizeof(*(x)), (char *)(&((x)->flexname)) - (char *)(x), (buf), (len)); \ +} while (0) +#define FLEXPTR_ALLOC_MEM(x, ptrname, buf, len) do { \ + (x) = xalloc_flex(sizeof(*(x)), sizeof(*(x)), (buf), (len)); \ + (x)->ptrname = (void *)((x)+1); \ +} while(0) +#define FLEX_ALLOC_STR(x, flexname, str) \ + FLEX_ALLOC_MEM((x), flexname, (str), strlen(str)) +#define FLEXPTR_ALLOC_STR(x, ptrname, str) \ + FLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str)) + +static inline void *xalloc_flex(size_t base_len, size_t offset, + const void *src, size_t src_len) +{ + unsigned char *ret = xcalloc(1, st_add3(base_len, src_len, 1)); + memcpy(ret + offset, src, src_len); + return ret; +} static inline char *xstrdup_or_null(const char *str) { diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 95e69b19a7..02c0445be1 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2664,7 +2664,7 @@ sub argsfromdir # co # Obtain list directly. # remove # HERE: TEST: MAYBE client does the recursion for us, # # since it only makes sense to remove stuff already in - # # the sandobx? + # # the sandbox? # ci # HERE: Similar to remove... # # Don't try to implement the confusing/weird # # ci -r bug er.."feature". diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 98f1779cf3..86b2ff1e07 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -404,7 +404,7 @@ while read commit parents; do then tree=$(git write-tree) else - tree="$commit^{tree}" + tree=$(git rev-parse "$commit^{tree}") fi workdir=$workdir @SHELL_PATH@ -c "$filter_commit" "git commit-tree" \ "$tree" $parentstr < ../message > ../map/$commit || diff --git a/git-gui/po/glossary/txt-to-pot.sh b/git-gui/po/glossary/txt-to-pot.sh index 49bf7c5365..8249915d3c 100755 --- a/git-gui/po/glossary/txt-to-pot.sh +++ b/git-gui/po/glossary/txt-to-pot.sh @@ -11,7 +11,7 @@ if [ $# -eq 0 ] then cat <<! -Usage: `basename $0` git-gui-glossary.txt > git-gui-glossary.pot +Usage: $(basename $0) git-gui-glossary.txt > git-gui-glossary.pot ! exit 1; fi @@ -33,7 +33,7 @@ cat <<! msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: `date +'%Y-%m-%d %H:%M%z'`\n" +"POT-Creation-Date: $(date +'%Y-%m-%d %H:%M%z')\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index cdc02af517..424b034e34 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -120,8 +120,7 @@ case "${1:-.}${2:-.}${3:-.}" in case "$1" in '') echo "Added $4 in both, but differently." - orig=$(git-unpack-file $2) - create_virtual_base "$orig" "$src2" + orig=$(git-unpack-file e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) ;; *) echo "Auto-merging $4" @@ -253,8 +253,8 @@ def p4_add(f): def p4_delete(f): p4_system(["delete", wildcard_encode(f)]) -def p4_edit(f): - p4_system(["edit", wildcard_encode(f)]) +def p4_edit(f, *options): + p4_system(["edit"] + list(options) + [wildcard_encode(f)]) def p4_revert(f): p4_system(["revert", wildcard_encode(f)]) @@ -1554,6 +1554,7 @@ class P4Submit(Command, P4UserMap): diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (self.diffOpts, id, id)) filesToAdd = set() + filesToChangeType = set() filesToDelete = set() editedFiles = set() pureRenameCopy = set() @@ -1614,6 +1615,8 @@ class P4Submit(Command, P4UserMap): os.unlink(dest) filesToDelete.add(src) editedFiles.add(dest) + elif modifier == "T": + filesToChangeType.add(path) else: die("unknown modifier %s for %s" % (modifier, path)) @@ -1673,6 +1676,8 @@ class P4Submit(Command, P4UserMap): # system(applyPatchCmd) + for f in filesToChangeType: + p4_edit(f, "-t", "auto") for f in filesToAdd: p4_add(f) for f in filesToDelete: diff --git a/git-rebase.sh b/git-rebase.sh index af7ba5fd90..cf60c43908 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -176,7 +176,7 @@ You can run "git stash pop" or "git stash drop" at any time. finish_rebase () { apply_autostash && - git gc --auto && + { git gc --auto || true; } && rm -rf "$state_dir" } diff --git a/git-send-email.perl b/git-send-email.perl index 6caa5b563f..d356901348 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -524,8 +524,13 @@ my %parse_alias = ( if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) { my ($alias, $addr) = ($1, $2); $addr =~ s/#.*$//; # mutt allows # comments - # commas delimit multiple addresses - $aliases{$alias} = [ split_addrs($addr) ]; + # commas delimit multiple addresses + my @addr = split_addrs($addr); + + # quotes may be escaped in the file, + # unescape them so we do not double-escape them later. + s/\\"/"/g foreach @addr; + $aliases{$alias} = \@addr }}}, mailrc => sub { my $fh = shift; while (<$fh>) { if (/^alias\s+(\S+)\s+(.*)$/) { diff --git a/git-submodule.sh b/git-submodule.sh index 9bc5c5f94d..43c68deee9 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -591,6 +591,24 @@ cmd_deinit() done } +is_tip_reachable () ( + clear_local_git_env + cd "$1" && + rev=$(git rev-list -n 1 "$2" --not --all 2>/dev/null) && + test -z "$rev" +) + +fetch_in_submodule () ( + clear_local_git_env + cd "$1" && + case "$2" in + '') + git fetch ;; + *) + git fetch $(get_default_remote) "$2" ;; + esac +) + # # Update each submodule path to correct revision, using clone and checkout as needed # @@ -745,10 +763,15 @@ Maybe you want to use 'update --init'?")" then # Run fetch only if $sha1 isn't present or it # is not reachable from a ref. - (clear_local_git_env; cd "$sm_path" && - ( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) && - test -z "$rev") || git-fetch)) || + is_tip_reachable "$sm_path" "$sha1" || + fetch_in_submodule "$sm_path" || die "$(eval_gettext "Unable to fetch in submodule path '\$displaypath'")" + + # Now we tried the usual fetch, but $sha1 may + # not be reachable from any of the refs + is_tip_reachable "$sm_path" "$sha1" || + fetch_in_submodule "$sm_path" "$sha1" || + die "$(eval_gettext "Fetched in submodule path '\$displaypath', but it did not contain $sha1. Direct fetching of that commit failed.")" fi # Is this something we just cloned? @@ -25,14 +25,14 @@ static const char *env_names[] = { GIT_PREFIX_ENVIRONMENT }; static char *orig_env[4]; -static int saved_environment; +static int save_restore_env_balance; -static void save_env(void) +static void save_env_before_alias(void) { int i; - if (saved_environment) - return; - saved_environment = 1; + + assert(save_restore_env_balance == 0); + save_restore_env_balance = 1; orig_cwd = xgetcwd(); for (i = 0; i < ARRAY_SIZE(env_names); i++) { orig_env[i] = getenv(env_names[i]); @@ -41,17 +41,25 @@ static void save_env(void) } } -static void restore_env(void) +static void restore_env(int external_alias) { int i; - if (orig_cwd && chdir(orig_cwd)) + + assert(save_restore_env_balance == 1); + save_restore_env_balance = 0; + if (!external_alias && orig_cwd && chdir(orig_cwd)) die_errno("could not move to %s", orig_cwd); free(orig_cwd); for (i = 0; i < ARRAY_SIZE(env_names); i++) { - if (orig_env[i]) + if (external_alias && + !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT)) + continue; + if (orig_env[i]) { setenv(env_names[i], orig_env[i], 1); - else + free(orig_env[i]); + } else { unsetenv(env_names[i]); + } } } @@ -226,32 +234,29 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) static int handle_alias(int *argcp, const char ***argv) { int envchanged = 0, ret = 0, saved_errno = errno; - const char *subdir; int count, option_count; const char **new_argv; const char *alias_command; char *alias_string; int unused_nongit; - subdir = setup_git_directory_gently(&unused_nongit); + save_env_before_alias(); + setup_git_directory_gently(&unused_nongit); alias_command = (*argv)[0]; alias_string = alias_lookup(alias_command); if (alias_string) { if (alias_string[0] == '!') { - const char **alias_argv; - int argc = *argcp, i; + struct child_process child = CHILD_PROCESS_INIT; commit_pager_choice(); + restore_env(1); - /* build alias_argv */ - alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1)); - alias_argv[0] = alias_string + 1; - for (i = 1; i < argc; ++i) - alias_argv[i] = (*argv)[i]; - alias_argv[argc] = NULL; + child.use_shell = 1; + argv_array_push(&child.args, alias_string + 1); + argv_array_pushv(&child.args, (*argv) + 1); - ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); + ret = run_command(&child); if (ret >= 0) /* normal exit */ exit(ret); @@ -291,8 +296,7 @@ static int handle_alias(int *argcp, const char ***argv) ret = 1; } - if (subdir && chdir(subdir)) - die_errno("Cannot change to '%s'", subdir); + restore_env(0); errno = saved_errno; @@ -307,7 +311,6 @@ static int handle_alias(int *argcp, const char ***argv) * RUN_SETUP for reading from the configuration file. */ #define NEED_WORK_TREE (1<<3) -#define NO_SETUP (1<<4) struct cmd_struct { const char *cmd; @@ -389,7 +392,7 @@ static struct cmd_struct commands[] = { { "cherry", cmd_cherry, RUN_SETUP }, { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE }, { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE }, - { "clone", cmd_clone, NO_SETUP }, + { "clone", cmd_clone }, { "column", cmd_column, RUN_SETUP_GENTLY }, { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE }, { "commit-tree", cmd_commit_tree, RUN_SETUP }, @@ -415,8 +418,8 @@ static struct cmd_struct commands[] = { { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY }, - { "init", cmd_init_db, NO_SETUP }, - { "init-db", cmd_init_db, NO_SETUP }, + { "init", cmd_init_db }, + { "init-db", cmd_init_db }, { "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY }, { "log", cmd_log, RUN_SETUP }, { "ls-files", cmd_ls_files, RUN_SETUP }, @@ -506,21 +509,25 @@ int is_builtin(const char *s) return !!get_builtin(s); } +#ifdef STRIP_EXTENSION +static void strip_extension(const char **argv) +{ + size_t len; + + if (strip_suffix(argv[0], STRIP_EXTENSION, &len)) + argv[0] = xmemdupz(argv[0], len); +} +#else +#define strip_extension(cmd) +#endif + static void handle_builtin(int argc, const char **argv) { - const char *cmd = argv[0]; - int i; - static const char ext[] = STRIP_EXTENSION; + const char *cmd; struct cmd_struct *builtin; - if (sizeof(ext) > 1) { - i = strlen(argv[0]) - strlen(ext); - if (i > 0 && !strcmp(argv[0] + i, ext)) { - char *argv0 = xstrdup(argv[0]); - argv[0] = cmd = argv0; - argv0[i] = '\0'; - } - } + strip_extension(argv); + cmd = argv[0]; /* Turn "git cmd --help" into "git help cmd" */ if (argc > 1 && !strcmp(argv[1], "--help")) { @@ -529,12 +536,8 @@ static void handle_builtin(int argc, const char **argv) } builtin = get_builtin(cmd); - if (builtin) { - if (saved_environment && (builtin->option & NO_SETUP)) - restore_env(); - else - exit(run_builtin(builtin, argc, argv)); - } + if (builtin) + exit(run_builtin(builtin, argc, argv)); } static void execv_dashed_external(const char **argv) @@ -578,8 +581,17 @@ static int run_argv(int *argcp, const char ***argv) int done_alias = 0; while (1) { - /* See if it's a builtin */ - handle_builtin(*argcp, *argv); + /* + * If we tried alias and futzed with our environment, + * it no longer is safe to invoke builtins directly in + * general. We have to spawn them as dashed externals. + * + * NEEDSWORK: if we can figure out cases + * where it is safe to do, we can avoid spawning a new + * process. + */ + if (!done_alias) + handle_builtin(*argcp, *argv); /* .. then try the external ones */ execv_dashed_external(*argv); @@ -590,7 +602,6 @@ static int run_argv(int *argcp, const char ***argv) */ if (done_alias) break; - save_env(); if (!handle_alias(argcp, argv)) break; done_alias = 1; diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7a5b23acf2..05d7910b7c 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -7576,7 +7576,7 @@ sub git_object { git_cmd(), 'cat-file', '-t', $object_id) . ' 2> /dev/null' or die_error(404, "Object does not exist"); $type = <$fd>; - chomp $type; + defined $type && chomp $type; close $fd or die_error(404, "Object does not exist"); @@ -234,12 +234,10 @@ struct git_graph *graph_init(struct rev_info *opt) * We'll automatically grow columns later if we need more room. */ graph->column_capacity = 30; - graph->columns = xmalloc(sizeof(struct column) * - graph->column_capacity); - graph->new_columns = xmalloc(sizeof(struct column) * - graph->column_capacity); - graph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity); - graph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity); + ALLOC_ARRAY(graph->columns, graph->column_capacity); + ALLOC_ARRAY(graph->new_columns, graph->column_capacity); + ALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity); + ALLOC_ARRAY(graph->new_mapping, 2 * graph->column_capacity); /* * The diff output prefix callback, with this we can make @@ -1741,7 +1741,7 @@ static int grep_source_load_file(struct grep_source *gs) i = open(filename, O_RDONLY); if (i < 0) goto err_ret; - data = xmalloc(size + 1); + data = xmallocz(size); if (st.st_size != read_in_full(i, data, size)) { error(_("'%s': short read %s"), filename, strerror(errno)); close(i); @@ -1749,7 +1749,6 @@ static int grep_source_load_file(struct grep_source *gs) return -1; } close(i); - data[size] = 0; gs->buf = data; gs->size = size; @@ -256,10 +256,9 @@ const void *memintern(const void *data, size_t len) e = hashmap_get(&map, &key, data); if (!e) { /* not found: create it */ - e = xmallocz(sizeof(struct pool_entry) + len); + FLEX_ALLOC_MEM(e, data, data, len); hashmap_entry_init(e, key.ent.hash); e->len = len; - memcpy(e->data, data, len); hashmap_add(&map, e); } return e->data; @@ -11,11 +11,9 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len) { - struct cmdname *ent = xmalloc(sizeof(*ent) + len + 1); - + struct cmdname *ent; + FLEX_ALLOC_MEM(ent, name, name, len); ent->len = len; - memcpy(ent->name, name, len); - ent->name[len] = 0; ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc); cmds->names[cmds->cnt++] = ent; diff --git a/http-push.c b/http-push.c index d857b131a8..bd60668707 100644 --- a/http-push.c +++ b/http-push.c @@ -1277,9 +1277,7 @@ static struct object_list **add_one_object(struct object *obj, struct object_lis } static struct object_list **process_blob(struct blob *blob, - struct object_list **p, - struct name_path *path, - const char *name) + struct object_list **p) { struct object *obj = &blob->object; @@ -1293,14 +1291,11 @@ static struct object_list **process_blob(struct blob *blob, } static struct object_list **process_tree(struct tree *tree, - struct object_list **p, - struct name_path *path, - const char *name) + struct object_list **p) { struct object *obj = &tree->object; struct tree_desc desc; struct name_entry entry; - struct name_path me; obj->flags |= LOCAL; @@ -1310,21 +1305,17 @@ static struct object_list **process_tree(struct tree *tree, die("bad tree object %s", oid_to_hex(&obj->oid)); obj->flags |= SEEN; - name = xstrdup(name); p = add_one_object(obj, p); - me.up = path; - me.elem = name; - me.elem_len = strlen(name); init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) switch (object_type(entry.mode)) { case OBJ_TREE: - p = process_tree(lookup_tree(entry.sha1), p, &me, name); + p = process_tree(lookup_tree(entry.sha1), p); break; case OBJ_BLOB: - p = process_blob(lookup_blob(entry.sha1), p, &me, name); + p = process_blob(lookup_blob(entry.sha1), p); break; default: /* Subproject commit - not in this repository */ @@ -1343,7 +1334,7 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock) int count = 0; while ((commit = get_revision(revs)) != NULL) { - p = process_tree(commit->tree, p, NULL, ""); + p = process_tree(commit->tree, p); commit->object.flags |= LOCAL; if (!(commit->object.flags & UNINTERESTING)) count += add_send_request(&commit->object, lock); @@ -1362,11 +1353,11 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock) continue; } if (obj->type == OBJ_TREE) { - p = process_tree((struct tree *)obj, p, NULL, name); + p = process_tree((struct tree *)obj, p); continue; } if (obj->type == OBJ_BLOB) { - p = process_blob((struct blob *)obj, p, NULL, name); + p = process_blob((struct blob *)obj, p); continue; } die("unknown pending object %s (%s)", oid_to_hex(&obj->oid), name); @@ -11,6 +11,11 @@ #include "gettext.h" #include "transport.h" +#if LIBCURL_VERSION_NUM >= 0x070a08 +long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER; +#else +long int git_curl_ipresolve; +#endif int active_requests; int http_is_verbose; size_t http_post_buffer = 16 * LARGE_PACKET_MAX; @@ -57,16 +62,40 @@ static const char *ssl_key; #if LIBCURL_VERSION_NUM >= 0x070908 static const char *ssl_capath; #endif +#if LIBCURL_VERSION_NUM >= 0x072c00 +static const char *ssl_pinnedkey; +#endif static const char *ssl_cainfo; static long curl_low_speed_limit = -1; static long curl_low_speed_time = -1; static int curl_ftp_no_epsv; static const char *curl_http_proxy; +static const char *http_proxy_authmethod; +static struct { + const char *name; + long curlauth_param; +} proxy_authmethods[] = { + { "basic", CURLAUTH_BASIC }, + { "digest", CURLAUTH_DIGEST }, + { "negotiate", CURLAUTH_GSSNEGOTIATE }, + { "ntlm", CURLAUTH_NTLM }, +#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY + { "anyauth", CURLAUTH_ANY }, +#endif + /* + * CURLAUTH_DIGEST_IE has no corresponding command-line option in + * curl(1) and is not included in CURLAUTH_ANY, so we leave it out + * here, too + */ +}; +static struct credential proxy_auth = CREDENTIAL_INIT; +static const char *curl_proxyuserpwd; static const char *curl_cookie_file; static int curl_save_cookies; struct credential http_auth = CREDENTIAL_INIT; static int http_proactive_auth; static const char *user_agent; +static int curl_empty_auth; #if LIBCURL_VERSION_NUM >= 0x071700 /* Use CURLOPT_KEYPASSWD as is */ @@ -159,6 +188,9 @@ static void finish_active_slot(struct active_request_slot *slot) #else slot->results->auth_avail = 0; #endif + + curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CONNECTCODE, + &slot->results->http_connectcode); } /* Run callback if appropriate */ @@ -256,6 +288,9 @@ static int http_options(const char *var, const char *value, void *cb) if (!strcmp("http.proxy", var)) return git_config_string(&curl_http_proxy, var, value); + if (!strcmp("http.proxyauthmethod", var)) + return git_config_string(&http_proxy_authmethod, var, value); + if (!strcmp("http.cookiefile", var)) return git_config_string(&curl_cookie_file, var, value); if (!strcmp("http.savecookies", var)) { @@ -273,14 +308,31 @@ static int http_options(const char *var, const char *value, void *cb) if (!strcmp("http.useragent", var)) return git_config_string(&user_agent, var, value); + if (!strcmp("http.emptyauth", var)) { + curl_empty_auth = git_config_bool(var, value); + return 0; + } + + if (!strcmp("http.pinnedpubkey", var)) { +#if LIBCURL_VERSION_NUM >= 0x072c00 + return git_config_pathname(&ssl_pinnedkey, var, value); +#else + warning(_("Public key pinning not supported with cURL < 7.44.0")); + return 0; +#endif + } + /* Fall back on the default ones */ return git_default_config(var, value, cb); } static void init_curl_http_auth(CURL *result) { - if (!http_auth.username) + if (!http_auth.username) { + if (curl_empty_auth) + curl_easy_setopt(result, CURLOPT_USERPWD, ":"); return; + } credential_fill(&http_auth); @@ -304,6 +356,64 @@ static void init_curl_http_auth(CURL *result) #endif } +/* *var must be free-able */ +static void var_override(const char **var, char *value) +{ + if (value) { + free((void *)*var); + *var = xstrdup(value); + } +} + +static void set_proxyauth_name_password(CURL *result) +{ +#if LIBCURL_VERSION_NUM >= 0x071301 + curl_easy_setopt(result, CURLOPT_PROXYUSERNAME, + proxy_auth.username); + curl_easy_setopt(result, CURLOPT_PROXYPASSWORD, + proxy_auth.password); +#else + struct strbuf s = STRBUF_INIT; + + strbuf_addstr_urlencode(&s, proxy_auth.username, 1); + strbuf_addch(&s, ':'); + strbuf_addstr_urlencode(&s, proxy_auth.password, 1); + curl_proxyuserpwd = strbuf_detach(&s, NULL); + curl_easy_setopt(result, CURLOPT_PROXYUSERPWD, curl_proxyuserpwd); +#endif +} + +static void init_curl_proxy_auth(CURL *result) +{ + if (proxy_auth.username) { + if (!proxy_auth.password) + credential_fill(&proxy_auth); + set_proxyauth_name_password(result); + } + + var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD")); + +#if LIBCURL_VERSION_NUM >= 0x070a07 /* CURLOPT_PROXYAUTH and CURLAUTH_ANY */ + if (http_proxy_authmethod) { + int i; + for (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) { + if (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) { + curl_easy_setopt(result, CURLOPT_PROXYAUTH, + proxy_authmethods[i].curlauth_param); + break; + } + } + if (i == ARRAY_SIZE(proxy_authmethods)) { + warning("unsupported proxy authentication method %s: using anyauth", + http_proxy_authmethod); + curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + } + } + else + curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); +#endif +} + static int has_cert_password(void) { if (ssl_cert == NULL || ssl_cert_password_required != 1) @@ -415,6 +525,10 @@ static CURL *get_curl_handle(void) if (ssl_capath != NULL) curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath); #endif +#if LIBCURL_VERSION_NUM >= 0x072c00 + if (ssl_pinnedkey != NULL) + curl_easy_setopt(result, CURLOPT_PINNEDPUBLICKEY, ssl_pinnedkey); +#endif if (ssl_cainfo != NULL) curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo); @@ -462,6 +576,31 @@ static CURL *get_curl_handle(void) curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY); #endif + /* + * CURL also examines these variables as a fallback; but we need to query + * them here in order to decide whether to prompt for missing password (cf. + * init_curl_proxy_auth()). + * + * Unlike many other common environment variables, these are historically + * lowercase only. It appears that CURL did not know this and implemented + * only uppercase variants, which was later corrected to take both - with + * the exception of http_proxy, which is lowercase only also in CURL. As + * the lowercase versions are the historical quasi-standard, they take + * precedence here, as in CURL. + */ + if (!curl_http_proxy) { + if (!strcmp(http_auth.protocol, "https")) { + var_override(&curl_http_proxy, getenv("HTTPS_PROXY")); + var_override(&curl_http_proxy, getenv("https_proxy")); + } else { + var_override(&curl_http_proxy, getenv("http_proxy")); + } + if (!curl_http_proxy) { + var_override(&curl_http_proxy, getenv("ALL_PROXY")); + var_override(&curl_http_proxy, getenv("all_proxy")); + } + } + if (curl_http_proxy) { curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy); #if LIBCURL_VERSION_NUM >= 0x071800 @@ -475,10 +614,18 @@ static CURL *get_curl_handle(void) curl_easy_setopt(result, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); #endif + if (strstr(curl_http_proxy, "://")) + credential_from_url(&proxy_auth, curl_http_proxy); + else { + struct strbuf url = STRBUF_INIT; + strbuf_addf(&url, "http://%s", curl_http_proxy); + credential_from_url(&proxy_auth, url.buf); + strbuf_release(&url); + } + + curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host); } -#if LIBCURL_VERSION_NUM >= 0x070a07 - curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); -#endif + init_curl_proxy_auth(result); set_curl_keepalive(result); @@ -519,6 +666,9 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) if (remote && remote->http_proxy) curl_http_proxy = xstrdup(remote->http_proxy); + if (remote) + var_override(&http_proxy_authmethod, remote->http_proxy_authmethod); + pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache"); no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); @@ -617,6 +767,18 @@ void http_cleanup(void) curl_http_proxy = NULL; } + if (proxy_auth.password) { + memset(proxy_auth.password, 0, strlen(proxy_auth.password)); + free(proxy_auth.password); + proxy_auth.password = NULL; + } + + free((void *)curl_proxyuserpwd); + curl_proxyuserpwd = NULL; + + free((void *)http_proxy_authmethod); + http_proxy_authmethod = NULL; + if (cert_auth.password != NULL) { memset(cert_auth.password, 0, strlen(cert_auth.password)); free(cert_auth.password); @@ -692,10 +854,14 @@ struct active_request_slot *get_active_slot(void) curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1); curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL); + +#if LIBCURL_VERSION_NUM >= 0x070a08 + curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve); +#endif #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods); #endif - if (http_auth.password) + if (http_auth.password || curl_empty_auth) init_curl_http_auth(slot->curl); return slot; @@ -946,6 +1112,8 @@ static int handle_curl_result(struct slot_results *results) if (results->curl_result == CURLE_OK) { credential_approve(&http_auth); + if (proxy_auth.password) + credential_approve(&proxy_auth); return HTTP_OK; } else if (missing_target(results)) return HTTP_MISSING_TARGET; @@ -960,6 +1128,8 @@ static int handle_curl_result(struct slot_results *results) return HTTP_REAUTH; } } else { + if (results->http_connectcode == 407) + credential_reject(&proxy_auth); #if LIBCURL_VERSION_NUM >= 0x070c00 if (!curl_errorstr[0]) strlcpy(curl_errorstr, @@ -54,6 +54,7 @@ struct slot_results { CURLcode curl_result; long http_code; long auth_avail; + long http_connectcode; }; struct active_request_slot { @@ -106,6 +107,7 @@ extern void http_init(struct remote *remote, const char *url, int proactive_auth); extern void http_cleanup(void); +extern long int git_curl_ipresolve; extern int active_requests; extern int http_is_verbose; extern size_t http_post_buffer; @@ -13,11 +13,14 @@ static struct strbuf git_default_date = STRBUF_INIT; static int default_email_is_bogus; static int default_name_is_bogus; +static int ident_use_config_only; + #define IDENT_NAME_GIVEN 01 #define IDENT_MAIL_GIVEN 02 #define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN) static int committer_ident_explicitly_given; static int author_ident_explicitly_given; +static int ident_config_given; #ifdef NO_GECOS_IN_PWENT #define get_gecos(ignored) "&" @@ -76,7 +79,7 @@ static int add_mailname_host(struct strbuf *buf) strerror(errno)); return -1; } - if (strbuf_getline(&mailnamebuf, mailname, '\n') == EOF) { + if (strbuf_getline(&mailnamebuf, mailname) == EOF) { if (ferror(mailname)) warning("cannot read /etc/mailname: %s", strerror(errno)); @@ -345,32 +348,40 @@ const char *fmt_ident(const char *name, const char *email, int want_date = !(flag & IDENT_NO_DATE); int want_name = !(flag & IDENT_NO_NAME); - if (want_name && !name) - name = ident_default_name(); - if (!email) - email = ident_default_email(); - - if (want_name && !*name) { - struct passwd *pw; - - if (strict) { - if (name == git_default_name.buf) + if (want_name) { + int using_default = 0; + if (!name) { + name = ident_default_name(); + using_default = 1; + if (strict && default_name_is_bogus) { fputs(env_hint, stderr); - die("empty ident name (for <%s>) not allowed", email); + die("unable to auto-detect name (got '%s')", name); + } + if (strict && ident_use_config_only + && !(ident_config_given & IDENT_NAME_GIVEN)) + die("user.useConfigOnly set but no name given"); + } + if (!*name) { + struct passwd *pw; + if (strict) { + if (using_default) + fputs(env_hint, stderr); + die("empty ident name (for <%s>) not allowed", email); + } + pw = xgetpwuid_self(NULL); + name = pw->pw_name; } - pw = xgetpwuid_self(NULL); - name = pw->pw_name; - } - - if (want_name && strict && - name == git_default_name.buf && default_name_is_bogus) { - fputs(env_hint, stderr); - die("unable to auto-detect name (got '%s')", name); } - if (strict && email == git_default_email.buf && default_email_is_bogus) { - fputs(env_hint, stderr); - die("unable to auto-detect email address (got '%s')", email); + if (!email) { + email = ident_default_email(); + if (strict && default_email_is_bogus) { + fputs(env_hint, stderr); + die("unable to auto-detect email address (got '%s')", email); + } + if (strict && ident_use_config_only + && !(ident_config_given & IDENT_MAIL_GIVEN)) + die("user.useConfigOnly set but no mail given"); } strbuf_reset(&ident); @@ -444,6 +455,11 @@ int author_ident_sufficiently_given(void) int git_ident_config(const char *var, const char *value, void *data) { + if (!strcmp(var, "user.useconfigonly")) { + ident_use_config_only = git_config_bool(var, value); + return 0; + } + if (!strcmp(var, "user.name")) { if (!value) return config_error_nonbool(var); @@ -451,6 +467,7 @@ int git_ident_config(const char *var, const char *value, void *data) strbuf_addstr(&git_default_name, value); committer_ident_explicitly_given |= IDENT_NAME_GIVEN; author_ident_explicitly_given |= IDENT_NAME_GIVEN; + ident_config_given |= IDENT_NAME_GIVEN; return 0; } @@ -461,6 +478,7 @@ int git_ident_config(const char *var, const char *value, void *data) strbuf_addstr(&git_default_email, value); committer_ident_explicitly_given |= IDENT_MAIL_GIVEN; author_ident_explicitly_given |= IDENT_MAIL_GIVEN; + ident_config_given |= IDENT_MAIL_GIVEN; return 0; } diff --git a/imap-send.c b/imap-send.c index 4d3b7737a9..2c52027c84 100644 --- a/imap-send.c +++ b/imap-send.c @@ -892,12 +892,11 @@ static char *cram(const char *challenge_64, const char *user, const char *pass) response = xstrfmt("%s %s", user, hex); resp_len = strlen(response) + 1; - response_64 = xmalloc(ENCODED_SIZE(resp_len) + 1); + response_64 = xmallocz(ENCODED_SIZE(resp_len)); encoded_len = EVP_EncodeBlock((unsigned char *)response_64, (unsigned char *)response, resp_len); if (encoded_len < 0) die("EVP_EncodeBlock error"); - response_64[encoded_len] = '\0'; return (char *)response_64; } @@ -1188,7 +1187,7 @@ static void lf_to_crlf(struct strbuf *msg) j++; } - new = xmalloc(j + 1); + new = xmallocz(j); /* * Second pass: write the new string. Note that this loop is @@ -117,7 +117,7 @@ static const double __ac_HASH_UPPER = 0.77; if (new_n_buckets < 4) new_n_buckets = 4; \ if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \ else { /* hash table size to be changed (shrink or expand); rehash */ \ - new_flags = (khint32_t*)xmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ + ALLOC_ARRAY(new_flags, __ac_fsize(new_n_buckets)); \ if (!new_flags) return -1; \ memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ if (h->n_buckets < new_n_buckets) { /* expand */ \ diff --git a/levenshtein.c b/levenshtein.c index fc281597fd..d2632690d5 100644 --- a/levenshtein.c +++ b/levenshtein.c @@ -42,11 +42,13 @@ int levenshtein(const char *string1, const char *string2, int w, int s, int a, int d) { int len1 = strlen(string1), len2 = strlen(string2); - int *row0 = xmalloc(sizeof(int) * (len2 + 1)); - int *row1 = xmalloc(sizeof(int) * (len2 + 1)); - int *row2 = xmalloc(sizeof(int) * (len2 + 1)); + int *row0, *row1, *row2; int i, j; + ALLOC_ARRAY(row0, len2 + 1); + ALLOC_ARRAY(row1, len2 + 1); + ALLOC_ARRAY(row2, len2 + 1); + for (j = 0; j <= len2; j++) row1[j] = j * a; for (i = 0; i < len1; i++) { diff --git a/line-log.c b/line-log.c index af6e2f799e..bbe31ed6fb 100644 --- a/line-log.c +++ b/line-log.c @@ -14,6 +14,7 @@ #include "graph.h" #include "userdiff.h" #include "line-log.h" +#include "argv-array.h" static void range_set_grow(struct range_set *rs, size_t extra) { @@ -521,7 +522,7 @@ static void fill_line_ends(struct diff_filespec *spec, long *lines, if (diff_populate_filespec(spec, 0)) die("Cannot read blob %s", sha1_to_hex(spec->sha1)); - ends = xmalloc(size * sizeof(*ends)); + ALLOC_ARRAY(ends, size); ends[cur++] = 0; data = spec->data; while (num < spec->size) { @@ -746,22 +747,17 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list add_line_range(rev, commit, range); if (!rev->diffopt.detect_rename) { - int i, count = 0; - struct line_log_data *r = range; + struct line_log_data *r; + struct argv_array array = ARGV_ARRAY_INIT; const char **paths; - while (r) { - count++; - r = r->next; - } - paths = xmalloc((count+1)*sizeof(char *)); - r = range; - for (i = 0; i < count; i++) { - paths[i] = xstrdup(r->path); - r = r->next; - } - paths[count] = NULL; + + for (r = range; r; r = r->next) + argv_array_push(&array, r->path); + paths = argv_array_detach(&array); + parse_pathspec(&rev->diffopt.pathspec, 0, PATHSPEC_PREFER_FULL, "", paths); + /* strings are now owned by pathspec */ free(paths); } } @@ -1146,9 +1142,9 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm if (nparents > 1 && rev->first_parent_only) nparents = 1; - diffqueues = xmalloc(nparents * sizeof(*diffqueues)); - cand = xmalloc(nparents * sizeof(*cand)); - parents = xmalloc(nparents * sizeof(*parents)); + ALLOC_ARRAY(diffqueues, nparents); + ALLOC_ARRAY(cand, nparents); + ALLOC_ARRAY(parents, nparents); p = commit->parents; for (i = 0; i < nparents; i++) { diff --git a/list-objects.c b/list-objects.c index 11732d9388..917cc5d7c9 100644 --- a/list-objects.c +++ b/list-objects.c @@ -11,11 +11,12 @@ static void process_blob(struct rev_info *revs, struct blob *blob, show_object_fn show, - struct name_path *path, + struct strbuf *path, const char *name, void *cb_data) { struct object *obj = &blob->object; + size_t pathlen; if (!revs->blob_objects) return; @@ -24,7 +25,11 @@ static void process_blob(struct rev_info *revs, if (obj->flags & (UNINTERESTING | SEEN)) return; obj->flags |= SEEN; - show(obj, path, name, cb_data); + + pathlen = path->len; + strbuf_addstr(path, name); + show(obj, path->buf, cb_data); + strbuf_setlen(path, pathlen); } /* @@ -52,7 +57,7 @@ static void process_blob(struct rev_info *revs, static void process_gitlink(struct rev_info *revs, const unsigned char *sha1, show_object_fn show, - struct name_path *path, + struct strbuf *path, const char *name, void *cb_data) { @@ -62,7 +67,6 @@ static void process_gitlink(struct rev_info *revs, static void process_tree(struct rev_info *revs, struct tree *tree, show_object_fn show, - struct name_path *path, struct strbuf *base, const char *name, void *cb_data) @@ -70,7 +74,6 @@ static void process_tree(struct rev_info *revs, struct object *obj = &tree->object; struct tree_desc desc; struct name_entry entry; - struct name_path me; enum interesting match = revs->diffopt.pathspec.nr == 0 ? all_entries_interesting: entry_not_interesting; int baselen = base->len; @@ -86,17 +89,12 @@ static void process_tree(struct rev_info *revs, return; die("bad tree object %s", oid_to_hex(&obj->oid)); } + obj->flags |= SEEN; - show(obj, path, name, cb_data); - me.up = path; - me.elem = name; - me.elem_len = strlen(name); - - if (!match) { - strbuf_addstr(base, name); - if (base->len) - strbuf_addch(base, '/'); - } + strbuf_addstr(base, name); + show(obj, base->buf, cb_data); + if (base->len) + strbuf_addch(base, '/'); init_tree_desc(&desc, tree->buffer, tree->size); @@ -113,16 +111,16 @@ static void process_tree(struct rev_info *revs, if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), - show, &me, base, entry.path, + show, base, entry.path, cb_data); else if (S_ISGITLINK(entry.mode)) process_gitlink(revs, entry.sha1, - show, &me, entry.path, + show, base, entry.path, cb_data); else process_blob(revs, lookup_blob(entry.sha1), - show, &me, entry.path, + show, base, entry.path, cb_data); } strbuf_setlen(base, baselen); @@ -213,19 +211,19 @@ void traverse_commit_list(struct rev_info *revs, continue; if (obj->type == OBJ_TAG) { obj->flags |= SEEN; - show_object(obj, NULL, name, data); + show_object(obj, name, data); continue; } if (!path) path = ""; if (obj->type == OBJ_TREE) { process_tree(revs, (struct tree *)obj, show_object, - NULL, &base, path, data); + &base, path, data); continue; } if (obj->type == OBJ_BLOB) { process_blob(revs, (struct blob *)obj, show_object, - NULL, path, data); + &base, path, data); continue; } die("unknown pending object %s (%s)", diff --git a/list-objects.h b/list-objects.h index 136a1da5a6..0cebf8585c 100644 --- a/list-objects.h +++ b/list-objects.h @@ -2,7 +2,7 @@ #define LIST_OBJECTS_H typedef void (*show_commit_fn)(struct commit *, void *); -typedef void (*show_object_fn)(struct object *, const struct name_path *, const char *, void *); +typedef void (*show_object_fn)(struct object *, const char *, void *); void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *); typedef void (*show_edge_fn)(struct commit *); diff --git a/ll-merge.c b/ll-merge.c index 0338630fc2..ff4a43a982 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -205,7 +205,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, if (fstat(fd, &st)) goto close_bad; result->size = st.st_size; - result->ptr = xmalloc(result->size + 1); + result->ptr = xmallocz(result->size); if (read_in_full(fd, result->ptr, result->size) != result->size) { free(result->ptr); result->ptr = NULL; diff --git a/log-tree.c b/log-tree.c index f70a30e127..60f983934d 100644 --- a/log-tree.c +++ b/log-tree.c @@ -77,9 +77,8 @@ int parse_decorate_color_config(const char *var, const char *slot_name, const ch void add_name_decoration(enum decoration_type type, const char *name, struct object *obj) { - int nlen = strlen(name); - struct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1); - memcpy(res->name, name, nlen + 1); + struct name_decoration *res; + FLEX_ALLOC_STR(res, name, name); res->type = type; res->next = add_decoration(&name_decoration, obj, res); } diff --git a/mailinfo.c b/mailinfo.c index f289941f7e..9f19ca1080 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -732,7 +732,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in) struct strbuf continuation = STRBUF_INIT; /* Get the first part of the line. */ - if (strbuf_getline(line, in, '\n')) + if (strbuf_getline_lf(line, in)) return 0; /* @@ -756,7 +756,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in) peek = fgetc(in); ungetc(peek, in); if (peek != ' ' && peek != '\t') break; - if (strbuf_getline(&continuation, in, '\n')) + if (strbuf_getline_lf(&continuation, in)) break; continuation.buf[0] = ' '; strbuf_rtrim(&continuation); @@ -769,7 +769,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in) static int find_boundary(struct mailinfo *mi, struct strbuf *line) { - while (!strbuf_getline(line, mi->input, '\n')) { + while (!strbuf_getline_lf(line, mi->input)) { if (*(mi->content_top) && is_multipart_boundary(mi, line)) return 1; } @@ -820,7 +820,7 @@ again: strbuf_release(&newline); /* replenish line */ - if (strbuf_getline(line, mi->input, '\n')) + if (strbuf_getline_lf(line, mi->input)) return 0; strbuf_addch(line, '\n'); return 1; diff --git a/merge-blobs.c b/merge-blobs.c index ddca601c77..9b6eac22e4 100644 --- a/merge-blobs.c +++ b/merge-blobs.c @@ -48,40 +48,6 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our return res.ptr; } -static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf) -{ - int i; - mmfile_t *dst = priv_; - - for (i = 0; i < nbuf; i++) { - memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size); - dst->size += mb[i].size; - } - return 0; -} - -static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2) -{ - unsigned long size = f1->size < f2->size ? f1->size : f2->size; - void *ptr = xmalloc(size); - xpparam_t xpp; - xdemitconf_t xecfg; - xdemitcb_t ecb; - - memset(&xpp, 0, sizeof(xpp)); - xpp.flags = 0; - memset(&xecfg, 0, sizeof(xecfg)); - xecfg.ctxlen = 3; - xecfg.flags = XDL_EMIT_COMMON; - ecb.outf = common_outf; - - res->ptr = ptr; - res->size = 0; - - ecb.priv = res; - return xdi_diff(f1, f2, &xpp, &xecfg, &ecb); -} - void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size) { void *res = NULL; @@ -112,8 +78,8 @@ void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct if (fill_mmfile_blob(&common, base) < 0) goto out_free_f2_f1; } else { - if (generate_common_file(&common, &f1, &f2) < 0) - goto out_free_f2_f1; + common.ptr = xstrdup(""); + common.size = 0; } res = three_way_filemerge(path, &common, &f1, &f2, size); free_mmfile(&common); diff --git a/merge-recursive.c b/merge-recursive.c index 8eabde20fb..b880ae50e7 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -482,6 +482,9 @@ static struct string_list *get_renames(struct merge_options *o, struct diff_options opts; renames = xcalloc(1, sizeof(struct string_list)); + if (!o->detect_rename) + return renames; + diff_setup(&opts); DIFF_OPT_SET(&opts, RECURSIVE); DIFF_OPT_CLR(&opts, RENAME_EMPTY); @@ -2039,6 +2042,7 @@ void init_merge_options(struct merge_options *o) o->diff_rename_limit = -1; o->merge_rename_limit = -1; o->renormalize = 0; + o->detect_rename = 1; merge_recursive_config(o); if (getenv("GIT_MERGE_VERBOSITY")) o->verbosity = @@ -2088,9 +2092,17 @@ int parse_merge_opt(struct merge_options *o, const char *s) o->renormalize = 1; else if (!strcmp(s, "no-renormalize")) o->renormalize = 0; - else if (skip_prefix(s, "rename-threshold=", &arg)) { + else if (!strcmp(s, "no-renames")) + o->detect_rename = 0; + else if (!strcmp(s, "find-renames")) { + o->detect_rename = 1; + o->rename_score = 0; + } + else if (skip_prefix(s, "find-renames=", &arg) || + skip_prefix(s, "rename-threshold=", &arg)) { if ((o->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0) return -1; + o->detect_rename = 1; } else return -1; diff --git a/merge-recursive.h b/merge-recursive.h index 9e090a3470..52f0201f68 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -17,6 +17,7 @@ struct merge_options { unsigned renormalize : 1; long xdl_opts; int verbosity; + int detect_rename; int diff_rename_limit; int merge_rename_limit; int rename_score; diff --git a/mergetools/vimdiff b/mergetools/vimdiff index 1ddfbfcd78..74ea6d5479 100644 --- a/mergetools/vimdiff +++ b/mergetools/vimdiff @@ -9,8 +9,8 @@ merge_cmd () { gvimdiff|vimdiff) if $base_present then - "$merge_tool_path" -f -d -c 'wincmd J' \ - "$MERGED" "$LOCAL" "$BASE" "$REMOTE" + "$merge_tool_path" -f -d -c '4wincmd w | wincmd J' \ + "$LOCAL" "$BASE" "$REMOTE" "$MERGED" else "$merge_tool_path" -f -d -c 'wincmd l' \ "$LOCAL" "$MERGED" "$REMOTE" diff --git a/name-hash.c b/name-hash.c index 332ba956e7..6d9f23e932 100644 --- a/name-hash.c +++ b/name-hash.c @@ -55,10 +55,9 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate, dir = find_dir_entry(istate, ce->name, namelen); if (!dir) { /* not found, create it and add to hash table */ - dir = xcalloc(1, sizeof(struct dir_entry) + namelen + 1); + FLEX_ALLOC_MEM(dir, name, ce->name, namelen); hashmap_entry_init(dir, memihash(ce->name, namelen)); dir->namelen = namelen; - strncpy(dir->name, ce->name, namelen); hashmap_add(&istate->dir_hash, dir); /* recursively add missing parent directories */ diff --git a/notes-cache.c b/notes-cache.c index c4e9bb7f6c..5dfc5cbd08 100644 --- a/notes-cache.c +++ b/notes-cache.c @@ -32,14 +32,14 @@ void notes_cache_init(struct notes_cache *c, const char *name, const char *validity) { struct strbuf ref = STRBUF_INIT; - int flags = 0; + int flags = NOTES_INIT_WRITABLE; memset(c, 0, sizeof(*c)); c->validity = xstrdup(validity); strbuf_addf(&ref, "refs/notes/%s", name); if (!notes_cache_match_validity(ref.buf, validity)) - flags = NOTES_INIT_EMPTY; + flags |= NOTES_INIT_EMPTY; init_notes(&c->tree, ref.buf, combine_notes_overwrite, flags); strbuf_release(&ref); } @@ -49,7 +49,8 @@ int notes_cache_write(struct notes_cache *c) unsigned char tree_sha1[20]; unsigned char commit_sha1[20]; - if (!c || !c->tree.initialized || !c->tree.ref || !*c->tree.ref) + if (!c || !c->tree.initialized || !c->tree.update_ref || + !*c->tree.update_ref) return -1; if (!c->tree.dirty) return 0; @@ -59,8 +60,8 @@ int notes_cache_write(struct notes_cache *c) if (commit_tree(c->validity, strlen(c->validity), tree_sha1, NULL, commit_sha1, NULL, NULL) < 0) return -1; - if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL, - 0, UPDATE_REFS_QUIET_ON_ERR) < 0) + if (update_ref("update notes cache", c->tree.update_ref, commit_sha1, + NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0) return -1; return 0; diff --git a/notes-utils.c b/notes-utils.c index 299e34bccc..24a33616a4 100644 --- a/notes-utils.c +++ b/notes-utils.c @@ -37,7 +37,7 @@ void commit_notes(struct notes_tree *t, const char *msg) if (!t) t = &default_notes_tree; - if (!t->initialized || !t->ref || !*t->ref) + if (!t->initialized || !t->update_ref || !*t->update_ref) die(_("Cannot commit uninitialized/unreferenced notes tree")); if (!t->dirty) return; /* don't have to commit an unchanged tree */ @@ -48,7 +48,7 @@ void commit_notes(struct notes_tree *t, const char *msg) create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1); strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */ - update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, + update_ref(buf.buf, t->update_ref, commit_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); strbuf_release(&buf); @@ -148,7 +148,7 @@ struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd) free(c); return NULL; } - c->trees = load_notes_trees(c->refs); + c->trees = load_notes_trees(c->refs, NOTES_INIT_WRITABLE); string_list_clear(c->refs, 0); free(c->refs); return c; @@ -1011,13 +1011,16 @@ void init_notes(struct notes_tree *t, const char *notes_ref, t->first_non_note = NULL; t->prev_non_note = NULL; t->ref = xstrdup_or_null(notes_ref); + t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL; t->combine_notes = combine_notes; t->initialized = 1; t->dirty = 0; if (flags & NOTES_INIT_EMPTY || !notes_ref || - read_ref(notes_ref, object_sha1)) + get_sha1_treeish(notes_ref, object_sha1)) return; + if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_sha1)) + die("Cannot use notes ref %s", notes_ref); if (get_tree_entry(object_sha1, "", sha1, &mode)) die("Failed to read notes tree referenced by %s (%s)", notes_ref, sha1_to_hex(object_sha1)); @@ -1027,15 +1030,15 @@ void init_notes(struct notes_tree *t, const char *notes_ref, load_subtree(t, &root_tree, t->root, 0); } -struct notes_tree **load_notes_trees(struct string_list *refs) +struct notes_tree **load_notes_trees(struct string_list *refs, int flags) { struct string_list_item *item; int counter = 0; struct notes_tree **trees; - trees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *)); + ALLOC_ARRAY(trees, refs->nr + 1); for_each_string_list_item(item, refs) { struct notes_tree *t = xcalloc(1, sizeof(struct notes_tree)); - init_notes(t, item->string, combine_notes_ignore, 0); + init_notes(t, item->string, combine_notes_ignore, flags); trees[counter++] = t; } trees[counter] = NULL; @@ -1071,7 +1074,7 @@ void init_display_notes(struct display_notes_opt *opt) item->string); } - display_notes_trees = load_notes_trees(&display_notes_refs); + display_notes_trees = load_notes_trees(&display_notes_refs, 0); string_list_clear(&display_notes_refs, 0); } @@ -1303,3 +1306,13 @@ void expand_notes_ref(struct strbuf *sb) else strbuf_insert(sb, 0, "refs/notes/", 11); } + +void expand_loose_notes_ref(struct strbuf *sb) +{ + unsigned char object[20]; + + if (get_sha1(sb->buf, object)) { + /* fallback to expand_notes_ref */ + expand_notes_ref(sb); + } +} @@ -44,6 +44,7 @@ extern struct notes_tree { struct int_node *root; struct non_note *first_non_note, *prev_non_note; char *ref; + char *update_ref; combine_notes_fn combine_notes; int initialized; int dirty; @@ -72,6 +73,13 @@ const char *default_notes_ref(void); #define NOTES_INIT_EMPTY 1 /* + * By default, the notes tree is only readable, and the notes ref can be + * any treeish. The notes tree can however be made writable with this flag, + * in which case only strict ref names can be used. + */ +#define NOTES_INIT_WRITABLE 2 + +/* * Initialize the given notes_tree with the notes tree structure at the given * ref. If given ref is NULL, the value of the $GIT_NOTES_REF environment * variable is used, and if that is missing, the default notes ref is used @@ -276,7 +284,7 @@ void format_display_notes(const unsigned char *object_sha1, * Load the notes tree from each ref listed in 'refs'. The output is * an array of notes_tree*, terminated by a NULL. */ -struct notes_tree **load_notes_trees(struct string_list *refs); +struct notes_tree **load_notes_trees(struct string_list *refs, int flags); /* * Add all refs that match 'glob' to the 'list'. @@ -294,4 +302,11 @@ void string_list_add_refs_from_colon_sep(struct string_list *list, /* Expand inplace a note ref like "foo" or "notes/foo" into "refs/notes/foo" */ void expand_notes_ref(struct strbuf *sb); +/* + * Similar to expand_notes_ref, but will check whether the ref can be located + * via get_sha1 first, and only falls back to expand_notes_ref in the case + * where get_sha1 fails. + */ +void expand_loose_notes_ref(struct strbuf *sb); + #endif diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index 6bff970c90..c30bcd06cb 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -148,8 +148,7 @@ static uint32_t find_object_pos(const unsigned char *sha1) return entry->in_pack_pos; } -static void show_object(struct object *object, const struct name_path *path, - const char *last, void *data) +static void show_object(struct object *object, const char *name, void *data) { struct bitmap *base = data; bitmap_set(base, find_object_pos(object->oid.hash)); diff --git a/pack-bitmap.c b/pack-bitmap.c index cb9c622803..b949e51716 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -33,9 +33,6 @@ static struct bitmap_index { /* Packfile to which this bitmap index belongs to */ struct packed_git *pack; - /* reverse index for the packfile */ - struct pack_revindex *reverse_index; - /* * Mark the first `reuse_objects` in the packfile as reused: * they will be sent as-is without using them for repacking @@ -308,7 +305,7 @@ static int load_pack_bitmap(void) bitmap_git.bitmaps = kh_init_sha1(); bitmap_git.ext_index.positions = kh_init_sha1_pos(); - bitmap_git.reverse_index = revindex_for_pack(bitmap_git.pack); + load_pack_revindex(bitmap_git.pack); if (!(bitmap_git.commits = read_bitmap_1(&bitmap_git)) || !(bitmap_git.trees = read_bitmap_1(&bitmap_git)) || @@ -380,7 +377,7 @@ static inline int bitmap_position_packfile(const unsigned char *sha1) if (!offset) return -1; - return find_revindex_position(bitmap_git.reverse_index, offset); + return find_revindex_position(bitmap_git.pack, offset); } static int bitmap_position(const unsigned char *sha1) @@ -417,19 +414,15 @@ static int ext_index_add_object(struct object *object, const char *name) return bitmap_pos + bitmap_git.pack->num_objects; } -static void show_object(struct object *object, const struct name_path *path, - const char *last, void *data) +static void show_object(struct object *object, const char *name, void *data) { struct bitmap *base = data; int bitmap_pos; bitmap_pos = bitmap_position(object->oid.hash); - if (bitmap_pos < 0) { - char *name = path_name(path, last); + if (bitmap_pos < 0) bitmap_pos = ext_index_add_object(object, name); - free(name); - } bitmap_set(base, bitmap_pos); } @@ -630,7 +623,7 @@ static void show_objects_for_type( if (pos + offset < bitmap_git.reuse_objects) continue; - entry = &bitmap_git.reverse_index->revindex[pos + offset]; + entry = &bitmap_git.pack->revindex[pos + offset]; sha1 = nth_packed_object_sha1(bitmap_git.pack, entry->nr); if (bitmap_git.hashes) @@ -804,7 +797,7 @@ int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, return -1; bitmap_git.reuse_objects = *entries = reuse_objects; - *up_to = bitmap_git.reverse_index->revindex[reuse_objects].offset; + *up_to = bitmap_git.pack->revindex[reuse_objects].offset; *packfile = bitmap_git.pack; return 0; @@ -897,9 +890,8 @@ struct bitmap_test_data { size_t seen; }; -static void test_show_object(struct object *object, - const struct name_path *path, - const char *last, void *data) +static void test_show_object(struct object *object, const char *name, + void *data) { struct bitmap_test_data *tdata = data; int bitmap_pos; @@ -1038,7 +1030,7 @@ int rebuild_existing_bitmaps(struct packing_data *mapping, struct revindex_entry *entry; struct object_entry *oe; - entry = &bitmap_git.reverse_index->revindex[i]; + entry = &bitmap_git.pack->revindex[i]; sha1 = nth_packed_object_sha1(bitmap_git.pack, entry->nr); oe = packlist_find(mapping, sha1, NULL); diff --git a/pack-check.c b/pack-check.c index 433bd86ccd..1da89a41ce 100644 --- a/pack-check.c +++ b/pack-check.c @@ -89,7 +89,7 @@ static int verify_packfile(struct packed_git *p, * we do not do scan-streaming check on the pack file. */ nr_objects = p->num_objects; - entries = xmalloc((nr_objects + 1) * sizeof(*entries)); + ALLOC_ARRAY(entries, nr_objects + 1); entries[nr_objects].offset = pack_sig_ofs; /* first sort entries by pack offset, since unpacking them is more efficient that way */ for (i = 0; i < nr_objects; i++) { diff --git a/pack-revindex.c b/pack-revindex.c index e542ea7703..96d51c3467 100644 --- a/pack-revindex.c +++ b/pack-revindex.c @@ -8,52 +8,13 @@ * size is easily available by examining the pack entry header). It is * also rather expensive to find the sha1 for an object given its offset. * - * We build a hashtable of existing packs (pack_revindex), and keep reverse - * index here -- pack index file is sorted by object name mapping to offset; - * this pack_revindex[].revindex array is a list of offset/index_nr pairs + * The pack index file is sorted by object name mapping to offset; + * this revindex array is a list of offset/index_nr pairs * ordered by offset, so if you know the offset of an object, next offset * is where its packed representation ends and the index_nr can be used to * get the object sha1 from the main index. */ -static struct pack_revindex *pack_revindex; -static int pack_revindex_hashsz; - -static int pack_revindex_ix(struct packed_git *p) -{ - unsigned long ui = (unsigned long)(intptr_t)p; - int i; - - ui = ui ^ (ui >> 16); /* defeat structure alignment */ - i = (int)(ui % pack_revindex_hashsz); - while (pack_revindex[i].p) { - if (pack_revindex[i].p == p) - return i; - if (++i == pack_revindex_hashsz) - i = 0; - } - return -1 - i; -} - -static void init_pack_revindex(void) -{ - int num; - struct packed_git *p; - - for (num = 0, p = packed_git; p; p = p->next) - num++; - if (!num) - return; - pack_revindex_hashsz = num * 11; - pack_revindex = xcalloc(pack_revindex_hashsz, sizeof(*pack_revindex)); - for (p = packed_git; p; p = p->next) { - num = pack_revindex_ix(p); - num = - 1 - num; - pack_revindex[num].p = p; - } - /* revindex elements are lazily initialized */ -} - /* * This is a least-significant-digit radix sort. * @@ -83,10 +44,14 @@ static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max) * keep track of them with alias pointers, always sorting from "from" * to "to". */ - struct revindex_entry *tmp = xmalloc(n * sizeof(*tmp)); - struct revindex_entry *from = entries, *to = tmp; + struct revindex_entry *tmp, *from, *to; int bits; - unsigned *pos = xmalloc(BUCKETS * sizeof(*pos)); + unsigned *pos; + + ALLOC_ARRAY(pos, BUCKETS); + ALLOC_ARRAY(tmp, n); + from = entries; + to = tmp; /* * If (max >> bits) is zero, then we know that the radix digit we are @@ -154,14 +119,13 @@ static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max) /* * Ordered list of offsets of objects in the pack. */ -static void create_pack_revindex(struct pack_revindex *rix) +static void create_pack_revindex(struct packed_git *p) { - struct packed_git *p = rix->p; unsigned num_ent = p->num_objects; unsigned i; const char *index = p->index_data; - rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1)); + ALLOC_ARRAY(p->revindex, num_ent + 1); index += 4 * 256; if (p->index_version > 1) { @@ -171,55 +135,42 @@ static void create_pack_revindex(struct pack_revindex *rix) for (i = 0; i < num_ent; i++) { uint32_t off = ntohl(*off_32++); if (!(off & 0x80000000)) { - rix->revindex[i].offset = off; + p->revindex[i].offset = off; } else { - rix->revindex[i].offset = + p->revindex[i].offset = ((uint64_t)ntohl(*off_64++)) << 32; - rix->revindex[i].offset |= + p->revindex[i].offset |= ntohl(*off_64++); } - rix->revindex[i].nr = i; + p->revindex[i].nr = i; } } else { for (i = 0; i < num_ent; i++) { uint32_t hl = *((uint32_t *)(index + 24 * i)); - rix->revindex[i].offset = ntohl(hl); - rix->revindex[i].nr = i; + p->revindex[i].offset = ntohl(hl); + p->revindex[i].nr = i; } } /* This knows the pack format -- the 20-byte trailer * follows immediately after the last object data. */ - rix->revindex[num_ent].offset = p->pack_size - 20; - rix->revindex[num_ent].nr = -1; - sort_revindex(rix->revindex, num_ent, p->pack_size); + p->revindex[num_ent].offset = p->pack_size - 20; + p->revindex[num_ent].nr = -1; + sort_revindex(p->revindex, num_ent, p->pack_size); } -struct pack_revindex *revindex_for_pack(struct packed_git *p) +void load_pack_revindex(struct packed_git *p) { - int num; - struct pack_revindex *rix; - - if (!pack_revindex_hashsz) - init_pack_revindex(); - - num = pack_revindex_ix(p); - if (num < 0) - die("internal error: pack revindex fubar"); - - rix = &pack_revindex[num]; - if (!rix->revindex) - create_pack_revindex(rix); - - return rix; + if (!p->revindex) + create_pack_revindex(p); } -int find_revindex_position(struct pack_revindex *pridx, off_t ofs) +int find_revindex_position(struct packed_git *p, off_t ofs) { int lo = 0; - int hi = pridx->p->num_objects + 1; - struct revindex_entry *revindex = pridx->revindex; + int hi = p->num_objects + 1; + struct revindex_entry *revindex = p->revindex; do { unsigned mi = lo + (hi - lo) / 2; @@ -237,11 +188,13 @@ int find_revindex_position(struct pack_revindex *pridx, off_t ofs) struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs) { - struct pack_revindex *pridx = revindex_for_pack(p); - int pos = find_revindex_position(pridx, ofs); + int pos; + + load_pack_revindex(p); + pos = find_revindex_position(p, ofs); if (pos < 0) return NULL; - return pridx->revindex + pos; + return p->revindex + pos; } diff --git a/pack-revindex.h b/pack-revindex.h index d737f98965..e262f3efe8 100644 --- a/pack-revindex.h +++ b/pack-revindex.h @@ -1,18 +1,15 @@ #ifndef PACK_REVINDEX_H #define PACK_REVINDEX_H +struct packed_git; + struct revindex_entry { off_t offset; unsigned int nr; }; -struct pack_revindex { - struct packed_git *p; - struct revindex_entry *revindex; -}; - -struct pack_revindex *revindex_for_pack(struct packed_git *p); -int find_revindex_position(struct pack_revindex *pridx, off_t ofs); +void load_pack_revindex(struct packed_git *p); +int find_revindex_position(struct packed_git *p, off_t ofs); struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs); @@ -11,7 +11,6 @@ * something different on Windows. */ -static const char *pager_argv[] = { NULL, NULL }; static struct child_process pager_process = CHILD_PROCESS_INIT; static void wait_for_pager(int in_signal) @@ -64,6 +63,16 @@ const char *git_pager(int stdout_is_tty) return pager; } +void prepare_pager_args(struct child_process *pager_process, const char *pager) +{ + argv_array_push(&pager_process->args, pager); + pager_process->use_shell = 1; + if (!getenv("LESS")) + argv_array_push(&pager_process->env_array, "LESS=FRX"); + if (!getenv("LV")) + argv_array_push(&pager_process->env_array, "LV=-c"); +} + void setup_pager(void) { const char *pager = git_pager(isatty(1)); @@ -80,14 +89,8 @@ void setup_pager(void) setenv("GIT_PAGER_IN_USE", "true", 1); /* spawn the pager */ - pager_argv[0] = pager; - pager_process.use_shell = 1; - pager_process.argv = pager_argv; + prepare_pager_args(&pager_process, pager); pager_process.in = -1; - if (!getenv("LESS")) - argv_array_push(&pager_process.env_array, "LESS=FRX"); - if (!getenv("LV")) - argv_array_push(&pager_process.env_array, "LV=-c"); argv_array_push(&pager_process.env_array, "GIT_PAGER_IN_USE"); if (start_command(&pager_process)) return; @@ -782,13 +782,10 @@ const char *relative_path(const char *in, const char *prefix, else if (!prefix_len) return in; - if (have_same_root(in, prefix)) { + if (have_same_root(in, prefix)) /* bypass dos_drive, for "c:" is identical to "C:" */ - if (has_dos_drive_prefix(in)) { - i = 2; - j = 2; - } - } else { + i = j = has_dos_drive_prefix(in); + else { return in; } @@ -943,11 +940,10 @@ const char *remove_leading_path(const char *in, const char *prefix) int normalize_path_copy_len(char *dst, const char *src, int *prefix_len) { char *dst0; + int i; - if (has_dos_drive_prefix(src)) { + for (i = has_dos_drive_prefix(src); i > 0; i--) *dst++ = *src++; - *dst++ = *src++; - } dst0 = dst; if (is_dir_sep(*src)) { diff --git a/pathspec.c b/pathspec.c index 9304ee33d7..c9e9b6c077 100644 --- a/pathspec.c +++ b/pathspec.c @@ -406,7 +406,8 @@ void parse_pathspec(struct pathspec *pathspec, n++; pathspec->nr = n; - pathspec->items = item = xmalloc(sizeof(*item) * n); + ALLOC_ARRAY(pathspec->items, n); + item = pathspec->items; pathspec->_raw = argv; prefixlen = prefix ? strlen(prefix) : 0; @@ -483,7 +484,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec) void copy_pathspec(struct pathspec *dst, const struct pathspec *src) { *dst = *src; - dst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr); + ALLOC_ARRAY(dst->items, dst->nr); memcpy(dst->items, src->items, sizeof(struct pathspec_item) * dst->nr); } diff --git a/perl/Git.pm b/perl/Git.pm index 19ef081103..49eb88af8d 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -188,7 +188,8 @@ sub repository { }; if ($dir) { - $dir =~ m#^/# or $dir = $opts{Directory} . '/' . $dir; + _verify_require(); + File::Spec->file_name_is_absolute($dir) or $dir = $opts{Directory} . '/' . $dir; $opts{Repository} = abs_path($dir); # If --git-dir went ok, this shouldn't die either. diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm index c50176eec9..4c4199afec 100644 --- a/perl/Git/SVN/Editor.pm +++ b/perl/Git/SVN/Editor.pm @@ -41,6 +41,7 @@ sub new { "$self->{svn_path}/" : ''; $self->{config} = $opts->{config}; $self->{mergeinfo} = $opts->{mergeinfo}; + $self->{pathnameencoding} = Git::config('svn.pathnameencoding'); return $self; } @@ -143,11 +144,12 @@ sub repo_path { sub url_path { my ($self, $path) = @_; + $path = $self->repo_path($path); if ($self->{url} =~ m#^https?://#) { # characters are taken from subversion/libsvn_subr/path.c $path =~ s#([^~a-zA-Z0-9_./!$&'()*+,-])#sprintf("%%%02X",ord($1))#eg; } - $self->{url} . '/' . $self->repo_path($path); + $self->{url} . '/' . $path; } sub rmdirs { diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 4a499fcb38..e764696801 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -81,7 +81,6 @@ sub prepare_config_once { SVN::_Core::svn_config_ensure($config_dir, undef); my ($baton, $callbacks) = SVN::Core::auth_open_helper(_auth_providers); my $config = SVN::Core::config_get_config($config_dir); - my $dont_store_passwords = 1; my $conf_t = $config->{'config'}; no warnings 'once'; @@ -93,9 +92,14 @@ sub prepare_config_once { $SVN::_Core::SVN_CONFIG_SECTION_AUTH, $SVN::_Core::SVN_CONFIG_OPTION_STORE_PASSWORDS, 1) == 0) { + my $val = '1'; + if (::compare_svn_version('1.9.0') < 0) { # pre-SVN r1553823 + my $dont_store_passwords = 1; + $val = bless \$dont_store_passwords, "_p_void"; + } SVN::_Core::svn_auth_set_parameter($baton, $SVN::_Core::SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, - bless (\$dont_store_passwords, "_p_void")); + $val); } if (SVN::_Core::svn_config_get_bool($conf_t, $SVN::_Core::SVN_CONFIG_SECTION_AUTH, @@ -32,6 +32,10 @@ Repository: https://github.com/quizzlo/git-po-it/ Leader: Marco Paolone <marcopaolone AT gmail.com> Members: Stefano Lattarini <stefano.lattarini AT gmail.com> +Language: ko (Korean) +Repository: https://github.com/changwoo/git-l10n-ko/ +Leader: Changwoo Ryu <cwryu@debian.org> + Language: pt_PT (Portuguese - Portugal) Repository: https://github.com/marcomsousa/git-l10n-pt_PT/ Leader: Marco Sousa <marcomsousa AT gmail.com> diff --git a/po/ko.po b/po/ko.po new file mode 100644 index 0000000000..8ec0eac134 --- /dev/null +++ b/po/ko.po @@ -0,0 +1,11859 @@ +# Git Korean translation +# Copyright (C) 2015-2016 Changwoo Ryu and contributors +# This file is distributed under the same license as the Git package. +# +# Contributors: +# Hyunjun Kim <yoloseem AT users.noreply.github.com>, 2015. +# Changwoo Ryu <cwryu@debian.org>, 2015-2016. +# +# - 작업자는 위 Contributors 목록에 추가해 주세요. +# - 번역하면서 80컬럼을 넘어가지 않도록 해 주세요. +# - 가능한한 원문이 1줄이면 1줄에 들어가게 하고, 부득이하면 경우에 따라 +# 알맞게 줄바꿈합니다. (커맨드라인이면 줄바꿈하고 다음 줄에 탭 2개) +# - 용어는 일관성을 지켜 주십시오. +# - 용어가 바뀌어야 한다고 생각하면 그렇게 번역하기 전에 충분히 의견 교환을 +# 하십시오. +# - 일반적인 문장에서 영어 단어를 그대로 쓰지 않습니다. 최소한 음역합니다. +# - 예외적으로 명령어 등 문자 그대로 가리키는 경우에만 원문 그대로 씁니다. +# - 예: 업스트림 추적에 'origin' 대신 <이름>을 사용합니다 +# - 번역된 용어가 깃 명령어와 연관되는 경우에는 괄호 안에 씁니다. +# - 예: 되돌리기(revert)가 진행 중입니다 +# - 용어: +# +--------------+----------------------------------------------+ +# | 3-way merge | 3-방향 병합 | +# | author | 작성자 | +# | bisect | 이등분 | +# | blob | 블롭 | +# | bundle | 번들 | +# | branch | 브랜치 | +# | cherry-pick | (커밋) 빼오기 | +# | commit | 커밋 | +# | commit-ish | 커밋-따위 | +# | committer | 커미터 | +# | conflict | 충돌 | +# | fast-forward | 정방향 진행 | +# | head | 헤드 | +# | hook | 훅 | +# | history | (커밋) 내역 | +# | Git | 깃 | +# | log | 기록 | +# | merge | 병합 | +# | note | 노트 | +# | pack | 묶음 | +# | pathspec | 경로명세 | +# | rebase | 리베이스 | +# | ref | 레퍼런스 | +# | repo | 저장소 | +# | remote | 리모트 (저장소) | +# | reset | 재지정 | +# | revert | 되돌리기 | +# | subcommand | 하위 명령 | +# | submodule | 하위 모듈 | +# | tree-ish | 트리-따위 | +# | working tree | 작업 폴더 | +# +--------------+----------------------------------------------+ +# +msgid "" +msgstr "" +"Project-Id-Version: git\n" +"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" +"POT-Creation-Date: 2015-12-22 22:50+0800\n" +"PO-Revision-Date: 2016-01-03 18:50+0900\n" +"Last-Translator: Changwoo Ryu <cwryu@debian.org>\n" +"Language-Team: Git Korean translation <http://github.com/changwoo/git-l10n-" +"ko>\n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: advice.c:55 +#, c-format +msgid "hint: %.*s\n" +msgstr "힌트: %.*s\n" + +#: advice.c:88 +msgid "" +"Fix them up in the work tree, and then use 'git add/rm <file>'\n" +"as appropriate to mark resolution and make a commit." +msgstr "" +"작업 폴더에서 문제를 바로잡은 다음, 'git add/rm <파일>'을 적절히\n" +"사용해 해결 표시하고 커밋하십시오." + +#: advice.c:101 builtin/merge.c:1225 +msgid "You have not concluded your merge (MERGE_HEAD exists)." +msgstr "병합 작업을 다 마치지 않았습니다 (MERGE_HEAD 파일이 있습니다)." + +#: advice.c:103 +msgid "Please, commit your changes before merging." +msgstr "병합하기 전에 변경 사항을 커밋하십시오." + +#: advice.c:104 +msgid "Exiting because of unfinished merge." +msgstr "병합을 마치지 못했기 때문에 끝납니다." + +#: archive.c:12 +msgid "git archive [<options>] <tree-ish> [<path>...]" +msgstr "git archive [<옵션>] <트리-따위> [<경로>...]" + +#: archive.c:13 +msgid "git archive --list" +msgstr "git archive --list" + +#: archive.c:14 +msgid "" +"git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]" +msgstr "" +"git archive --remote <저장소> [--exec <명령>] [<옵션>] <트리-따위> [<경로" +">...]" + +#: archive.c:15 +msgid "git archive --remote <repo> [--exec <cmd>] --list" +msgstr "git archive --remote <저장소> [--exec <명령>] --list" + +#: archive.c:344 builtin/add.c:137 builtin/add.c:420 builtin/rm.c:327 +#, c-format +msgid "pathspec '%s' did not match any files" +msgstr "'%s' 경로명세가 어떤 파일과도 일치하지 않습니다" + +#: archive.c:429 +msgid "fmt" +msgstr "형식" + +#: archive.c:429 +msgid "archive format" +msgstr "압축 형식" + +#: archive.c:430 builtin/log.c:1229 +msgid "prefix" +msgstr "접두어" + +#: archive.c:431 +msgid "prepend prefix to each pathname in the archive" +msgstr "아카이브의 각 경로 이름의 앞에 지정한 경로를 붙입니다" + +#: archive.c:432 builtin/archive.c:88 builtin/blame.c:2535 builtin/blame.c:2536 +#: builtin/config.c:58 builtin/fast-export.c:987 builtin/fast-export.c:989 +#: builtin/grep.c:707 builtin/hash-object.c:99 builtin/ls-files.c:446 +#: builtin/ls-files.c:449 builtin/notes.c:395 builtin/notes.c:558 +#: builtin/read-tree.c:109 parse-options.h:153 +msgid "file" +msgstr "파일" + +#: archive.c:433 builtin/archive.c:89 +msgid "write the archive to this file" +msgstr "아카이브를 이 파일에 씁니다" + +#: archive.c:435 +msgid "read .gitattributes in working directory" +msgstr "작업 폴더의 .gitattributes를 읽습니다" + +#: archive.c:436 +msgid "report archived files on stderr" +msgstr "아카이브에 포함된 파일을 표준오류로 표시합니다" + +#: archive.c:437 +msgid "store only" +msgstr "저장만 하기" + +#: archive.c:438 +msgid "compress faster" +msgstr "더 빠르게 압축" + +#: archive.c:446 +msgid "compress better" +msgstr "더 작게 압축" + +#: archive.c:449 +msgid "list supported archive formats" +msgstr "지원하는 압축 형식의 목록을 표시합니다" + +#: archive.c:451 builtin/archive.c:90 builtin/clone.c:77 +msgid "repo" +msgstr "저장소" + +#: archive.c:452 builtin/archive.c:91 +msgid "retrieve the archive from remote repository <repo>" +msgstr "원격 저장소 <저장소>에서 아카이브를 가져옵니다" + +#: archive.c:453 builtin/archive.c:92 builtin/notes.c:479 +msgid "command" +msgstr "명령" + +#: archive.c:454 builtin/archive.c:93 +msgid "path to the remote git-upload-archive command" +msgstr "원격 git-upload-archive 명령의 경로" + +#: attr.c:265 +msgid "" +"Negative patterns are ignored in git attributes\n" +"Use '\\!' for literal leading exclamation." +msgstr "" +"git attributes에서 반대 패턴은 무시됩니다.\n" +"앞에 느낌표를 쓰려면 '\\!'를 사용하십시오." + +#: branch.c:61 +#, c-format +msgid "Not setting branch %s as its own upstream." +msgstr "%s 브랜치를 자신의 업스트림으로 지정하지 않음." + +#: branch.c:84 +#, c-format +msgid "Branch %s set up to track remote branch %s from %s by rebasing." +msgstr "" +"%s 브랜치가 리베이스를 통해 리모트의 %s 브랜치를 (%s에서) 따라가도록 설정되었" +"습니다." + +#: branch.c:85 +#, c-format +msgid "Branch %s set up to track remote branch %s from %s." +msgstr "%s 브랜치가 리모트의 %s 브랜치를 (%s에서) 따라가도록 설정되었습니다." + +#: branch.c:89 +#, c-format +msgid "Branch %s set up to track local branch %s by rebasing." +msgstr "" +"%s 브랜치가 리베이스를 통해 리모트의 %s 브랜치를 따라가도록 설정되었습니다." + +#: branch.c:90 +#, c-format +msgid "Branch %s set up to track local branch %s." +msgstr "%s 브랜치가 %s 브랜치를 따라가도록 설정되었습니다." + +#: branch.c:95 +#, c-format +msgid "Branch %s set up to track remote ref %s by rebasing." +msgstr "" +"%s 브랜치가 리베이스를 통해 리모트의 %s 레퍼런스를 따라가도록 설정되었습니다." + +#: branch.c:96 +#, c-format +msgid "Branch %s set up to track remote ref %s." +msgstr "%s 브랜치가 리모트의 %s 레퍼런스를 따라가도록 설정되었습니다." + +#: branch.c:100 +#, c-format +msgid "Branch %s set up to track local ref %s by rebasing." +msgstr "" +"%s 브랜치가 리베이스를 통해 로컬의 %s 레퍼런스를 따라가도록 설정되었습니다." + +#: branch.c:101 +#, c-format +msgid "Branch %s set up to track local ref %s." +msgstr "%s 브랜치가 로컬의 %s 레퍼런스를 따라가도록 설정되었습니다." + +#: branch.c:134 +#, c-format +msgid "Not tracking: ambiguous information for ref %s" +msgstr "따라가지 않음: %s 레퍼런스에 대해 애매한 정보" + +#: branch.c:163 +#, c-format +msgid "'%s' is not a valid branch name." +msgstr "'%s'은(는) 올바른 브랜치 이름이 아닙니다." + +#: branch.c:168 +#, c-format +msgid "A branch named '%s' already exists." +msgstr "이름이 '%s'인 브랜치가 이미 있습니다." + +#: branch.c:176 +msgid "Cannot force update the current branch." +msgstr "현재 브랜치를 강제로 업데이트할 수 없습니다." + +#: branch.c:196 +#, c-format +msgid "Cannot setup tracking information; starting point '%s' is not a branch." +msgstr "" +"따라가기 정보를 설정할 수 없습니다. 시작 위치 '%s'이(가) 브랜치가 아닙니다." + +#: branch.c:198 +#, c-format +msgid "the requested upstream branch '%s' does not exist" +msgstr "요청한 업스트림 '%s' 브랜치가 없습니다" + +#: branch.c:200 +msgid "" +"\n" +"If you are planning on basing your work on an upstream\n" +"branch that already exists at the remote, you may need to\n" +"run \"git fetch\" to retrieve it.\n" +"\n" +"If you are planning to push out a new local branch that\n" +"will track its remote counterpart, you may want to use\n" +"\"git push -u\" to set the upstream config as you push." +msgstr "" +"\n" +"리모트에 이미 있는 업스트림 브랜치를 기반으로 작업하려면,\n" +"먼저 \"git fetch\"로 가져 리모트 브랜치를 가져옵니다.\n" +"\n" +"새 로컬 브랜치를 거기에 해당하는 리모트 브랜치로 push하려면,\n" +"\"git push -u\"로 push하는 업스트림을 설정할 수 있습니다." + +#: branch.c:244 +#, c-format +msgid "Not a valid object name: '%s'." +msgstr "올바른 오브젝트 이름이 아닙니다: '%s'." + +#: branch.c:264 +#, c-format +msgid "Ambiguous object name: '%s'." +msgstr "애매한 오브젝트 이름: '%s'." + +#: branch.c:269 +#, c-format +msgid "Not a valid branch point: '%s'." +msgstr "올바른 브랜치 위치가 아닙니다: '%s'." + +#: branch.c:322 +#, c-format +msgid "'%s' is already checked out at '%s'" +msgstr "'%s'은(는) 이미 '%s' 위치에 받아져 있습니다" + +#: bundle.c:34 +#, c-format +msgid "'%s' does not look like a v2 bundle file" +msgstr "'%s' 파일이 버전2 번들 파일로 보이지 않습니다" + +#: bundle.c:61 +#, c-format +msgid "unrecognized header: %s%s (%d)" +msgstr "인식할 수 없는 헤더: %s%s (%d)" + +#: bundle.c:87 builtin/commit.c:766 +#, c-format +msgid "could not open '%s'" +msgstr "'%s'을(를) 열 수 없습니다" + +#: bundle.c:139 +msgid "Repository lacks these prerequisite commits:" +msgstr "저장소에 필수적인 다음 커밋이 없습니다:" + +#: bundle.c:163 ref-filter.c:1372 sequencer.c:636 sequencer.c:1083 +#: builtin/blame.c:2734 builtin/commit.c:1045 builtin/log.c:334 +#: builtin/log.c:849 builtin/log.c:1461 builtin/log.c:1694 builtin/merge.c:358 +#: builtin/shortlog.c:158 +msgid "revision walk setup failed" +msgstr "리비전 walk 준비가 실패했습니다" + +#: bundle.c:185 +#, c-format +msgid "The bundle contains this ref:" +msgid_plural "The bundle contains these %d refs:" +msgstr[0] "번들에 다음 레퍼런스 %d개가 있습니다:" + +#: bundle.c:192 +msgid "The bundle records a complete history." +msgstr "번들은 전체 커밋 내역을 기록합니다." + +#: bundle.c:194 +#, c-format +msgid "The bundle requires this ref:" +msgid_plural "The bundle requires these %d refs:" +msgstr[0] "번들에 다음 레퍼런스 %d개가 필요합니다:" + +#: bundle.c:253 +msgid "Could not spawn pack-objects" +msgstr "pack-objects 명령을 실행할 수 없습니다" + +#: bundle.c:264 +msgid "pack-objects died" +msgstr "pack-objects 명령이 죽었습니다" + +#: bundle.c:304 +msgid "rev-list died" +msgstr "rev-list 명령이 죽었습니다" + +#: bundle.c:353 +#, c-format +msgid "ref '%s' is excluded by the rev-list options" +msgstr "rev-list 옵션에서 '%s' 레퍼런스가 제외되었습니다" + +#: bundle.c:443 builtin/log.c:157 builtin/log.c:1369 builtin/shortlog.c:261 +#, c-format +msgid "unrecognized argument: %s" +msgstr "알 수 없는 인자: %s" + +#: bundle.c:449 +msgid "Refusing to create empty bundle." +msgstr "빈 번들은 만들지 않습니다." + +#: bundle.c:459 +#, c-format +msgid "cannot create '%s'" +msgstr "'%s'을(를) 만들 수 없습니다" + +#: bundle.c:480 +msgid "index-pack died" +msgstr "index-pack 명령이 죽었습니다" + +#: color.c:275 +#, c-format +msgid "invalid color value: %.*s" +msgstr "잘못된 색 값: %.*s" + +#: commit.c:40 builtin/am.c:452 builtin/am.c:488 builtin/am.c:1520 +#: builtin/am.c:2149 +#, c-format +msgid "could not parse %s" +msgstr "parse %s을(를) 파싱할 수 없습니다" + +#: commit.c:42 +#, c-format +msgid "%s %s is not a commit!" +msgstr "%s %s, 커밋이 아닙니다" + +#: compat/obstack.c:406 compat/obstack.c:408 +msgid "memory exhausted" +msgstr "메모리 바닥남" + +#: config.c:474 config.c:476 +#, c-format +msgid "bad config file line %d in %s" +msgstr "%2$s 파일 %1$d번 줄에 잘못된 설정" + +#: config.c:592 +#, c-format +msgid "bad numeric config value '%s' for '%s' in %s: %s" +msgstr "잘못된 수치 설정 값 '%s' (키 '%s', %s 파일): %s" + +#: config.c:594 +#, c-format +msgid "bad numeric config value '%s' for '%s': %s" +msgstr "잘못된 수치 설정 값 '%s' (키 '%s'): %s" + +#: config.c:679 +#, c-format +msgid "failed to expand user dir in: '%s'" +msgstr "다음에 사용자 디렉터리 확장에 실패: '%s'" + +#: config.c:757 config.c:768 +#, c-format +msgid "bad zlib compression level %d" +msgstr "%d번은 올바른 zlib 압축 단계가 아닙니다" + +#: config.c:890 +#, c-format +msgid "invalid mode for object creation: %s" +msgstr "오브젝트 생성 모드가 올바르지 않습니다: %s" + +#: config.c:1216 +msgid "unable to parse command-line config" +msgstr "명령행 설정을 파싱할 수 없습니다" + +#: config.c:1277 +msgid "unknown error occured while reading the configuration files" +msgstr "설정 파일을 읽는 중 알 수 없는 오류가 생겼습니다" + +#: config.c:1601 +#, c-format +msgid "unable to parse '%s' from command-line config" +msgstr "명령행 설정에서 '%s'을(를) 설정할 수 없습니다" + +#: config.c:1603 +#, c-format +msgid "bad config variable '%s' in file '%s' at line %d" +msgstr "'%2$s' 파일의 %3$d번 줄 '%1$s' 설정 변수가 잘못되었습니다" + +#: config.c:1662 +#, c-format +msgid "%s has multiple values" +msgstr "%s은(는) 여러 개 값이 있습니다" + +#: connected.c:69 +msgid "Could not run 'git rev-list'" +msgstr "'git rev-list'를 실행할 수 없습니다" + +#: connected.c:89 +#, c-format +msgid "failed write to rev-list: %s" +msgstr "rev-list 쓰기에 실패했습니다: %s" + +#: connected.c:97 +#, c-format +msgid "failed to close rev-list's stdin: %s" +msgstr "rev-list의 표준입력을 닫는데 실패했습니다: %s" + +#: date.c:95 +msgid "in the future" +msgstr "미래에" + +#: date.c:101 +#, c-format +msgid "%lu second ago" +msgid_plural "%lu seconds ago" +msgstr[0] "%lu초 전" + +#: date.c:108 +#, c-format +msgid "%lu minute ago" +msgid_plural "%lu minutes ago" +msgstr[0] "%lu분 전" + +#: date.c:115 +#, c-format +msgid "%lu hour ago" +msgid_plural "%lu hours ago" +msgstr[0] "%lu시간 전" + +#: date.c:122 +#, c-format +msgid "%lu day ago" +msgid_plural "%lu days ago" +msgstr[0] "%lu일 전" + +#: date.c:128 +#, c-format +msgid "%lu week ago" +msgid_plural "%lu weeks ago" +msgstr[0] "%lu주 전" + +#: date.c:135 +#, c-format +msgid "%lu month ago" +msgid_plural "%lu months ago" +msgstr[0] "%lu달 전" + +#: date.c:146 +#, c-format +msgid "%lu year" +msgid_plural "%lu years" +msgstr[0] "%lu년" + +#. TRANSLATORS: "%s" is "<n> years" +#: date.c:149 +#, c-format +msgid "%s, %lu month ago" +msgid_plural "%s, %lu months ago" +msgstr[0] "%s %lu달 전" + +#: date.c:154 date.c:159 +#, c-format +msgid "%lu year ago" +msgid_plural "%lu years ago" +msgstr[0] "%lu년 전" + +#: diffcore-order.c:24 +#, c-format +msgid "failed to read orderfile '%s'" +msgstr "'%s' 순서 파일을 읽는데 실패했습니다" + +#: diffcore-rename.c:536 +msgid "Performing inexact rename detection" +msgstr "부정확한 이름 바꾸기 탐색을 수행하는 중" + +#: diff.c:115 +#, c-format +msgid " Failed to parse dirstat cut-off percentage '%s'\n" +msgstr " dirstat 자름 퍼센트 값 '%s' 파싱에 실패했습니다\n" + +#: diff.c:120 +#, c-format +msgid " Unknown dirstat parameter '%s'\n" +msgstr " 알 수 없는 dirstat 파라미터 '%s'\n" + +#: diff.c:215 +#, c-format +msgid "Unknown value for 'diff.submodule' config variable: '%s'" +msgstr "'diff.submodule' 설정 변수에 알 수 없는 값: '%s'" + +#: diff.c:267 +#, c-format +msgid "" +"Found errors in 'diff.dirstat' config variable:\n" +"%s" +msgstr "" +"'diff.submodule' 설정 변수에 오류:\n" +"%s'" + +#: diff.c:3000 +#, c-format +msgid "external diff died, stopping at %s" +msgstr "외부 diff 프로그램이 죽음, %s 위치에서 멈춤" + +#: diff.c:3396 +msgid "--follow requires exactly one pathspec" +msgstr "--follow 옵션에는 정확히 하나의 경로명세가 필요합니다" + +#: diff.c:3559 +#, c-format +msgid "" +"Failed to parse --dirstat/-X option parameter:\n" +"%s" +msgstr "" +"--dirstat/-X 옵션 파라미터를 파싱하는데 실패했습니다:\n" +"%s" + +#: diff.c:3573 +#, c-format +msgid "Failed to parse --submodule option parameter: '%s'" +msgstr "--submodule 옵션 파라미터 파싱에 실패했습니다: '%s'" + +#: dir.c:1915 +msgid "failed to get kernel name and information" +msgstr "커널 이름과 정보를 가져오는데 실패했습니다" + +#: dir.c:1998 +msgid "Untracked cache is disabled on this system." +msgstr "이 시스템에서는 추적되지 않는 캐시를 사용하지 않습니다." + +#: gpg-interface.c:166 gpg-interface.c:237 +msgid "could not run gpg." +msgstr "gpg를 실행할 수 없습니다." + +#: gpg-interface.c:178 +msgid "gpg did not accept the data" +msgstr "gpg에서 데이터를 받아들이지 않습니다" + +#: gpg-interface.c:189 +msgid "gpg failed to sign the data" +msgstr "gpg에서 데이터를 서명하는데 실패했습니다." + +#: gpg-interface.c:222 +#, c-format +msgid "could not create temporary file '%s': %s" +msgstr "임시 파일 '%s'을(를) 만들 수 없습니다: %s" + +#: gpg-interface.c:225 +#, c-format +msgid "failed writing detached signature to '%s': %s" +msgstr "분리된 서명을 '%s'에 쓰는데 실패했습니다: %s" + +#: grep.c:1718 +#, c-format +msgid "'%s': unable to read %s" +msgstr "'%s': %s을(를) 읽을 수 없습니다" + +#: grep.c:1735 +#, c-format +msgid "'%s': %s" +msgstr "'%s': %s" + +#: grep.c:1746 +#, c-format +msgid "'%s': short read %s" +msgstr "'%s': %s에서 읽다가 잘림" + +#: help.c:207 +#, c-format +msgid "available git commands in '%s'" +msgstr "'%s'에 있는 깃 명령" + +#: help.c:214 +msgid "git commands available from elsewhere on your $PATH" +msgstr "다른 $PATH에 있는 깃 명령" + +#: help.c:246 +msgid "These are common Git commands used in various situations:" +msgstr "다음은 여러가지 상황에서 자주 사용하는 깃 명령입니다:" + +#: help.c:311 +#, c-format +msgid "" +"'%s' appears to be a git command, but we were not\n" +"able to execute it. Maybe git-%s is broken?" +msgstr "" +"'%s'은(는) 깃 명령으로 보이지만, 실행할 수\n" +"없습니다. 아마도 git-%s 망가진 것 같습니다." + +#: help.c:368 +msgid "Uh oh. Your system reports no Git commands at all." +msgstr "어라라. 시스템에 깃 명령이 하나도 없다고 나옵니다." + +#: help.c:390 +#, c-format +msgid "" +"WARNING: You called a Git command named '%s', which does not exist.\n" +"Continuing under the assumption that you meant '%s'" +msgstr "" +"경고: 이름이 '%s'인 깃 명령을 실행했지만, 그 명령이 없습니다.\n" +"자동으로 '%s' 명령이라고 가정하고 계속합니다" + +#: help.c:395 +#, c-format +msgid "in %0.1f seconds automatically..." +msgstr "(%0.1f초 뒤에)..." + +#: help.c:402 +#, c-format +msgid "git: '%s' is not a git command. See 'git --help'." +msgstr "git: '%s'은(는) 깃 명령이 아닙니다. 'git --help'를 참고하십시오." + +#: help.c:406 help.c:466 +msgid "" +"\n" +"Did you mean this?" +msgid_plural "" +"\n" +"Did you mean one of these?" +msgstr[0] "" +"\n" +"다음을 의도하신 것 아니었나요?" + +#: help.c:462 +#, c-format +msgid "%s: %s - %s" +msgstr "%s: %s - %s" + +#: merge.c:41 +msgid "failed to read the cache" +msgstr "캐시를 읽는데 실패했습니다" + +#: merge.c:94 builtin/am.c:2022 builtin/am.c:2057 builtin/checkout.c:376 +#: builtin/checkout.c:587 builtin/clone.c:722 +msgid "unable to write new index file" +msgstr "새 인덱스 파일을 쓸 수 없습니다" + +#: merge-recursive.c:189 +#, c-format +msgid "(bad commit)\n" +msgstr "(잘못된 커밋)\n" + +#: merge-recursive.c:209 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "'%s' 경로에 대해 addinfo_cache가 실패했습니다" + +#: merge-recursive.c:270 +msgid "error building trees" +msgstr "트리 빌드에 오류" + +#: merge-recursive.c:686 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "'%s' 경로 만들기에 실패했습니다%s" + +#: merge-recursive.c:697 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "하위 디렉터리에 공간을 만드려고 %s을(를) 제거합니다\n" + +#: merge-recursive.c:711 merge-recursive.c:732 +msgid ": perhaps a D/F conflict?" +msgstr ": 아마도 D/F 충돌?" + +#: merge-recursive.c:722 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "'%s' 위치의 추적되지 않는 파일을 잃기를 거부합니다" + +#: merge-recursive.c:762 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "%s '%s' 오브젝트를 읽을 수 없음" + +#: merge-recursive.c:764 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "%s '%s'에 대해 블롭을 예상" + +#: merge-recursive.c:787 builtin/clone.c:369 +#, c-format +msgid "failed to open '%s'" +msgstr "'%s'을(를) 여는데 실패" + +#: merge-recursive.c:795 +#, c-format +msgid "failed to symlink '%s'" +msgstr "'%s' 심볼릭 링크에 실패" + +#: merge-recursive.c:798 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "다음을 어떻게 할지 알 수 없습니다: %06o %s '%s'" + +#: merge-recursive.c:936 +msgid "Failed to execute internal merge" +msgstr "내부 병합 실행에 실패" + +#: merge-recursive.c:940 +#, c-format +msgid "Unable to add %s to database" +msgstr "%s을(를) 데이터베이스에 추가할 수 없습니다" + +#: merge-recursive.c:956 +msgid "unsupported object type in the tree" +msgstr "트리에서 지원하지 않는 오브젝트 종류" + +#: merge-recursive.c:1031 merge-recursive.c:1045 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" +"충돌! (%s/삭제): %s (위치 %s) 및 %s (%s에서) 삭제. %s 버전의 %s 트리에 남음." + +#: merge-recursive.c:1037 merge-recursive.c:1050 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" +"충돌! (%s/삭제): %s (위치 %s) 및 %s (위치 %s) 삭제. %s 버전의 %s 트리에 " +"%s(으)로 남음." + +#: merge-recursive.c:1091 +msgid "rename" +msgstr "이름바꾸기" + +#: merge-recursive.c:1091 +msgid "renamed" +msgstr "이름바꿈" + +#: merge-recursive.c:1147 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s은(는) %s에 있는 디렉터리로 %s(으)로 이름을 바꿉니다" + +#: merge-recursive.c:1169 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" +"충돌! (이름바꾸기/이름바꾸기): \"%3$s\" 브랜치에서 이름바꾸기 \"%1$s\"->" +"\"%2$s\" \"%6$s\" 브랜치에서 이름 바꾸기 \"%4$s\"->\"%5$s\"%7$s" + +#: merge-recursive.c:1174 +msgid " (left unresolved)" +msgstr " (해결되지 않음)" + +#: merge-recursive.c:1228 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" +"충돌! (rename/rename): 이름 바꾸기 %s->%s (위치 %s). 이름 바꾸기 %s->%s (위" +"치 %s)" + +#: merge-recursive.c:1258 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "대신 이름을 %s에서 %s(으)로 바꾸고 %s에서 %s(으)로 바꿉니다" + +#: merge-recursive.c:1457 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "충돌! (rename/add): 이름 바꾸기 %s->%s (위치 %s). %s 추가 (위치 %s)" + +#: merge-recursive.c:1467 +#, c-format +msgid "Adding merged %s" +msgstr "병합된 %s을(를) 추가합니다" + +#: merge-recursive.c:1472 merge-recursive.c:1674 +#, c-format +msgid "Adding as %s instead" +msgstr "대신 %s(으)로 추가합니다" + +#: merge-recursive.c:1523 +#, c-format +msgid "cannot read object %s" +msgstr "%s 오브젝트를 읽을 수 없습니다" + +#: merge-recursive.c:1526 +#, c-format +msgid "object %s is not a blob" +msgstr "%s 오브젝트는 블롭이 아닙니다" + +#: merge-recursive.c:1578 +msgid "modify" +msgstr "수정" + +#: merge-recursive.c:1578 +msgid "modified" +msgstr "수정됨" + +#: merge-recursive.c:1588 +msgid "content" +msgstr "내용" + +#: merge-recursive.c:1595 +msgid "add/add" +msgstr "추가/추가" + +#: merge-recursive.c:1629 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "건너뛰기: %s (기존과 같게 병합)" + +#: merge-recursive.c:1643 +#, c-format +msgid "Auto-merging %s" +msgstr "자동 병합: %s" + +#: merge-recursive.c:1647 git-submodule.sh:1025 +msgid "submodule" +msgstr "하위 모듈" + +#: merge-recursive.c:1648 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "충돌! (%s): %s에 병합 충돌" + +#: merge-recursive.c:1734 +#, c-format +msgid "Removing %s" +msgstr "제거: %s" + +#: merge-recursive.c:1759 +msgid "file/directory" +msgstr "파일/디렉터리" + +#: merge-recursive.c:1765 +msgid "directory/file" +msgstr "디렉터리/파일" + +#: merge-recursive.c:1770 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "" +"충돌! (%s): 이름이 %s인 디렉터리가 %s에 있습니다. %s을(를) %s(으)로 추가합니" +"다" + +#: merge-recursive.c:1780 +#, c-format +msgid "Adding %s" +msgstr "추가: %s" + +#: merge-recursive.c:1797 +msgid "Fatal merge failure, shouldn't happen." +msgstr "치명적인 병합 실패, 일어날 수 없는 상황." + +#: merge-recursive.c:1816 +msgid "Already up-to-date!" +msgstr "이미 업데이트 상태입니다!" + +#: merge-recursive.c:1825 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "%s 및 %s 트리의 병합이 실패했습니다" + +#: merge-recursive.c:1855 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "처리되지 않은 경로??? %s" + +#: merge-recursive.c:1903 +msgid "Merging:" +msgstr "병합:" + +#: merge-recursive.c:1916 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "과거의 공통 커밋 %u개 발견:" + +#: merge-recursive.c:1953 +msgid "merge returned no commit" +msgstr "병합 결과에 커밋이 없습니다" + +#: merge-recursive.c:2010 +#, c-format +msgid "Could not parse object '%s'" +msgstr "'%s' 오브젝트를 파싱할 수 없습니다" + +#: merge-recursive.c:2021 builtin/merge.c:645 +msgid "Unable to write index." +msgstr "인덱스를 쓸 수 없습니다." + +#: notes-utils.c:41 +msgid "Cannot commit uninitialized/unreferenced notes tree" +msgstr "초기화하지 않았거나 레퍼런스하지 않은 notes 트리를 커밋할 수 없습니다" + +#: notes-utils.c:100 +#, c-format +msgid "Bad notes.rewriteMode value: '%s'" +msgstr "잘못된 notes.rewriteMode 값: '%s'" + +#: notes-utils.c:110 +#, c-format +msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" +msgstr "%s에서 노트를 다시 쓰기를 거부합니다 (refs/notes/ 밖임)" + +#. TRANSLATORS: The first %s is the name of the +#. environment variable, the second %s is its value +#: notes-utils.c:137 +#, c-format +msgid "Bad %s value: '%s'" +msgstr "잘못된 %s 값: '%s'" + +#: object.c:242 +#, c-format +msgid "unable to parse object: %s" +msgstr "오브젝트를 파싱할 수 없습니다: %s" + +#: parse-options.c:570 +msgid "..." +msgstr "..." + +#: parse-options.c:588 +#, c-format +msgid "usage: %s" +msgstr "사용법: %s" + +#. TRANSLATORS: the colon here should align with the +#. one in "usage: %s" translation +#: parse-options.c:592 +#, c-format +msgid " or: %s" +msgstr " 또는: %s" + +#: parse-options.c:595 +#, c-format +msgid " %s" +msgstr " %s" + +#: parse-options.c:629 +msgid "-NUM" +msgstr "-NUM" + +#: parse-options-cb.c:108 +#, c-format +msgid "malformed object name '%s'" +msgstr "잘못된 형식의 오브젝트 이름 '%s'" + +#: path.c:752 +#, c-format +msgid "Could not make %s writable by group" +msgstr "%s을(를) 그룹에서 쓰기 가능하도록 만들 수 없습니다" + +#: pathspec.c:133 +msgid "global 'glob' and 'noglob' pathspec settings are incompatible" +msgstr "'glob' 및 'noglob' 경로명세 전체 설정은 호환되지 않습니다" + +#: pathspec.c:143 +msgid "" +"global 'literal' pathspec setting is incompatible with all other global " +"pathspec settings" +msgstr "" +"'literal' 경로명세 전체 설정은 다른 경로명세 전체 설정과 호환되지 않습니다" + +#: pathspec.c:177 +msgid "invalid parameter for pathspec magic 'prefix'" +msgstr "경로명세 지시어 'prefix'에 잘못된 파라미터" + +#: pathspec.c:183 +#, c-format +msgid "Invalid pathspec magic '%.*s' in '%s'" +msgstr "잘못된 경로명세 지시어 '%.*s' (위치 '%s')" + +#: pathspec.c:187 +#, c-format +msgid "Missing ')' at the end of pathspec magic in '%s'" +msgstr "경로 명세 지시어 끝에 ')' 빠짐 (위치 '%s')" + +#: pathspec.c:205 +#, c-format +msgid "Unimplemented pathspec magic '%c' in '%s'" +msgstr "구현되지 않은 경로명세 지시어 '%c' (위치 '%s')" + +#: pathspec.c:230 +#, c-format +msgid "%s: 'literal' and 'glob' are incompatible" +msgstr "%s: 'literal'과 'glob'은 호환되지 않습니다" + +#: pathspec.c:241 +#, c-format +msgid "%s: '%s' is outside repository" +msgstr "%s: '%s'은(는) 저장소 밖입니다" + +#: pathspec.c:291 +#, c-format +msgid "Pathspec '%s' is in submodule '%.*s'" +msgstr "경로명세 '%s'은(는) ''%.*s' 하위 모듈 안에 있습니다" + +#: pathspec.c:353 +#, c-format +msgid "%s: pathspec magic not supported by this command: %s" +msgstr "%s: 경로명세 지시어가 이 명령어에서 지원하지 않습니다: %s" + +#: pathspec.c:432 +#, c-format +msgid "pathspec '%s' is beyond a symbolic link" +msgstr "'%s' 경로명세는 심볼릭 링크 아래에 있습니다" + +#: pathspec.c:441 +msgid "" +"There is nothing to exclude from by :(exclude) patterns.\n" +"Perhaps you forgot to add either ':/' or '.' ?" +msgstr "" +":(exclude) 패턴으로 제외할 사항이 없습니다.\n" +"':/' 또는 '.' 추가를 잊으신 것 아닙니까?" + +#: pretty.c:969 +msgid "unable to parse --pretty format" +msgstr "--pretty 형식을 파싱할 수 없습니다" + +#: progress.c:235 +msgid "done" +msgstr "완료" + +#: read-cache.c:1281 +#, c-format +msgid "" +"index.version set, but the value is invalid.\n" +"Using version %i" +msgstr "" +"index.version이 설정되었지만, 이 값이 잘못되었습니다.\n" +"%i 버전을 사용합니다" + +#: read-cache.c:1291 +#, c-format +msgid "" +"GIT_INDEX_VERSION set, but the value is invalid.\n" +"Using version %i" +msgstr "" +"GIT_INDEX_VERSION이 설정되었지만, 이 값이 잘못되었습니다.\n" +"%i 버전을 사용합니다" + +#: refs.c:543 builtin/merge.c:760 builtin/merge.c:871 builtin/merge.c:973 +#: builtin/merge.c:983 +#, c-format +msgid "Could not open '%s' for writing" +msgstr "'%s'을(를) 쓰기용으로 열 수 없습니다" + +#: refs/files-backend.c:2359 +#, c-format +msgid "could not delete reference %s: %s" +msgstr "%s 레퍼런스를 삭제할 수 없습니다: %s" + +#: refs/files-backend.c:2362 +#, c-format +msgid "could not delete references: %s" +msgstr "레퍼런스를 삭제할 수 없습니다: %s" + +#: refs/files-backend.c:2371 +#, c-format +msgid "could not remove reference %s" +msgstr "%s 레퍼런스를 제거할 수 없습니다" + +#: ref-filter.c:245 +#, c-format +msgid "format: %%(end) atom used without corresponding atom" +msgstr "형식: %%(end) 아톰이 대응되는 아톰 없이 사용되었습니다" + +#: ref-filter.c:704 +#, c-format +msgid "positive value expected contents:lines=%s" +msgstr "'contents:lines=%s'에서 0보다 큰 값이 와야 합니다" + +#: ref-filter.c:833 +#, c-format +msgid "expected format: %%(color:<color>)" +msgstr "예상한 형식: %%(color:<색>)" + +#: ref-filter.c:835 +msgid "unable to parse format" +msgstr "형식을 파싱할 수 없습니다" + +#: ref-filter.c:870 +#, c-format +msgid "expected format: %%(align:<width>,<position>)" +msgstr "예상한 형식: %%(align:<너비>,<위치>)" + +#: ref-filter.c:893 +#, c-format +msgid "improper format entered align:%s" +msgstr "align:%s 잘못된 형식이 입력되었습니다" + +#: ref-filter.c:898 +#, c-format +msgid "positive width expected with the %%(align) atom" +msgstr "%%(align) 아톰에 너비가 0보다 커야 합니다" + +#: ref-filter.c:1219 +#, c-format +msgid "malformed object at '%s'" +msgstr "'%s'에 잘못된 형식의 오브젝트" + +#: ref-filter.c:1561 +#, c-format +msgid "format: %%(end) atom missing" +msgstr "형식: %%(end) 아톰이 없습니다" + +#: ref-filter.c:1615 +#, c-format +msgid "malformed object name %s" +msgstr "잘못된 형식의 오브젝트 이름 %s" + +#: remote.c:756 +#, c-format +msgid "Cannot fetch both %s and %s to %s" +msgstr "%s 및 %s을(를) 모두 %s에 가져올 수 없습니다" + +#: remote.c:760 +#, c-format +msgid "%s usually tracks %s, not %s" +msgstr "%s은(는) 보통 %s을(를) 추적하고, %s을(를) 추적하지 않습니다" + +#: remote.c:764 +#, c-format +msgid "%s tracks both %s and %s" +msgstr "%s은(는) %s 및 %s 모두 추적합니다" + +#: remote.c:772 +msgid "Internal error" +msgstr "내부 오류" + +#: remote.c:1687 remote.c:1730 +msgid "HEAD does not point to a branch" +msgstr "HEAD가 브랜치를 가리키지 않습니다" + +#: remote.c:1696 +#, c-format +msgid "no such branch: '%s'" +msgstr "그런 브랜치가 없습니다: '%s'" + +#: remote.c:1699 +#, c-format +msgid "no upstream configured for branch '%s'" +msgstr "'%s' 브랜치에 대해 업스트림을 설정하지 않았습니다" + +#: remote.c:1705 +#, c-format +msgid "upstream branch '%s' not stored as a remote-tracking branch" +msgstr "업스트림 '%s' 브랜치가 리모트 추적 브랜치로 저장되지 않았습니다" + +#: remote.c:1720 +#, c-format +msgid "push destination '%s' on remote '%s' has no local tracking branch" +msgstr "리모트 '%2$s'의 푸시 대상 '%1$s'에 로컬 추적 브랜치가 없습니다" + +#: remote.c:1735 +#, c-format +msgid "branch '%s' has no remote for pushing" +msgstr "'%s' 브랜치에 푸시 리모트가 없습니다" + +#: remote.c:1746 +#, c-format +msgid "push refspecs for '%s' do not include '%s'" +msgstr "'%s'에 대한 푸시 레퍼런스명세에 '%s'이(가) 들어 있지 않습니다" + +#: remote.c:1759 +msgid "push has no destination (push.default is 'nothing')" +msgstr "푸시의 대상이 없습니다 (push.default가 'nothing'입니다)" + +#: remote.c:1781 +msgid "cannot resolve 'simple' push to a single destination" +msgstr "하나의 대상에 대해 'simple' 푸시를 처리할 수 없습니다" + +#: remote.c:2083 +#, c-format +msgid "Your branch is based on '%s', but the upstream is gone.\n" +msgstr "현재 브랜치가 '%s' 기반이지만, 업스트림이 없어졌습니다.\n" + +#: remote.c:2087 +msgid " (use \"git branch --unset-upstream\" to fixup)\n" +msgstr " (바로잡으려면 \"git branch --unset-upstream\"을 사용하십시오)\n" + +#: remote.c:2090 +#, c-format +msgid "Your branch is up-to-date with '%s'.\n" +msgstr "브랜치가 '%s'에 맞게 업데이트된 상태입니다.\n" + +#: remote.c:2094 +#, c-format +msgid "Your branch is ahead of '%s' by %d commit.\n" +msgid_plural "Your branch is ahead of '%s' by %d commits.\n" +msgstr[0] "브랜치가 '%s'보다 %d개 커밋만큼 앞에 있습니다.\n" + +#: remote.c:2100 +msgid " (use \"git push\" to publish your local commits)\n" +msgstr " (로컬에 있는 커밋을 제출하려면 \"git push\"를 사용하십시오)\n" + +#: remote.c:2103 +#, c-format +msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" +msgid_plural "" +"Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n" +msgstr[0] "브랜치가 '%s'보다 %d개 커밋 뒤에 있고, 앞으로 돌릴 수 있습니다.\n" + +#: remote.c:2111 +msgid " (use \"git pull\" to update your local branch)\n" +msgstr " (로컬 브랜치를 업데이트하려면 \"git pull\"을 사용하십시오)\n" + +#: remote.c:2114 +#, c-format +msgid "" +"Your branch and '%s' have diverged,\n" +"and have %d and %d different commit each, respectively.\n" +msgid_plural "" +"Your branch and '%s' have diverged,\n" +"and have %d and %d different commits each, respectively.\n" +msgstr[0] "" +"현재 브랜치와 '%s'이(가) 갈라졌습니다,\n" +"다른 커밋이 각각 %d개와 %d개 있습니다.\n" + +#: remote.c:2124 +msgid " (use \"git pull\" to merge the remote branch into yours)\n" +msgstr "" +" (리모트의 브랜치를 현재 브랜치로 병합하려면 \"git pull\"을 사용하십시오)\n" + +#: revision.c:2193 +msgid "your current branch appears to be broken" +msgstr "현재 브랜치가 망가진 것처럼 보입니다" + +#: revision.c:2196 +#, c-format +msgid "your current branch '%s' does not have any commits yet" +msgstr "현재 '%s' 브랜치에 아직 아무 커밋도 없습니다" + +#: revision.c:2390 +msgid "--first-parent is incompatible with --bisect" +msgstr "--first-parent 옵션은 --bisect 옵션과 호환되지 않습니다" + +#: run-command.c:90 +msgid "open /dev/null failed" +msgstr "/dev/null 열기 실패" + +#: run-command.c:92 +#, c-format +msgid "dup2(%d,%d) failed" +msgstr "dup2(%d,%d) 실패" + +#: send-pack.c:295 +msgid "failed to sign the push certificate" +msgstr "푸시 인증서 서명에 실패했습니다" + +#: send-pack.c:404 +msgid "the receiving end does not support --signed push" +msgstr "받는 쪽에서 --signed 푸시를 지원하지 않습니다" + +#: send-pack.c:406 +msgid "" +"not sending a push certificate since the receiving end does not support --" +"signed push" +msgstr "" +"받는 쪽에서 --signed 푸시를 지원하지 않으므로 푸시 인증서를 보내지 않습니다" + +#: send-pack.c:418 +msgid "the receiving end does not support --atomic push" +msgstr "받는 쪽에서 --atomic 푸시를 지원하지 않습니다" + +#: sequencer.c:183 +msgid "" +"after resolving the conflicts, mark the corrected paths\n" +"with 'git add <paths>' or 'git rm <paths>'" +msgstr "" +"이 충돌을 해결한 뒤에, 바로잡은 경로를\n" +"'git add <경로>' 또는 'git rm <경로>'로 표시하십시오" + +#: sequencer.c:186 +msgid "" +"after resolving the conflicts, mark the corrected paths\n" +"with 'git add <paths>' or 'git rm <paths>'\n" +"and commit the result with 'git commit'" +msgstr "" +"이 충돌을 해결한 뒤에, 바로잡은 경로를\n" +"'git add <경로>' 또는 'git rm <경로>'로 표시하십시오.\n" +"그리고 결과물을 'git commit'으로 커밋하십시오" + +#: sequencer.c:199 sequencer.c:842 sequencer.c:922 +#, c-format +msgid "Could not write to %s" +msgstr "%s에 쓸 수 없습니다" + +#: sequencer.c:202 +#, c-format +msgid "Error wrapping up %s" +msgstr "%s 잠그는데 오류" + +#: sequencer.c:217 +msgid "Your local changes would be overwritten by cherry-pick." +msgstr "로컬 변경 사항을 cherry-pick 때문에 덮어 쓰게 됩니다." + +#: sequencer.c:219 +msgid "Your local changes would be overwritten by revert." +msgstr "로컬 변경 사항을 revert 때문에 덮어 쓰게 됩니다." + +#: sequencer.c:222 +msgid "Commit your changes or stash them to proceed." +msgstr "변경 사항을 스테이징하거나 스태시한 다음 계속하십시오." + +#. TRANSLATORS: %s will be "revert" or "cherry-pick" +#: sequencer.c:309 +#, c-format +msgid "%s: Unable to write new index file" +msgstr "%s: 새 인덱스 파일을 쓸 수 없습니다" + +#: sequencer.c:327 +msgid "Could not resolve HEAD commit\n" +msgstr "HEAD 커밋을 처리할 수 없습니다\n" + +#: sequencer.c:347 +msgid "Unable to update cache tree\n" +msgstr "캐시 트리를 업데이트할 수 없습니다\n" + +#: sequencer.c:399 +#, c-format +msgid "Could not parse commit %s\n" +msgstr "%s 커밋을 파싱할 수 없습니다\n" + +#: sequencer.c:404 +#, c-format +msgid "Could not parse parent commit %s\n" +msgstr "%s 이전 커밋을 파싱할 수 없습니다\n" + +#: sequencer.c:469 +msgid "Your index file is unmerged." +msgstr "인덱스 파일이 병합되지 않았습니다." + +#: sequencer.c:488 +#, c-format +msgid "Commit %s is a merge but no -m option was given." +msgstr "%s 커밋은 병합이지만 -m 옵션이 주어지지 않았습니다." + +# FIXME: "parent %d" 번호가 무슨 의미? +#: sequencer.c:496 +#, c-format +msgid "Commit %s does not have parent %d" +msgstr "Commit %s 커밋에 이전 커밋 %d이(가) 없습니다" + +#: sequencer.c:500 +#, c-format +msgid "Mainline was specified but commit %s is not a merge." +msgstr "메인라인을 지정했지만 %s 커밋이 병합 커밋이 아닙니다." + +#. TRANSLATORS: The first %s will be "revert" or +#. "cherry-pick", the second %s a SHA1 +#: sequencer.c:513 +#, c-format +msgid "%s: cannot parse parent commit %s" +msgstr "%s: %s 이전 커밋을 파싱할 수 없습니다" + +#: sequencer.c:517 +#, c-format +msgid "Cannot get commit message for %s" +msgstr "%s에 대한 커밋 메시지를 가져올 수 없습니다" + +#: sequencer.c:603 +#, c-format +msgid "could not revert %s... %s" +msgstr "다음을 되돌릴(revert) 수 없습니다: %s... %s" + +#: sequencer.c:604 +#, c-format +msgid "could not apply %s... %s" +msgstr "다음을 적용할(apply) 수 없습니다: %s... %s" + +#: sequencer.c:639 +msgid "empty commit set passed" +msgstr "빈 커밋 모음을 건너 뜁니다" + +#: sequencer.c:647 +#, c-format +msgid "git %s: failed to read the index" +msgstr "git %s: 인덱스 읽기에 실패했습니다" + +#: sequencer.c:651 +#, c-format +msgid "git %s: failed to refresh the index" +msgstr "git %s: 인덱스 새로 고침에 실패했습니다" + +#: sequencer.c:711 +#, c-format +msgid "Cannot %s during a %s" +msgstr "%2$s 동안 %1$s 할 수 없습니다" + +#: sequencer.c:733 +#, c-format +msgid "Could not parse line %d." +msgstr "%d번 줄을 파싱할 수 없습니다." + +#: sequencer.c:738 +msgid "No commits parsed." +msgstr "파싱한 커밋이 없습니다." + +#: sequencer.c:750 +#, c-format +msgid "Could not open %s" +msgstr "%s을(를) 열 수 없습니다" + +#: sequencer.c:754 +#, c-format +msgid "Could not read %s." +msgstr "%s을(를) 읽을 수 없습니다." + +#: sequencer.c:761 +#, c-format +msgid "Unusable instruction sheet: %s" +msgstr "사용 불가능 인스트럭션 파일: %s" + +#: sequencer.c:791 +#, c-format +msgid "Invalid key: %s" +msgstr "잘못된 키: %s" + +#: sequencer.c:794 builtin/pull.c:47 builtin/pull.c:49 +#, c-format +msgid "Invalid value for %s: %s" +msgstr "%s의 값이 올바르지 않습니다: %s" + +#: sequencer.c:804 +#, c-format +msgid "Malformed options sheet: %s" +msgstr "형식이 잘못된 옵션 파일: %s" + +#: sequencer.c:823 +msgid "a cherry-pick or revert is already in progress" +msgstr "이미 커밋 빼오기(cherry-pick) 또는 되돌리기(revert)가 진행 중입니다" + +#: sequencer.c:824 +msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" +msgstr "\"git cherry-pick (--continue | --quit | --abort)\" 명령을 해 보십시오" + +#: sequencer.c:828 +#, c-format +msgid "Could not create sequencer directory %s" +msgstr "%s 시퀀서 디렉터리를 만들 수 없습니다" + +#: sequencer.c:844 sequencer.c:926 +#, c-format +msgid "Error wrapping up %s." +msgstr "%s 잠그는데 오류." + +#: sequencer.c:863 sequencer.c:996 +msgid "no cherry-pick or revert in progress" +msgstr "빼오기(cherry-pick) 또는 되돌리기(revert)가 진행 중이지 않습니다" + +#: sequencer.c:865 +msgid "cannot resolve HEAD" +msgstr "HEAD를 구해 올 수 없습니다" + +#: sequencer.c:867 +msgid "cannot abort from a branch yet to be born" +msgstr "새로 만들고 있는 브랜치에서 중지할 수 없습니다" + +#: sequencer.c:887 builtin/apply.c:4287 +#, c-format +msgid "cannot open %s: %s" +msgstr "%s을(를) 열 수 없습니다: %s" + +#: sequencer.c:890 +#, c-format +msgid "cannot read %s: %s" +msgstr "%s을(를) 읽을 수 없습니다: %s" + +#: sequencer.c:891 +msgid "unexpected end of file" +msgstr "예상치 못하게 파일이 끝났습니다" + +#: sequencer.c:897 +#, c-format +msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" +msgstr "빼오기 전에 저장한 HEAD 파일이('%s') 손상되었습니다" + +#: sequencer.c:919 +#, c-format +msgid "Could not format %s." +msgstr "%s에 포매팅할 수 없습니다." + +#: sequencer.c:1064 +#, c-format +msgid "%s: can't cherry-pick a %s" +msgstr "%s: %s 커밋을 빼올 수 없습니다" + +#: sequencer.c:1067 +#, c-format +msgid "%s: bad revision" +msgstr "%s: 잘못된 리비전" + +#: sequencer.c:1101 +msgid "Can't revert as initial commit" +msgstr "최초의 커밋을 되돌릴 수 없습니다" + +#: sequencer.c:1102 +msgid "Can't cherry-pick into empty head" +msgstr "빈 헤드로 커밋을 빼올 수 없습니다." + +#: setup.c:248 +#, c-format +msgid "failed to read %s" +msgstr "%s을(를) 읽는데 실패했습니다" + +#: sha1_name.c:463 +msgid "" +"Git normally never creates a ref that ends with 40 hex characters\n" +"because it will be ignored when you just specify 40-hex. These refs\n" +"may be created by mistake. For example,\n" +"\n" +" git checkout -b $br $(git rev-parse ...)\n" +"\n" +"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" +"examine these refs and maybe delete them. Turn this message off by\n" +"running \"git config advice.objectNameWarning false\"" +msgstr "" +"깃에서는 보통 40개의 16진수 문자로 끝나는 레퍼런스를 만들지 않습니다.\n" +"16진수 문자 40자를 지정했을 때 이 레퍼런스가 무시되기 때문입니다. 이\n" +"레퍼런스는 실수로 만들어졌을 수도 있습니다. 예를 들어,\n" +"\n" +" git checkout -b $br $(git rev-parse ...)\n" +"\n" +"여기서 \"$br\"은 비어 있으므로 40자 레퍼런스가 만들어집니다. 이 레퍼런스를\n" +"확인해 보시고 잘못 만들어진 것이면 지우십시오. 이 메시지를 보고 싶지\n" +"않으면 \"git config advice.objectNameWarning false\" 명령을 사용하십시오." + +#: submodule.c:61 submodule.c:95 +msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first" +msgstr "" +"병합하지 않은 .gitmodules를 바꿀 수 없습니다. 병합 충돌을 먼저 해결하십시오" + +#: submodule.c:65 submodule.c:99 +#, c-format +msgid "Could not find section in .gitmodules where path=%s" +msgstr "경로가 %s일 때 .gitmodules의 섹션을 찾을 수 없습니다" + +#: submodule.c:73 +#, c-format +msgid "Could not update .gitmodules entry %s" +msgstr ".gitmodules 항목 %s을(를) 업데이트할 수 없습니다" + +#: submodule.c:106 +#, c-format +msgid "Could not remove .gitmodules entry for %s" +msgstr "%s에 대한 .gitmodules 항목을 제거할 수 없습니다" + +#: submodule.c:117 +msgid "staging updated .gitmodules failed" +msgstr "업데이트한 .gitmodules를 커밋할 사항으로 표시하는데 실패" + +#: submodule.c:1040 +#, c-format +msgid "Could not set core.worktree in %s" +msgstr "%s에서 core.worktree를 설정할 수 없습니다" + +#: trailer.c:491 trailer.c:495 trailer.c:499 trailer.c:553 trailer.c:557 +#: trailer.c:561 +#, c-format +msgid "unknown value '%s' for key '%s'" +msgstr "알 수 없는 값 '%s', 키 '%s'" + +#: trailer.c:543 trailer.c:548 builtin/remote.c:296 +#, c-format +msgid "more than one %s" +msgstr "%s이(가) 여러개입니다" + +#: trailer.c:581 +#, c-format +msgid "empty trailer token in trailer '%.*s'" +msgstr "트레일러 '%.*s'에서 빈 트레일러 토큰" + +#: trailer.c:701 +#, c-format +msgid "could not read input file '%s'" +msgstr "'%s' 입력 파일을 읽을 수 없습니다" + +#: trailer.c:704 +msgid "could not read from stdin" +msgstr "표준 입력에서 읽을 수 없습니다" + +#: transport-helper.c:1025 +#, c-format +msgid "Could not read ref %s" +msgstr "%s 레퍼런스를 읽을 수 없습니다" + +#: unpack-trees.c:203 +msgid "Checking out files" +msgstr "파일을 가져옵니다" + +#: urlmatch.c:120 +msgid "invalid URL scheme name or missing '://' suffix" +msgstr "URL 스킴 이름이 잘못되었거나 '://'가 뒤에 붙지 않았습니다" + +#: urlmatch.c:144 urlmatch.c:297 urlmatch.c:356 +#, c-format +msgid "invalid %XX escape sequence" +msgstr "잘못된 %XX 이스케이프 시퀀스" + +#: urlmatch.c:172 +msgid "missing host and scheme is not 'file:'" +msgstr "호스트가 없고 스킴이 'file:'이 아닙니다" + +#: urlmatch.c:189 +msgid "a 'file:' URL may not have a port number" +msgstr "'file:' URL에는 포트 번호를 쓸 수 없습니다" + +#: urlmatch.c:199 +msgid "invalid characters in host name" +msgstr "호스트 이름에 잘못된 문자" + +#: urlmatch.c:244 urlmatch.c:255 +msgid "invalid port number" +msgstr "잘못된 포트 번호" + +#: urlmatch.c:322 +msgid "invalid '..' path segment" +msgstr "경로에서 잘못된 '..' 부분" + +#: wrapper.c:219 wrapper.c:362 +#, c-format +msgid "could not open '%s' for reading and writing" +msgstr "읽기와 쓰기용으로 '%s'을(를) 열 수 없습니다" + +#: wrapper.c:221 wrapper.c:364 +#, c-format +msgid "could not open '%s' for writing" +msgstr "'%s'을(를) 쓰기용으로 열 수 없습니다" + +#: wrapper.c:223 wrapper.c:366 builtin/am.c:338 builtin/commit.c:1691 +#: builtin/merge.c:1074 builtin/pull.c:380 +#, c-format +msgid "could not open '%s' for reading" +msgstr "'%s'을(를) 읽기용으로 열 수 없습니다" + +#: wrapper.c:579 +#, c-format +msgid "unable to access '%s': %s" +msgstr "'%s'에 접근할 수 없습니다: %s" + +#: wrapper.c:600 +#, c-format +msgid "unable to access '%s'" +msgstr "'%s'에 접근할 수 없습니다" + +#: wrapper.c:608 +msgid "unable to get current working directory" +msgstr "현재 작업 디렉터리를 가져올 수 없습니다" + +#: wrapper.c:635 +#, c-format +msgid "could not open %s for writing" +msgstr "%s을(를) 쓰기용으로 열 수 없습니다" + +#: wrapper.c:646 builtin/am.c:425 +#, c-format +msgid "could not write to %s" +msgstr "%s에 쓸 수 없습니다" + +#: wrapper.c:652 +#, c-format +msgid "could not close %s" +msgstr "%s을(를) 닫을 수 없습니다" + +#: wt-status.c:149 +msgid "Unmerged paths:" +msgstr "병합하지 않은 경로:" + +#: wt-status.c:176 wt-status.c:203 +#, c-format +msgid " (use \"git reset %s <file>...\" to unstage)" +msgstr " (스테이지 해제하려면 \"git reset %s <파일>...\"을 사용하십시오)" + +#: wt-status.c:178 wt-status.c:205 +msgid " (use \"git rm --cached <file>...\" to unstage)" +msgstr " (스테이지 해제하려면 \"git rm --cached <파일>...\"을 사용하십시오)" + +#: wt-status.c:182 +msgid " (use \"git add <file>...\" to mark resolution)" +msgstr " (해결했다고 표시하려면 \"git add <파일>...\"을 사용하십시오)" + +#: wt-status.c:184 wt-status.c:188 +msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" +msgstr "" +" (해결했다고 표시하려면 알맞게 \"git add/rm <파일>...\"을 사용하십시오)" + +#: wt-status.c:186 +msgid " (use \"git rm <file>...\" to mark resolution)" +msgstr " (해결했다고 표시하려면 \"git rm <파일>...\"을 사용하십시오)" + +#: wt-status.c:197 wt-status.c:880 +msgid "Changes to be committed:" +msgstr "커밋할 변경 사항:" + +#: wt-status.c:215 wt-status.c:889 +msgid "Changes not staged for commit:" +msgstr "커밋하도록 정하지 않은 변경 사항:" + +#: wt-status.c:219 +msgid " (use \"git add <file>...\" to update what will be committed)" +msgstr " (무엇을 커밋할지 바꾸려면 \"git add <파일>...\"을 사용하십시오)" + +#: wt-status.c:221 +msgid " (use \"git add/rm <file>...\" to update what will be committed)" +msgstr " (무엇을 커밋할지 바꾸려면 \"git add/rm <파일>...\"을 사용하십시오)" + +#: wt-status.c:222 +msgid "" +" (use \"git checkout -- <file>...\" to discard changes in working directory)" +msgstr "" +" (작업 폴더의 변경 사항을 버리려면 \"git checkout -- <파일>...\"을 사용하십" +"시오)" + +#: wt-status.c:224 +msgid " (commit or discard the untracked or modified content in submodules)" +msgstr "" +" (하위 모듈의 추적되지 않는 파일이나 수정된 내용을 커밋하거나 버리십시오)" + +#: wt-status.c:236 +#, c-format +msgid " (use \"git %s <file>...\" to include in what will be committed)" +msgstr " (커밋할 사항에 포함하려면 \"git %s <파일>...\"을 사용하십시오)" + +#: wt-status.c:251 +msgid "both deleted:" +msgstr "양쪽에서 삭제:" + +#: wt-status.c:253 +msgid "added by us:" +msgstr "이 쪽에서 추가:" + +#: wt-status.c:255 +msgid "deleted by them:" +msgstr "저 쪽에서 삭제:" + +#: wt-status.c:257 +msgid "added by them:" +msgstr "저 쪽에서 추가:" + +#: wt-status.c:259 +msgid "deleted by us:" +msgstr "이 쪽에서 삭제:" + +#: wt-status.c:261 +msgid "both added:" +msgstr "양쪽에서 추가:" + +#: wt-status.c:263 +msgid "both modified:" +msgstr "양쪽에서 수정:" + +#: wt-status.c:265 +#, c-format +msgid "bug: unhandled unmerged status %x" +msgstr "bug: 병합하지 않은 상태 %x 처리되지 않음" + +#: wt-status.c:273 +msgid "new file:" +msgstr "새 파일:" + +#: wt-status.c:275 +msgid "copied:" +msgstr "복사함:" + +#: wt-status.c:277 +msgid "deleted:" +msgstr "삭제함:" + +#: wt-status.c:279 +msgid "modified:" +msgstr "수정함:" + +#: wt-status.c:281 +msgid "renamed:" +msgstr "이름 바꿈:" + +#: wt-status.c:283 +msgid "typechange:" +msgstr "종류 바뀜:" + +#: wt-status.c:285 +msgid "unknown:" +msgstr "알 수 없음:" + +#: wt-status.c:287 +msgid "unmerged:" +msgstr "병합하지 않음:" + +#: wt-status.c:369 +msgid "new commits, " +msgstr "새 커밋, " + +#: wt-status.c:371 +msgid "modified content, " +msgstr "수정한 내용, " + +#: wt-status.c:373 +msgid "untracked content, " +msgstr "추적하지 않은 내용, " + +#: wt-status.c:390 +#, c-format +msgid "bug: unhandled diff status %c" +msgstr "버그: 처리되지 않은 diff 상태 %c" + +#: wt-status.c:754 +msgid "Submodules changed but not updated:" +msgstr "변경되었지만 업데이트하지 않은 하위 모듈:" + +#: wt-status.c:756 +msgid "Submodule changes to be committed:" +msgstr "커밋할 하위 모듈의 변경 사항:" + +#: wt-status.c:837 +msgid "" +"Do not touch the line above.\n" +"Everything below will be removed." +msgstr "" +"위의 줄을 바꾸지 마십시오.\n" +"아래 있는 내용은 모두 제거됩니다." + +#: wt-status.c:948 +msgid "You have unmerged paths." +msgstr "병합하지 않은 경로가 있습니다." + +#: wt-status.c:951 +msgid " (fix conflicts and run \"git commit\")" +msgstr " (충돌을 바로잡고 \"git commit\"을 실행하십시오)" + +#: wt-status.c:954 +msgid "All conflicts fixed but you are still merging." +msgstr "모든 충돌을 바로잡았지만 아직 병합하는 중입니다." + +#: wt-status.c:957 +msgid " (use \"git commit\" to conclude merge)" +msgstr " (병합을 마무리하려면 \"git commit\"을 사용하십시오)" + +#: wt-status.c:967 +msgid "You are in the middle of an am session." +msgstr "am 세션 중간에 있습니다." + +#: wt-status.c:970 +msgid "The current patch is empty." +msgstr "현재 패치가 비어 있습니다." + +#: wt-status.c:974 +msgid " (fix conflicts and then run \"git am --continue\")" +msgstr " (충돌을 바로잡은 다음 \"git am --continue\"를 사용하십시오)" + +#: wt-status.c:976 +msgid " (use \"git am --skip\" to skip this patch)" +msgstr " (이 패치를 건너 뛰려면 \"git am --skip\"을 사용하십시오)" + +#: wt-status.c:978 +msgid " (use \"git am --abort\" to restore the original branch)" +msgstr " (원본 브랜치를 복구하려면 \"git am --abort\"를 사용하십시오)" + +#: wt-status.c:1105 +msgid "No commands done." +msgstr "완료한 명령 없음." + +#: wt-status.c:1108 +#, c-format +msgid "Last command done (%d command done):" +msgid_plural "Last commands done (%d commands done):" +msgstr[0] "최근 완료한 명령 (%d개 명령 완료):" + +#: wt-status.c:1119 +#, c-format +msgid " (see more in file %s)" +msgstr " (자세한 정보는 %s 파일 참고)" + +#: wt-status.c:1124 +msgid "No commands remaining." +msgstr "명령이 남아있지 않음." + +#: wt-status.c:1127 +#, c-format +msgid "Next command to do (%d remaining command):" +msgid_plural "Next commands to do (%d remaining commands):" +msgstr[0] "다음에 할 명령 (%d개 명령 남음):" + +#: wt-status.c:1135 +msgid " (use \"git rebase --edit-todo\" to view and edit)" +msgstr " (보고 편집하려면 \"git rebase --edit-todo\"를 사용하십시오)" + +#: wt-status.c:1148 +#, c-format +msgid "You are currently rebasing branch '%s' on '%s'." +msgstr "현재 '%s' 브랜치를 '%s' 위로 리베이스하는 중입니다." + +#: wt-status.c:1153 +msgid "You are currently rebasing." +msgstr "현재 리베이스하는 중입니다." + +#: wt-status.c:1167 +msgid " (fix conflicts and then run \"git rebase --continue\")" +msgstr " (충돌을 바로잡고 \"git rebase --continue\"를 사용하십시오)" + +#: wt-status.c:1169 +msgid " (use \"git rebase --skip\" to skip this patch)" +msgstr " (이 패치를 건너뛰려면 \"git rebase --skip\"을 사용하십시오)" + +#: wt-status.c:1171 +msgid " (use \"git rebase --abort\" to check out the original branch)" +msgstr " (원본 브랜치를 가져오려면 \"git rebase --abort\"를 사용하십시오)" + +#: wt-status.c:1177 +msgid " (all conflicts fixed: run \"git rebase --continue\")" +msgstr "" +" (모든 충돌을 바로잡았습니다: \"git rebase --continue\"를 실행하십시오)" + +#: wt-status.c:1181 +#, c-format +msgid "" +"You are currently splitting a commit while rebasing branch '%s' on '%s'." +msgstr "현재 '%s' 브랜치를 '%s' 위로 리베이스하는 중 커밋을 분리하는 중입니다." + +#: wt-status.c:1186 +msgid "You are currently splitting a commit during a rebase." +msgstr "현재 리베이스하는 중 커밋을 분리하는 중입니다." + +#: wt-status.c:1189 +msgid " (Once your working directory is clean, run \"git rebase --continue\")" +msgstr " (작업 폴더가 깨끗해지면, \"git rebase --continue\"를 실행하십시오)" + +#: wt-status.c:1193 +#, c-format +msgid "You are currently editing a commit while rebasing branch '%s' on '%s'." +msgstr "'%s' 브랜치를 '%s' 위로 리베이스하는 중 커밋을 편집하는 중입니다." + +#: wt-status.c:1198 +msgid "You are currently editing a commit during a rebase." +msgstr "리베이스 중에 커밋을 편집하는 중입니다." + +#: wt-status.c:1201 +msgid " (use \"git commit --amend\" to amend the current commit)" +msgstr " (현재 커밋을 수정하려면 \"git commit --amend\"을 사용하십시오)" + +#: wt-status.c:1203 +msgid "" +" (use \"git rebase --continue\" once you are satisfied with your changes)" +msgstr " (변경 사항에 만족할 때 \"git rebase --continue\"를 사용하십시오)" + +#: wt-status.c:1213 +#, c-format +msgid "You are currently cherry-picking commit %s." +msgstr "현재 %s 커밋을 뽑아 내고 있습니다." + +#: wt-status.c:1218 +msgid " (fix conflicts and run \"git cherry-pick --continue\")" +msgstr " (충돌을 바로잡고 \"git cherry-pick --continue\"를 실행하십시오)" + +#: wt-status.c:1221 +msgid " (all conflicts fixed: run \"git cherry-pick --continue\")" +msgstr "" +" (모든 충돌을 바로잡았습니다: \"git cherry-pick --continue\"를 실행하십시오)" + +#: wt-status.c:1223 +msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)" +msgstr " (뽑기 작업을 취소하려면 \"git cherry-pick --abort\"를 사용하십시오)" + +#: wt-status.c:1232 +#, c-format +msgid "You are currently reverting commit %s." +msgstr "현재 %s 커밋을 되돌리는 중입니다." + +#: wt-status.c:1237 +msgid " (fix conflicts and run \"git revert --continue\")" +msgstr " (충돌을 바로잡고 \"git revert --continue\"를 실행하십시오)" + +#: wt-status.c:1240 +msgid " (all conflicts fixed: run \"git revert --continue\")" +msgstr "" +" (모든 충돌을 바로잡았습니다: \"git revert --continue\"를 실행하십시오)" + +#: wt-status.c:1242 +msgid " (use \"git revert --abort\" to cancel the revert operation)" +msgstr " (되돌리기 작업을 취소하려면 \"git revert --abort\"를 사용하십시오)" + +#: wt-status.c:1253 +#, c-format +msgid "You are currently bisecting, started from branch '%s'." +msgstr "'이등분하는 중입니다. '%s' 브랜치부터 시작." + +#: wt-status.c:1257 +msgid "You are currently bisecting." +msgstr "'이등분하는 중입니다." + +#: wt-status.c:1260 +msgid " (use \"git bisect reset\" to get back to the original branch)" +msgstr " (원래 브랜치로 돌아가려면 \"git bisect reset\"을 사용하십시오)" + +#: wt-status.c:1438 +msgid "On branch " +msgstr "현재 브랜치 " + +#: wt-status.c:1444 +msgid "interactive rebase in progress; onto " +msgstr "대화형 리베이스 진행 중. 갈 위치는 " + +#: wt-status.c:1446 +msgid "rebase in progress; onto " +msgstr "리베이스 진행 중. 갈 위치는 " + +#: wt-status.c:1451 +msgid "HEAD detached at " +msgstr "HEAD가 다음 위치에서 분리: " + +#: wt-status.c:1453 +msgid "HEAD detached from " +msgstr "HEAD가 다음으로부터 분리: " + +#: wt-status.c:1456 +msgid "Not currently on any branch." +msgstr "현재 어떤 브랜치도 사용하지 않음." + +#: wt-status.c:1474 +msgid "Initial commit" +msgstr "최초 커밋" + +#: wt-status.c:1488 +msgid "Untracked files" +msgstr "추적하지 않는 파일" + +#: wt-status.c:1490 +msgid "Ignored files" +msgstr "무시한 파일" + +#: wt-status.c:1494 +#, c-format +msgid "" +"It took %.2f seconds to enumerate untracked files. 'status -uno'\n" +"may speed it up, but you have to be careful not to forget to add\n" +"new files yourself (see 'git help status')." +msgstr "" +"추적하지 않는 파일을 모두 확인하는데 %.2f초가 걸렸습니다.\n" +"'status -uno' 옵션을 쓰면 빨라질 수도 있지만, 새 파일을\n" +"직접 찾아서 추가해야 합니다. ('git help status' 참고)" + +#: wt-status.c:1500 +#, c-format +msgid "Untracked files not listed%s" +msgstr "추적하지 않는 파일을 보지 않습니다%s" + +#: wt-status.c:1502 +msgid " (use -u option to show untracked files)" +msgstr " (추적하지 않는 파일을 보려면 -u 옵션을 사용하십시오)" + +#: wt-status.c:1508 +msgid "No changes" +msgstr "변경 사항 없음" + +#: wt-status.c:1513 +#, c-format +msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n" +msgstr "" +"커밋할 변경 사항을 추가하지 않았습니다 (\"git add\" 및/또는 \"git commit -a" +"\"를\n" +"사용하십시오)\n" + +#: wt-status.c:1516 +#, c-format +msgid "no changes added to commit\n" +msgstr "커밋할 변경 사항을 추가하지 않았습니다\n" + +#: wt-status.c:1519 +#, c-format +msgid "" +"nothing added to commit but untracked files present (use \"git add\" to " +"track)\n" +msgstr "" +"커밋할 사항을 추가하지 않았지만 추적하지 않는 파일이 있습니다 (추적하려면 " +"\"git\n" +"add\"를 사용하십시오)\n" + +#: wt-status.c:1522 +#, c-format +msgid "nothing added to commit but untracked files present\n" +msgstr "커밋할 사항을 추가하지 않았지만 추적하지 않는 파일이 있습니다\n" + +#: wt-status.c:1525 +#, c-format +msgid "nothing to commit (create/copy files and use \"git add\" to track)\n" +msgstr "" +"커밋할 사항 없음 (파일을 만들거나 복사하고 \"git add\"를 사용하면 추적합니" +"다)\n" + +#: wt-status.c:1528 wt-status.c:1533 +#, c-format +msgid "nothing to commit\n" +msgstr "커밋할 사항 없음\n" + +#: wt-status.c:1531 +#, c-format +msgid "nothing to commit (use -u to show untracked files)\n" +msgstr "" +"커밋할 사항 없음 (추적하지 않는 파일을 보려면 -u 옵션을 사용하십시오)\n" + +#: wt-status.c:1535 +#, c-format +msgid "nothing to commit, working directory clean\n" +msgstr "커밋할 사항 없음, 작업 폴더 깨끗함\n" + +#: wt-status.c:1642 +msgid "Initial commit on " +msgstr "최초 커밋, 브랜치: " + +#: wt-status.c:1646 +msgid "HEAD (no branch)" +msgstr "HEAD (브랜치 없음)" + +#: wt-status.c:1675 +msgid "gone" +msgstr "없음" + +#: wt-status.c:1677 wt-status.c:1685 +msgid "behind " +msgstr "뒤에: " + +#: compat/precompose_utf8.c:56 builtin/clone.c:408 +#, c-format +msgid "failed to unlink '%s'" +msgstr "'%s' 파일 삭제에 실패했습니다" + +#: builtin/add.c:22 +msgid "git add [<options>] [--] <pathspec>..." +msgstr "git add [<옵션>] [--] <경로명세>..." + +#: builtin/add.c:65 +#, c-format +msgid "unexpected diff status %c" +msgstr "예상치 못한 diff 상태 %c" + +#: builtin/add.c:70 builtin/commit.c:278 +msgid "updating files failed" +msgstr "파일 업데이트가 실패했습니다" + +#: builtin/add.c:80 +#, c-format +msgid "remove '%s'\n" +msgstr "'%s' 제거\n" + +#: builtin/add.c:134 +msgid "Unstaged changes after refreshing the index:" +msgstr "인덱스를 새로 고친 다음 커밋 표시하지 않은 변경 사항:" + +#: builtin/add.c:194 builtin/rev-parse.c:796 +msgid "Could not read the index" +msgstr "인덱스를 읽을 수 없습니다" + +#: builtin/add.c:205 +#, c-format +msgid "Could not open '%s' for writing." +msgstr "'%s' 파일을 쓰기용으로 열 수 없습니다." + +#: builtin/add.c:209 +msgid "Could not write patch" +msgstr "패치를 쓸 수 없습니다" + +#: builtin/add.c:212 +msgid "editing patch failed" +msgstr "패치 편집에 실패했습니다" + +#: builtin/add.c:215 +#, c-format +msgid "Could not stat '%s'" +msgstr "'%s'을(를) stat()할 수 없습니다" + +#: builtin/add.c:217 +msgid "Empty patch. Aborted." +msgstr "빈 패치. 중지." + +#: builtin/add.c:222 +#, c-format +msgid "Could not apply '%s'" +msgstr "'%s'을(를) 적용할 수 없습니다" + +#: builtin/add.c:232 +msgid "The following paths are ignored by one of your .gitignore files:\n" +msgstr "다음 경로는 .gitignore 파일 중 하나 때문에 무시합니다:\n" + +#: builtin/add.c:249 builtin/clean.c:894 builtin/fetch.c:108 builtin/mv.c:110 +#: builtin/prune-packed.c:55 builtin/pull.c:182 builtin/push.c:543 +#: builtin/remote.c:1345 builtin/rm.c:268 builtin/send-pack.c:162 +msgid "dry run" +msgstr "가짜로 실행" + +#: builtin/add.c:250 builtin/apply.c:4571 builtin/check-ignore.c:19 +#: builtin/commit.c:1322 builtin/count-objects.c:85 builtin/fsck.c:558 +#: builtin/log.c:1645 builtin/mv.c:109 builtin/read-tree.c:114 +msgid "be verbose" +msgstr "자세히 표시" + +#: builtin/add.c:252 +msgid "interactive picking" +msgstr "대화식으로 고릅니다" + +#: builtin/add.c:253 builtin/checkout.c:1153 builtin/reset.c:286 +msgid "select hunks interactively" +msgstr "대화식으로 변경된 부분을 선택합니다" + +#: builtin/add.c:254 +msgid "edit current diff and apply" +msgstr "현재 diff를 편집하고 적용합니다" + +#: builtin/add.c:255 +msgid "allow adding otherwise ignored files" +msgstr "무시하는 파일의 추가를 허용합니다" + +#: builtin/add.c:256 +msgid "update tracked files" +msgstr "추적되는 파일을 업데이트합니다" + +#: builtin/add.c:257 +msgid "record only the fact that the path will be added later" +msgstr "나중에 추가할 것이라는 사실만 기록합니다" + +#: builtin/add.c:258 +msgid "add changes from all tracked and untracked files" +msgstr "추적되고 추적되지 않는 모든 파일의 변경 사항을 추가합니다" + +#: builtin/add.c:261 +msgid "ignore paths removed in the working tree (same as --no-all)" +msgstr "작업 폴더에서 제거한 경로를 무시합니다 (--no-all과 동일)" + +#: builtin/add.c:263 +msgid "don't add, only refresh the index" +msgstr "추가하지 않고 인덱스만 새로 고칩니다" + +#: builtin/add.c:264 +msgid "just skip files which cannot be added because of errors" +msgstr "오류 때문에 추가할 수 없는 파일을 건너뜁니다" + +#: builtin/add.c:265 +msgid "check if - even missing - files are ignored in dry run" +msgstr "가짜로 실행했을 때 파일을 무시하는지 확인합니다" + +#: builtin/add.c:287 +#, c-format +msgid "Use -f if you really want to add them.\n" +msgstr "정말로 추가하려면 -f 옵션을 사용하십시오.\n" + +#: builtin/add.c:294 +msgid "adding files failed" +msgstr "파일 추가가 실패했습니다" + +#: builtin/add.c:330 +msgid "-A and -u are mutually incompatible" +msgstr "-A 및 -u 옵션은 서로 호환되지 않습니다" + +#: builtin/add.c:337 +msgid "Option --ignore-missing can only be used together with --dry-run" +msgstr "" +"--ignore-missing 옵션은 --dry-run 옵션과 같이 사용할 경우에만 쓸 수 있습니다." + +#: builtin/add.c:352 +#, c-format +msgid "Nothing specified, nothing added.\n" +msgstr "아무 것도 지정하지 않았으므로 아무 것도 추가하지 않습니다.\n" + +#: builtin/add.c:353 +#, c-format +msgid "Maybe you wanted to say 'git add .'?\n" +msgstr "'git add .' 명령을 실행하려고 한 것 아니었습니까?\n" + +#: builtin/add.c:358 builtin/check-ignore.c:172 builtin/clean.c:938 +#: builtin/commit.c:337 builtin/mv.c:130 builtin/reset.c:235 builtin/rm.c:298 +#: builtin/submodule--helper.c:40 +msgid "index file corrupt" +msgstr "인덱스 파일이 손상되었습니다" + +#: builtin/add.c:439 builtin/apply.c:4669 builtin/mv.c:279 builtin/rm.c:430 +msgid "Unable to write new index file" +msgstr "새 인덱스 파일에 쓸 수 없습니다" + +#: builtin/am.c:42 +#, c-format +msgid "could not stat %s" +msgstr "%s에 대해 stat()할 수 없습니다" + +#: builtin/am.c:271 builtin/commit.c:738 builtin/merge.c:1077 +#, c-format +msgid "could not read '%s'" +msgstr "'%s'에서 읽을 수 없습니다" + +#: builtin/am.c:445 +msgid "could not parse author script" +msgstr "작성자 스크립트를 파싱할 수 없습니다" + +#: builtin/am.c:522 +#, c-format +msgid "'%s' was deleted by the applypatch-msg hook" +msgstr "applypatch-msg 훅 때문에 '%s'이(가) 삭제되었습니다." + +#: builtin/am.c:563 builtin/notes.c:300 +#, c-format +msgid "Malformed input line: '%s'." +msgstr "잘못된 형식의 입력 줄: '%s'." + +#: builtin/am.c:600 builtin/notes.c:315 +#, c-format +msgid "Failed to copy notes from '%s' to '%s'" +msgstr "'%s'에서 '%s'(으)로 노트를 복사하는데 실패했습니다" + +#: builtin/am.c:626 +msgid "fseek failed" +msgstr "fseek 실패" + +#: builtin/am.c:787 builtin/am.c:875 +#, c-format +msgid "could not open '%s' for reading: %s" +msgstr "'%s'을(를) 읽기용으로 열 수 없습니다: %s" + +#: builtin/am.c:794 +#, c-format +msgid "could not open '%s' for writing: %s" +msgstr "'%s'을(를) 쓰기용으로 열 수 없습니다: %s" + +#: builtin/am.c:803 +#, c-format +msgid "could not parse patch '%s'" +msgstr "'%s' 패치를 파싱할 수 없습니다" + +#: builtin/am.c:868 +msgid "Only one StGIT patch series can be applied at once" +msgstr "한번에 하나의 StGIT 패치 시리즈만 적용할 수 있습니다" + +#: builtin/am.c:916 +msgid "invalid timestamp" +msgstr "시각이 잘못되었습니다" + +#: builtin/am.c:919 builtin/am.c:927 +msgid "invalid Date line" +msgstr "Date 줄이 잘못되었습니다" + +#: builtin/am.c:924 +msgid "invalid timezone offset" +msgstr "시간대 오프셋이 잘못되었습니다" + +#: builtin/am.c:1011 +msgid "Patch format detection failed." +msgstr "패치 형식 검색이 실패했습니다." + +#: builtin/am.c:1016 builtin/clone.c:373 +#, c-format +msgid "failed to create directory '%s'" +msgstr "'%s' 디렉터리 만들기가 실패했습니다" + +#: builtin/am.c:1020 +msgid "Failed to split patches." +msgstr "패치를 쪼개는데 실패했습니다." + +#: builtin/am.c:1152 builtin/commit.c:363 +msgid "unable to write index file" +msgstr "인덱스 파일을 쓸 수 없습니다" + +#: builtin/am.c:1203 +#, c-format +msgid "When you have resolved this problem, run \"%s --continue\"." +msgstr "이 문제를 해결했을 때 \"%s --continue\"를 실행하십시오." + +#: builtin/am.c:1204 +#, c-format +msgid "If you prefer to skip this patch, run \"%s --skip\" instead." +msgstr "이 패치를 건너뛰려면, 그 대신 \"%s --skip\"을 실행하십시오." + +#: builtin/am.c:1205 +#, c-format +msgid "To restore the original branch and stop patching, run \"%s --abort\"." +msgstr "" +"원래 브랜치를 복구하고 패치 적용을 중지하려면 \"%s --abort\"를 실행하십시오." + +#: builtin/am.c:1343 +msgid "Patch is empty. Was it split wrong?" +msgstr "패치가 비어 있습니다. 잘못 쪼개지지 않았나요?" + +#: builtin/am.c:1417 builtin/log.c:1347 +#, c-format +msgid "invalid ident line: %s" +msgstr "잘못된 신원 줄: %s" + +#: builtin/am.c:1444 +#, c-format +msgid "unable to parse commit %s" +msgstr "%s 커밋을 파싱할 수 없습니다" + +#: builtin/am.c:1646 +msgid "Repository lacks necessary blobs to fall back on 3-way merge." +msgstr "저장소에 3-방향 병합으로 대신할 때 필요한 블롭이 없습니다." + +#: builtin/am.c:1648 +msgid "Using index info to reconstruct a base tree..." +msgstr "인덱스 정보를 사용해 기본 트리를 다시 만듭니다..." + +#: builtin/am.c:1667 +msgid "" +"Did you hand edit your patch?\n" +"It does not apply to blobs recorded in its index." +msgstr "" +"패치를 직접 편집하셨습니까?\n" +"이 패치는 인덱스에 기록된 블롭에는 적용되지 않습니다." + +#: builtin/am.c:1673 +msgid "Falling back to patching base and 3-way merge..." +msgstr "베이스 패치 적용 및 3-방향 병합으로 대신합니다..." + +#: builtin/am.c:1688 +msgid "Failed to merge in the changes." +msgstr "변경 사항에서 병합하는데 실패했습니다." + +#: builtin/am.c:1712 builtin/merge.c:632 +msgid "git write-tree failed to write a tree" +msgstr "git write-tree가 트리를 쓰는데 실패했습니다" + +#: builtin/am.c:1719 +msgid "applying to an empty history" +msgstr "빈 커밋 내역에 대해 적용합니다" + +#: builtin/am.c:1732 builtin/commit.c:1755 builtin/merge.c:829 +#: builtin/merge.c:854 +msgid "failed to write commit object" +msgstr "커밋 오브젝트를 쓰는데 실패했습니다" + +#: builtin/am.c:1764 builtin/am.c:1768 +#, c-format +msgid "cannot resume: %s does not exist." +msgstr "다시 시작할 수 없습니다: %s이(가) 없습니다." + +#: builtin/am.c:1784 +msgid "cannot be interactive without stdin connected to a terminal." +msgstr "" +"터미널에 표준 입력이 연결되지 않은 상태에서 대화형으로 실행할 수 없습니다." + +#: builtin/am.c:1789 +msgid "Commit Body is:" +msgstr "커밋 본문은:" + +#. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] +#. in your translation. The program will only accept English +#. input at this point. +#. +#: builtin/am.c:1799 +msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: " +msgstr "적용? 예[y]/아니오[n]/편집[e]/패치 보기[v]/모두 적용[a]: " + +#: builtin/am.c:1849 +#, c-format +msgid "Dirty index: cannot apply patches (dirty: %s)" +msgstr "변경된 인덱스: 패치를 적용할 수 없습니다 (dirty: %s)" + +#: builtin/am.c:1884 builtin/am.c:1955 +#, c-format +msgid "Applying: %.*s" +msgstr "적용하는 중: %.*s" + +#: builtin/am.c:1900 +msgid "No changes -- Patch already applied." +msgstr "변경 사항 없음 -- 패치가 이미 적용되었습니다." + +#: builtin/am.c:1908 +#, c-format +msgid "Patch failed at %s %.*s" +msgstr "패치가 %s %.*s 위치에서 실패했습니다" + +#: builtin/am.c:1914 +#, c-format +msgid "The copy of the patch that failed is found in: %s" +msgstr "실패한 패치의 복사본이 다음 위치에 있습니다: %s" + +#: builtin/am.c:1958 +msgid "" +"No changes - did you forget to use 'git add'?\n" +"If there is nothing left to stage, chances are that something else\n" +"already introduced the same changes; you might want to skip this patch." +msgstr "" +"변경 사항이 없습니다 - 'git add' 사용을 잊으셨습니까?\n" +"커밋으로 표시할 사항이 남아 있지 않으면, 이미 같은 패치에서 적용된\n" +"경우일 수도 있습니다. 그런 경우에는 이 패치를 건너뛰면 됩니다." + +#: builtin/am.c:1965 +msgid "" +"You still have unmerged paths in your index.\n" +"Did you forget to use 'git add'?" +msgstr "" +"인덱스에 병합하지 않은 경로가 남아 있습니다.\n" +"'git add' 사용을 잊지 않으셨습니까?" + +#: builtin/am.c:2073 builtin/am.c:2077 builtin/am.c:2089 builtin/reset.c:308 +#: builtin/reset.c:316 +#, c-format +msgid "Could not parse object '%s'." +msgstr "'%s' 오브젝트를 파싱할 수 없습니다." + +#: builtin/am.c:2125 +msgid "failed to clean index" +msgstr "인덱스 지우기에 실패했습니다" + +#: builtin/am.c:2159 +msgid "" +"You seem to have moved HEAD since the last 'am' failure.\n" +"Not rewinding to ORIG_HEAD" +msgstr "" +"마지막 'am' 실패 이후 HEAD를 옮긴 것 같습니다.\n" +"ORIG_HEAD로 되돌리지 않습니다." + +#: builtin/am.c:2220 +#, c-format +msgid "Invalid value for --patch-format: %s" +msgstr "--patch-format 옵션에 대해 잘못된 값: %s" + +#: builtin/am.c:2253 +msgid "git am [<options>] [(<mbox>|<Maildir>)...]" +msgstr "git am [<옵션>] [(<mbox>|<Maildir>)...]" + +#: builtin/am.c:2254 +msgid "git am [<options>] (--continue | --skip | --abort)" +msgstr "git am [<옵션>] (--continue | --skip | --abort)" + +#: builtin/am.c:2260 +msgid "run interactively" +msgstr "대화형으로 실행합니다" + +#: builtin/am.c:2262 +msgid "historical option -- no-op" +msgstr "아무 동작도 하지 않습니다 (과거부터 있었던 옵션)" + +#: builtin/am.c:2264 +msgid "allow fall back on 3way merging if needed" +msgstr "필요하면 3-방향 병합으로 대신하도록 허용합니다" + +#: builtin/am.c:2265 builtin/init-db.c:474 builtin/prune-packed.c:57 +#: builtin/repack.c:171 +msgid "be quiet" +msgstr "간략히 표시합니다" + +#: builtin/am.c:2267 +msgid "add a Signed-off-by line to the commit message" +msgstr "커밋 메시지에 Signed-off-by 줄을 남깁니다" + +#: builtin/am.c:2270 +msgid "recode into utf8 (default)" +msgstr "UTF-8 인코딩으로 변환합니다 (기본값)" + +#: builtin/am.c:2272 +msgid "pass -k flag to git-mailinfo" +msgstr "git-mailinfo에 -k 옵션을 씁니다" + +#: builtin/am.c:2274 +msgid "pass -b flag to git-mailinfo" +msgstr "git-mailinfo에 -b 옵션을 씁니다" + +#: builtin/am.c:2276 +msgid "pass -m flag to git-mailinfo" +msgstr "git-mailinfo에 -m 옵션을 씁니다" + +#: builtin/am.c:2278 +msgid "pass --keep-cr flag to git-mailsplit for mbox format" +msgstr "mbox 형식에 대해 git-mailsplit에 --keep-cr 옵션을 사용합니다" + +#: builtin/am.c:2281 +msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr" +msgstr "" +"am.keepcr에 무관하게 git-mailsplit에 --keep-cr 옵션을 사용하지 않습니다." + +#: builtin/am.c:2284 +msgid "strip everything before a scissors line" +msgstr "절취선 앞의 모든 사항을 무시합니다" + +#: builtin/am.c:2285 builtin/apply.c:4554 +msgid "action" +msgstr "동작" + +#: builtin/am.c:2286 builtin/am.c:2289 builtin/am.c:2292 builtin/am.c:2295 +#: builtin/am.c:2298 builtin/am.c:2301 builtin/am.c:2304 builtin/am.c:2307 +#: builtin/am.c:2313 +msgid "pass it through git-apply" +msgstr "git-apply에 넘깁니다" + +#: builtin/am.c:2294 builtin/apply.c:4578 +msgid "root" +msgstr "최상위" + +#: builtin/am.c:2297 builtin/am.c:2300 builtin/apply.c:4516 +#: builtin/apply.c:4519 builtin/clone.c:85 builtin/fetch.c:93 +#: builtin/pull.c:167 builtin/submodule--helper.c:78 +#: builtin/submodule--helper.c:166 builtin/submodule--helper.c:169 +msgid "path" +msgstr "경로" + +#: builtin/am.c:2303 builtin/fmt-merge-msg.c:666 builtin/fmt-merge-msg.c:669 +#: builtin/grep.c:693 builtin/merge.c:198 builtin/pull.c:127 +#: builtin/repack.c:178 builtin/repack.c:182 builtin/show-branch.c:645 +#: builtin/show-ref.c:175 builtin/tag.c:340 parse-options.h:132 +#: parse-options.h:134 parse-options.h:244 +msgid "n" +msgstr "n" + +#: builtin/am.c:2306 builtin/apply.c:4522 +msgid "num" +msgstr "개수" + +#: builtin/am.c:2309 builtin/for-each-ref.c:37 builtin/replace.c:438 +#: builtin/tag.c:372 +msgid "format" +msgstr "형식" + +#: builtin/am.c:2310 +msgid "format the patch(es) are in" +msgstr "패치의 형식" + +#: builtin/am.c:2316 +msgid "override error message when patch failure occurs" +msgstr "패치 실패가 발생했을 때 오류 메시지 대신 사용합니다" + +#: builtin/am.c:2318 +msgid "continue applying patches after resolving a conflict" +msgstr "충돌을 해결한 다음 패치 적용을 계속합니다" + +#: builtin/am.c:2321 +msgid "synonyms for --continue" +msgstr "--continue 옵션과 동일" + +#: builtin/am.c:2324 +msgid "skip the current patch" +msgstr "현재 패치 건너뛰기" + +#: builtin/am.c:2327 +msgid "restore the original branch and abort the patching operation." +msgstr "원래 브랜치를 복구하고 패치 적용 작업을 중지합니다." + +# NOTE: 옵션의 의미는 이게 맞다. 원문에서는 사용자가 +# --committer-date-is-author-date라는 옵션을 보고 의미를 알 수 있다고 가정하고 있다. +#: builtin/am.c:2331 +msgid "lie about committer date" +msgstr "커미터 시각을 작성자 시각으로 넣습니다" + +#: builtin/am.c:2333 +msgid "use current timestamp for author date" +msgstr "현재 시각을 작성자 시각으로 사용합니다" + +#: builtin/am.c:2335 builtin/commit.c:1593 builtin/merge.c:225 +#: builtin/pull.c:155 builtin/revert.c:92 builtin/tag.c:355 +msgid "key-id" +msgstr "키-ID" + +#: builtin/am.c:2336 +msgid "GPG-sign commits" +msgstr "GPG 서명 커밋" + +#: builtin/am.c:2339 +msgid "(internal use for git-rebase)" +msgstr "(git-rebase를 위한 내부 용도)" + +#: builtin/am.c:2354 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"-b/--binary 옵션은 오랜 시간 동안 아무 동작도 하지 않았으므로, 이\n" +"옵션은 제거될 예정입니다. 이제 사용하지 마십시오." + +#: builtin/am.c:2361 +msgid "failed to read the index" +msgstr "인덱스 읽기에 실패했습니다" + +#: builtin/am.c:2376 +#, c-format +msgid "previous rebase directory %s still exists but mbox given." +msgstr "이전 리베이스 디렉터리 %s이(가) 아직 있고 mbox를 지정했습니다." + +#: builtin/am.c:2400 +#, c-format +msgid "" +"Stray %s directory found.\n" +"Use \"git am --abort\" to remove it." +msgstr "" +"벗어난 %s 디렉터리가 발견되었습니다.\n" +"제거하려면 \"git am --abort\"를 사용하십시오." + +#: builtin/am.c:2406 +msgid "Resolve operation not in progress, we are not resuming." +msgstr "해소 작업이 진행 중입니다. 다시 시작하지 않습니다." + +#: builtin/apply.c:59 +msgid "git apply [<options>] [<patch>...]" +msgstr "git apply [<옵션>] [<패치>...]" + +#: builtin/apply.c:111 +#, c-format +msgid "unrecognized whitespace option '%s'" +msgstr "알 수 없는 공백 옵션 '%s'" + +#: builtin/apply.c:126 +#, c-format +msgid "unrecognized whitespace ignore option '%s'" +msgstr "알 수 없는 공백 무시 옵션 '%s'" + +#: builtin/apply.c:818 +#, c-format +msgid "Cannot prepare timestamp regexp %s" +msgstr "타임스탬프 정규식을 준비할 수 없습니다 (%s)" + +#: builtin/apply.c:827 +#, c-format +msgid "regexec returned %d for input: %s" +msgstr "regexec()에서 다음 입력에 대해 %d번을 리턴했습니다: %s" + +#: builtin/apply.c:908 +#, c-format +msgid "unable to find filename in patch at line %d" +msgstr "패치의 %d번 줄에 파일 이름을 찾을 수 없습니다" + +#: builtin/apply.c:940 +#, c-format +msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" +msgstr "git apply: 잘못된 git-diff - %2$d번 줄에서 /dev/null을 기대했지만, '%1$s'이(가) 왔습니다" + +#: builtin/apply.c:944 +#, c-format +msgid "git apply: bad git-diff - inconsistent new filename on line %d" +msgstr "git apply: 잘못된 git-diff - %d번 줄에 새 파일 이름이 올바르지 않습니다" + +#: builtin/apply.c:945 +#, c-format +msgid "git apply: bad git-diff - inconsistent old filename on line %d" +msgstr "git apply: 잘못된 git-diff - %d번 줄에 예전 파일 이름이 올바르지 않습니다" + +#: builtin/apply.c:952 +#, c-format +msgid "git apply: bad git-diff - expected /dev/null on line %d" +msgstr "git apply: 잘못된 git-diff - %d번 줄에서 /dev/null을 기대했습니다" + +#: builtin/apply.c:1415 +#, c-format +msgid "recount: unexpected line: %.*s" +msgstr "recount: 예상치 못한 줄: %.*s" + +#: builtin/apply.c:1472 +#, c-format +msgid "patch fragment without header at line %d: %.*s" +msgstr "%d번 줄에 헤더 없는 패치 부분: %.*s" + +#: builtin/apply.c:1489 +#, c-format +msgid "" +"git diff header lacks filename information when removing %d leading pathname " +"component (line %d)" +msgid_plural "" +"git diff header lacks filename information when removing %d leading pathname " +"components (line %d)" +msgstr[0] "" +"경로 이름 부분에서 %d개를 제거라 때 git diff 헤더에 파일 이름 정보가 없습니" +"다. (%d번 줄)" + +#: builtin/apply.c:1655 +msgid "new file depends on old contents" +msgstr "새 파일이 예전 내용에 의존합니다" + +#: builtin/apply.c:1657 +msgid "deleted file still has contents" +msgstr "삭제한 파일에 아직 내용이 들어 있습니다" + +#: builtin/apply.c:1683 +#, c-format +msgid "corrupt patch at line %d" +msgstr "패치가 %d번 줄에서 망가졌습니다" + +#: builtin/apply.c:1719 +#, c-format +msgid "new file %s depends on old contents" +msgstr "새 파일 %s이(가) 예전 내용에 의존합니다" + +#: builtin/apply.c:1721 +#, c-format +msgid "deleted file %s still has contents" +msgstr "삭제한 파일 %s이(가) 아직 내용이 들어 있습니다" + +#: builtin/apply.c:1724 +#, c-format +msgid "** warning: file %s becomes empty but is not deleted" +msgstr "** 경고: %s 파일의 내용이 비어 있지만 삭제되지 않았습니다" + +#: builtin/apply.c:1870 +#, c-format +msgid "corrupt binary patch at line %d: %.*s" +msgstr "%d번 줄에 바이너리 패치가 손상되었습니다: %.*s" + +#: builtin/apply.c:1899 +#, c-format +msgid "unrecognized binary patch at line %d" +msgstr "%d번 줄에 바이너리 패치가 이해할 수 없습니다" + +#: builtin/apply.c:2050 +#, c-format +msgid "patch with only garbage at line %d" +msgstr "%d번 줄에 쓰레기 데이터만 있는 패치" + +#: builtin/apply.c:2140 +#, c-format +msgid "unable to read symlink %s" +msgstr "%s 심볼릭 링크를 읽을 수 없습니다" + +#: builtin/apply.c:2144 +#, c-format +msgid "unable to open or read %s" +msgstr "%s을(를) 열거나 읽을 수 없습니다" + +#: builtin/apply.c:2777 +#, c-format +msgid "invalid start of line: '%c'" +msgstr "줄 시작이 잘못됨: '%c'" + +#: builtin/apply.c:2896 +#, c-format +msgid "Hunk #%d succeeded at %d (offset %d line)." +msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." +msgstr[0] "패치 %d번 부분 %d번 줄에서 성공 (오프셋 %d줄)" + +#: builtin/apply.c:2908 +#, c-format +msgid "Context reduced to (%ld/%ld) to apply fragment at %d" +msgstr "컨텍스트가 (%ld/%ld)로 줄어듭니다. (%d번 줄에서 적용)" + +#: builtin/apply.c:2914 +#, c-format +msgid "" +"while searching for:\n" +"%.*s" +msgstr "" +"다음을 검색하던 중:\n" +"%.*s" + +#: builtin/apply.c:2934 +#, c-format +msgid "missing binary patch data for '%s'" +msgstr "'%s'에 대한 바이너리 패치 데이터가 없습니다" + +#: builtin/apply.c:3035 +#, c-format +msgid "binary patch does not apply to '%s'" +msgstr "바이너리 패치를 '%s'에 적용할 수 없습니다" + +#: builtin/apply.c:3041 +#, c-format +msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" +msgstr "" +"'%s'에 대한 바이너리 패치가 올바르지 않은 결과를 만듭니다. (기대한 값 %s, 실" +"제 %s)" + +#: builtin/apply.c:3062 +#, c-format +msgid "patch failed: %s:%ld" +msgstr "패치 실패: %s:%ld" + +#: builtin/apply.c:3186 +#, c-format +msgid "cannot checkout %s" +msgstr "%s을(를) 가져올 수 없습니다" + +#: builtin/apply.c:3231 builtin/apply.c:3242 builtin/apply.c:3287 +#, c-format +msgid "read of %s failed" +msgstr "%s 읽기가 실패했습니다" + +#: builtin/apply.c:3239 +#, c-format +msgid "reading from '%s' beyond a symbolic link" +msgstr "심볼릭 링크 뒤에 있는 '%s' 읽기" + +#: builtin/apply.c:3267 builtin/apply.c:3489 +#, c-format +msgid "path %s has been renamed/deleted" +msgstr "%s 경로가 이름이 바뀌었거나 삭제되었습니다" + +#: builtin/apply.c:3348 builtin/apply.c:3503 +#, c-format +msgid "%s: does not exist in index" +msgstr "%s: 인덱스에 없습니다" + +#: builtin/apply.c:3352 builtin/apply.c:3495 builtin/apply.c:3517 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: builtin/apply.c:3357 builtin/apply.c:3511 +#, c-format +msgid "%s: does not match index" +msgstr "%s: 인덱스와 맞지 않습니다" + +#: builtin/apply.c:3459 +msgid "removal patch leaves file contents" +msgstr "제거하는 패치 다음에 파일 내용이 남았습니다" + +#: builtin/apply.c:3528 +#, c-format +msgid "%s: wrong type" +msgstr "%s: 잘못된 종류" + +#: builtin/apply.c:3530 +#, c-format +msgid "%s has type %o, expected %o" +msgstr "%s의 종류가 %o이지만 %o이(가) 되어야 합니다" + +#: builtin/apply.c:3689 builtin/apply.c:3691 +#, c-format +msgid "invalid path '%s'" +msgstr "잘못된 경로 '%s'" + +#: builtin/apply.c:3746 +#, c-format +msgid "%s: already exists in index" +msgstr "%s: 이미 인덱스에 있습니다" + +#: builtin/apply.c:3749 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s: 이미 작업 디렉터리에 있습니다" + +#: builtin/apply.c:3769 +#, c-format +msgid "new mode (%o) of %s does not match old mode (%o)" +msgstr "%2$s의 새 모드(%1$o)가 예전 모드(%3$o)와 다릅니다" + +#: builtin/apply.c:3774 +#, c-format +msgid "new mode (%o) of %s does not match old mode (%o) of %s" +msgstr "%2$s의 새 모드(%1$o)가 %4$s의 예전 모드(%3$o)와 다릅니다" + +#: builtin/apply.c:3794 +#, c-format +msgid "affected file '%s' is beyond a symbolic link" +msgstr "영향 받는 '%s' 파일이 심볼릭 링크 뒤에 있습니다" + +#: builtin/apply.c:3798 +#, c-format +msgid "%s: patch does not apply" +msgstr "%s: 패치를 적용하지 않습니다" + +#: builtin/apply.c:3812 +#, c-format +msgid "Checking patch %s..." +msgstr "%s 패치를 확인하는 중입니다..." + +#: builtin/apply.c:3905 builtin/checkout.c:233 builtin/reset.c:135 +#, c-format +msgid "make_cache_entry failed for path '%s'" +msgstr "경로 '%s'에 대해 make_cache_entry 실패" + +#: builtin/apply.c:4048 +#, c-format +msgid "unable to remove %s from index" +msgstr "인덱스에서 %s을(를) 제거할 수 없습니다" + +#: builtin/apply.c:4077 +#, c-format +msgid "corrupt patch for submodule %s" +msgstr "하위 모듈 %s에 대해 손상된 패치" + +#: builtin/apply.c:4081 +#, c-format +msgid "unable to stat newly created file '%s'" +msgstr "새로 만든 파일 '%s'에 대해 stat()할 수 없습니다" + +#: builtin/apply.c:4086 +#, c-format +msgid "unable to create backing store for newly created file %s" +msgstr "새로 만든 파일 '%s'에 대해 예비 저장소를 만들 수 없습니다" + +#: builtin/apply.c:4089 builtin/apply.c:4197 +#, c-format +msgid "unable to add cache entry for %s" +msgstr "%s에 대해 캐시 항목을 추가할 수 없습니다" + +#: builtin/apply.c:4122 +#, c-format +msgid "closing file '%s'" +msgstr "'%s' 파일을 닫는 중입니다" + +#: builtin/apply.c:4171 +#, c-format +msgid "unable to write file '%s' mode %o" +msgstr "'%s' 파일에 쓸 수 없습니다 ('%o' 모드)" + +#: builtin/apply.c:4258 +#, c-format +msgid "Applied patch %s cleanly." +msgstr "%s 패치 깔끔하게 적용." + +#: builtin/apply.c:4266 +msgid "internal error" +msgstr "내부 오류" + +#: builtin/apply.c:4269 +#, c-format +msgid "Applying patch %%s with %d reject..." +msgid_plural "Applying patch %%s with %d rejects..." +msgstr[0] "%%s 패치를 (%d개 거부) 적용..." + +#: builtin/apply.c:4279 +#, c-format +msgid "truncating .rej filename to %.*s.rej" +msgstr "truncating .rej 파일 이름을 '%.*s.rej'(으)로 자름" + +#: builtin/apply.c:4300 +#, c-format +msgid "Hunk #%d applied cleanly." +msgstr "패치 부위 #%d 깔끔하게 적용." + +#: builtin/apply.c:4303 +#, c-format +msgid "Rejected hunk #%d." +msgstr "패치 부위 #%d 거부됨." + +#: builtin/apply.c:4393 +msgid "unrecognized input" +msgstr "인식할 수 없는 입력" + +#: builtin/apply.c:4404 +msgid "unable to read index file" +msgstr "인덱스 파일을 읽을 수 없습니다" + +#: builtin/apply.c:4517 +msgid "don't apply changes matching the given path" +msgstr "주어진 경로에 해당하는 변경 사항을 적용하지 않습니다" + +#: builtin/apply.c:4520 +msgid "apply changes matching the given path" +msgstr "주어진 경로에 해당하는 변경 사항을 적용합니다" + +#: builtin/apply.c:4523 +msgid "remove <num> leading slashes from traditional diff paths" +msgstr "전통적인 diff 경로 앞의 <개수>개의 앞 슬래시(/)를 제거합니다" + +#: builtin/apply.c:4526 +msgid "ignore additions made by the patch" +msgstr "패치에서 추가하는 파일을 무시합니다" + +#: builtin/apply.c:4528 +msgid "instead of applying the patch, output diffstat for the input" +msgstr "패치를 적용하는 대신, 입력에 대한 diffstat을 출력합니다" + +#: builtin/apply.c:4532 +msgid "show number of added and deleted lines in decimal notation" +msgstr "십진수로 추가 및 삭제한 줄 수를 표시합니다" + +#: builtin/apply.c:4534 +msgid "instead of applying the patch, output a summary for the input" +msgstr "패치를 적용하는 대신, 입력에 대한 요약을 출력합니다" + +#: builtin/apply.c:4536 +msgid "instead of applying the patch, see if the patch is applicable" +msgstr "패치를 적용하는 대신, 패치를 적용 가능한지 확인합니다" + +#: builtin/apply.c:4538 +msgid "make sure the patch is applicable to the current index" +msgstr "현재 인덱스에서 패치가 적용 가능한지 확인합니다" + +#: builtin/apply.c:4540 +msgid "apply a patch without touching the working tree" +msgstr "작업 폴더를 바꾸지 않고 패치를 적용합니다" + +#: builtin/apply.c:4542 +msgid "accept a patch that touches outside the working area" +msgstr "작업 영역 밖의 파일을 바꾸는 패치를 허용합니다" + +#: builtin/apply.c:4544 +msgid "also apply the patch (use with --stat/--summary/--check)" +msgstr "그리고 패치도 적용합니다 (--stat/--summary/--check 옵션과 같이 사용)" + +#: builtin/apply.c:4546 +msgid "attempt three-way merge if a patch does not apply" +msgstr "패치를 적용하지 않으면 3-방향 병합을 시도합니다" + +#: builtin/apply.c:4548 +msgid "build a temporary index based on embedded index information" +msgstr "내장 인덱스 정보를 사용해 임시 인덱스를 만듭니다" + +#: builtin/apply.c:4550 builtin/checkout-index.c:198 builtin/ls-files.c:412 +msgid "paths are separated with NUL character" +msgstr "경로를 NUL 문자로 구분합니다" + +#: builtin/apply.c:4553 +msgid "ensure at least <n> lines of context match" +msgstr "최소한 <n>줄이 컨텍스트와 일치하는지 확인합니다" + +#: builtin/apply.c:4555 +msgid "detect new or modified lines that have whitespace errors" +msgstr "공백 오류가 있는 추가됐거나 수정된 줄을 찾습니다" + +#: builtin/apply.c:4558 builtin/apply.c:4561 +msgid "ignore changes in whitespace when finding context" +msgstr "컨텍스트를 찾을 때 공백 변경 사항을 무시합니다" + +#: builtin/apply.c:4564 +msgid "apply the patch in reverse" +msgstr "패치를 반대 순서로 적용합니다" + +#: builtin/apply.c:4566 +msgid "don't expect at least one line of context" +msgstr "최소한의 컨텍스트 한 줄도 없이 적용합니다" + +#: builtin/apply.c:4568 +msgid "leave the rejected hunks in corresponding *.rej files" +msgstr "거부된 패치 부분을 대응되는 *.rej 파일에 남겨둡니다" + +#: builtin/apply.c:4570 +msgid "allow overlapping hunks" +msgstr "패치 부분이 겹쳐도 허용합니다" + +#: builtin/apply.c:4573 +msgid "tolerate incorrectly detected missing new-line at the end of file" +msgstr "파일 끝에 줄바꿈이 빠졌음을 잘못 검색한 경우에 무시합니다" + +#: builtin/apply.c:4576 +msgid "do not trust the line counts in the hunk headers" +msgstr "패치 부분의 헤더의 줄 수를 신용하지 않습니다" + +#: builtin/apply.c:4579 +msgid "prepend <root> to all filenames" +msgstr "모든 파일 이름에 <최상위>를 앞에 붙입니다" + +#: builtin/apply.c:4601 +msgid "--3way outside a repository" +msgstr "저장소 밖에서 --3way 옵션 사용" + +#: builtin/apply.c:4609 +msgid "--index outside a repository" +msgstr "저장소 밖에서 --index 옵션 사용" + +#: builtin/apply.c:4612 +msgid "--cached outside a repository" +msgstr "저장소 밖에서 --cached 옵션 사용" + +#: builtin/apply.c:4631 +#, c-format +msgid "can't open patch '%s'" +msgstr "'%s' 패치를 열 수 없습니다" + +#: builtin/apply.c:4645 +#, c-format +msgid "squelched %d whitespace error" +msgid_plural "squelched %d whitespace errors" +msgstr[0] "공백 오류 %d개를 넘어갑니다" + +#: builtin/apply.c:4651 builtin/apply.c:4661 +#, c-format +msgid "%d line adds whitespace errors." +msgid_plural "%d lines add whitespace errors." +msgstr[0] "%d줄에서 공백 오류를 추가합니다." + +#: builtin/archive.c:17 +#, c-format +msgid "could not create archive file '%s'" +msgstr "'%s' 아카이브 파일을 만들 수 없습니다" + +#: builtin/archive.c:20 +msgid "could not redirect output" +msgstr "출력 방향을 돌릴 수 없습니다" + +#: builtin/archive.c:37 +msgid "git archive: Remote with no URL" +msgstr "git archive: URL 없는 리모트" + +#: builtin/archive.c:58 +msgid "git archive: expected ACK/NAK, got EOF" +msgstr "git archive: ACK/NAK가 와야 하지만, EOF를 받았습니다" + +#: builtin/archive.c:61 +#, c-format +msgid "git archive: NACK %s" +msgstr "git archive: NACK %s" + +#: builtin/archive.c:63 +#, c-format +msgid "remote error: %s" +msgstr "리모트 오류: %s" + +#: builtin/archive.c:64 +msgid "git archive: protocol error" +msgstr "git archive: 프로토콜 오류" + +#: builtin/archive.c:68 +msgid "git archive: expected a flush" +msgstr "git archive: 파일 끝을 예상함" + +#: builtin/bisect--helper.c:7 +msgid "git bisect--helper --next-all [--no-checkout]" +msgstr "git bisect--helper --next-all [--no-checkout]" + +#: builtin/bisect--helper.c:17 +msgid "perform 'git bisect next'" +msgstr "'git bisect next'를 수행합니다" + +#: builtin/bisect--helper.c:19 +msgid "update BISECT_HEAD instead of checking out the current commit" +msgstr "현재 커밋을 가져오는 대신 BISECT_HEAD를 업데이트합니다" + +#: builtin/blame.c:32 +msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>" +msgstr "git blame [<옵션>] [<리비전-옵션>] [<리비전>] [--] <파일>" + +#: builtin/blame.c:37 +msgid "<rev-opts> are documented in git-rev-list(1)" +msgstr "<리비전-옵션>은 git-rev-list(1)에 설명되어 있습니다" + +#: builtin/blame.c:2519 +msgid "Show blame entries as we find them, incrementally" +msgstr "blame 항목을 찾자마자 점진적으로 표시합니다" + +#: builtin/blame.c:2520 +msgid "Show blank SHA-1 for boundary commits (Default: off)" +msgstr "가장자리 커밋에 대해 빈 SHA-1을 표시합니다 (기본값: 꺼짐)" + +#: builtin/blame.c:2521 +msgid "Do not treat root commits as boundaries (Default: off)" +msgstr "최상위 커밋을 가장자리 커밋으로 취급하지 않습니다 (기본값: 꺼짐)" + +#: builtin/blame.c:2522 +msgid "Show work cost statistics" +msgstr "작업 비용 통계를 표시합니다" + +#: builtin/blame.c:2523 +msgid "Show output score for blame entries" +msgstr "blame 항목에 대해 출력 점수를 표시합니다" + +#: builtin/blame.c:2524 +msgid "Show original filename (Default: auto)" +msgstr "원래 파일 이름 표시 (기본값: 자동)" + +#: builtin/blame.c:2525 +msgid "Show original linenumber (Default: off)" +msgstr "원래 줄 번호 표시 (기본값: 하지 않음)" + +#: builtin/blame.c:2526 +msgid "Show in a format designed for machine consumption" +msgstr "컴퓨터 처리용으로 설계된 형식으로 표시합니다" + +#: builtin/blame.c:2527 +msgid "Show porcelain format with per-line commit information" +msgstr "줄마다 커밋 정보가 표시되는 사용자용 형식으로 표시합니다" + +#: builtin/blame.c:2528 +msgid "Use the same output mode as git-annotate (Default: off)" +msgstr "git-annotate와 동일한 형식을 사용합니다 (기본값: 꺼짐)" + +#: builtin/blame.c:2529 +msgid "Show raw timestamp (Default: off)" +msgstr "내부 형식으로 시각을 표시합니다 (기본값: 꺼짐)" + +#: builtin/blame.c:2530 +msgid "Show long commit SHA1 (Default: off)" +msgstr "길게 커밋 SHA1을 표시합니다 (기본값: 꺼짐)" + +#: builtin/blame.c:2531 +msgid "Suppress author name and timestamp (Default: off)" +msgstr "작성자 이름과 시각을 표시하지 않습니다 (기본값: 꺼짐)" + +#: builtin/blame.c:2532 +msgid "Show author email instead of name (Default: off)" +msgstr "작성자 이름 대신에 전자메일을 표시합니다 (기본값: 꺼짐)" + +#: builtin/blame.c:2533 +msgid "Ignore whitespace differences" +msgstr "공백 문자 차이점을 무시합니다" + +#: builtin/blame.c:2534 +msgid "Spend extra cycles to find better match" +msgstr "더 일치하는 항목을 찾는데 더 시간을 소모합니다" + +#: builtin/blame.c:2535 +msgid "Use revisions from <file> instead of calling git-rev-list" +msgstr "git-rev-list를 호출하는 대신 <파일>에서 리비전을 사용합니다" + +#: builtin/blame.c:2536 +msgid "Use <file>'s contents as the final image" +msgstr "<파일>의 내용을 최종 이미지로 사용합니다" + +#: builtin/blame.c:2537 builtin/blame.c:2538 +msgid "score" +msgstr "점수" + +#: builtin/blame.c:2537 +msgid "Find line copies within and across files" +msgstr "파일 내부와 파일 사이의 복사된 줄을 찾습니다" + +#: builtin/blame.c:2538 +msgid "Find line movements within and across files" +msgstr "파일 내부와 파일 사이의 옮겨진 줄을 찾습니다" + +#: builtin/blame.c:2539 +msgid "n,m" +msgstr "n,m" + +#: builtin/blame.c:2539 +msgid "Process only line range n,m, counting from 1" +msgstr "n,m줄 (1번 줄부터 시작) 사이의 범위만 처리" + +#. TRANSLATORS: This string is used to tell us the maximum +#. display width for a relative timestamp in "git blame" +#. output. For C locale, "4 years, 11 months ago", which +#. takes 22 places, is the longest among various forms of +#. relative timestamps, but your language may need more or +#. fewer display columns. +#: builtin/blame.c:2620 +msgid "4 years, 11 months ago" +msgstr "4년 11달 전" + +#: builtin/branch.c:25 +msgid "git branch [<options>] [-r | -a] [--merged | --no-merged]" +msgstr "git branch [<옵션>] [-r | -a] [--merged | --no-merged]" + +#: builtin/branch.c:26 +msgid "git branch [<options>] [-l] [-f] <branch-name> [<start-point>]" +msgstr "git branch [<옵션>] [-l] [-f] <브랜치-이름> [<시작-지점>]" + +#: builtin/branch.c:27 +msgid "git branch [<options>] [-r] (-d | -D) <branch-name>..." +msgstr "git branch [<옵션>] [-r] (-d | -D) <브랜치-이름>..." + +#: builtin/branch.c:28 +msgid "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>" +msgstr "git branch [<옵션>] (-m | -M) [<과거-브랜치>] <새-브랜치>" + +#: builtin/branch.c:29 +msgid "git branch [<options>] [-r | -a] [--points-at]" +msgstr "git branch [<옵션>] [-r | -a] [--points-at]" + +#: builtin/branch.c:142 +#, c-format +msgid "" +"deleting branch '%s' that has been merged to\n" +" '%s', but not yet merged to HEAD." +msgstr "" +"'%s' 브랜치를 삭제합니다. 이 브랜치는 '%s'에\n" +" 병합되었지만, HEAD에는 병합되지 않았습니다." + +#: builtin/branch.c:146 +#, c-format +msgid "" +"not deleting branch '%s' that is not yet merged to\n" +" '%s', even though it is merged to HEAD." +msgstr "" +"'%s' 브랜치를 삭제하지 않습니다. 이 브랜치는 '%s'에\n" +" 병합되지 않았지만, HEAD에는 병합되었습니다." + +#: builtin/branch.c:160 +#, c-format +msgid "Couldn't look up commit object for '%s'" +msgstr "'%s'에 대한 커밋 오브젝트를 찾아볼 수 없습니다" + +#: builtin/branch.c:164 +#, c-format +msgid "" +"The branch '%s' is not fully merged.\n" +"If you are sure you want to delete it, run 'git branch -D %s'." +msgstr "" +"'%s' 브랜치가 완전히 병합되지 않았습니다.\n" +"정말로 삭제하려면 'git branch -D %s' 명령을 실행하십시오." + +#: builtin/branch.c:177 +msgid "Update of config-file failed" +msgstr "config-file 업데이트가 실패했습니다" + +#: builtin/branch.c:205 +msgid "cannot use -a with -d" +msgstr "-a 옵션을 -d 옵션과 같이 쓸 수 없습니다" + +#: builtin/branch.c:211 +msgid "Couldn't look up commit object for HEAD" +msgstr "HEAD에 대한 커밋 오브젝트를 찾아볼 수 없습니다" + +#: builtin/branch.c:219 +#, c-format +msgid "Cannot delete the branch '%s' which you are currently on." +msgstr "'%s' 브랜치는 현재 위치한 브랜치이기 때문에 삭제할 수 없습니다." + +#: builtin/branch.c:235 +#, c-format +msgid "remote-tracking branch '%s' not found." +msgstr "리모트 추적 '%s' 브랜치가 없습니다." + +#: builtin/branch.c:236 +#, c-format +msgid "branch '%s' not found." +msgstr "'%s' 브랜치가 없습니다." + +#: builtin/branch.c:251 +#, c-format +msgid "Error deleting remote-tracking branch '%s'" +msgstr "리모트 추적 '%s' 브랜치를 삭제하는데 오류" + +#: builtin/branch.c:252 +#, c-format +msgid "Error deleting branch '%s'" +msgstr "'%s' 브랜치를 삭제하는데 오류" + +#: builtin/branch.c:259 +#, c-format +msgid "Deleted remote-tracking branch %s (was %s).\n" +msgstr "리모트 추적 '%s' 브랜치를 삭제합니다. (과거 %s)\n" + +#: builtin/branch.c:260 +#, c-format +msgid "Deleted branch %s (was %s).\n" +msgstr "%s 브랜치 삭제 (과거 %s).\n" + +#: builtin/branch.c:303 +#, c-format +msgid "[%s: gone]" +msgstr "[%s: 사라짐]" + +#: builtin/branch.c:308 +#, c-format +msgid "[%s]" +msgstr "[%s]" + +#: builtin/branch.c:313 +#, c-format +msgid "[%s: behind %d]" +msgstr "[%s: %d개 뒤]" + +#: builtin/branch.c:315 +#, c-format +msgid "[behind %d]" +msgstr "[%d개 뒤]" + +#: builtin/branch.c:319 +#, c-format +msgid "[%s: ahead %d]" +msgstr "[%s: %d개 앞]" + +#: builtin/branch.c:321 +#, c-format +msgid "[ahead %d]" +msgstr "[%d개 앞]" + +#: builtin/branch.c:324 +#, c-format +msgid "[%s: ahead %d, behind %d]" +msgstr "[%s: %d개 앞, %d개 뒤]" + +#: builtin/branch.c:327 +#, c-format +msgid "[ahead %d, behind %d]" +msgstr "[%d개 앞, %d개 뒤]" + +#: builtin/branch.c:340 +msgid " **** invalid ref ****" +msgstr " **** 잘못된 레퍼런스 ****" + +#: builtin/branch.c:366 +#, c-format +msgid "(no branch, rebasing %s)" +msgstr "(브랜치 없음, %s 리베이스)" + +#: builtin/branch.c:369 +#, c-format +msgid "(no branch, bisect started on %s)" +msgstr "(브랜치 없음, 이등분 %s에서 시작)" + +#: builtin/branch.c:375 +#, c-format +msgid "(HEAD detached at %s)" +msgstr "(HEAD %s 위치에서 분리됨)" + +#: builtin/branch.c:378 +#, c-format +msgid "(HEAD detached from %s)" +msgstr "(HEAD %s(으)로부터 분리됨)" + +#: builtin/branch.c:382 +msgid "(no branch)" +msgstr "(브랜치 없음)" + +#: builtin/branch.c:524 +msgid "cannot rename the current branch while not on any." +msgstr "브랜치 위에 없으면서 현재 브랜치 이름을 바꿀 수 없습니다." + +#: builtin/branch.c:534 +#, c-format +msgid "Invalid branch name: '%s'" +msgstr "잘못된 브랜치 이름: '%s'" + +#: builtin/branch.c:549 +msgid "Branch rename failed" +msgstr "브랜치 이름 바꾸기 실패" + +#: builtin/branch.c:553 +#, c-format +msgid "Renamed a misnamed branch '%s' away" +msgstr "이름이 잘못된 '%s' 브랜치의 이름을 다르게 바꿉니다" + +#: builtin/branch.c:557 +#, c-format +msgid "Branch renamed to %s, but HEAD is not updated!" +msgstr "브랜치 이름을 %s(으)로 바꾸지만, HEAD를 업데이트하지 않습니다!" + +#: builtin/branch.c:564 +msgid "Branch is renamed, but update of config-file failed" +msgstr "브랜치의 이름을 바꾸지만, config-file 업데이트가 실패했습니다" + +#: builtin/branch.c:587 +#, c-format +msgid "could not write branch description template: %s" +msgstr "브랜치 설명 서식을 쓸 수 없습니다: %s" + +#: builtin/branch.c:616 +msgid "Generic options" +msgstr "일반 옵션" + +# FIXME: give twice? +#: builtin/branch.c:618 +msgid "show hash and subject, give twice for upstream branch" +msgstr "해시와 제목을 표시하고, 업스트림 브랜치에 대한 위치를 표시합니다" + +#: builtin/branch.c:619 +msgid "suppress informational messages" +msgstr "여러가지 안내 메시지를 표시하지 않습니다" + +#: builtin/branch.c:620 +msgid "set up tracking mode (see git-pull(1))" +msgstr "추적 모드를 설정합니다 (git-pull(1) 참고)" + +#: builtin/branch.c:622 +msgid "change upstream info" +msgstr "업스트림 정보를 바꿉니다" + +#: builtin/branch.c:626 +msgid "use colored output" +msgstr "여러 색으로 출력합니다" + +#: builtin/branch.c:627 +msgid "act on remote-tracking branches" +msgstr "리모트 추적 브랜치에 대해 동작합니다" + +#: builtin/branch.c:629 builtin/branch.c:630 +msgid "print only branches that contain the commit" +msgstr "커밋이 있는 브랜치만 표시합니다" + +#: builtin/branch.c:633 +msgid "Specific git-branch actions:" +msgstr "특정 git-branch 동작:" + +#: builtin/branch.c:634 +msgid "list both remote-tracking and local branches" +msgstr "리모트와 로컬의 브랜치 목록을 모두 표시합니다" + +#: builtin/branch.c:636 +msgid "delete fully merged branch" +msgstr "완전히 병합된 브랜치를 삭제합니다" + +#: builtin/branch.c:637 +msgid "delete branch (even if not merged)" +msgstr "브랜치를 삭제합니다 (병합되지 않았더라도)" + +#: builtin/branch.c:638 +msgid "move/rename a branch and its reflog" +msgstr "브랜치와 그 reflog를 옮기거나 이름을 바꿉니다" + +#: builtin/branch.c:639 +msgid "move/rename a branch, even if target exists" +msgstr "대상이 이미 있더라도 브랜치를 옮기거나 이름을 바꿉니다" + +#: builtin/branch.c:640 +msgid "list branch names" +msgstr "브랜치 이름 목록을 표시합니다" + +#: builtin/branch.c:641 +msgid "create the branch's reflog" +msgstr "브랜치의 reflog를 만듭니다" + +#: builtin/branch.c:643 +msgid "edit the description for the branch" +msgstr "브랜치의 설명을 편집합니다" + +#: builtin/branch.c:644 +msgid "force creation, move/rename, deletion" +msgstr "강제로 만들고, 옮기거나 이름을 바꾸고, 삭제합니다" + +#: builtin/branch.c:645 +msgid "print only branches that are merged" +msgstr "병합되는 브랜치만 표시합니다" + +#: builtin/branch.c:646 +msgid "print only branches that are not merged" +msgstr "병합되지 않는 브랜치만 표시합니다" + +#: builtin/branch.c:647 +msgid "list branches in columns" +msgstr "목록을 여러 열로 표시합니다" + +#: builtin/branch.c:648 builtin/for-each-ref.c:38 builtin/tag.c:366 +msgid "key" +msgstr "키" + +#: builtin/branch.c:649 builtin/for-each-ref.c:39 builtin/tag.c:367 +msgid "field name to sort on" +msgstr "정렬한 기준이 되는 필드 이름" + +#: builtin/branch.c:651 builtin/for-each-ref.c:41 builtin/notes.c:398 +#: builtin/notes.c:401 builtin/notes.c:561 builtin/notes.c:564 +#: builtin/tag.c:369 +msgid "object" +msgstr "오브젝트" + +#: builtin/branch.c:652 +msgid "print only branches of the object" +msgstr "해당 오브젝트의 브랜치만 표시합니다" + +#: builtin/branch.c:670 +msgid "Failed to resolve HEAD as a valid ref." +msgstr "HEAD를 올바른 레퍼런스로 구해내는데 실패했습니다." + +#: builtin/branch.c:674 builtin/clone.c:697 +msgid "HEAD not found below refs/heads!" +msgstr "레퍼런스/헤드 아래에 HEAD가 없습니다!" + +#: builtin/branch.c:694 +msgid "--column and --verbose are incompatible" +msgstr "--column 및 --verbose 옵션은 호환되지 않습니다" + +#: builtin/branch.c:705 builtin/branch.c:747 +msgid "branch name required" +msgstr "브랜치 이름이 필요합니다" + +#: builtin/branch.c:723 +msgid "Cannot give description to detached HEAD" +msgstr "분리된 HEAD에 대한 설명을 부여할 수 없습니다" + +#: builtin/branch.c:728 +msgid "cannot edit description of more than one branch" +msgstr "여러 브랜치에 대한 설명을 편집할 수 없습니다" + +#: builtin/branch.c:735 +#, c-format +msgid "No commit on branch '%s' yet." +msgstr "아직 '%s' 브랜치에 커밋이 없습니다." + +#: builtin/branch.c:738 +#, c-format +msgid "No branch named '%s'." +msgstr "이름이 '%s'인 브랜치가 없습니다." + +#: builtin/branch.c:753 +msgid "too many branches for a rename operation" +msgstr "이름 바꾸기 작업에 대해 브랜치가 너무 많습니다" + +#: builtin/branch.c:758 +msgid "too many branches to set new upstream" +msgstr "새 업스트림을 설정하는데 브랜치가 너무 많습니다" + +#: builtin/branch.c:762 +#, c-format +msgid "" +"could not set upstream of HEAD to %s when it does not point to any branch." +msgstr "HEAD의 업스트림을 %s(으)로 설정할 수 없습니다. 어떤 브랜치도 가리키지 않습니다." + +#: builtin/branch.c:765 builtin/branch.c:787 builtin/branch.c:808 +#, c-format +msgid "no such branch '%s'" +msgstr "그런 브랜치가 ('%s') 없습니다" + +#: builtin/branch.c:769 +#, c-format +msgid "branch '%s' does not exist" +msgstr "'%s' 브랜치가 없습니다" + +#: builtin/branch.c:781 +msgid "too many branches to unset upstream" +msgstr "업스트림 설정을 해제하는데 브랜치가 너무 많습니다" + +#: builtin/branch.c:785 +msgid "could not unset upstream of HEAD when it does not point to any branch." +msgstr "HEAD의 업스트림 설정을 해제할 수 없습니다. 어떤 브랜치도 가리키지 않습니다." + +#: builtin/branch.c:791 +#, c-format +msgid "Branch '%s' has no upstream information" +msgstr "'%s' 브랜치에 업스트림 정보가 없습니다" + +#: builtin/branch.c:805 +msgid "it does not make sense to create 'HEAD' manually" +msgstr "'HEAD'를 수동으로 만드는 건 앞뒤가 맞지 않습니다" + +#: builtin/branch.c:811 +msgid "-a and -r options to 'git branch' do not make sense with a branch name" +msgstr "'git branch'에 대해 -a 및 -r 옵션은 브랜치 이름과 같이 쓰면 앞뒤가 맞지 않습니다" + +#: builtin/branch.c:814 +#, c-format +msgid "" +"The --set-upstream flag is deprecated and will be removed. Consider using --" +"track or --set-upstream-to\n" +msgstr "--set-upstream 옵션은 더 이상 사용되지 않고 제거될 예정입니다. --track 또는 --set-upstream-to 옵션을 사용해 보십시오\n" + +#: builtin/branch.c:831 +#, c-format +msgid "" +"\n" +"If you wanted to make '%s' track '%s', do this:\n" +"\n" +msgstr "\n'%s'을(를) 만들고 '%s'을(를) 추적하게 하려면, 다음을 하십시오:\n" + +#: builtin/branch.c:832 +#, c-format +msgid " git branch -d %s\n" +msgstr " git branch -d %s\n" + +#: builtin/branch.c:833 +#, c-format +msgid " git branch --set-upstream-to %s\n" +msgstr " git branch --set-upstream-to %s\n" + +#: builtin/bundle.c:51 +#, c-format +msgid "%s is okay\n" +msgstr "%s 정상입니다\n" + +#: builtin/bundle.c:64 +msgid "Need a repository to create a bundle." +msgstr "번들을 만드려면 저장소가 필요합니다." + +#: builtin/bundle.c:68 +msgid "Need a repository to unbundle." +msgstr "번들을 해제하려면 저장소가 필요합니다." + +#: builtin/cat-file.c:428 +msgid "" +"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|" +"<type>|--textconv) <object>" +msgstr "" +"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<종류" +">|--textconv) <오브젝트>" + +#: builtin/cat-file.c:429 +msgid "git cat-file (--batch | --batch-check) [--follow-symlinks]" +msgstr "git cat-file (--batch | --batch-check) [--follow-symlinks]" + +#: builtin/cat-file.c:466 +msgid "<type> can be one of: blob, tree, commit, tag" +msgstr "<종류>는 다음 중 하나가 될 수 있습니다: blob, tree, commit, tag" + +#: builtin/cat-file.c:467 +msgid "show object type" +msgstr "오브젝트 종류를 봅니다" + +#: builtin/cat-file.c:468 +msgid "show object size" +msgstr "오브젝트 크기를 봅니다" + +#: builtin/cat-file.c:470 +msgid "exit with zero when there's no error" +msgstr "오류가 없을 때 0을 리턴하고 끝냅니다" + +#: builtin/cat-file.c:471 +msgid "pretty-print object's content" +msgstr "오브젝트의 내용을 예쁘게 표시합니다" + +#: builtin/cat-file.c:473 +msgid "for blob objects, run textconv on object's content" +msgstr "블롭 오브젝트에 대해서는, 오브젝트의 내용에 대해 textconv를 실행합니다" + +#: builtin/cat-file.c:475 +msgid "allow -s and -t to work with broken/corrupt objects" +msgstr "-s 및 -t 옵션이 손상된 오브젝트에 대해 동작하도록 허용합니다" + +#: builtin/cat-file.c:476 +msgid "buffer --batch output" +msgstr "--batch 출력에 대해 버퍼링합니다" + +#: builtin/cat-file.c:478 +msgid "show info and content of objects fed from the standard input" +msgstr "표준 입력에서 입력된 오브젝트의 정보와 내용을 표시합니다" + +#: builtin/cat-file.c:481 +msgid "show info about objects fed from the standard input" +msgstr "표준 입력에서 입력된 오브젝트의 정보를 표시합니다" + +#: builtin/cat-file.c:484 +msgid "follow in-tree symlinks (used with --batch or --batch-check)" +msgstr "트리 내부의 심볼릭 링크를 따라갑니다 (--batch 또는 --batch-check와 같이 사용)" + +#: builtin/cat-file.c:486 +msgid "show all objects with --batch or --batch-check" +msgstr "--batch 또는 --batch-check에서 모든 오브젝트를 표시합니다" + +#: builtin/check-attr.c:11 +msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..." +msgstr "git check-attr [-a | --all | <속성>...] [--] <경로이름>..." + +#: builtin/check-attr.c:12 +msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]" +msgstr "git check-attr --stdin [-z] [-a | --all | <속성>...]" + +#: builtin/check-attr.c:19 +msgid "report all attributes set on file" +msgstr "파일에 설정된 모든 속성을 표시합니다" + +#: builtin/check-attr.c:20 +msgid "use .gitattributes only from the index" +msgstr "인덱스에서만 .gitattributes를 사용합니다" + +#: builtin/check-attr.c:21 builtin/check-ignore.c:22 builtin/hash-object.c:96 +msgid "read file names from stdin" +msgstr "표준 입력에서 파일 이름을 읽습니다" + +#: builtin/check-attr.c:23 builtin/check-ignore.c:24 +msgid "terminate input and output records by a NUL character" +msgstr "NUL 문자를 기준으로 자료 입력 및 출력을 멈춥니다" + +#: builtin/check-ignore.c:18 builtin/checkout.c:1134 builtin/gc.c:325 +msgid "suppress progress reporting" +msgstr "진행 상황 표시를 하지 않습니다" + +#: builtin/check-ignore.c:26 +msgid "show non-matching input paths" +msgstr "일치하지 않는 입력 경로를 표시합니다" + +#: builtin/check-ignore.c:28 +msgid "ignore index when checking" +msgstr "검사할 때 인덱스를 무시합니다" + +#: builtin/check-ignore.c:154 +msgid "cannot specify pathnames with --stdin" +msgstr "--stdin으로 경로 이름을 지정할 수 없습니다" + +#: builtin/check-ignore.c:157 +msgid "-z only makes sense with --stdin" +msgstr "-z 옵션은 --stdin 옵션과 같이 써야만 의미가 있습니다" + +#: builtin/check-ignore.c:159 +msgid "no path specified" +msgstr "경로를 지정하지 않았습니다" + +#: builtin/check-ignore.c:163 +msgid "--quiet is only valid with a single pathname" +msgstr "--quiet 옵션은 하나의 경로 이름과 같이 써야 합니다" + +#: builtin/check-ignore.c:165 +msgid "cannot have both --quiet and --verbose" +msgstr "--quiet 및 --verbose 옵션을 같이 쓸 수 없습니다" + +#: builtin/check-ignore.c:168 +msgid "--non-matching is only valid with --verbose" +msgstr "--non-matching 옵션은 --verbose 옵션과 같이 써야 합니다" + +#: builtin/check-mailmap.c:8 +msgid "git check-mailmap [<options>] <contact>..." +msgstr "git check-mailmap [<옵션>] <연락처>..." + +#: builtin/check-mailmap.c:13 +msgid "also read contacts from stdin" +msgstr "또 연락처를 표준 입력에서 읽습니다" + +#: builtin/check-mailmap.c:24 +#, c-format +msgid "unable to parse contact: %s" +msgstr "연락처를 파싱할 수 없습니다: %s" + +#: builtin/check-mailmap.c:47 +msgid "no contacts specified" +msgstr "연락처를 지정하지 않았습니다" + +#: builtin/checkout-index.c:126 +msgid "git checkout-index [<options>] [--] [<file>...]" +msgstr "git checkout-index [<옵션>] [--] [<파일>...]" + +#: builtin/checkout-index.c:188 +msgid "check out all files in the index" +msgstr "인덱스의 모든 파일을 가져옵니다" + +#: builtin/checkout-index.c:189 +msgid "force overwrite of existing files" +msgstr "기존 파일을 강제로 덮어 씁니다" + +#: builtin/checkout-index.c:191 +msgid "no warning for existing files and files not in index" +msgstr "기존 파일과 인덱스에 없는 파일에 대해 경고하지 않습니다" + +#: builtin/checkout-index.c:193 +msgid "don't checkout new files" +msgstr "새 파일을 가져오지 않습니다" + +#: builtin/checkout-index.c:195 +msgid "update stat information in the index file" +msgstr "인덱스 파일의 stat 정보를 업데이트합니다" + +#: builtin/checkout-index.c:201 +msgid "read list of paths from the standard input" +msgstr "표준 입력에서 경로의 목록을 읽습니다" + +#: builtin/checkout-index.c:203 +msgid "write the content to temporary files" +msgstr "내용을 임시 파일에 씁니다" + +#: builtin/checkout-index.c:204 builtin/column.c:30 +#: builtin/submodule--helper.c:172 builtin/submodule--helper.c:175 +#: builtin/submodule--helper.c:178 builtin/submodule--helper.c:181 +msgid "string" +msgstr "문자열" + +#: builtin/checkout-index.c:205 +msgid "when creating files, prepend <string>" +msgstr "파일을 만들 때, 앞에 <문자열>을 붙입니다" + +#: builtin/checkout-index.c:208 +msgid "copy out the files from named stage" +msgstr "지정한 스테이지에서 파일을 복사해 옵니다" + +#: builtin/checkout.c:25 +msgid "git checkout [<options>] <branch>" +msgstr "git checkout [<옵션>] <브랜치>" + +#: builtin/checkout.c:26 +msgid "git checkout [<options>] [<branch>] -- <file>..." +msgstr "git checkout [<옵션>] [<브랜치>] -- <파일>..." + +#: builtin/checkout.c:134 builtin/checkout.c:167 +#, c-format +msgid "path '%s' does not have our version" +msgstr "'%s' 경로에 우리쪽 버전이 없습니다" + +#: builtin/checkout.c:136 builtin/checkout.c:169 +#, c-format +msgid "path '%s' does not have their version" +msgstr "'%s' 경로에 상대편 버전이 없습니다" + +#: builtin/checkout.c:152 +#, c-format +msgid "path '%s' does not have all necessary versions" +msgstr "'%s' 경로에 필요한 모든 버전이 없습니다" + +#: builtin/checkout.c:196 +#, c-format +msgid "path '%s' does not have necessary versions" +msgstr "'%s' 경로에 필요한 버전이 없습니다" + +#: builtin/checkout.c:213 +#, c-format +msgid "path '%s': cannot merge" +msgstr "'%s' 경로: 병합할 수 없습니다" + +#: builtin/checkout.c:230 +#, c-format +msgid "Unable to add merge result for '%s'" +msgstr "'%s'에 대한 병합 결과를 추가할 수 없습니다" + +#: builtin/checkout.c:251 builtin/checkout.c:254 builtin/checkout.c:257 +#: builtin/checkout.c:260 +#, c-format +msgid "'%s' cannot be used with updating paths" +msgstr "'%s' 옵션은 업데이트하는 경로에서 쓸 수 없습니다" + +#: builtin/checkout.c:263 builtin/checkout.c:266 +#, c-format +msgid "'%s' cannot be used with %s" +msgstr "'%s' 옵션은 %s 옵션과 같이 쓸 수 없습니다" + +#: builtin/checkout.c:269 +#, c-format +msgid "Cannot update paths and switch to branch '%s' at the same time." +msgstr "경로를 업데이트하고 '%s' 브랜치로 전환하는 일은 동시에 할 수 없습니다." + +#: builtin/checkout.c:280 builtin/checkout.c:474 +msgid "corrupt index file" +msgstr "손상된 인덱스 파일" + +#: builtin/checkout.c:340 builtin/checkout.c:347 +#, c-format +msgid "path '%s' is unmerged" +msgstr "'%s' 경로를 병합하지 않았습니다" + +#: builtin/checkout.c:496 +msgid "you need to resolve your current index first" +msgstr "현재 인덱스를 먼저 해결해야 합니다" + +#: builtin/checkout.c:623 +#, c-format +msgid "Can not do reflog for '%s': %s\n" +msgstr "'%s'에 대해 reflog할 수 없습니다: %s\n" + +#: builtin/checkout.c:661 +msgid "HEAD is now at" +msgstr "HEAD의 현재 위치는" + +#: builtin/checkout.c:668 +#, c-format +msgid "Reset branch '%s'\n" +msgstr "'%s' 브랜치 리셋\n" + +#: builtin/checkout.c:671 +#, c-format +msgid "Already on '%s'\n" +msgstr "이미 '%s'에 있습니다\n" + +#: builtin/checkout.c:675 +#, c-format +msgid "Switched to and reset branch '%s'\n" +msgstr "'%s' 브랜치로 전환하고 리셋합니다\n" + +#: builtin/checkout.c:677 builtin/checkout.c:1066 +#, c-format +msgid "Switched to a new branch '%s'\n" +msgstr "새로 만든 '%s' 브랜치로 전환합니다\n" + +#: builtin/checkout.c:679 +#, c-format +msgid "Switched to branch '%s'\n" +msgstr "'%s' 브랜치로 전환합니다\n" + +#: builtin/checkout.c:731 +#, c-format +msgid " ... and %d more.\n" +msgstr " ... 그리고 %d개 더.\n" + +#: builtin/checkout.c:737 +#, c-format +msgid "" +"Warning: you are leaving %d commit behind, not connected to\n" +"any of your branches:\n" +"\n" +"%s\n" +msgid_plural "" +"Warning: you are leaving %d commits behind, not connected to\n" +"any of your branches:\n" +"\n" +"%s\n" +msgstr[0] "" +"경고: 브랜치 중에 아무것에도 연결되지 않은 커밋이 뒤에\n" +"%d개 있습니다:\n" +"\n" +"%s\n" + +#: builtin/checkout.c:756 +#, c-format +msgid "" +"If you want to keep it by creating a new branch, this may be a good time\n" +"to do so with:\n" +"\n" +" git branch <new-branch-name> %s\n" +"\n" +msgid_plural "" +"If you want to keep them by creating a new branch, this may be a good time\n" +"to do so with:\n" +"\n" +" git branch <new-branch-name> %s\n" +"\n" +msgstr[0] "" +"새 브랜치를 만들어서 이 커밋을 저장하고 싶으면, 지금 다음과\n" +"같이 할 수 있습니다:\n" +"\n" +" git branch <새-브랜치-이름> %s\n" +"\n" + +#: builtin/checkout.c:792 +msgid "internal error in revision walk" +msgstr "리비전 walk에 내부 오류" + +#: builtin/checkout.c:796 +msgid "Previous HEAD position was" +msgstr "이전 HEAD 위치는" + +#: builtin/checkout.c:823 builtin/checkout.c:1061 +msgid "You are on a branch yet to be born" +msgstr "현재 위치가 만들 예정인 브랜치에 있습니다" + +#: builtin/checkout.c:968 +#, c-format +msgid "only one reference expected, %d given." +msgstr "하나의 레퍼런스만 지정해야 하지만 %d개를 지정했습니다." + +#: builtin/checkout.c:1007 builtin/worktree.c:213 +#, c-format +msgid "invalid reference: %s" +msgstr "잘못된 레퍼런스: %s" + +#: builtin/checkout.c:1036 +#, c-format +msgid "reference is not a tree: %s" +msgstr "레퍼런스가 트리가 아닙니다: %s" + +#: builtin/checkout.c:1075 +msgid "paths cannot be used with switching branches" +msgstr "브랜치를 전환하는데 경로를 사용할 수 없습니다" + +#: builtin/checkout.c:1078 builtin/checkout.c:1082 +#, c-format +msgid "'%s' cannot be used with switching branches" +msgstr "'%s' 옵션은 브랜치를 전환할 때 쓸 수 없습니다" + +#: builtin/checkout.c:1086 builtin/checkout.c:1089 builtin/checkout.c:1094 +#: builtin/checkout.c:1097 +#, c-format +msgid "'%s' cannot be used with '%s'" +msgstr "'%s' 옵션은 '%s' 옵션과 같이 쓸 수 없습니다" + +#: builtin/checkout.c:1102 +#, c-format +msgid "Cannot switch branch to a non-commit '%s'" +msgstr "브랜치를 커밋이 아닌 '%s'(으)로 전환할 수 없습니다" + +#: builtin/checkout.c:1135 builtin/checkout.c:1137 builtin/clone.c:83 +#: builtin/remote.c:165 builtin/remote.c:167 builtin/worktree.c:320 +#: builtin/worktree.c:322 +msgid "branch" +msgstr "브랜치" + +#: builtin/checkout.c:1136 +msgid "create and checkout a new branch" +msgstr "새 브랜치를 만들고 가져옵니다" + +#: builtin/checkout.c:1138 +msgid "create/reset and checkout a branch" +msgstr "브랜치를 만들거나 리셋하고 가져옵니다" + +#: builtin/checkout.c:1139 +msgid "create reflog for new branch" +msgstr "새 브랜치에 대한 reflog를 만듭니다" + +#: builtin/checkout.c:1140 +msgid "detach the HEAD at named commit" +msgstr "지정한 커밋에서 HEAD를 분리합니다" + +#: builtin/checkout.c:1141 +msgid "set upstream info for new branch" +msgstr "새 브랜치에 대한 업스트림 정보를 설정합니다" + +#: builtin/checkout.c:1143 +msgid "new-branch" +msgstr "새-브랜치" + +#: builtin/checkout.c:1143 +msgid "new unparented branch" +msgstr "상위 브랜치가 없는 새 브랜치" + +#: builtin/checkout.c:1144 +msgid "checkout our version for unmerged files" +msgstr "병합되지 않은 파일에 대해 우리쪽 버전을 가져옵니다" + +#: builtin/checkout.c:1146 +msgid "checkout their version for unmerged files" +msgstr "병합되지 않은 파일에 대해 상대편 버전을 가져옵니다" + +#: builtin/checkout.c:1148 +msgid "force checkout (throw away local modifications)" +msgstr "강제로 체크아웃합니다 (로컬에서 수정한 사항을 버립니다)" + +#: builtin/checkout.c:1149 +msgid "perform a 3-way merge with the new branch" +msgstr "새 브랜치에 대해 3-방향 병합을 수행합니다" + +#: builtin/checkout.c:1150 builtin/merge.c:227 +msgid "update ignored files (default)" +msgstr "무시하는 파일을 업데이트합니다 (기본값)" + +#: builtin/checkout.c:1151 builtin/log.c:1266 parse-options.h:250 +msgid "style" +msgstr "스타일" + +#: builtin/checkout.c:1152 +msgid "conflict style (merge or diff3)" +msgstr "충돌 스타일 (merge 또는 diff3)" + +# FIXME: 의미 불명 +#: builtin/checkout.c:1155 +msgid "do not limit pathspecs to sparse entries only" +msgstr "경로명세를 드문 항목에만 제한하지 않습니다" + +#: builtin/checkout.c:1157 +msgid "second guess 'git checkout <no-such-branch>'" +msgstr "'git checkout <없는-브랜치>'에 대해 추측합니다" + +#: builtin/checkout.c:1159 +msgid "do not check if another worktree is holding the given ref" +msgstr "다른 작업폴더에 주어진 레퍼런스가 있는지 확인하지 않습니다" + +#: builtin/checkout.c:1160 builtin/clone.c:57 builtin/fetch.c:112 +#: builtin/merge.c:224 builtin/pull.c:109 builtin/push.c:558 +#: builtin/send-pack.c:168 +msgid "force progress reporting" +msgstr "강제로 진행 상황을 표시합니다" + +#: builtin/checkout.c:1191 +msgid "-b, -B and --orphan are mutually exclusive" +msgstr "-b, -B 및 --orphan 옵션은 서로 호환되지 않습니다" + +#: builtin/checkout.c:1208 +msgid "--track needs a branch name" +msgstr "--track 옵션은 브랜치 이름이 필요합니다" + +#: builtin/checkout.c:1213 +msgid "Missing branch name; try -b" +msgstr "브랜치 이름이 없습니다. -b 옵션을 사용해 보십시오" + +#: builtin/checkout.c:1249 +msgid "invalid path specification" +msgstr "경로 명세가 잘못되었습니다" + +#: builtin/checkout.c:1256 +#, c-format +msgid "" +"Cannot update paths and switch to branch '%s' at the same time.\n" +"Did you intend to checkout '%s' which can not be resolved as commit?" +msgstr "" +"동시에 경로를 업데이트하고 '%s' 브랜치로 전환할 수 없습니다.\n" +"커밋을 확인할 수 없는 '%s'을(를) 가져오려고 하셨습니까?" + +#: builtin/checkout.c:1261 +#, c-format +msgid "git checkout: --detach does not take a path argument '%s'" +msgstr "git checkout: --detach 옵션은 경로 인자를 받지 않습니다 '%s'" + +#: builtin/checkout.c:1265 +msgid "" +"git checkout: --ours/--theirs, --force and --merge are incompatible when\n" +"checking out of the index." +msgstr "" +"git checkout: --ours/--theirs, --force 및 --merge 옵션은 인덱스에서\n" +"가져올 경우에는 서로 호환되지 않습니다." + +#: builtin/clean.c:25 +msgid "" +"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..." +msgstr "" +"git clean [-d] [-f] [-i] [-n] [-q] [-e <패턴>] [-x | -X] [--] <경로>..." + +#: builtin/clean.c:29 +#, c-format +msgid "Removing %s\n" +msgstr "%s 제거\n" + +#: builtin/clean.c:30 +#, c-format +msgid "Would remove %s\n" +msgstr "%s 제거할 예정\n" + +#: builtin/clean.c:31 +#, c-format +msgid "Skipping repository %s\n" +msgstr "%s 저장소 건너뜀\n" + +#: builtin/clean.c:32 +#, c-format +msgid "Would skip repository %s\n" +msgstr "%s 저장소 건너뛸 예정\n" + +#: builtin/clean.c:33 +#, c-format +msgid "failed to remove %s" +msgstr "%s 제거에 실패했습니다" + +#: builtin/clean.c:315 +msgid "" +"Prompt help:\n" +"1 - select a numbered item\n" +"foo - select item based on unique prefix\n" +" - (empty) select nothing" +msgstr "" +"프롬프트 도움말:\n" +"1 - 해당 번호의 항목을 선택\n" +"foo - 유일한 접두어에 해당하는 항목 선택\n" +" - (빈 입력) 선택하지 않음" + +#: builtin/clean.c:319 +msgid "" +"Prompt help:\n" +"1 - select a single item\n" +"3-5 - select a range of items\n" +"2-3,6-9 - select multiple ranges\n" +"foo - select item based on unique prefix\n" +"-... - unselect specified items\n" +"* - choose all items\n" +" - (empty) finish selecting" +msgstr "" +"프롬프트 도움말:\n" +"1 - 해당 번호의 항목을 선택\n" +"3-5 - 해당 범위의 항목을 선택\n" +"2-3,6-9 - 여러 개 범위를 선택\n" +"foo - 유일한 접두어에 해당하는 항목 선택\n" +"-... - 해당 항목 선택 해제\n" +"* - 모든 항목 선택\n" +" - (빈 입력) 선택 마침" + +#: builtin/clean.c:535 +#, c-format +msgid "Huh (%s)?" +msgstr "어라라 (%s)?" + +#: builtin/clean.c:677 +#, c-format +msgid "Input ignore patterns>> " +msgstr "무시할 패턴을 입력하십시오>> " + +#: builtin/clean.c:714 +#, c-format +msgid "WARNING: Cannot find items matched by: %s" +msgstr "경고: 다음에 해당하는 항목을 찾을 수 없습니다: %s" + +#: builtin/clean.c:735 +msgid "Select items to delete" +msgstr "삭제할 항목을 선택하십시오" + +#. TRANSLATORS: Make sure to keep [y/N] as is +#: builtin/clean.c:776 +#, c-format +msgid "Remove %s [y/N]? " +msgstr "%s 제거합니까 [y/N]? " + +#: builtin/clean.c:801 +msgid "Bye." +msgstr "끝." + +#: builtin/clean.c:809 +msgid "" +"clean - start cleaning\n" +"filter by pattern - exclude items from deletion\n" +"select by numbers - select items to be deleted by numbers\n" +"ask each - confirm each deletion (like \"rm -i\")\n" +"quit - stop cleaning\n" +"help - this screen\n" +"? - help for prompt selection" +msgstr "" +"clean - 지우기 시작\n" +"filter by pattern - exclude items from deletion\n" +"select by numbers - 삭제할 항목을 번호로 선택\n" +"ask each - 삭제 항목을 (\"rm -i\" 처럼) 하나하나 확인\n" +"quit - 지우기 중지\n" +"help - 이 화면 표시\n" +"? - 프롬프트 선택 도움말" + +#: builtin/clean.c:836 +msgid "*** Commands ***" +msgstr "*** 명령 ***" + +#: builtin/clean.c:837 +msgid "What now" +msgstr "무엇을 할까요" + +#: builtin/clean.c:845 +msgid "Would remove the following item:" +msgid_plural "Would remove the following items:" +msgstr[0] "다음 항목을 제거할 예정입니다:" + +#: builtin/clean.c:862 +msgid "No more files to clean, exiting." +msgstr "지울 파일이 이제 없으므로 끝냅니다." + +#: builtin/clean.c:893 +msgid "do not print names of files removed" +msgstr "제거할 파일 이름을 표시하지 않습니다" + +#: builtin/clean.c:895 +msgid "force" +msgstr "강제" + +#: builtin/clean.c:896 +msgid "interactive cleaning" +msgstr "대화형 지우기" + +#: builtin/clean.c:898 +msgid "remove whole directories" +msgstr "전체 디렉터리 제거" + +#: builtin/clean.c:899 builtin/describe.c:407 builtin/grep.c:709 +#: builtin/ls-files.c:443 builtin/name-rev.c:307 builtin/show-ref.c:182 +msgid "pattern" +msgstr "패턴" + +#: builtin/clean.c:900 +msgid "add <pattern> to ignore rules" +msgstr "규칙을 무시하려면 <패턴>을 추가하십시오" + +#: builtin/clean.c:901 +msgid "remove ignored files, too" +msgstr "무시한 파일도 제거" + +#: builtin/clean.c:903 +msgid "remove only ignored files" +msgstr "무시한 파일만 제거" + +#: builtin/clean.c:921 +msgid "-x and -X cannot be used together" +msgstr "-x 및 -X 옵션은 같이 쓸 수 없습니다" + +#: builtin/clean.c:925 +msgid "" +"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to " +"clean" +msgstr "clean.requireForce가 true로 설정되었고 -i, -n, -f 옵션 중 하나도 쓰지 않았습니다. 지우지 않습니다" + +#: builtin/clean.c:928 +msgid "" +"clean.requireForce defaults to true and neither -i, -n, nor -f given; " +"refusing to clean" +msgstr "clean.requireForce 기본값이 true이고 -i, -n, -f 옵션 중 하나도 쓰지 않았습니다. 지우지 않습니다" + +#: builtin/clone.c:37 +msgid "git clone [<options>] [--] <repo> [<dir>]" +msgstr "git clone [<옵션>] [--] <저장소> [<디렉터리>]" + +#: builtin/clone.c:59 +msgid "don't create a checkout" +msgstr "체크아웃을 만들지 않습니다" + +#: builtin/clone.c:60 builtin/clone.c:62 builtin/init-db.c:469 +msgid "create a bare repository" +msgstr "간략한 저장소를 만듭니다" + +#: builtin/clone.c:64 +msgid "create a mirror repository (implies bare)" +msgstr "미러 저장소를 만듭니다 (간략한 저장소로 취급)" + +#: builtin/clone.c:66 +msgid "to clone from a local repository" +msgstr "로컬 저장소에서 복제합니다" + +#: builtin/clone.c:68 +msgid "don't use local hardlinks, always copy" +msgstr "로컬 하드링크를 사용하지 않고, 항상 복사합니다" + +#: builtin/clone.c:70 +msgid "setup as shared repository" +msgstr "공유 저장소로 설정합니다" + +#: builtin/clone.c:72 builtin/clone.c:74 +msgid "initialize submodules in the clone" +msgstr "복제한 결과물에서 하위 모듈을 초기화합니다" + +#: builtin/clone.c:75 builtin/init-db.c:466 +msgid "template-directory" +msgstr "서식-디렉터리" + +#: builtin/clone.c:76 builtin/init-db.c:467 +msgid "directory from which templates will be used" +msgstr "서식을 사용할 디렉터리 위치" + +#: builtin/clone.c:78 builtin/submodule--helper.c:179 +msgid "reference repository" +msgstr "레퍼런스 저장소" + +#: builtin/clone.c:80 +msgid "use --reference only while cloning" +msgstr "복제할 경우에만 --reference를 사용합니다" + +#: builtin/clone.c:81 builtin/column.c:26 builtin/merge-file.c:44 +msgid "name" +msgstr "이름" + +#: builtin/clone.c:82 +msgid "use <name> instead of 'origin' to track upstream" +msgstr "업스트림 추적에 'origin' 대신 <이름>을 사용합니다" + +#: builtin/clone.c:84 +msgid "checkout <branch> instead of the remote's HEAD" +msgstr "리모트의 HEAD 대신 <브랜치>를 가져옵니다" + +#: builtin/clone.c:86 +msgid "path to git-upload-pack on the remote" +msgstr "리모트의 git-upload-pack 경로" + +#: builtin/clone.c:87 builtin/fetch.c:113 builtin/grep.c:654 builtin/pull.c:186 +msgid "depth" +msgstr "깊이" + +#: builtin/clone.c:88 +msgid "create a shallow clone of that depth" +msgstr "지정한 깊이의 얕은 복제를 만듭니다" + +#: builtin/clone.c:90 +msgid "clone only one branch, HEAD or --branch" +msgstr "하나의 브랜치만 복제합니다 (HEAD 또는 --branch로 지정)" + +#: builtin/clone.c:91 builtin/init-db.c:475 +msgid "gitdir" +msgstr "gitdir" + +#: builtin/clone.c:92 builtin/init-db.c:476 +msgid "separate git dir from working tree" +msgstr "깃 디렉터리를 작업 폴더와 별개의 위치에 놓습니다" + +#: builtin/clone.c:93 +msgid "key=value" +msgstr "키=값" + +#: builtin/clone.c:94 +msgid "set config inside the new repository" +msgstr "새 저장소 안에서 설정합니다" + +#: builtin/clone.c:300 +#, c-format +msgid "reference repository '%s' as a linked checkout is not supported yet." +msgstr "레퍼런스 '%s' 저장소를 연결된 체크아웃으로 쓰기는 아직 지원하지 않습니다." + +#: builtin/clone.c:302 +#, c-format +msgid "reference repository '%s' is not a local repository." +msgstr "레퍼런스 '%s' 저장소가 로컬 저장소가 아닙니다." + +#: builtin/clone.c:307 +#, c-format +msgid "reference repository '%s' is shallow" +msgstr "레퍼런스 '%s' 저장소가 얕은 저장소입니다" + +#: builtin/clone.c:310 +#, c-format +msgid "reference repository '%s' is grafted" +msgstr "레퍼런스 '%s' 저장소가 붙어 있는 저장소입니다" + +#: builtin/clone.c:375 builtin/diff.c:84 +#, c-format +msgid "failed to stat '%s'" +msgstr "'%s'에 대해 stat()이 실패했습니다" + +#: builtin/clone.c:377 +#, c-format +msgid "%s exists and is not a directory" +msgstr "'%s'이(가) 있지만 디렉터리가 아닙니다" + +#: builtin/clone.c:391 +#, c-format +msgid "failed to stat %s\n" +msgstr "'%s'에 대해 stat()이 실패했습니다\n" + +#: builtin/clone.c:413 +#, c-format +msgid "failed to create link '%s'" +msgstr "'%s' 링크를 만드는데 실패했습니다" + +#: builtin/clone.c:417 +#, c-format +msgid "failed to copy file to '%s'" +msgstr "파일을 '%s'(으)로 복사하는데 실패했습니다" + +#: builtin/clone.c:442 builtin/clone.c:626 +#, c-format +msgid "done.\n" +msgstr "완료.\n" + +#: builtin/clone.c:454 +msgid "" +"Clone succeeded, but checkout failed.\n" +"You can inspect what was checked out with 'git status'\n" +"and retry the checkout with 'git checkout -f HEAD'\n" +msgstr "" +"복제가 성공했지만, 체크아웃이 실패했습니다.\n" +"'git status' 명령으로 무엇을 체크아웃했는지 살펴볼 수 있고\n" +"'git checkout -f HEAD'로 체크아웃을 다시 할 수 있습니다\n" + +#: builtin/clone.c:531 +#, c-format +msgid "Could not find remote branch %s to clone." +msgstr "복제할 리모트의 %s 브랜치를 찾을 수 없습니다." + +#: builtin/clone.c:621 +#, c-format +msgid "Checking connectivity... " +msgstr "연결을 확인하는 중입니다..." + +#: builtin/clone.c:624 +msgid "remote did not send all necessary objects" +msgstr "리모트에서 필요한 오브젝트를 모두 보내지 않았습니다" + +#: builtin/clone.c:688 +msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" +msgstr "리모트 HEAD가 없는 레퍼런스를 참고하므로, 체크아웃할 수 없습니다.\n" + +#: builtin/clone.c:719 +msgid "unable to checkout working tree" +msgstr "작업 폴더를 체크아웃할 수 없습니다" + +#: builtin/clone.c:808 +msgid "cannot repack to clean up" +msgstr "정리용으로 repack할 수 없습니다" + +#: builtin/clone.c:810 +msgid "cannot unlink temporary alternates file" +msgstr "보조 임시 파일을 삭제할 수 없습니다" + +#: builtin/clone.c:842 +msgid "Too many arguments." +msgstr "너무 인자가 많습니다." + +#: builtin/clone.c:846 +msgid "You must specify a repository to clone." +msgstr "복제할 저장소를 지정해야 합니다." + +#: builtin/clone.c:857 +#, c-format +msgid "--bare and --origin %s options are incompatible." +msgstr "--bare 및 --origin %s 옵션은 호환되지 않습니다." + +#: builtin/clone.c:860 +msgid "--bare and --separate-git-dir are incompatible." +msgstr "--bare 및 --separate-git-dir 옵션은 호환되지 않습니다." + +#: builtin/clone.c:873 +#, c-format +msgid "repository '%s' does not exist" +msgstr "'%s' 저장소가 없습니다" + +#: builtin/clone.c:879 builtin/fetch.c:1166 +#, c-format +msgid "depth %s is not a positive number" +msgstr "깊이가(%s) 0보다 큰 수가 아닙니다" + +#: builtin/clone.c:889 +#, c-format +msgid "destination path '%s' already exists and is not an empty directory." +msgstr "대상 경로가('%s') 이미 있고 빈 디렉터리가 아닙니다." + +#: builtin/clone.c:899 +#, c-format +msgid "working tree '%s' already exists." +msgstr "작업 폴더가('%s') 이미 있습니다." + +#: builtin/clone.c:914 builtin/clone.c:925 builtin/submodule--helper.c:224 +#: builtin/worktree.c:221 builtin/worktree.c:248 +#, c-format +msgid "could not create leading directories of '%s'" +msgstr "'%s'의 앞 디렉터리를 만들 수 없습니다" + +#: builtin/clone.c:917 +#, c-format +msgid "could not create work tree dir '%s'" +msgstr "작업 디렉터리를('%s') 만들 수 없습니다" + +#: builtin/clone.c:935 +#, c-format +msgid "Cloning into bare repository '%s'...\n" +msgstr "간략한 저장소로('%s') 복제합니다...\n" + +#: builtin/clone.c:937 +#, c-format +msgid "Cloning into '%s'...\n" +msgstr "'%s'에 복제합니다...\n" + +#: builtin/clone.c:975 +msgid "--depth is ignored in local clones; use file:// instead." +msgstr "--depth 옵션은 로컬 복제에서 무시됩니다. 대신에 'file://'을 사용하십시오." + +#: builtin/clone.c:978 +msgid "source repository is shallow, ignoring --local" +msgstr "원본 저장소가 얕은 저장소이므로, --local 옵션을 무시합니다" + +#: builtin/clone.c:983 +msgid "--local is ignored" +msgstr "--local 옵션은 무시됩니다" + +#: builtin/clone.c:987 +#, c-format +msgid "Don't know how to clone %s" +msgstr "%s의 복제 방법을 알지 못합니다" + +#: builtin/clone.c:1036 builtin/clone.c:1044 +#, c-format +msgid "Remote branch %s not found in upstream %s" +msgstr "리모트의 %s 브랜치가 업스트림 %s에 없습니다" + +#: builtin/clone.c:1047 +msgid "You appear to have cloned an empty repository." +msgstr "빈 저장소를 복제한 것처럼 보입니다." + +#: builtin/column.c:9 +msgid "git column [<options>]" +msgstr "git column [<옵션>]" + +#: builtin/column.c:26 +msgid "lookup config vars" +msgstr "설정 변수를 찾아 봅니다" + +#: builtin/column.c:27 builtin/column.c:28 +msgid "layout to use" +msgstr "사용할 배치" + +#: builtin/column.c:29 +msgid "Maximum width" +msgstr "최대 너비" + +#: builtin/column.c:30 +msgid "Padding space on left border" +msgstr "왼쪽 가장자리에 채울 공백" + +#: builtin/column.c:31 +msgid "Padding space on right border" +msgstr "오른쪽 가장자리에 채울 공백" + +#: builtin/column.c:32 +msgid "Padding space between columns" +msgstr "열 사이에 채울 공백" + +#: builtin/column.c:51 +msgid "--command must be the first argument" +msgstr "--command는 첫 번째 인자여야 합니다" + +#: builtin/commit.c:38 +msgid "git commit [<options>] [--] <pathspec>..." +msgstr "git commit [<옵션>] [--] <경로명세>..." + +#: builtin/commit.c:43 +msgid "git status [<options>] [--] <pathspec>..." +msgstr "git status [<옵션>] [--] <경로명세>..." + +#: builtin/commit.c:48 +msgid "" +"Your name and email address were configured automatically based\n" +"on your username and hostname. Please check that they are accurate.\n" +"You can suppress this message by setting them explicitly. Run the\n" +"following command and follow the instructions in your editor to edit\n" +"your configuration file:\n" +"\n" +" git config --global --edit\n" +"\n" +"After doing this, you may fix the identity used for this commit with:\n" +"\n" +" git commit --amend --reset-author\n" +msgstr "" +"이름과 전자메일 주소를 사용자 이름과 호스트 이름을 이용해서 자동으로\n" +"설정했습니다. 이 정보가 맞는지 확인하십시오. 이 메시지를 보지 않으려면 정보" +"를\n" +"명시적으로 설정하십시오. 다음 명령어를 실행하고 편집기의 안내에 따라 설정\n" +"파일을 편집하십시오:\n" +"\n" +" git config --global --edit\n" +"\n" +"이렇게 한 다음, 이 커밋에 사용한 신원 정보를 다음과 같이 해서 바꿀 수 있습니" +"다:\n" +"\n" +" git commit --amend --reset-author\n" + +#: builtin/commit.c:61 +msgid "" +"Your name and email address were configured automatically based\n" +"on your username and hostname. Please check that they are accurate.\n" +"You can suppress this message by setting them explicitly:\n" +"\n" +" git config --global user.name \"Your Name\"\n" +" git config --global user.email you@example.com\n" +"\n" +"After doing this, you may fix the identity used for this commit with:\n" +"\n" +" git commit --amend --reset-author\n" +msgstr "" +"이름과 전자메일 주소를 사용자 이름과 호스트 이름을 이용해서\n" +"자동으로 설정했습니다. 이 정보가 맞는지 확인하십시오. 이 메시지를\n" +"보지 않으려면 정보를 명시적으로 설정하십시오:\n" +"\n" +" git config --global user.name \"내 이름\"\n" +" git config --global user.email you@example.com\n" +"\n" +"이렇게 한 다음, 이 커밋에 사용한 신원 정보를 다음과 같이 해서 바꿀 수 있습니" +"다:\n" +"\n" +" git commit --amend --reset-author\n" + +#: builtin/commit.c:73 +msgid "" +"You asked to amend the most recent commit, but doing so would make\n" +"it empty. You can repeat your command with --allow-empty, or you can\n" +"remove the commit entirely with \"git reset HEAD^\".\n" +msgstr "" +"최초의 커밋을 바꾸려고 하지만, 그렇게 하면 커밋이 비어 있게 됩니다.\n" +"--allow-empty 옵션과 같이 이 명령을 반복할 수도 있고, \"git reset HEAD\"\n" +"명령으로 커밋을 완전히 제거할 수도 있습니다.\n" + +#: builtin/commit.c:78 +msgid "" +"The previous cherry-pick is now empty, possibly due to conflict resolution.\n" +"If you wish to commit it anyway, use:\n" +"\n" +" git commit --allow-empty\n" +"\n" +msgstr "" +"이전 커맷 빼오기가 비어 있습니다. 아마도 충돌 해결 과정에서 그렇게 됐을\n" +"것입니다. 그래도 커밋하려면 다음과 같이 하십시오:\n" +"\n" +" git commit --allow-empty\n" +"\n" + +#: builtin/commit.c:85 +msgid "Otherwise, please use 'git reset'\n" +msgstr "아니면 'git reset'을 사용하십시오\n" + +#: builtin/commit.c:88 +msgid "" +"If you wish to skip this commit, use:\n" +"\n" +" git reset\n" +"\n" +"Then \"git cherry-pick --continue\" will resume cherry-picking\n" +"the remaining commits.\n" +msgstr "" +"이 커밋을 건너뛰려면, 다음을 사용하십시오:\n" +"\n" +" git reset\n" +"\n" +"그 다음에 \"git cherry-pick --continue\"를 하면 나머지 커밋에\n" +"대해 커밋 빼오기를 다시 시작합니다.\n" + +#: builtin/commit.c:305 +msgid "failed to unpack HEAD tree object" +msgstr "HEAD 트리 오브젝트의 묶음을 푸는데 실패했습니다" + +#: builtin/commit.c:346 +msgid "unable to create temporary index" +msgstr "임시 인덱스를 만들 수 없습니다" + +#: builtin/commit.c:352 +msgid "interactive add failed" +msgstr "대화형 추가가 실패했습니다" + +#: builtin/commit.c:365 +msgid "unable to update temporary index" +msgstr "임시 인덱스를 업데이트할 수 없습니다" + +#: builtin/commit.c:367 +msgid "Failed to update main cache tree" +msgstr "주요 캐시 트리를 업데이트하는데 실패했습니다" + +#: builtin/commit.c:391 builtin/commit.c:414 builtin/commit.c:463 +msgid "unable to write new_index file" +msgstr "new_index 파일에 쓸 수 없습니다" + +#: builtin/commit.c:445 +msgid "cannot do a partial commit during a merge." +msgstr "병합하는 중 부분 커밋을 할 수 없습니다." + +#: builtin/commit.c:447 +msgid "cannot do a partial commit during a cherry-pick." +msgstr "커밋 빼오기를 하는 중 부분 커밋을 할 수 없습니다." + +#: builtin/commit.c:456 +msgid "cannot read the index" +msgstr "인덱스를 읽을 수 없습니다" + +#: builtin/commit.c:475 +msgid "unable to write temporary index file" +msgstr "임시 인덱스 파일을 쓸 수 없습니다" + +#: builtin/commit.c:580 +#, c-format +msgid "commit '%s' lacks author header" +msgstr "'%s' 커밋에 작성자 헤더가 없습니다" + +#: builtin/commit.c:582 +#, c-format +msgid "commit '%s' has malformed author line" +msgstr "'%s' 커밋의 작성자 헤더 형식이 잘못되었습니다" + +#: builtin/commit.c:601 +msgid "malformed --author parameter" +msgstr "--author 파라미터 형식이 잘못되었습니다" + +#: builtin/commit.c:609 +#, c-format +msgid "invalid date format: %s" +msgstr "시각 형식이 잘못되었습니다: %s" + +#: builtin/commit.c:653 +msgid "" +"unable to select a comment character that is not used\n" +"in the current commit message" +msgstr "" +"현재 커밋 메시지에서 사용되지 않는 주석 문자를\n" +"선택할 수 없습니다" + +#: builtin/commit.c:690 builtin/commit.c:723 builtin/commit.c:1080 +#, c-format +msgid "could not lookup commit %s" +msgstr "%s 커밋을 찾아볼 수 없습니다" + +#: builtin/commit.c:702 builtin/shortlog.c:273 +#, c-format +msgid "(reading log message from standard input)\n" +msgstr "(표준 입력에서 로그 메시지를 읽음)\n" + +#: builtin/commit.c:704 +msgid "could not read log from standard input" +msgstr "표준 입력에서 로그 메시지를 읽을 수 없습니다" + +#: builtin/commit.c:708 +#, c-format +msgid "could not read log file '%s'" +msgstr "'%s' 로그 파일을 읽을 수 없습니다" + +#: builtin/commit.c:730 +msgid "could not read MERGE_MSG" +msgstr "MERGE_MSG를 읽을 수 없습니다" + +#: builtin/commit.c:734 +msgid "could not read SQUASH_MSG" +msgstr "SQUASH_MSG를 읽을 수 없습니다" + +#: builtin/commit.c:785 +msgid "could not write commit template" +msgstr "커밋 서식을 쓸 수 없습니다" + +#: builtin/commit.c:803 +#, c-format +msgid "" +"\n" +"It looks like you may be committing a merge.\n" +"If this is not correct, please remove the file\n" +"\t%s\n" +"and try again.\n" +msgstr "" +"\n" +"병합을 커밋하려는 것으로 보입니다.\n" +"그렇지 않다면, 다음 파일을 지우고,\n" +"\t%s\n" +"다시 시도하십시오.\n" + +#: builtin/commit.c:808 +#, c-format +msgid "" +"\n" +"It looks like you may be committing a cherry-pick.\n" +"If this is not correct, please remove the file\n" +"\t%s\n" +"and try again.\n" +msgstr "" +"\n" +"커밋 빼오기를 커밋하려는 것으로 보입니다.\n" +"그렇지 않다면, 다음 파일을 지우고,\n" +"\t%s\n" +"다시 시도하십시오.\n" + +#: builtin/commit.c:821 +#, c-format +msgid "" +"Please enter the commit message for your changes. Lines starting\n" +"with '%c' will be ignored, and an empty message aborts the commit.\n" +msgstr "" +"변경 사항에 대한 커밋 메시지를 입력하십시오. '%c' 문자로 시작하는\n" +"줄은 무시되고, 메시지를 입력하지 않으면 커밋이 중지됩니다.\n" + +#: builtin/commit.c:828 +#, c-format +msgid "" +"Please enter the commit message for your changes. Lines starting\n" +"with '%c' will be kept; you may remove them yourself if you want to.\n" +"An empty message aborts the commit.\n" +msgstr "" +"변경 사항에 대한 커밋 메시지를 입력하십시오. '%c' 문자로 시작하는\n" +"줄은 보존되니, 필요하면 직접 제거하십시오. 메시지를 입력하지\n" +"않으면 커밋이 중지됩니다.\n" + +#: builtin/commit.c:848 +#, c-format +msgid "%sAuthor: %.*s <%.*s>" +msgstr "%s작성자: %.*s <%.*s>" + +#: builtin/commit.c:856 +#, c-format +msgid "%sDate: %s" +msgstr "%s시각: %s" + +#: builtin/commit.c:863 +#, c-format +msgid "%sCommitter: %.*s <%.*s>" +msgstr "%s커미터: %.*s <%.*s>" + +#: builtin/commit.c:881 +msgid "Cannot read index" +msgstr "인덱스를 읽을 수 없습니다" + +#: builtin/commit.c:938 +msgid "Error building trees" +msgstr "트리를 만드는데 오류" + +#: builtin/commit.c:953 builtin/tag.c:266 +#, c-format +msgid "Please supply the message using either -m or -F option.\n" +msgstr "메시지를 -m 또는 -F 옵션으로 입력하십시오.\n" + +#: builtin/commit.c:1055 +#, c-format +msgid "--author '%s' is not 'Name <email>' and matches no existing author" +msgstr "" +"--author '%s' 옵션이 '이름 <전자메일>' 형식이 아니고 기존 작성자에도 없습니다" + +#: builtin/commit.c:1070 builtin/commit.c:1310 +#, c-format +msgid "Invalid untracked files mode '%s'" +msgstr "추적되지 않는 파일 모드가 ('%s') 잘못되었습니다" + +#: builtin/commit.c:1107 +msgid "--long and -z are incompatible" +msgstr "--long 및 -z 옵션은 호환되지 않습니다" + +#: builtin/commit.c:1137 +msgid "Using both --reset-author and --author does not make sense" +msgstr "--reset-author 및 --author 옵션을 모두 사용하면 앞뒤가 맞지 않습니다" + +#: builtin/commit.c:1146 +msgid "You have nothing to amend." +msgstr "바꿀 사항이 없습니다." + +#: builtin/commit.c:1149 +msgid "You are in the middle of a merge -- cannot amend." +msgstr "병합 중에 있습니다 -- 커밋을 바꿀 수 없습니다." + +#: builtin/commit.c:1151 +msgid "You are in the middle of a cherry-pick -- cannot amend." +msgstr "커밋 빼오기 중에 있습니다 -- 커밋을 바꿀 수 없습니다." + +#: builtin/commit.c:1154 +msgid "Options --squash and --fixup cannot be used together" +msgstr "--squash 및 --fixup 옵션은 같이 쓸 수 없습니다" + +#: builtin/commit.c:1164 +msgid "Only one of -c/-C/-F/--fixup can be used." +msgstr "-c/-C/-F/--fixup 옵션 중에 하나만 사용할 수 있습니다." + +#: builtin/commit.c:1166 +msgid "Option -m cannot be combined with -c/-C/-F/--fixup." +msgstr "-m 옵션은 -c/-C/-F/--fixup 옵션과 같이 쓸 수 없습니다." + +#: builtin/commit.c:1174 +msgid "--reset-author can be used only with -C, -c or --amend." +msgstr "--reset-author 옵션은 -C, -c 또는 --amend 옵션과 같이 써야 합니다." + +#: builtin/commit.c:1191 +msgid "Only one of --include/--only/--all/--interactive/--patch can be used." +msgstr "" +"--include/--only/--all/--interactive/--patch 옵션 중 하나만 사용할 수 있습니" +"다." + +#: builtin/commit.c:1193 +msgid "No paths with --include/--only does not make sense." +msgstr "경로가 없이 --include/--only 옵션을 쓰면 앞뒤가 맞지 않습니다." + +#: builtin/commit.c:1195 +msgid "Clever... amending the last one with dirty index." +msgstr "기발하네요... 마지막을 변경된 인덱스로 바꿉니다." + +#: builtin/commit.c:1197 +msgid "Explicit paths specified without -i or -o; assuming --only paths..." +msgstr "-i 또는 -o 없이 명시적인 경로를 지정했습니다. --only 경로를 가정합니다..." + +#: builtin/commit.c:1209 builtin/tag.c:475 +#, c-format +msgid "Invalid cleanup mode %s" +msgstr "잘못된 정리 모드 %s" + +#: builtin/commit.c:1214 +msgid "Paths with -a does not make sense." +msgstr "-a 옵션과 경로를 같이 사용하면 앞뒤가 맞지 않습니다." + +#: builtin/commit.c:1324 builtin/commit.c:1605 +msgid "show status concisely" +msgstr "상태를 간략하게 표시합니다" + +#: builtin/commit.c:1326 builtin/commit.c:1607 +msgid "show branch information" +msgstr "브랜치 정보를 표시합니다" + +#: builtin/commit.c:1328 builtin/commit.c:1609 builtin/push.c:544 +#: builtin/worktree.c:423 +msgid "machine-readable output" +msgstr "컴퓨터가 읽을 수 있는 형식" + +#: builtin/commit.c:1331 builtin/commit.c:1611 +msgid "show status in long format (default)" +msgstr "긴 형식으로 상태를 표시합니다 (기본값)" + +#: builtin/commit.c:1334 builtin/commit.c:1614 +msgid "terminate entries with NUL" +msgstr "NUL 문자로 항목을 끝냅니다" + +#: builtin/commit.c:1336 builtin/commit.c:1617 builtin/fast-export.c:981 +#: builtin/fast-export.c:984 builtin/tag.c:353 +msgid "mode" +msgstr "모드" + +#: builtin/commit.c:1337 builtin/commit.c:1617 +msgid "show untracked files, optional modes: all, normal, no. (Default: all)" +msgstr "추적되지 않는 파일을 표시합니다. 추가 옵션: all, normal, no (기본값: all)" + +#: builtin/commit.c:1340 +msgid "show ignored files" +msgstr "무시되는 파일을 표시합니다" + +#: builtin/commit.c:1341 parse-options.h:155 +msgid "when" +msgstr "언제" + +#: builtin/commit.c:1342 +msgid "" +"ignore changes to submodules, optional when: all, dirty, untracked. " +"(Default: all)" +msgstr "하위 모듈의 변경을 무시합니다. 추가 옵션: all, dirty, untracked. (기본값: all)" + +#: builtin/commit.c:1344 +msgid "list untracked files in columns" +msgstr "추적되지 않는 파일의 목록을 여러 열로 표시합니다" + +#: builtin/commit.c:1430 +msgid "couldn't look up newly created commit" +msgstr "새로 만든 커밋을 찾아볼 수 없습니다" + +#: builtin/commit.c:1432 +msgid "could not parse newly created commit" +msgstr "새로 만든 커밋을 파싱할 수 없습니다" + +#: builtin/commit.c:1477 +msgid "detached HEAD" +msgstr "HEAD 분리됨" + +#: builtin/commit.c:1480 +msgid " (root-commit)" +msgstr " (최상위-커밋)" + +#: builtin/commit.c:1575 +msgid "suppress summary after successful commit" +msgstr "성공적인 커밋 후에 요약을 표시하지 않습니다" + +#: builtin/commit.c:1576 +msgid "show diff in commit message template" +msgstr "커밋 메시지 서식에 diff를 표시합니다" + +#: builtin/commit.c:1578 +msgid "Commit message options" +msgstr "커밋 메시지 옵션" + +#: builtin/commit.c:1579 builtin/tag.c:351 +msgid "read message from file" +msgstr "파일에서 메시지를 읽습니다" + +#: builtin/commit.c:1580 +msgid "author" +msgstr "작성자" + +#: builtin/commit.c:1580 +msgid "override author for commit" +msgstr "커밋의 작성자를 지정합니다" + +#: builtin/commit.c:1581 builtin/gc.c:326 +msgid "date" +msgstr "시각" + +#: builtin/commit.c:1581 +msgid "override date for commit" +msgstr "커밋의 시각을 지정합니다" + +#: builtin/commit.c:1582 builtin/merge.c:218 builtin/notes.c:392 +#: builtin/notes.c:555 builtin/tag.c:349 +msgid "message" +msgstr "메시지" + +#: builtin/commit.c:1582 +msgid "commit message" +msgstr "커밋 메시지" + +#: builtin/commit.c:1583 builtin/commit.c:1584 builtin/commit.c:1585 +#: builtin/commit.c:1586 parse-options.h:256 ref-filter.h:79 +msgid "commit" +msgstr "커밋" + +#: builtin/commit.c:1583 +msgid "reuse and edit message from specified commit" +msgstr "지정한 커밋의 메시지를 재사용하고 편집합니다" + +#: builtin/commit.c:1584 +msgid "reuse message from specified commit" +msgstr "지정한 커밋에서 메시지를 재사용합니다" + +#: builtin/commit.c:1585 +msgid "use autosquash formatted message to fixup specified commit" +msgstr "지정한 커밋을 수정하는데 autosquash 형식 메시지를 사용합니다" + +#: builtin/commit.c:1586 +msgid "use autosquash formatted message to squash specified commit" +msgstr "지정한 커밋을 합치는데 autosquash 형식 메시지를 사용합니다" + +#: builtin/commit.c:1587 +msgid "the commit is authored by me now (used with -C/-c/--amend)" +msgstr "커밋을 내가 작성한 것으로 만듭니다 (-C/-c/--amend와 같이 사용)" + +#: builtin/commit.c:1588 builtin/log.c:1216 builtin/revert.c:86 +msgid "add Signed-off-by:" +msgstr "Signed-off-by: 줄을 추가합니다" + +#: builtin/commit.c:1589 +msgid "use specified template file" +msgstr "지정한 서식 파일을 사용합니다" + +#: builtin/commit.c:1590 +msgid "force edit of commit" +msgstr "커밋 편집을 강제합니다" + +#: builtin/commit.c:1591 +msgid "default" +msgstr "기본값" + +#: builtin/commit.c:1591 builtin/tag.c:354 +msgid "how to strip spaces and #comments from message" +msgstr "메시지에서 공백과 #주석을 지웁니다" + +#: builtin/commit.c:1592 +msgid "include status in commit message template" +msgstr "커밋 메시지 서식에 상태를 포함합니다" + +#: builtin/commit.c:1594 builtin/merge.c:226 builtin/pull.c:156 +#: builtin/revert.c:93 +msgid "GPG sign commit" +msgstr "GPG 서명 커밋" + +#: builtin/commit.c:1597 +msgid "Commit contents options" +msgstr "커밋 내용 옵션" + +#: builtin/commit.c:1598 +msgid "commit all changed files" +msgstr "변경된 파일을 모두 커밋합니다" + +#: builtin/commit.c:1599 +msgid "add specified files to index for commit" +msgstr "지정한 파일을 커밋할 인덱스에 추가합니다" + +#: builtin/commit.c:1600 +msgid "interactively add files" +msgstr "대화형으로 파일을 추가합니다" + +#: builtin/commit.c:1601 +msgid "interactively add changes" +msgstr "대화형으로 변경 사항을 추가합니다" + +#: builtin/commit.c:1602 +msgid "commit only specified files" +msgstr "지정한 파일만 커밋합니다" + +#: builtin/commit.c:1603 +msgid "bypass pre-commit hook" +msgstr "커밋 전 후크를 건너뜁니다" + +#: builtin/commit.c:1604 +msgid "show what would be committed" +msgstr "무엇을 커밋할지 표시합니다" + +#: builtin/commit.c:1615 +msgid "amend previous commit" +msgstr "바로 앞 커밋을 바꿉니다" + +#: builtin/commit.c:1616 +msgid "bypass post-rewrite hook" +msgstr "다시쓰기 후 후크를 건너뜁니다" + +#: builtin/commit.c:1621 +msgid "ok to record an empty change" +msgstr "빈 변경 사항을 기록하도록 허용합니다" + +#: builtin/commit.c:1623 +msgid "ok to record a change with an empty message" +msgstr "빈 메시지와 같이 변경 사항을 기록하도록 허용합니다" + +#: builtin/commit.c:1652 +msgid "could not parse HEAD commit" +msgstr "HEAD 커밋을 파싱할 수 없습니다" + +#: builtin/commit.c:1698 +#, c-format +msgid "Corrupt MERGE_HEAD file (%s)" +msgstr "손상된 MERGE_HEAD 파일 (%s)" + +#: builtin/commit.c:1705 +msgid "could not read MERGE_MODE" +msgstr "MERGE_MODE를 읽을 수 없습니다" + +#: builtin/commit.c:1724 +#, c-format +msgid "could not read commit message: %s" +msgstr "커밋 메시지를 읽을 수 없습니다: %s" + +#: builtin/commit.c:1735 +#, c-format +msgid "Aborting commit; you did not edit the message.\n" +msgstr "커밋을 중지합니다. 메시지를 편집하지 않았습니다.\n" + +#: builtin/commit.c:1740 +#, c-format +msgid "Aborting commit due to empty commit message.\n" +msgstr "커밋을 중지합니다. 커밋 메시지가 비어 있습니다.\n" + +#: builtin/commit.c:1788 +msgid "" +"Repository has been updated, but unable to write\n" +"new_index file. Check that disk is not full and quota is\n" +"not exceeded, and then \"git reset HEAD\" to recover." +msgstr "" +"저장소를 업데이트했습니다. 하지만 new_index 파일을 쓸 수\n" +"없습니다. 디스크가 꽉 차지 않았고 제한 용량을 넘어가지\n" +"않았는지 확인하십시오. 그리고 'git reset HEAD'로 복구하십시오." + +#: builtin/config.c:8 +msgid "git config [<options>]" +msgstr "git config [<옵션>]" + +#: builtin/config.c:54 +msgid "Config file location" +msgstr "설정 파일 위치" + +#: builtin/config.c:55 +msgid "use global config file" +msgstr "공통 설정 파일을 사용합니다" + +#: builtin/config.c:56 +msgid "use system config file" +msgstr "시스템 설정 파일을 사용합니다" + +#: builtin/config.c:57 +msgid "use repository config file" +msgstr "저장소 설정 파일을 사용합니다" + +#: builtin/config.c:58 +msgid "use given config file" +msgstr "지정한 설정 파일을 사용합니다" + +#: builtin/config.c:59 +msgid "blob-id" +msgstr "블롭-id" + +#: builtin/config.c:59 +msgid "read config from given blob object" +msgstr "지정한 블롭 오브젝트에서 설정을 읽습니다" + +#: builtin/config.c:60 +msgid "Action" +msgstr "동작" + +#: builtin/config.c:61 +msgid "get value: name [value-regex]" +msgstr "값을 가져옵니다: <이름> [<값-정규식>]" + +#: builtin/config.c:62 +msgid "get all values: key [value-regex]" +msgstr "모든 값을 가져옵니다: <키> [<값-정규식>]" + +#: builtin/config.c:63 +msgid "get values for regexp: name-regex [value-regex]" +msgstr "정규식에 대한 값을 가져옵니다: <이름-정규식> [<값-정규식>]" + +#: builtin/config.c:64 +msgid "get value specific for the URL: section[.var] URL" +msgstr "<URL>에 특정되는 값을 가져옵니다: <섹션>[.<변수>] <URL>" + +#: builtin/config.c:65 +msgid "replace all matching variables: name value [value_regex]" +msgstr "해당하는 변수를 모두 제거합니다: <이름> <값> [<값-정규식>]" + +#: builtin/config.c:66 +msgid "add a new variable: name value" +msgstr "새 변수를 추가합니다: <이름> <값>" + +#: builtin/config.c:67 +msgid "remove a variable: name [value-regex]" +msgstr "변수를 제거합니다: <이름> [<값-정규식>]" + +#: builtin/config.c:68 +msgid "remove all matches: name [value-regex]" +msgstr "해당하는 항목을 모두 제거합니다: <이름> [<값-정규식>]" + +#: builtin/config.c:69 +msgid "rename section: old-name new-name" +msgstr "섹션의 이름을 바꿉니다: <옛-이름> <새-이름>" + +#: builtin/config.c:70 +msgid "remove a section: name" +msgstr "섹션을 제거합니다: <이름>" + +#: builtin/config.c:71 +msgid "list all" +msgstr "전체 목록을 표시합니다" + +#: builtin/config.c:72 +msgid "open an editor" +msgstr "편집기를 엽니다" + +#: builtin/config.c:73 +msgid "find the color configured: slot [default]" +msgstr "설정한 색을 찾습니다: slot [<기본값>]" + +#: builtin/config.c:74 +msgid "find the color setting: slot [stdout-is-tty]" +msgstr "색 설정을 찾습니다: slot [<표준출력이-TTY인지-여부>]" + +#: builtin/config.c:75 +msgid "Type" +msgstr "값 종류" + +#: builtin/config.c:76 +msgid "value is \"true\" or \"false\"" +msgstr "값이 \"true\" 또는 \"false\"입니다" + +#: builtin/config.c:77 +msgid "value is decimal number" +msgstr "값이 십진수입니다" + +#: builtin/config.c:78 +msgid "value is --bool or --int" +msgstr "값이 --bool 또는 --int입니다" + +#: builtin/config.c:79 +msgid "value is a path (file or directory name)" +msgstr "값이 경로(파일 또는 디렉터리 이름)입니다" + +#: builtin/config.c:80 +msgid "Other" +msgstr "기타" + +#: builtin/config.c:81 +msgid "terminate values with NUL byte" +msgstr "값을 NUL 바이트로 끝냅니다" + +#: builtin/config.c:82 +msgid "show variable names only" +msgstr "변수 이름만 표시합니다" + +#: builtin/config.c:83 +msgid "respect include directives on lookup" +msgstr "찾아볼 때 include 지시어를 고려합니다" + +#: builtin/config.c:303 +msgid "unable to parse default color value" +msgstr "기본 색 값을 파싱할 수 없습니다" + +#: builtin/config.c:441 +#, c-format +msgid "" +"# This is Git's per-user configuration file.\n" +"[user]\n" +"# Please adapt and uncomment the following lines:\n" +"#\tname = %s\n" +"#\temail = %s\n" +msgstr "" +"# 깃의 사용자별 설정 파일입니다.\n" +"[user]\n" +"# 다음 줄을 알맞게 고치고 앞의 주석을 제거하십시오:\n" +"#\tname = %s\n" +"#\temail = %s\n" + +#: builtin/config.c:575 +#, c-format +msgid "cannot create configuration file %s" +msgstr "%s 설정 파일을 만들 수 없습니다" + +#: builtin/count-objects.c:77 +msgid "git count-objects [-v] [-H | --human-readable]" +msgstr "git count-objects [-v] [-H | --human-readable]" + +#: builtin/count-objects.c:87 +msgid "print sizes in human readable format" +msgstr "사람이 읽기 좋은 형식으로 크기를 표시합니다" + +#: builtin/describe.c:17 +msgid "git describe [<options>] [<commit-ish>...]" +msgstr "git describe [<옵션>] [<커밋-따위>...]" + +#: builtin/describe.c:18 +msgid "git describe [<options>] --dirty" +msgstr "git describe [<옵션>] --dirty" + +#: builtin/describe.c:217 +#, c-format +msgid "annotated tag %s not available" +msgstr "주석 달린 %s 태그를 사용할 수 없습니다" + +#: builtin/describe.c:221 +#, c-format +msgid "annotated tag %s has no embedded name" +msgstr "주석 달린 %s 태그에 내장된 이름이 없습니다" + +#: builtin/describe.c:223 +#, c-format +msgid "tag '%s' is really '%s' here" +msgstr "'%s' 태그가 실제 여기 '%s'입니다" + +#: builtin/describe.c:250 builtin/log.c:459 +#, c-format +msgid "Not a valid object name %s" +msgstr "올바른 오브젝트 이름이 아닙니다 (%s)" + +#: builtin/describe.c:253 +#, c-format +msgid "%s is not a valid '%s' object" +msgstr "%s은(는) 올바른 '%s' 오브젝트가 아닙니다" + +#: builtin/describe.c:270 +#, c-format +msgid "no tag exactly matches '%s'" +msgstr "어떤 태그도 '%s'와(과) 정확히 일치하지 않습니다" + +#: builtin/describe.c:272 +#, c-format +msgid "searching to describe %s\n" +msgstr "%s 설명을 위해 검색하는 중\n" + +#: builtin/describe.c:319 +#, c-format +msgid "finished search at %s\n" +msgstr "%s에서 검색 마침\n" + +#: builtin/describe.c:346 +#, c-format +msgid "" +"No annotated tags can describe '%s'.\n" +"However, there were unannotated tags: try --tags." +msgstr "" +"어떤 주석 달린 태그도 '%s'을(를) 설명하지 않습니다.\n" +"하지만 주석 달리지 않은 태그가 있습니다: --tags 옵션을 해 보십시오." + +#: builtin/describe.c:350 +#, c-format +msgid "" +"No tags can describe '%s'.\n" +"Try --always, or create some tags." +msgstr "" +"어떤 태그도 '%s'을(를) 설명할 수 없습니다.\n" +"--always 옵션을 써 보거나, 태그를 만들어 보십시오." + +#: builtin/describe.c:371 +#, c-format +msgid "traversed %lu commits\n" +msgstr "커밋 %lu개를 가로질렀습니다\n" + +#: builtin/describe.c:374 +#, c-format +msgid "" +"more than %i tags found; listed %i most recent\n" +"gave up search at %s\n" +msgstr "" +"태그를 %i개 넘게 찾았습니다. 가장 최근의 %i개 목록을\n" +"표시합니다. %s 위치에서 검색을 중지합니다.\n" + +#: builtin/describe.c:396 +msgid "find the tag that comes after the commit" +msgstr "커밋 다음에 오는 태그를 찾습니다" + +#: builtin/describe.c:397 +msgid "debug search strategy on stderr" +msgstr "표준 오류에서 검색 전략을 디버깅합니다" + +#: builtin/describe.c:398 +msgid "use any ref" +msgstr "모든 레퍼런스를 사용합니다" + +#: builtin/describe.c:399 +msgid "use any tag, even unannotated" +msgstr "모든 태그를, 주석 달리지 않은 태그까지 사용합니다" + +#: builtin/describe.c:400 +msgid "always use long format" +msgstr "항상 긴 형식을 사용합니다" + +#: builtin/describe.c:401 +msgid "only follow first parent" +msgstr "첫 번째 이전 커밋만 따라갑니다" + +#: builtin/describe.c:404 +msgid "only output exact matches" +msgstr "정확히 일치하는 항목만 출력합니다" + +#: builtin/describe.c:406 +msgid "consider <n> most recent tags (default: 10)" +msgstr "<n>개의 가장 최근의 태그만 고려합니다 (기본값: 10)" + +#: builtin/describe.c:408 +msgid "only consider tags matching <pattern>" +msgstr "<패턴>과 일치하는 태그만 고려합니다" + +#: builtin/describe.c:410 builtin/name-rev.c:314 +msgid "show abbreviated commit object as fallback" +msgstr "대안으로 요약한 커밋 오브젝트를 표시합니다" + +#: builtin/describe.c:411 +msgid "mark" +msgstr "표시" + +#: builtin/describe.c:412 +msgid "append <mark> on dirty working tree (default: \"-dirty\")" +msgstr "변경된 작업 폴더에 <표시>를 뒤에 붙입니다 (기본값: \"-dirty\")" + +#: builtin/describe.c:430 +msgid "--long is incompatible with --abbrev=0" +msgstr "--long 옵션은 --abbrev=0 옵션과 호환되지 않습니다" + +#: builtin/describe.c:456 +msgid "No names found, cannot describe anything." +msgstr "이름이 없습니다. 아무것도 설명할 수 없습니다." + +#: builtin/describe.c:476 +msgid "--dirty is incompatible with commit-ishes" +msgstr "--dirty 옵션은 커밋같은 항목과 호환되지 않았습니다" + +#: builtin/diff.c:86 +#, c-format +msgid "'%s': not a regular file or symlink" +msgstr "'%s': 일반 파일이나 심볼릭 링크가 아닙니다" + +#: builtin/diff.c:237 +#, c-format +msgid "invalid option: %s" +msgstr "잘못된 옵션: %s" + +#: builtin/diff.c:358 +msgid "Not a git repository" +msgstr "깃 저장소가 아닙니다" + +#: builtin/diff.c:401 +#, c-format +msgid "invalid object '%s' given." +msgstr "잘못된 '%s' 오브젝트가 주어졌습니다." + +#: builtin/diff.c:410 +#, c-format +msgid "more than two blobs given: '%s'" +msgstr "두 개보다 많은 블롭이 주어졌습니다: '%s'" + +#: builtin/diff.c:417 +#, c-format +msgid "unhandled object '%s' given." +msgstr "처리하지 않은 '%s' 오브젝트가 주어졌습니다." + +#: builtin/fast-export.c:25 +msgid "git fast-export [rev-list-opts]" +msgstr "git fast-export [rev-list-옵션]" + +#: builtin/fast-export.c:980 +msgid "show progress after <n> objects" +msgstr "오브젝트 <n>개 뒤에 진행 상황을 표시합니다" + +#: builtin/fast-export.c:982 +msgid "select handling of signed tags" +msgstr "서명한 태그의 처리 방식을 선택합니다" + +#: builtin/fast-export.c:985 +msgid "select handling of tags that tag filtered objects" +msgstr "필터링한 오브젝트에 대한 태그의 처리 방식을 선택합니다" + +#: builtin/fast-export.c:988 +msgid "Dump marks to this file" +msgstr "이 파일로 표시를 내보냅니다" + +#: builtin/fast-export.c:990 +msgid "Import marks from this file" +msgstr "이 파일에서 표시를 가져옵니다" + +#: builtin/fast-export.c:992 +msgid "Fake a tagger when tags lack one" +msgstr "태그에 태그붙인 사람이 없을 때 가짜로 만듭니다" + +#: builtin/fast-export.c:994 +msgid "Output full tree for each commit" +msgstr "커밋 마다 전체 트리를 출력합니다" + +#: builtin/fast-export.c:996 +msgid "Use the done feature to terminate the stream" +msgstr "스트림을 끝내는데 완료 기능을 사용합니다" + +#: builtin/fast-export.c:997 +msgid "Skip output of blob data" +msgstr "블롭 데이터의 출력을 건너뜁니다" + +#: builtin/fast-export.c:998 +msgid "refspec" +msgstr "레퍼런스명세" + +#: builtin/fast-export.c:999 +msgid "Apply refspec to exported refs" +msgstr "레퍼런스명세를 내보낸 레퍼런스에 적용합니다" + +#: builtin/fast-export.c:1000 +msgid "anonymize output" +msgstr "출력을 익명화합니다" + +#: builtin/fetch.c:20 +msgid "git fetch [<options>] [<repository> [<refspec>...]]" +msgstr "git fetch [<옵션>] [<저장소> [<레퍼런스명세>...]]" + +#: builtin/fetch.c:21 +msgid "git fetch [<options>] <group>" +msgstr "git fetch [<옵션>] <그룹>" + +#: builtin/fetch.c:22 +msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]" +msgstr "git fetch --multiple [<옵션>] [(<저장소> | <그룹>)...]" + +#: builtin/fetch.c:23 +msgid "git fetch --all [<options>]" +msgstr "git fetch --all [<옵션>]" + +#: builtin/fetch.c:90 builtin/pull.c:162 +msgid "fetch from all remotes" +msgstr "모든 리모트에서 가져옵니다" + +#: builtin/fetch.c:92 builtin/pull.c:165 +msgid "append to .git/FETCH_HEAD instead of overwriting" +msgstr "덮어쓰지 말고 .git/FETCH_HEAD에 덧붙입니다" + +#: builtin/fetch.c:94 builtin/pull.c:168 +msgid "path to upload pack on remote end" +msgstr "리모트 쪽에 묶음을 업로드할 경로" + +#: builtin/fetch.c:95 builtin/pull.c:170 +msgid "force overwrite of local branch" +msgstr "로컬 브랜치를 강제로 덮어씁니다" + +#: builtin/fetch.c:97 +msgid "fetch from multiple remotes" +msgstr "여러 리모트에서 가져옵니다" + +#: builtin/fetch.c:99 builtin/pull.c:172 +msgid "fetch all tags and associated objects" +msgstr "모든 태그와 관련 오브젝트를 가져옵니다" + +#: builtin/fetch.c:101 +msgid "do not fetch all tags (--no-tags)" +msgstr "모든 태그를 가져오지 않습니다 (--no-tags)" + +#: builtin/fetch.c:103 builtin/pull.c:175 +msgid "prune remote-tracking branches no longer on remote" +msgstr "리모트에 이제 없는 리모트 추적 브랜치를 잘라냅니다" + +#: builtin/fetch.c:104 builtin/pull.c:178 +msgid "on-demand" +msgstr "주문형" + +#: builtin/fetch.c:105 builtin/pull.c:179 +msgid "control recursive fetching of submodules" +msgstr "하위 모듈 재귀적으로 가져오기 방식을 설정합니다" + +#: builtin/fetch.c:109 builtin/pull.c:184 +msgid "keep downloaded pack" +msgstr "다운로드한 묶음을 보존합니다" + +#: builtin/fetch.c:111 +msgid "allow updating of HEAD ref" +msgstr "HEAD 레퍼런스 업데이트를 허용합니다" + +#: builtin/fetch.c:114 builtin/pull.c:187 +msgid "deepen history of shallow clone" +msgstr "얕은 복제의 커밋 내역을 깊게 만듭니다" + +#: builtin/fetch.c:116 builtin/pull.c:190 +msgid "convert to a complete repository" +msgstr "완전한 저장소로 전환합니다" + +#: builtin/fetch.c:118 builtin/log.c:1233 +msgid "dir" +msgstr "디렉터리" + +#: builtin/fetch.c:119 +msgid "prepend this to submodule path output" +msgstr "하위 모듈 경로 출력의 앞에 이 디렉터리를 붙입니다" + +#: builtin/fetch.c:122 +msgid "default mode for recursion" +msgstr "재귀 기본 모드" + +#: builtin/fetch.c:124 builtin/pull.c:193 +msgid "accept refs that update .git/shallow" +msgstr ".git/shallow를 업데이트하는 레퍼런스를 허용합니다" + +#: builtin/fetch.c:125 builtin/pull.c:195 +msgid "refmap" +msgstr "레퍼런스맵" + +#: builtin/fetch.c:126 builtin/pull.c:196 +msgid "specify fetch refmap" +msgstr "레퍼런스맵 가져오기를 지정합니다" + +#: builtin/fetch.c:378 +msgid "Couldn't find remote ref HEAD" +msgstr "리모트 레퍼런스 HEAD를 찾을 수 없습니다" + +#: builtin/fetch.c:458 +#, c-format +msgid "object %s not found" +msgstr "%s 오브젝트가 없습니다" + +#: builtin/fetch.c:463 +msgid "[up to date]" +msgstr "[최신 상태]" + +#: builtin/fetch.c:477 +#, c-format +msgid "! %-*s %-*s -> %s (can't fetch in current branch)" +msgstr "! %-*s %-*s -> %s (현재 브랜치에서 가져올 수 없음)" + +#: builtin/fetch.c:478 builtin/fetch.c:566 +msgid "[rejected]" +msgstr "[거부됨]" + +#: builtin/fetch.c:489 +msgid "[tag update]" +msgstr "[태그 업데이트]" + +#: builtin/fetch.c:491 builtin/fetch.c:526 builtin/fetch.c:544 +msgid " (unable to update local ref)" +msgstr " (로컬 레퍼런스를 업데이트할 수 없음)" + +#: builtin/fetch.c:509 +msgid "[new tag]" +msgstr "[새로운 태그]" + +#: builtin/fetch.c:512 +msgid "[new branch]" +msgstr "[새로운 브랜치]" + +#: builtin/fetch.c:515 +msgid "[new ref]" +msgstr "[새로운 레퍼런스]" + +#: builtin/fetch.c:561 +msgid "unable to update local ref" +msgstr "로컬 레퍼런스를 업데이트할 수 없습니다" + +#: builtin/fetch.c:561 +msgid "forced update" +msgstr "강제 업데이트" + +#: builtin/fetch.c:568 +msgid "(non-fast-forward)" +msgstr "(정방향 진행이 아님)" + +#: builtin/fetch.c:602 builtin/fetch.c:843 +#, c-format +msgid "cannot open %s: %s\n" +msgstr "%s을(를) 열 수 없습니다: %s\n" + +#: builtin/fetch.c:611 +#, c-format +msgid "%s did not send all necessary objects\n" +msgstr "%s이(가) 모든 필요한 오브젝트를 보내지 않았습니다\n" + +#: builtin/fetch.c:629 +#, c-format +msgid "reject %s because shallow roots are not allowed to be updated" +msgstr "얕은 최상위의 업데이트가 허용되지 않으므로 %s을(를) 거부합니다" + +#: builtin/fetch.c:716 builtin/fetch.c:808 +#, c-format +msgid "From %.*s\n" +msgstr "%.*s URL에서\n" + +#: builtin/fetch.c:727 +#, c-format +msgid "" +"some local refs could not be updated; try running\n" +" 'git remote prune %s' to remove any old, conflicting branches" +msgstr "" +"업데이트할 수 없는 로컬 레퍼런스가 있습니다. 과거 충돌 브랜치를\n" +" 제거하려면 'git remote prune %s' 명령을 실행해 보십시오" + +#: builtin/fetch.c:779 +#, c-format +msgid " (%s will become dangling)" +msgstr " (%s 레퍼런스가 연결이 끊어지게 됩니다)" + +#: builtin/fetch.c:780 +#, c-format +msgid " (%s has become dangling)" +msgstr " (%s 레퍼런스가 연결이 끊어졌습니다)" + +#: builtin/fetch.c:812 +msgid "[deleted]" +msgstr "[삭제됨]" + +#: builtin/fetch.c:813 builtin/remote.c:1040 +msgid "(none)" +msgstr "(없음)" + +#: builtin/fetch.c:833 +#, c-format +msgid "Refusing to fetch into current branch %s of non-bare repository" +msgstr "간략한 저장소가 아닌 저장소의 현재 %s 브랜치로 가져오기를 거절합니다" + +#: builtin/fetch.c:852 +#, c-format +msgid "Option \"%s\" value \"%s\" is not valid for %s" +msgstr "\"%s\" 옵션의 \"%s\" 값은 %s에 대해 올바르지 않습니다" + +#: builtin/fetch.c:855 +#, c-format +msgid "Option \"%s\" is ignored for %s\n" +msgstr "\"%s\" 옵션은 '%s'에 대해 무시됩니다\n" + +#: builtin/fetch.c:911 +#, c-format +msgid "Don't know how to fetch from %s" +msgstr "'%s'에서 가져오는 방법을 알 수 없습니다" + +#: builtin/fetch.c:1072 +#, c-format +msgid "Fetching %s\n" +msgstr "%s을(를) 가져오는 중\n" + +#: builtin/fetch.c:1074 builtin/remote.c:96 +#, c-format +msgid "Could not fetch %s" +msgstr "%s을(를) 가져올 수 없습니다" + +#: builtin/fetch.c:1092 +msgid "" +"No remote repository specified. Please, specify either a URL or a\n" +"remote name from which new revisions should be fetched." +msgstr "" +"리모트 저장소를 지정하지 않았습니다. 새 리비전을 가져올 수 있는\n" +"URL이나 리모트 이름을 지정하십시오." + +#: builtin/fetch.c:1115 +msgid "You need to specify a tag name." +msgstr "태그 이름을 지정해야 합니다." + +#: builtin/fetch.c:1157 +msgid "--depth and --unshallow cannot be used together" +msgstr "--depth 및 --unshallow 옵션은 같이 쓸 수 없습니다" + +#: builtin/fetch.c:1159 +msgid "--unshallow on a complete repository does not make sense" +msgstr "완전한 저장소에 대해 --unshallow 옵션을 사용하는 건 앞뒤가 맞지 않습니다" + +#: builtin/fetch.c:1179 +msgid "fetch --all does not take a repository argument" +msgstr "fetch --all 명령에 저장소 인자가 없습니다" + +#: builtin/fetch.c:1181 +msgid "fetch --all does not make sense with refspecs" +msgstr "fetch --all 명령은 레퍼런스명세 인자와 같이 쓰면 앞뒤가 맞지 않습니다" + +#: builtin/fetch.c:1192 +#, c-format +msgid "No such remote or remote group: %s" +msgstr "그런 리모트나 리모트 그룹이 없습니다: %s" + +#: builtin/fetch.c:1200 +msgid "Fetching a group and specifying refspecs does not make sense" +msgstr "그룹을 가져오고 레퍼런스명세를 지정하면 앞뒤가 맞지 않습니다" + +#: builtin/fmt-merge-msg.c:14 +msgid "" +"git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]" +msgstr "" +"git fmt-merge-msg [-m <메시지>] [--log[=<n>] | --no-log] [--file <파일>]" + +#: builtin/fmt-merge-msg.c:667 +msgid "populate log with at most <n> entries from shortlog" +msgstr "shortlog에서 최대 <n>개 로그를 표시합니다" + +#: builtin/fmt-merge-msg.c:670 +msgid "alias for --log (deprecated)" +msgstr "--log와 동일 (없어질 예정)" + +#: builtin/fmt-merge-msg.c:673 +msgid "text" +msgstr "텍스트" + +#: builtin/fmt-merge-msg.c:674 +msgid "use <text> as start of message" +msgstr "<텍스트>를 시작 메시지로 사용합니다" + +#: builtin/fmt-merge-msg.c:675 +msgid "file to read from" +msgstr "읽어들일 파일" + +#: builtin/for-each-ref.c:9 +msgid "git for-each-ref [<options>] [<pattern>]" +msgstr "git for-each-ref [<옵션>] [<패턴>]" + +#: builtin/for-each-ref.c:10 +msgid "git for-each-ref [--points-at <object>]" +msgstr "git for-each-ref [--points-at <오브젝트>]" + +#: builtin/for-each-ref.c:11 +msgid "git for-each-ref [(--merged | --no-merged) [<object>]]" +msgstr "git for-each-ref [(--merged | --no-merged) [<오브젝트>]]" + +#: builtin/for-each-ref.c:12 +msgid "git for-each-ref [--contains [<object>]]" +msgstr "git for-each-ref [--contains [<오브젝트>]]" + +#: builtin/for-each-ref.c:27 +msgid "quote placeholders suitably for shells" +msgstr "셸에 적합하게 플레이스홀더를 인용합니다" + +#: builtin/for-each-ref.c:29 +msgid "quote placeholders suitably for perl" +msgstr "펄에 적합하게 플레이스홀더를 인용합니다" + +#: builtin/for-each-ref.c:31 +msgid "quote placeholders suitably for python" +msgstr "파이썬에 적합하게 플레이스홀더를 인용합니다" + +#: builtin/for-each-ref.c:33 +msgid "quote placeholders suitably for Tcl" +msgstr "티클에 적합하게 플레이스홀더를 인용합니다" + +#: builtin/for-each-ref.c:36 +msgid "show only <n> matched refs" +msgstr "<n>개의 해당하는 레퍼런스만 표시합니다" + +#: builtin/for-each-ref.c:37 builtin/tag.c:372 +msgid "format to use for the output" +msgstr "출력에 사용할 형식" + +#: builtin/for-each-ref.c:41 +msgid "print only refs which points at the given object" +msgstr "주어진 오브젝트를 가리키는 레퍼런스만 표시합니다" + +#: builtin/for-each-ref.c:43 +msgid "print only refs that are merged" +msgstr "병합하는 레퍼런스만 표시합니다" + +#: builtin/for-each-ref.c:44 +msgid "print only refs that are not merged" +msgstr "병합하지 않는 레퍼런스만 표시합니다" + +#: builtin/for-each-ref.c:45 +msgid "print only refs which contain the commit" +msgstr "커밋이 포함된 레퍼런스만 표시합니다" + +#: builtin/fsck.c:156 builtin/prune.c:140 +msgid "Checking connectivity" +msgstr "연결을 확인하는 중입니다" + +#: builtin/fsck.c:486 +msgid "Checking object directories" +msgstr "오브젝트 디렉터리를 확인하는 중입니다" + +#: builtin/fsck.c:553 +msgid "git fsck [<options>] [<object>...]" +msgstr "git fsck [<옵션>] [<오브젝트>...]" + +#: builtin/fsck.c:559 +msgid "show unreachable objects" +msgstr "점근할 수 없는 오브젝트를 표시합니다" + +#: builtin/fsck.c:560 +msgid "show dangling objects" +msgstr "연결이 끊어진 오브젝트를 표시합니다" + +#: builtin/fsck.c:561 +msgid "report tags" +msgstr "태그를 알립니다" + +#: builtin/fsck.c:562 +msgid "report root nodes" +msgstr "최상위 노드를 알립니다" + +#: builtin/fsck.c:563 +msgid "make index objects head nodes" +msgstr "인덱스 오브젝트 헤드 노드를 만듭니다" + +#: builtin/fsck.c:564 +msgid "make reflogs head nodes (default)" +msgstr "reflog 헤드 노드를 만듭니다 (기본값)" + +#: builtin/fsck.c:565 +msgid "also consider packs and alternate objects" +msgstr "묶음과 보조 오브젝트도 만듭니다" + +#: builtin/fsck.c:566 +msgid "check only connectivity" +msgstr "연결만 확인합니다" + +#: builtin/fsck.c:567 +msgid "enable more strict checking" +msgstr "더 엄격하게 확인합니다" + +#: builtin/fsck.c:569 +msgid "write dangling objects in .git/lost-found" +msgstr ".git/lost-found 안에 연결이 끊어진 오브젝트를 씁니다" + +#: builtin/fsck.c:570 builtin/prune.c:107 +msgid "show progress" +msgstr "진행 상황을 표시합니다" + +#: builtin/fsck.c:631 +msgid "Checking objects" +msgstr "오브젝트를 확인합니다" + +#: builtin/gc.c:25 +msgid "git gc [<options>]" +msgstr "git gc [<옵션>]" + +#: builtin/gc.c:72 +#, c-format +msgid "Invalid %s: '%s'" +msgstr "잘못된 %s: '%s'" + +#: builtin/gc.c:139 +#, c-format +msgid "insanely long object directory %.*s" +msgstr "비정상적으로 긴 오브젝트 디렉터리 %.*s" + +#: builtin/gc.c:290 +#, c-format +msgid "" +"The last gc run reported the following. Please correct the root cause\n" +"and remove %s.\n" +"Automatic cleanup will not be performed until the file is removed.\n" +"\n" +"%s" +msgstr "" +"마지막 가비지컬렉터에서 다음을 알려왔습니다. 원인을 바로잡은\n" +"다음 %s 파일을 제거하십시오.\n" +"이 파일을 제거하기 전에는 자동 정리 작업을 수행하지 않습니다.\n" +"\n" +"%s" + +#: builtin/gc.c:327 +msgid "prune unreferenced objects" +msgstr "레퍼런스하지 않는 오브젝트를 잘라냅니다" + +#: builtin/gc.c:329 +msgid "be more thorough (increased runtime)" +msgstr "더 자세히 검사합니다 (실행 시간 늘어남)" + +#: builtin/gc.c:330 +msgid "enable auto-gc mode" +msgstr "자동 가비지컬렉터 모드를 사용합니다" + +#: builtin/gc.c:331 +msgid "force running gc even if there may be another gc running" +msgstr "이미 가비지컬렉터가 실행 중이더라도 강제로 가비지컬렉터를 실행합니다" + +#: builtin/gc.c:373 +#, c-format +msgid "Auto packing the repository in background for optimum performance.\n" +msgstr "최적 성능을 위해 백그라운드에서 자동으로 저장소의 묶음을 만듭니다.\n" + +#: builtin/gc.c:375 +#, c-format +msgid "Auto packing the repository for optimum performance.\n" +msgstr "최적 성능을 위해 자동으로 저장소의 묶음을 만듭니다.\n" + +#: builtin/gc.c:376 +#, c-format +msgid "See \"git help gc\" for manual housekeeping.\n" +msgstr "수동 관리 작업은 \"git help gc\" 내용을 참고하십시오.\n" + +#: builtin/gc.c:397 +#, c-format +msgid "" +"gc is already running on machine '%s' pid %<PRIuMAX> (use --force if not)" +msgstr "가비지컬렉터가 이미 '%s' 컴퓨터에서 %<PRIuMAX> PID로 실행 중입니다 (아니면 --force를 사용하십시오)" + +#: builtin/gc.c:441 +msgid "" +"There are too many unreachable loose objects; run 'git prune' to remove them." +msgstr "느슨한 오브젝트가 너무 많습니다. 제거하려면 'git prune'을 실행하십시오." + +#: builtin/grep.c:23 +msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]" +msgstr "git grep [<옵션>] [-e] <패턴> [<리비전>...] [[--] <경로>...]" + +#: builtin/grep.c:218 +#, c-format +msgid "grep: failed to create thread: %s" +msgstr "grep: 스레드를 만드는데 실패했습니다: %s" + +#: builtin/grep.c:441 builtin/grep.c:476 +#, c-format +msgid "unable to read tree (%s)" +msgstr "트리를 읽을 수 없습니다 (%s)" + +#: builtin/grep.c:491 +#, c-format +msgid "unable to grep from object of type %s" +msgstr "종류가 %s인 오브젝트에서 grep을 할 수 없습니다" + +#: builtin/grep.c:547 +#, c-format +msgid "switch `%c' expects a numerical value" +msgstr "`%c' 옵션에는 숫자 값이 와야 합니다" + +#: builtin/grep.c:564 +#, c-format +msgid "cannot open '%s'" +msgstr "'%s'을(를) 열 수 없습니다" + +#: builtin/grep.c:633 +msgid "search in index instead of in the work tree" +msgstr "작업 폴더 대신에 인덱스에서 검색합니다" + +#: builtin/grep.c:635 +msgid "find in contents not managed by git" +msgstr "깃으로 관리하지 않은 내용에서 찾습니다" + +#: builtin/grep.c:637 +msgid "search in both tracked and untracked files" +msgstr "추적되는 파일과 추적되지 않는 파일 모두에서 검색합니다" + +#: builtin/grep.c:639 +msgid "ignore files specified via '.gitignore'" +msgstr "'.gitignore'로 지정한 파일을 무시합니다" + +#: builtin/grep.c:642 +msgid "show non-matching lines" +msgstr "일치하지 않는 줄을 표시합니다" + +#: builtin/grep.c:644 +msgid "case insensitive matching" +msgstr "대소문자 구별하지 않고 맞춥니다" + +#: builtin/grep.c:646 +msgid "match patterns only at word boundaries" +msgstr "단어 경계 부분에 대해서만 패턴을 맞춥니다" + +#: builtin/grep.c:648 +msgid "process binary files as text" +msgstr "바이너리 파일을 텍스트로 처리합니다" + +#: builtin/grep.c:650 +msgid "don't match patterns in binary files" +msgstr "바이너리 파일에서 패턴을 맞추지 않습니다" + +#: builtin/grep.c:653 +msgid "process binary files with textconv filters" +msgstr "textconv 필터를 사용해 바이너리 파일을 처리합니다" + +#: builtin/grep.c:655 +msgid "descend at most <depth> levels" +msgstr "최대 <깊이> 단계만큼 내려갑니다" + +#: builtin/grep.c:659 +msgid "use extended POSIX regular expressions" +msgstr "POSIX 확장 정규식을 사용합니다" + +#: builtin/grep.c:662 +msgid "use basic POSIX regular expressions (default)" +msgstr "기본 POSIX 정규식을 사용합니다 (기본값)" + +#: builtin/grep.c:665 +msgid "interpret patterns as fixed strings" +msgstr "패턴을 고정 문자열로 해석합니다" + +#: builtin/grep.c:668 +msgid "use Perl-compatible regular expressions" +msgstr "펄과 호환되는 정규식을 사용합니다" + +#: builtin/grep.c:671 +msgid "show line numbers" +msgstr "줄 번호를 표시합니다" + +#: builtin/grep.c:672 +msgid "don't show filenames" +msgstr "파일 이름을 표시하지 않습니다" + +#: builtin/grep.c:673 +msgid "show filenames" +msgstr "파일 이름을 표시합니다" + +#: builtin/grep.c:675 +msgid "show filenames relative to top directory" +msgstr "파일 이름을 최상위 디렉터리 상대 경로로 표시합니다" + +#: builtin/grep.c:677 +msgid "show only filenames instead of matching lines" +msgstr "일치하는 줄을 표시하지 않고 파일 이름만 표시합니다" + +#: builtin/grep.c:679 +msgid "synonym for --files-with-matches" +msgstr "--files-with-matches 옵션과 동일" + +#: builtin/grep.c:682 +msgid "show only the names of files without match" +msgstr "일치하지 않는 파일의 이름만 표시합니다" + +#: builtin/grep.c:684 +msgid "print NUL after filenames" +msgstr "파일 이름 다음에 NUL을 출력합니다" + +#: builtin/grep.c:686 +msgid "show the number of matches instead of matching lines" +msgstr "일치하는 줄을 표시하지 않고 일치하는 수를 표시합니다" + +#: builtin/grep.c:687 +msgid "highlight matches" +msgstr "일치하는 부분을 강조합니다" + +#: builtin/grep.c:689 +msgid "print empty line between matches from different files" +msgstr "다른 파일 사이에 일치하는 부분의 사이에 빈 줄을 출력합니다" + +#: builtin/grep.c:691 +msgid "show filename only once above matches from same file" +msgstr "같은 파일에서 여러 개가 일치하면 파일 이름을 한 번만 표시합니다" + +#: builtin/grep.c:694 +msgid "show <n> context lines before and after matches" +msgstr "일치하는 부분 앞뒤에 컨텍스트를 <n>줄 표시합니다" + +#: builtin/grep.c:697 +msgid "show <n> context lines before matches" +msgstr "일치하는 부분 앞에 컨텍스트를 <n>줄 표시합니다" + +#: builtin/grep.c:699 +msgid "show <n> context lines after matches" +msgstr "일치하는 부분 뒤에 컨텍스트를 <n>줄 표시합니다" + +#: builtin/grep.c:700 +msgid "shortcut for -C NUM" +msgstr "-C NUM 옵션의 줄임" + +#: builtin/grep.c:703 +msgid "show a line with the function name before matches" +msgstr "일치 항목 앞에 함수 이름 줄을 표시합니다" + +#: builtin/grep.c:705 +msgid "show the surrounding function" +msgstr "들어 있는 함수를 표시합니다" + +#: builtin/grep.c:708 +msgid "read patterns from file" +msgstr "파일에서 패턴을 읽습니다" + +#: builtin/grep.c:710 +msgid "match <pattern>" +msgstr "<패턴>과 일치" + +#: builtin/grep.c:712 +msgid "combine patterns specified with -e" +msgstr "-e 옵션으로 지정한 패턴을 결합합니다" + +#: builtin/grep.c:724 +msgid "indicate hit with exit status without output" +msgstr "출력하지 않고 일치하는 항목을 exit() 상태 번호로 리턴합니다" + +#: builtin/grep.c:726 +msgid "show only matches from files that match all patterns" +msgstr "모든 패턴과 일치하는 파일의 일치하는 부분만 표시합니다" + +#: builtin/grep.c:728 +msgid "show parse tree for grep expression" +msgstr "grep 표현식에 대한 파싱 트리를 표시합니다" + +#: builtin/grep.c:732 +msgid "pager" +msgstr "페이저" + +#: builtin/grep.c:732 +msgid "show matching files in the pager" +msgstr "일치하는 파일을 페이저 프로그램에서 표시합니다" + +#: builtin/grep.c:735 +msgid "allow calling of grep(1) (ignored by this build)" +msgstr "grep(1) 실행을 허용합니다 (이 빌드에서는 무시)" + +#: builtin/grep.c:793 +msgid "no pattern given." +msgstr "패턴을 지정하지 않았습니다." + +#: builtin/grep.c:851 +msgid "--open-files-in-pager only works on the worktree" +msgstr "--open-files-in-pager 옵션은 작업 폴더에서만 동작합니다" + +#: builtin/grep.c:877 +msgid "--cached or --untracked cannot be used with --no-index." +msgstr "--cached 또는 --untracked 옵션은 --no-index 옵션과 같이 쓸 수 없습니다." + +#: builtin/grep.c:882 +msgid "--no-index or --untracked cannot be used with revs." +msgstr "--no-index 또는 --untracked 옵션은 리비전과 같이 쓸 수 없습니다." + +#: builtin/grep.c:885 +msgid "--[no-]exclude-standard cannot be used for tracked contents." +msgstr "--[no-]exclude-standard 옵션은 추적되는 내용에 대해 쓸 수 없습니다." + +#: builtin/grep.c:893 +msgid "both --cached and trees are given." +msgstr "--cached 옵션과 트리를 모두 지정했습니다." + +#: builtin/hash-object.c:80 +msgid "" +"git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] " +"[--] <file>..." +msgstr "" +"git hash-object [-t <종류>] [-w] [--path=<파일> | --no-filters] [--stdin] " +"[--] <파일>..." + +#: builtin/hash-object.c:81 +msgid "git hash-object --stdin-paths" +msgstr "git hash-object --stdin-paths" + +#: builtin/hash-object.c:92 +msgid "type" +msgstr "종류" + +#: builtin/hash-object.c:92 +msgid "object type" +msgstr "오브젝트 종류" + +#: builtin/hash-object.c:93 +msgid "write the object into the object database" +msgstr "오브젝트를 오브젝트 데이터베이스로 씁니다" + +#: builtin/hash-object.c:95 +msgid "read the object from stdin" +msgstr "표준 입력에서 오브젝트를 읽습니다" + +#: builtin/hash-object.c:97 +msgid "store file as is without filters" +msgstr "파일을 필터 없이 그대로 저장합니다" + +#: builtin/hash-object.c:98 +msgid "" +"just hash any random garbage to create corrupt objects for debugging Git" +msgstr "임의의 쓰레기 데이터를 해시해 손상된 오브젝트를 만듭니다 (디버깅용)" + +#: builtin/hash-object.c:99 +msgid "process file as it were from this path" +msgstr "파일이 이 경로에서 온 것처럼 처리합니다" + +#: builtin/help.c:41 +msgid "print all available commands" +msgstr "사용 가능한 모든 명령의 목록을 표시합니다" + +#: builtin/help.c:42 +msgid "print list of useful guides" +msgstr "유용한 안내서 목록을 표시합니다" + +#: builtin/help.c:43 +msgid "show man page" +msgstr "맨 페이지를 표시합니다" + +#: builtin/help.c:44 +msgid "show manual in web browser" +msgstr "웹 브라우저에서 설명서를 표시합니다" + +#: builtin/help.c:46 +msgid "show info page" +msgstr "인포 페이지를 표시합니다" + +#: builtin/help.c:52 +msgid "git help [--all] [--guides] [--man | --web | --info] [<command>]" +msgstr "git help [--all] [--guides] [--man | --web | --info] [<명령>]" + +#: builtin/help.c:64 +#, c-format +msgid "unrecognized help format '%s'" +msgstr "'%s' 도움말 포맷을 인식할 수 없습니다" + +#: builtin/help.c:91 +msgid "Failed to start emacsclient." +msgstr "emacsclient 시작에 실패했습니다." + +#: builtin/help.c:104 +msgid "Failed to parse emacsclient version." +msgstr "emacsclient 버전 파싱에 실패했습니다." + +#: builtin/help.c:112 +#, c-format +msgid "emacsclient version '%d' too old (< 22)." +msgstr "emacsclient '%d' 버전은 너무 과거 (< 22) 버전입니다." + +#: builtin/help.c:130 builtin/help.c:151 builtin/help.c:160 builtin/help.c:168 +#, c-format +msgid "failed to exec '%s': %s" +msgstr "실행 실패: '%s': %s" + +#: builtin/help.c:208 +#, c-format +msgid "" +"'%s': path for unsupported man viewer.\n" +"Please consider using 'man.<tool>.cmd' instead." +msgstr "" +"'%s': 지원하지 않는 맨 페이지 보기 프로그램 경로.\n" +"대신에 'man.<도구>.cmd' 옵션을 사용해 보십시오." + +#: builtin/help.c:220 +#, c-format +msgid "" +"'%s': cmd for supported man viewer.\n" +"Please consider using 'man.<tool>.path' instead." +msgstr "" +"'%s': 지원하지 않는 맨 페이지 보기 프로그램 명령.\n" +"대신에 'man.<도구>.path' 옵션을 사용해 보십시오." + +#: builtin/help.c:337 +#, c-format +msgid "'%s': unknown man viewer." +msgstr "'%s': 알 수 없는 맨 페이지 보기 프로그램." + +#: builtin/help.c:354 +msgid "no man viewer handled the request" +msgstr "요청을 처리한 맨 페이지 보기 프로그램이 없습니다" + +#: builtin/help.c:362 +msgid "no info viewer handled the request" +msgstr "요청을 처리한 인포 페이지 보기 프로그램이 없습니다" + +#: builtin/help.c:411 +msgid "Defining attributes per path" +msgstr "경로마다 속성 정의하기" + +#: builtin/help.c:412 +msgid "Everyday Git With 20 Commands Or So" +msgstr "매일매일 사용하는 20개 내외의 깃 명령" + +#: builtin/help.c:413 +msgid "A Git glossary" +msgstr "깃 용어 사전" + +#: builtin/help.c:414 +msgid "Specifies intentionally untracked files to ignore" +msgstr "의도적으로 추적하지 않는 파일을 무시하게 지정하기" + +#: builtin/help.c:415 +msgid "Defining submodule properties" +msgstr "하위 모듈 속성 정의하기" + +#: builtin/help.c:416 +msgid "Specifying revisions and ranges for Git" +msgstr "깃의 리비전 및 범위를 지정하기" + +#: builtin/help.c:417 +msgid "A tutorial introduction to Git (for version 1.5.1 or newer)" +msgstr "깃 따라하기 안내서 (버전 1.5.1 이후)" + +#: builtin/help.c:418 +msgid "An overview of recommended workflows with Git" +msgstr "추천하는 깃 활용 작업 순서의 개요" + +#: builtin/help.c:430 +msgid "The common Git guides are:\n" +msgstr "자주 사용하는 깃 안내서는 다음과 같습니다:\n" + +#: builtin/help.c:451 builtin/help.c:468 +#, c-format +msgid "usage: %s%s" +msgstr "사용법: %s%s" + +#: builtin/help.c:484 +#, c-format +msgid "`git %s' is aliased to `%s'" +msgstr "`git %s' 명령은 `%s' 명령의 단축입니다" + +#: builtin/index-pack.c:152 +#, c-format +msgid "unable to open %s" +msgstr "%s을(를) 열 수 없습니다" + +#: builtin/index-pack.c:202 +#, c-format +msgid "object type mismatch at %s" +msgstr "오브젝트 종류가 맞지 않습니다 (%s)" + +#: builtin/index-pack.c:222 +#, c-format +msgid "did not receive expected object %s" +msgstr "예상한 %s 오브젝트를 받지 않았습니다" + +#: builtin/index-pack.c:225 +#, c-format +msgid "object %s: expected type %s, found %s" +msgstr "%s 오브젝트: 예상한 종류 %s, 실제 %s" + +#: builtin/index-pack.c:267 +#, c-format +msgid "cannot fill %d byte" +msgid_plural "cannot fill %d bytes" +msgstr[0] "%d 바이트를 채울 수 없습니다" + +#: builtin/index-pack.c:277 +msgid "early EOF" +msgstr "너무 빨리 파일이 끝남" + +#: builtin/index-pack.c:278 +msgid "read error on input" +msgstr "입력에 읽기 오류" + +#: builtin/index-pack.c:290 +msgid "used more bytes than were available" +msgstr "있는 바이트보다 더 많이 사용합니다" + +#: builtin/index-pack.c:297 +msgid "pack too large for current definition of off_t" +msgstr "현재 정의된 off_t에 비해 묶음이 너무 큽니다" + +#: builtin/index-pack.c:313 +#, c-format +msgid "unable to create '%s'" +msgstr "'%s'을(를) 만들 수 없습니다" + +#: builtin/index-pack.c:318 +#, c-format +msgid "cannot open packfile '%s'" +msgstr "'%s' 묶음 파일을 열 수 없습니다" + +#: builtin/index-pack.c:332 +msgid "pack signature mismatch" +msgstr "묶음 서명이 맞지 않습니다" + +#: builtin/index-pack.c:334 +#, c-format +msgid "pack version %<PRIu32> unsupported" +msgstr "묶음의 %<PRIu32> 버전을 지원하지 않습니다" + +#: builtin/index-pack.c:352 +#, c-format +msgid "pack has bad object at offset %lu: %s" +msgstr "묶음의 %lu 오프셋에 잘못된 오브젝트가 있습니다: %s" + +#: builtin/index-pack.c:473 +#, c-format +msgid "inflate returned %d" +msgstr "inflate가 %d번을 리턴했습니다" + +#: builtin/index-pack.c:522 +msgid "offset value overflow for delta base object" +msgstr "델타 베이스 오브젝트에 대해 오프셋 값이 오버플로우" + +#: builtin/index-pack.c:530 +msgid "delta base offset is out of bound" +msgstr "델타 베이스 오프셋이 범위를 벗어났습니다" + +#: builtin/index-pack.c:538 +#, c-format +msgid "unknown object type %d" +msgstr "알 수 없는 오브젝트 종류 %d번" + +#: builtin/index-pack.c:569 +msgid "cannot pread pack file" +msgstr "묶음 파일에 대해 pread를 할 수 없습니다" + +#: builtin/index-pack.c:571 +#, c-format +msgid "premature end of pack file, %lu byte missing" +msgid_plural "premature end of pack file, %lu bytes missing" +msgstr[0] "묶음 파일이 너무 일찍 끝남. %lu 바이트 부족" + +#: builtin/index-pack.c:597 +msgid "serious inflate inconsistency" +msgstr "심각한 inflate 부조화" + +#: builtin/index-pack.c:743 builtin/index-pack.c:749 builtin/index-pack.c:772 +#: builtin/index-pack.c:806 builtin/index-pack.c:815 +#, c-format +msgid "SHA1 COLLISION FOUND WITH %s !" +msgstr "SHA1 충돌이 %s에서 발견되었습니다!" + +#: builtin/index-pack.c:746 builtin/pack-objects.c:162 +#: builtin/pack-objects.c:254 +#, c-format +msgid "unable to read %s" +msgstr "%s을(를) 읽을 수 없습니다" + +#: builtin/index-pack.c:812 +#, c-format +msgid "cannot read existing object %s" +msgstr "기존 %s 오브젝트를 읽을 수 없습니다" + +#: builtin/index-pack.c:826 +#, c-format +msgid "invalid blob object %s" +msgstr "잘못된 블롭 오브젝트 %s" + +#: builtin/index-pack.c:840 +#, c-format +msgid "invalid %s" +msgstr "잘못된 %s" + +#: builtin/index-pack.c:843 +msgid "Error in object" +msgstr "오브젝트에 오류" + +#: builtin/index-pack.c:845 +#, c-format +msgid "Not all child objects of %s are reachable" +msgstr "%s의 모든 하위 오브젝트에 접근할 수 없습니다" + +#: builtin/index-pack.c:917 builtin/index-pack.c:948 +msgid "failed to apply delta" +msgstr "델타를 적용하는데 실패했습니다" + +#: builtin/index-pack.c:1118 +msgid "Receiving objects" +msgstr "오브젝트를 받는 중" + +#: builtin/index-pack.c:1118 +msgid "Indexing objects" +msgstr "오브젝트 인덱스를 만드는 중" + +#: builtin/index-pack.c:1150 +msgid "pack is corrupted (SHA1 mismatch)" +msgstr "묶음이 손상되었습니다 (SHA1 일치하지 않음)" + +#: builtin/index-pack.c:1155 +msgid "cannot fstat packfile" +msgstr "묶음 파일에 대해 fstat()할 수 없습니다" + +#: builtin/index-pack.c:1158 +msgid "pack has junk at the end" +msgstr "묶음의 끝에 쓰레기 데이터가 있습니다" + +#: builtin/index-pack.c:1169 +msgid "confusion beyond insanity in parse_pack_objects()" +msgstr "parse_pack_objects()에서 극심한 혼란" + +#: builtin/index-pack.c:1194 +msgid "Resolving deltas" +msgstr "델타를 알아내는 중" + +#: builtin/index-pack.c:1205 +#, c-format +msgid "unable to create thread: %s" +msgstr "스레드를 만들 수 없습니다: %s" + +#: builtin/index-pack.c:1247 +msgid "confusion beyond insanity" +msgstr "극심한 혼란" + +#: builtin/index-pack.c:1253 +#, c-format +msgid "completed with %d local objects" +msgstr "로컬 오브젝트 %d개 마침" + +#: builtin/index-pack.c:1263 +#, c-format +msgid "Unexpected tail checksum for %s (disk corruption?)" +msgstr "%s에 대해 예상치 못한 테일 체크섬 (디스크 손상?)" + +#: builtin/index-pack.c:1267 +#, c-format +msgid "pack has %d unresolved delta" +msgid_plural "pack has %d unresolved deltas" +msgstr[0] "묶음에 알아내지 못한 델타 %d개가 있습니다" + +#: builtin/index-pack.c:1291 +#, c-format +msgid "unable to deflate appended object (%d)" +msgstr "추가한 오브젝트를 deflate할 수 없습니다 (%d)" + +#: builtin/index-pack.c:1367 +#, c-format +msgid "local object %s is corrupt" +msgstr "%s 로컬 오브젝트가 손상되었습니다" + +#: builtin/index-pack.c:1391 +msgid "error while closing pack file" +msgstr "묶음 파일을 닫는데 오류" + +#: builtin/index-pack.c:1404 +#, c-format +msgid "cannot write keep file '%s'" +msgstr "'%s' 보존 파일을 쓸 수 없습니다" + +#: builtin/index-pack.c:1412 +#, c-format +msgid "cannot close written keep file '%s'" +msgstr "쓴 '%s' 보존 파일을 닫지 못했습니다" + +#: builtin/index-pack.c:1425 +msgid "cannot store pack file" +msgstr "묶음 파일을 저장할 수 없습니다" + +#: builtin/index-pack.c:1436 +msgid "cannot store index file" +msgstr "인덱스 파일을 저장할 수 없습니다" + +#: builtin/index-pack.c:1469 +#, c-format +msgid "bad pack.indexversion=%<PRIu32>" +msgstr "잘못된 pack.indexversion=%<PRIu32>" + +#: builtin/index-pack.c:1475 +#, c-format +msgid "invalid number of threads specified (%d)" +msgstr "잘못된 스레드 수를 지정했습니다 (%d)" + +#: builtin/index-pack.c:1479 builtin/index-pack.c:1663 +#, c-format +msgid "no threads support, ignoring %s" +msgstr "스레드 기능이 없습니다. %s 무시" + +#: builtin/index-pack.c:1537 +#, c-format +msgid "Cannot open existing pack file '%s'" +msgstr "기존 '%s' 묶음 파일을 열 수 없습니다" + +#: builtin/index-pack.c:1539 +#, c-format +msgid "Cannot open existing pack idx file for '%s'" +msgstr "'%s'에 대한 기존 묶음 idx 파일을 열 수 없습니다" + +#: builtin/index-pack.c:1586 +#, c-format +msgid "non delta: %d object" +msgid_plural "non delta: %d objects" +msgstr[0] "델타 아님: 오브젝트 %d개" + +#: builtin/index-pack.c:1593 +#, c-format +msgid "chain length = %d: %lu object" +msgid_plural "chain length = %d: %lu objects" +msgstr[0] "체인 길이 = %d: 오브젝트 %lu개" + +#: builtin/index-pack.c:1623 +msgid "Cannot come back to cwd" +msgstr "현재 디렉터리로 돌아올 수 없습니다" + +#: builtin/index-pack.c:1675 builtin/index-pack.c:1678 +#: builtin/index-pack.c:1690 builtin/index-pack.c:1694 +#, c-format +msgid "bad %s" +msgstr "잘못된 %s" + +#: builtin/index-pack.c:1708 +msgid "--fix-thin cannot be used without --stdin" +msgstr "--fix-thin 옵션은 --stdin 옵션과 같이 쓸 수 없습니다" + +#: builtin/index-pack.c:1712 builtin/index-pack.c:1721 +#, c-format +msgid "packfile name '%s' does not end with '.pack'" +msgstr "'%s' 묶음파일 이름이 '.pack'으로 끝나지 않습니다" + +#: builtin/index-pack.c:1729 +msgid "--verify with no packfile name given" +msgstr "--verify 옵션에 묶음파일 이름을 지정하지 않았습니다" + +#: builtin/init-db.c:55 +#, c-format +msgid "cannot stat '%s'" +msgstr "'%s'을(를) stat()할 수 없습니다" + +#: builtin/init-db.c:61 +#, c-format +msgid "cannot stat template '%s'" +msgstr "'%s' 서식을 stat()할 수 없습니다" + +#: builtin/init-db.c:66 +#, c-format +msgid "cannot opendir '%s'" +msgstr "'%s'을(를) opendir()할 수 없습니다" + +#: builtin/init-db.c:77 +#, c-format +msgid "cannot readlink '%s'" +msgstr "'%s'을(를) readlink()할 수 없습니다" + +#: builtin/init-db.c:79 +#, c-format +msgid "cannot symlink '%s' '%s'" +msgstr "'%s'을(를) '%s'에 symlink()할 수 없습니다" + +#: builtin/init-db.c:85 +#, c-format +msgid "cannot copy '%s' to '%s'" +msgstr "'%s'을(를) '%s'에 복사할 수 없습니다" + +#: builtin/init-db.c:89 +#, c-format +msgid "ignoring template %s" +msgstr "%s 서식을 무시합니다" + +#: builtin/init-db.c:118 +#, c-format +msgid "templates not found %s" +msgstr "%s에 서식이 없습니다" + +#: builtin/init-db.c:131 +#, c-format +msgid "not copying templates of a wrong format version %d from '%s'" +msgstr "'%2$s'에서 잘못된 형식 버전 %1$d의 서식을 복사하지 않습니다" + +#: builtin/init-db.c:309 builtin/init-db.c:312 +#, c-format +msgid "%s already exists" +msgstr "%s 파일이 이미 있습니다" + +#: builtin/init-db.c:340 +#, c-format +msgid "unable to handle file type %d" +msgstr "파일 종류 %d번을 처리할 수 없습니다" + +#: builtin/init-db.c:343 +#, c-format +msgid "unable to move %s to %s" +msgstr "%s을(를) %s(으)로 옮길 수 없습니다" + +#. TRANSLATORS: The first '%s' is either "Reinitialized +#. existing" or "Initialized empty", the second " shared" or +#. "", and the last '%s%s' is the verbatim directory name. +#: builtin/init-db.c:399 +#, c-format +msgid "%s%s Git repository in %s%s\n" +msgstr "%s%s 깃 저장소, 위치 %s%s\n" + +#: builtin/init-db.c:400 +msgid "Reinitialized existing" +msgstr "다시 초기화: 기존" + +#: builtin/init-db.c:400 +msgid "Initialized empty" +msgstr "초기화: 빈" + +#: builtin/init-db.c:401 +msgid " shared" +msgstr " 공유" + +#: builtin/init-db.c:448 +msgid "" +"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--" +"shared[=<permissions>]] [<directory>]" +msgstr "" +"git init [-q | --quiet] [--bare] [--template=<서식-디렉터리>] [--shared[=<권" +"한>]] [<디렉터리>]" + +#: builtin/init-db.c:471 +msgid "permissions" +msgstr "권한" + +#: builtin/init-db.c:472 +msgid "specify that the git repository is to be shared amongst several users" +msgstr "깃 저장소를 다른 사용자가 공유할 수 있게 지정" + +#: builtin/init-db.c:506 builtin/init-db.c:511 +#, c-format +msgid "cannot mkdir %s" +msgstr "%s에 대해 mkdir를 할 수 없습니다" + +#: builtin/init-db.c:515 +#, c-format +msgid "cannot chdir to %s" +msgstr "%s에 대해 chdir를 할 수 없습니다" + +#: builtin/init-db.c:536 +#, c-format +msgid "" +"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" +"dir=<directory>)" +msgstr "" +"%s (또는 --work-tree=<디렉터리>) 허용되지 않음. %s (또는 --git-" +"dir=<directory>) 지정이 없으면" + +#: builtin/init-db.c:564 +#, c-format +msgid "Cannot access work tree '%s'" +msgstr "작업 폴더 '%s'에 접근할 수 없습니다" + +#: builtin/interpret-trailers.c:15 +msgid "" +"git interpret-trailers [--trim-empty] [(--trailer <token>[(=|:)<value>])...] " +"[<file>...]" +msgstr "" +"git interpret-trailers [--trim-empty] [(--trailer <토큰>[(=|:)<값>])...] [<파" +"일>...]" + +#: builtin/interpret-trailers.c:25 +msgid "trim empty trailers" +msgstr "빈 트레일러를 잘라냅니다" + +#: builtin/interpret-trailers.c:26 +msgid "trailer" +msgstr "트레일러" + +#: builtin/interpret-trailers.c:27 +msgid "trailer(s) to add" +msgstr "추가할 트레일러" + +#: builtin/log.c:43 +msgid "git log [<options>] [<revision-range>] [[--] <path>...]" +msgstr "git log [<옵션>] [<리비전-범위>] [[--] <경로>...]" + +#: builtin/log.c:44 +msgid "git show [<options>] <object>..." +msgstr "git show [<옵션>] <오브젝트>..." + +#: builtin/log.c:83 +#, c-format +msgid "invalid --decorate option: %s" +msgstr "잘못된 --decorate 옵션: %s" + +#: builtin/log.c:131 +msgid "suppress diff output" +msgstr "diff를 출력하지 않습니다" + +#: builtin/log.c:132 +msgid "show source" +msgstr "소스를 표시합니다" + +#: builtin/log.c:133 +msgid "Use mail map file" +msgstr "메일 맵 파일을 사용합니다" + +#: builtin/log.c:134 +msgid "decorate options" +msgstr "꾸미기 옵션" + +#: builtin/log.c:137 +msgid "Process line range n,m in file, counting from 1" +msgstr "파일에서 n,m 범위의 줄을 처리합니다 (1부터 시작)" + +#: builtin/log.c:233 +#, c-format +msgid "Final output: %d %s\n" +msgstr "최종 출력: %d %s\n" + +#: builtin/log.c:465 +#, c-format +msgid "git show %s: bad file" +msgstr "git show %s: 잘못된 파일" + +#: builtin/log.c:479 builtin/log.c:572 +#, c-format +msgid "Could not read object %s" +msgstr "%s 오브젝트를 읽을 수 없습니다" + +#: builtin/log.c:596 +#, c-format +msgid "Unknown type: %d" +msgstr "알 수 없는 종류: %d" + +#: builtin/log.c:714 +msgid "format.headers without value" +msgstr "format.headers 설정에 값이 없음" + +#: builtin/log.c:798 +msgid "name of output directory is too long" +msgstr "출력 디렉터리의 이름이 너무 깁니다" + +#: builtin/log.c:813 +#, c-format +msgid "Cannot open patch file %s" +msgstr "%s 패치 파일을 열 수 없습니다" + +#: builtin/log.c:827 +msgid "Need exactly one range." +msgstr "정확히 하나의 범위가 필요합니다." + +#: builtin/log.c:837 +msgid "Not a range." +msgstr "범위가 아닙니다." + +#: builtin/log.c:943 +msgid "Cover letter needs email format" +msgstr "커버레터는 전자메일 형식이어야 합니다" + +#: builtin/log.c:1022 +#, c-format +msgid "insane in-reply-to: %s" +msgstr "정신나간 in-reply-to 헤더: %s" + +#: builtin/log.c:1050 +msgid "git format-patch [<options>] [<since> | <revision-range>]" +msgstr "git format-patch [<옵션>] [<시작시각> | <리비전-범위>]" + +#: builtin/log.c:1095 +msgid "Two output directories?" +msgstr "출력 디렉터리가 두개?" + +#: builtin/log.c:1211 +msgid "use [PATCH n/m] even with a single patch" +msgstr "하나의 패치에 대해서도 [PATCh n/m]을 붙입니다" + +#: builtin/log.c:1214 +msgid "use [PATCH] even with multiple patches" +msgstr "여러 개 패치에 대해서도 [PATCH]를 붙입니다" + +#: builtin/log.c:1218 +msgid "print patches to standard out" +msgstr "패치를 표준 출력으로 표시합니다" + +#: builtin/log.c:1220 +msgid "generate a cover letter" +msgstr "커버레터를 만듭니다" + +#: builtin/log.c:1222 +msgid "use simple number sequence for output file names" +msgstr "출력 파일 이름에 간단한 일련 번호를 사용합니다" + +#: builtin/log.c:1223 +msgid "sfx" +msgstr "확장자" + +#: builtin/log.c:1224 +msgid "use <sfx> instead of '.patch'" +msgstr "'.patch' 대신 <확장자>를 사용합니다" + +#: builtin/log.c:1226 +msgid "start numbering patches at <n> instead of 1" +msgstr "패치 번호를 1 대신 <n>에서 시작합니다" + +#: builtin/log.c:1228 +msgid "mark the series as Nth re-roll" +msgstr "시리즈를 N번째 re-roll로 표시합니다" + +#: builtin/log.c:1230 +msgid "Use [<prefix>] instead of [PATCH]" +msgstr "[PATCH] 대신 [<접두어>]를 사용합니다" + +#: builtin/log.c:1233 +msgid "store resulting files in <dir>" +msgstr "결과 파일을 <디렉터리>에 저장합니다" + +#: builtin/log.c:1236 +msgid "don't strip/add [PATCH]" +msgstr "[PATCH]를 자르거나 추가하지 않습니다" + +#: builtin/log.c:1239 +msgid "don't output binary diffs" +msgstr "바이너리 diff를 만들지 않습니다" + +#: builtin/log.c:1241 +msgid "output all-zero hash in From header" +msgstr "From 헤더에서 모두 0인 해시를 출력합니다" + +#: builtin/log.c:1243 +msgid "don't include a patch matching a commit upstream" +msgstr "업스트림에 있는 패치를 포함하지 않습니다" + +#: builtin/log.c:1245 +msgid "show patch format instead of default (patch + stat)" +msgstr "기본값 (패치 + 통계) 대신 패치 형식을 표시합니다" + +#: builtin/log.c:1247 +msgid "Messaging" +msgstr "메시징" + +#: builtin/log.c:1248 +msgid "header" +msgstr "헤더" + +#: builtin/log.c:1249 +msgid "add email header" +msgstr "전자메일 헤더" + +#: builtin/log.c:1250 builtin/log.c:1252 +msgid "email" +msgstr "전자메일" + +#: builtin/log.c:1250 +msgid "add To: header" +msgstr "To: 헤더를 추가합니다" + +#: builtin/log.c:1252 +msgid "add Cc: header" +msgstr "Cc: 헤더를 추가합니다" + +#: builtin/log.c:1254 +msgid "ident" +msgstr "신원" + +#: builtin/log.c:1255 +msgid "set From address to <ident> (or committer ident if absent)" +msgstr "<신원>에서 From 주소를 설정합니다 (없으면 커미터 주소 신원 사용)" + +#: builtin/log.c:1257 +msgid "message-id" +msgstr "메시지-ID" + +#: builtin/log.c:1258 +msgid "make first mail a reply to <message-id>" +msgstr "첫 메일을 <메시지-ID>에 대한 답장 메일로 만듭니다" + +#: builtin/log.c:1259 builtin/log.c:1262 +msgid "boundary" +msgstr "경계" + +#: builtin/log.c:1260 +msgid "attach the patch" +msgstr "패치를 첨부합니다" + +#: builtin/log.c:1263 +msgid "inline the patch" +msgstr "패치를 본문에 포함합니다" + +#: builtin/log.c:1267 +msgid "enable message threading, styles: shallow, deep" +msgstr "메시지에 스레드를 사용, 스타일: shallow, deep" + +#: builtin/log.c:1269 +msgid "signature" +msgstr "서명" + +#: builtin/log.c:1270 +msgid "add a signature" +msgstr "서명을 추가합니다" + +#: builtin/log.c:1272 +msgid "add a signature from a file" +msgstr "파일에서 서명을 추가합니다" + +#: builtin/log.c:1273 +msgid "don't print the patch filenames" +msgstr "패치 파일 이름을 표시하지 않습니다" + +#: builtin/log.c:1362 +msgid "-n and -k are mutually exclusive." +msgstr "-n 및 -k 옵션은 하나만 써야 합니다." + +#: builtin/log.c:1364 +msgid "--subject-prefix and -k are mutually exclusive." +msgstr "--subject-prefix 및 -k 옵션은 하나만 써야 합니다." + +#: builtin/log.c:1372 +msgid "--name-only does not make sense" +msgstr "--name-only 옵션은 앞뒤가 맞지 않습니다" + +#: builtin/log.c:1374 +msgid "--name-status does not make sense" +msgstr "--name-status 옵션은 앞뒤가 맞지 않습니다" + +#: builtin/log.c:1376 +msgid "--check does not make sense" +msgstr "--check 옵션은 앞뒤가 맞지 않습니다" + +#: builtin/log.c:1401 +msgid "standard output, or directory, which one?" +msgstr "표준 출력이나 디렉터리 중에 하나만 지정해야 합니다." + +#: builtin/log.c:1403 +#, c-format +msgid "Could not create directory '%s'" +msgstr "'%s' 디렉터리를 만들 수 없습니다" + +#: builtin/log.c:1500 +#, c-format +msgid "unable to read signature file '%s'" +msgstr "'%s' 서명 파일을 읽을 수 없습니다" + +#: builtin/log.c:1563 +msgid "Failed to create output files" +msgstr "출력 파일을 만드는데 실패했습니다" + +#: builtin/log.c:1611 +msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]" +msgstr "git cherry [-v] [<업스트림> [<헤드> [<한계값>]]]" + +#: builtin/log.c:1665 +#, c-format +msgid "" +"Could not find a tracked remote branch, please specify <upstream> manually.\n" +msgstr "추적되는 리모트 브랜치를 찾을 수 없습니다. <업스트림>을 수동으로 지정하십시오.\n" + +#: builtin/log.c:1676 builtin/log.c:1678 builtin/log.c:1690 +#, c-format +msgid "Unknown commit %s" +msgstr "알 수 없는 커밋 %s" + +#: builtin/ls-files.c:358 +msgid "git ls-files [<options>] [<file>...]" +msgstr "git ls-files [<옵션>] [<파일>...]" + +#: builtin/ls-files.c:415 +msgid "identify the file status with tags" +msgstr "파일 상태를 태그와 같이 표시합니다" + +#: builtin/ls-files.c:417 +msgid "use lowercase letters for 'assume unchanged' files" +msgstr "'변경되지 않았다고 가정' 파일에 소문자를 사용합니다" + +#: builtin/ls-files.c:419 +msgid "show cached files in the output (default)" +msgstr "출력에 캐시된 파일을 표시합니다 (기본값)" + +#: builtin/ls-files.c:421 +msgid "show deleted files in the output" +msgstr "출력에 삭제된 파일을 표시합니다" + +#: builtin/ls-files.c:423 +msgid "show modified files in the output" +msgstr "출력에 수정된 파일을 표시합니다" + +#: builtin/ls-files.c:425 +msgid "show other files in the output" +msgstr "출력에 기타 파일을 표시합니다" + +#: builtin/ls-files.c:427 +msgid "show ignored files in the output" +msgstr "출력에 무시된 파일을 표시합니다" + +#: builtin/ls-files.c:430 +msgid "show staged contents' object name in the output" +msgstr "출력에 커밋 표시된 내용의 오브젝트 이름을 표시합니다" + +#: builtin/ls-files.c:432 +msgid "show files on the filesystem that need to be removed" +msgstr "파일 시스템에서 제거해야 하는 파일을 표시합니다" + +#: builtin/ls-files.c:434 +msgid "show 'other' directories' names only" +msgstr "기타 디렉터리의 이름만 표시합니다" + +#: builtin/ls-files.c:437 +msgid "don't show empty directories" +msgstr "빈 디렉터리 표시하지 않기" + +#: builtin/ls-files.c:440 +msgid "show unmerged files in the output" +msgstr "출력에 병합하지 않은 파일을 표시합니다" + +#: builtin/ls-files.c:442 +msgid "show resolve-undo information" +msgstr "resolve-undo 정보를 표시합니다" + +#: builtin/ls-files.c:444 +msgid "skip files matching pattern" +msgstr "패턴에 일치하는 파일을 건너뜁니다" + +#: builtin/ls-files.c:447 +msgid "exclude patterns are read from <file>" +msgstr "제외할 패턴을 <파일>에서 읽습니다" + +#: builtin/ls-files.c:450 +msgid "read additional per-directory exclude patterns in <file>" +msgstr "<파일>에서 추가적인 디렉토리별 제외 패턴을 읽습니다" + +#: builtin/ls-files.c:452 +msgid "add the standard git exclusions" +msgstr "표준 깃 제외 패턴을 추가합니다" + +#: builtin/ls-files.c:455 +msgid "make the output relative to the project top directory" +msgstr "최상위 디렉토리 상대 경로로 출력합니다" + +#: builtin/ls-files.c:458 +msgid "if any <file> is not in the index, treat this as an error" +msgstr "<파일>이 인덱스 안에 없으면 오류로 취급합니다" + +#: builtin/ls-files.c:459 +msgid "tree-ish" +msgstr "트리-따위" + +#: builtin/ls-files.c:460 +msgid "pretend that paths removed since <tree-ish> are still present" +msgstr "<트리-따위> 뒤로 제거한 경로가 있다고 가정합니다" + +#: builtin/ls-files.c:462 +msgid "show debugging data" +msgstr "디버깅 데이터를 표시합니다" + +#: builtin/ls-tree.c:28 +msgid "git ls-tree [<options>] <tree-ish> [<path>...]" +msgstr "git ls-tree [<옵션>] <트리-따위> [<경로>...]" + +#: builtin/ls-tree.c:128 +msgid "only show trees" +msgstr "트리만 표시" + +#: builtin/ls-tree.c:130 +msgid "recurse into subtrees" +msgstr "하위 트리로 재귀적으로 적용" + +#: builtin/ls-tree.c:132 +msgid "show trees when recursing" +msgstr "재귀적으로 적용할 때 트리 표시" + +#: builtin/ls-tree.c:135 +msgid "terminate entries with NUL byte" +msgstr "항목을 NUL 바이트로 끝냅니다" + +#: builtin/ls-tree.c:136 +msgid "include object size" +msgstr "오브젝트 크기 포함" + +#: builtin/ls-tree.c:138 builtin/ls-tree.c:140 +msgid "list only filenames" +msgstr "파일 이름만 목록 표시" + +#: builtin/ls-tree.c:143 +msgid "use full path names" +msgstr "전체 경로 이름 사용" + +#: builtin/ls-tree.c:145 +msgid "list entire tree; not just current directory (implies --full-name)" +msgstr "전체 트리 목록 표시, 현재 디렉터리만 아니라 (--full-name 옵션 포함)" + +#: builtin/merge.c:45 +msgid "git merge [<options>] [<commit>...]" +msgstr "git merge [<옵션>] [<커밋>...]" + +#: builtin/merge.c:46 +msgid "git merge [<options>] <msg> HEAD <commit>" +msgstr "git merge [<옵션>] <메시지> HEAD <커밋>" + +#: builtin/merge.c:47 +msgid "git merge --abort" +msgstr "git merge --abort" + +#: builtin/merge.c:100 +msgid "switch `m' requires a value" +msgstr "`m' 옵션에는 값이 필요합니다" + +#: builtin/merge.c:137 +#, c-format +msgid "Could not find merge strategy '%s'.\n" +msgstr "'%s' 병합 전략을 찾을 수 없습니다.\n" + +#: builtin/merge.c:138 +#, c-format +msgid "Available strategies are:" +msgstr "사용 가능한 전략은:" + +#: builtin/merge.c:143 +#, c-format +msgid "Available custom strategies are:" +msgstr "사용 가능한 사용자 설정 전략은:" + +#: builtin/merge.c:193 builtin/pull.c:119 +msgid "do not show a diffstat at the end of the merge" +msgstr "병합이 끝날 때 diffstat을 표시하지 않습니다" + +#: builtin/merge.c:196 builtin/pull.c:122 +msgid "show a diffstat at the end of the merge" +msgstr "병합이 끝날 때 diffstat을 표시합니다" + +#: builtin/merge.c:197 builtin/pull.c:125 +msgid "(synonym to --stat)" +msgstr "(--stat 옵션과 동일)" + +#: builtin/merge.c:199 builtin/pull.c:128 +msgid "add (at most <n>) entries from shortlog to merge commit message" +msgstr "병합 커밋의 메시지에 shortlog 항목을 (최대 <n>개) 추가합니다" + +#: builtin/merge.c:202 builtin/pull.c:131 +msgid "create a single commit instead of doing a merge" +msgstr "병합하는 대신 하나의 커밋을 만듭니다" + +#: builtin/merge.c:204 builtin/pull.c:134 +msgid "perform a commit if the merge succeeds (default)" +msgstr "병합이 성공하면 커밋을 합니다 (기본값)" + +#: builtin/merge.c:206 builtin/pull.c:137 +msgid "edit message before committing" +msgstr "커밋 전에 메시지를 편집합니다" + +#: builtin/merge.c:207 +msgid "allow fast-forward (default)" +msgstr "정방향 진행을 허용합니다 (기본값)" + +#: builtin/merge.c:209 builtin/pull.c:143 +msgid "abort if fast-forward is not possible" +msgstr "정방향 진행이 불가능하면 중지합니다" + +#: builtin/merge.c:213 +msgid "Verify that the named commit has a valid GPG signature" +msgstr "이름 붙인 커밋에 올바른 GPG 서명이 있는지 검증합니다" + +#: builtin/merge.c:214 builtin/notes.c:767 builtin/pull.c:148 +#: builtin/revert.c:89 +msgid "strategy" +msgstr "전략" + +#: builtin/merge.c:215 builtin/pull.c:149 +msgid "merge strategy to use" +msgstr "사용할 병합 전략" + +#: builtin/merge.c:216 builtin/pull.c:152 +msgid "option=value" +msgstr "옵션=값" + +#: builtin/merge.c:217 builtin/pull.c:153 +msgid "option for selected merge strategy" +msgstr "선택한 병합 전략에 대한 옵션" + +#: builtin/merge.c:219 +msgid "merge commit message (for a non-fast-forward merge)" +msgstr "병합 커밋 메시지 (정방향이 아닌 병합에 대해)" + +#: builtin/merge.c:223 +msgid "abort the current in-progress merge" +msgstr "현재 진행 중인 병합을 중지합니다" + +#: builtin/merge.c:251 +msgid "could not run stash." +msgstr "stash를 실행할 수 없습니다." + +#: builtin/merge.c:256 +msgid "stash failed" +msgstr "stash 실패" + +#: builtin/merge.c:261 +#, c-format +msgid "not a valid object: %s" +msgstr "올바른 오브젝트가 아닙니다: %s" + +#: builtin/merge.c:280 builtin/merge.c:297 +msgid "read-tree failed" +msgstr "read-tree 실패" + +#: builtin/merge.c:327 +msgid " (nothing to squash)" +msgstr " (합칠 내용이 없습니다)" + +#: builtin/merge.c:340 +#, c-format +msgid "Squash commit -- not updating HEAD\n" +msgstr "커밋 합치기 -- HEAD를 업데이트하지 않습니다\n" + +#: builtin/merge.c:344 builtin/merge.c:763 builtin/merge.c:975 +#: builtin/merge.c:988 +#, c-format +msgid "Could not write to '%s'" +msgstr "'%s'에 쓸 수 없습니다" + +#: builtin/merge.c:372 +msgid "Writing SQUASH_MSG" +msgstr "SQUASH_MSG를 쓰는 중" + +#: builtin/merge.c:374 +msgid "Finishing SQUASH_MSG" +msgstr "SQUASH_MSG를 마치는 중" + +#: builtin/merge.c:397 +#, c-format +msgid "No merge message -- not updating HEAD\n" +msgstr "병합 메시지가 없습니다 -- HEAD를 업데이트하지 않습니다\n" + +#: builtin/merge.c:447 +#, c-format +msgid "'%s' does not point to a commit" +msgstr "'%s'이(가) 커밋을 가리키지 않습니다" + +#: builtin/merge.c:537 +#, c-format +msgid "Bad branch.%s.mergeoptions string: %s" +msgstr "잘못된 branch.%s.mergeoptions 문자열: %s" + +#: builtin/merge.c:656 +msgid "Not handling anything other than two heads merge." +msgstr "두 개의 헤드 병합 외에는 처리하지 않습니다." + +#: builtin/merge.c:670 +#, c-format +msgid "Unknown option for merge-recursive: -X%s" +msgstr "merge-recursive에 대해 알 수 없는 옵션: -X%s" + +#: builtin/merge.c:683 +#, c-format +msgid "unable to write %s" +msgstr "%s에 쓸 수 없습니다" + +#: builtin/merge.c:772 +#, c-format +msgid "Could not read from '%s'" +msgstr "'%s'에서 읽을 수 없습니다" + +#: builtin/merge.c:781 +#, c-format +msgid "Not committing merge; use 'git commit' to complete the merge.\n" +msgstr "병합을 커밋하지 않습니다. 병합을 마치려면 'git commit'을 사용하십시오.\n" + +#: builtin/merge.c:787 +#, c-format +msgid "" +"Please enter a commit message to explain why this merge is necessary,\n" +"especially if it merges an updated upstream into a topic branch.\n" +"\n" +"Lines starting with '%c' will be ignored, and an empty message aborts\n" +"the commit.\n" +msgstr "" +"왜 이 병합이 필요한지를 설명하는 커밋 메시지를 입력하십시오. 특히\n" +"업스트림 업데이트를 어떤 목적용 브랜치로 병합할 때는 반드시 그렇게\n" +"하십시오.\n" +"\n" +"'%c' 문자로 시작하는 줄은 무시되고, 메시지가 비어 있으면 커밋을\n" +"중지합니다.\n" + +#: builtin/merge.c:811 +msgid "Empty commit message." +msgstr "빈 커밋 메시지." + +#: builtin/merge.c:823 +#, c-format +msgid "Wonderful.\n" +msgstr "훌륭합니다.\n" + +#: builtin/merge.c:878 +#, c-format +msgid "Automatic merge failed; fix conflicts and then commit the result.\n" +msgstr "자동 병합이 실패했습니다. 충돌을 바로잡고 결과물을 커밋하십시오.\n" + +#: builtin/merge.c:894 +#, c-format +msgid "'%s' is not a commit" +msgstr "'%s'은(는) 커밋이 아닙니다" + +#: builtin/merge.c:935 +msgid "No current branch." +msgstr "현재 브랜치가 없습니다." + +#: builtin/merge.c:937 +msgid "No remote for the current branch." +msgstr "현재 브랜치에 대한 리모트가 없습니다." + +#: builtin/merge.c:939 +msgid "No default upstream defined for the current branch." +msgstr "현재 브랜치에 대해 기본 업스트림을 지정하지 않았습니다." + +#: builtin/merge.c:944 +#, c-format +msgid "No remote-tracking branch for %s from %s" +msgstr "리모트 %2$s에서 %1$s에 대한 리모트 추적 브랜치가 없습니다" + +#: builtin/merge.c:1079 +#, c-format +msgid "could not close '%s'" +msgstr "'%s'을(를) 닫을 수 없습니다" + +#: builtin/merge.c:1206 +msgid "There is no merge to abort (MERGE_HEAD missing)." +msgstr "중지할 병합 작업이 없습니다. (MERGE_HEAD가 없음)" + +#: builtin/merge.c:1222 +msgid "" +"You have not concluded your merge (MERGE_HEAD exists).\n" +"Please, commit your changes before you merge." +msgstr "" +"병합을 마치지 않았습니다. (MERGE_HEAD 있음)\n" +"병합하기 전에 변경 사항을 커밋하십시오." + +#: builtin/merge.c:1229 +msgid "" +"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" +"Please, commit your changes before you merge." +msgstr "" +"커밋 빼오기를 마치지 않았습니다. (COMMIT_PICK_HEAD 있음)\n" +"병합하기 전에 변경 사항을 커밋하십시오." + +#: builtin/merge.c:1232 +msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." +msgstr "커밋 빼오기를 마치지 않았습니다. (CHERRY_PICK_HEAD 있음)" + +#: builtin/merge.c:1241 +msgid "You cannot combine --squash with --no-ff." +msgstr "--squash 옵션을 --no-ff 옵션과 같이 쓸 수 없습니다." + +#: builtin/merge.c:1249 +msgid "No commit specified and merge.defaultToUpstream not set." +msgstr "커밋을 지정하지 않았고 merge.defaultToUpstream를 설정하지 않았습니다." + +#: builtin/merge.c:1266 +msgid "Squash commit into empty head not supported yet" +msgstr "빈 헤드로 커밋을 합치기는 지원하지 않습니다" + +#: builtin/merge.c:1268 +msgid "Non-fast-forward commit does not make sense into an empty head" +msgstr "정방향이 아닌 커밋은 빈 헤드에서는 앞뒤가 맞지 않습니다" + +#: builtin/merge.c:1274 +#, c-format +msgid "%s - not something we can merge" +msgstr "%s - 병합할 수 있는 항목이 아닙니다" + +#: builtin/merge.c:1276 +msgid "Can merge only exactly one commit into empty head" +msgstr "빈 헤드에는 정확히 하나의 커밋만 병합할 수 있습니다" + +#: builtin/merge.c:1331 +#, c-format +msgid "Commit %s has an untrusted GPG signature, allegedly by %s." +msgstr "%s 커밋에 신뢰하지 않는 (서명자가 %s라고 하는) GPG 서명이 있습니다." + +#: builtin/merge.c:1334 +#, c-format +msgid "Commit %s has a bad GPG signature allegedly by %s." +msgstr "%s 커밋에 잘못된 (서명자가 %s라고 하는) GPG 서명이 있습니다." + +#: builtin/merge.c:1337 +#, c-format +msgid "Commit %s does not have a GPG signature." +msgstr "%s 커밋에 GPG 서명이 없습니다." + +#: builtin/merge.c:1340 +#, c-format +msgid "Commit %s has a good GPG signature by %s\n" +msgstr "%s 커밋에 %s의 올바른 GPG 서명이 없습니다\n" + +#: builtin/merge.c:1423 +#, c-format +msgid "Updating %s..%s\n" +msgstr "업데이트 중 %s..%s\n" + +#: builtin/merge.c:1460 +#, c-format +msgid "Trying really trivial in-index merge...\n" +msgstr "아주 간단한 인덱스 내부 병합을 시도합니다...\n" + +#: builtin/merge.c:1467 +#, c-format +msgid "Nope.\n" +msgstr "아님.\n" + +#: builtin/merge.c:1499 +msgid "Not possible to fast-forward, aborting." +msgstr "정방향이 불가능하므로, 중지합니다." + +#: builtin/merge.c:1522 builtin/merge.c:1601 +#, c-format +msgid "Rewinding the tree to pristine...\n" +msgstr "트리를 본래 위치로 되돌립니다...\n" + +#: builtin/merge.c:1526 +#, c-format +msgid "Trying merge strategy %s...\n" +msgstr "병합 전략 %s 시도...\n" + +#: builtin/merge.c:1592 +#, c-format +msgid "No merge strategy handled the merge.\n" +msgstr "병합을 처리한 전략이 없습니다.\n" + +#: builtin/merge.c:1594 +#, c-format +msgid "Merge with strategy %s failed.\n" +msgstr "전략 %s(으)로 병합이 실패했습니다.\n" + +#: builtin/merge.c:1603 +#, c-format +msgid "Using the %s to prepare resolving by hand.\n" +msgstr "수동 해결의 준비를 위해 %s 전략을 사용합니다.\n" + +#: builtin/merge.c:1615 +#, c-format +msgid "Automatic merge went well; stopped before committing as requested\n" +msgstr "자동 병합이 잘 진행되었습니다. 요청한대로 커밋 전에 중지합니다\n" + +#: builtin/merge-base.c:29 +msgid "git merge-base [-a | --all] <commit> <commit>..." +msgstr "git merge-base [-a | --all] <커밋> <커밋>..." + +#: builtin/merge-base.c:30 +msgid "git merge-base [-a | --all] --octopus <commit>..." +msgstr "git merge-base [-a | --all] --octopus <커밋>..." + +#: builtin/merge-base.c:31 +msgid "git merge-base --independent <commit>..." +msgstr "git merge-base --independent <커밋>..." + +#: builtin/merge-base.c:32 +msgid "git merge-base --is-ancestor <commit> <commit>" +msgstr "git merge-base --is-ancestor <커밋> <커밋>" + +#: builtin/merge-base.c:33 +msgid "git merge-base --fork-point <ref> [<commit>]" +msgstr "git merge-base --fork-point <레퍼런스> [<커밋>]" + +#: builtin/merge-base.c:214 +msgid "output all common ancestors" +msgstr "모든 과거 공통 커밋을 출력합니다" + +#: builtin/merge-base.c:216 +msgid "find ancestors for a single n-way merge" +msgstr "하나의 n-방향 병합에 대한 과거 커밋을 찾습니다" + +#: builtin/merge-base.c:218 +msgid "list revs not reachable from others" +msgstr "다른 곳에서 접근 불가능한 리비전 목록을 출력합니다" + +#: builtin/merge-base.c:220 +msgid "is the first one ancestor of the other?" +msgstr "첫번째가 다른 것의 과거 커밋인지 여부?" + +#: builtin/merge-base.c:222 +msgid "find where <commit> forked from reflog of <ref>" +msgstr "<레퍼런스>의 reflog에서 <커밋>이 분리된 위치를 찾습니다" + +#: builtin/merge-file.c:8 +msgid "" +"git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> " +"<orig-file> <file2>" +msgstr "git merge-file [<옵션>] [-L <이름1> [-L <orig> [-L <이름2>]]] <파일1> <본래-파일> <파일2>" + +#: builtin/merge-file.c:33 +msgid "send results to standard output" +msgstr "결과를 표준 출력으로 보냅니다" + +#: builtin/merge-file.c:34 +msgid "use a diff3 based merge" +msgstr "diff3 기반 병합을 사용합니다" + +#: builtin/merge-file.c:35 +msgid "for conflicts, use our version" +msgstr "충돌이 발생하면, 우리쪽 버전을 사용합니다" + +#: builtin/merge-file.c:37 +msgid "for conflicts, use their version" +msgstr "충돌이 발생하면, 상대편 버전을 사용합니다" + +#: builtin/merge-file.c:39 +msgid "for conflicts, use a union version" +msgstr "충돌이 발생하면, 합친 버전을 사용합니다" + +#: builtin/merge-file.c:42 +msgid "for conflicts, use this marker size" +msgstr "충돌이 발생하면, 이 크기로 표시합니다" + +#: builtin/merge-file.c:43 +msgid "do not warn about conflicts" +msgstr "충돌에 대해 경고하지 않습니다" + +#: builtin/merge-file.c:45 +msgid "set labels for file1/orig-file/file2" +msgstr "<파일1>/<본래-파일>/<파일2>에 대한 레이블을 설정합니다" + +#: builtin/mktree.c:64 +msgid "git mktree [-z] [--missing] [--batch]" +msgstr "git mktree [-z] [--missing] [--batch]" + +#: builtin/mktree.c:150 +msgid "input is NUL terminated" +msgstr "입력이 NUL로 끝납니다" + +#: builtin/mktree.c:151 builtin/write-tree.c:24 +msgid "allow missing objects" +msgstr "없는 오브젝트를 허용합니다" + +#: builtin/mktree.c:152 +msgid "allow creation of more than one tree" +msgstr "여러개 트리 만들기를 허용합니다" + +#: builtin/mv.c:15 +msgid "git mv [<options>] <source>... <destination>" +msgstr "git mv [<옵션>] <원본>... <대상>" + +#: builtin/mv.c:69 +#, c-format +msgid "Directory %s is in index and no submodule?" +msgstr "%s 디렉터리가 인덱스에 있고 하위 모듈이 없습니다?" + +#: builtin/mv.c:71 +msgid "Please stage your changes to .gitmodules or stash them to proceed" +msgstr "계속하려면 .gitmodules의 변경 사항을 스테이지에 넣거나 stash 하십시오" + +#: builtin/mv.c:89 +#, c-format +msgid "%.*s is in index" +msgstr "%.*s이(가) 인덱스에 있습니다" + +#: builtin/mv.c:111 +msgid "force move/rename even if target exists" +msgstr "대상이 이미 있어도 강제로 옮기기/이름 바꾸기를 합니다" + +#: builtin/mv.c:112 +msgid "skip move/rename errors" +msgstr "옮기기/이름 바꾸기 오류를 건너 뜁니다" + +#: builtin/mv.c:151 +#, c-format +msgid "destination '%s' is not a directory" +msgstr "대상이 ('%s') 디렉터리가 아닙니다" + +#: builtin/mv.c:162 +#, c-format +msgid "Checking rename of '%s' to '%s'\n" +msgstr "'%s'을(를) '%s'(으)로 이름 바꾸기합니다\n" + +#: builtin/mv.c:166 +msgid "bad source" +msgstr "잘못된 원본" + +#: builtin/mv.c:169 +msgid "can not move directory into itself" +msgstr "디렉터리를 자기 자신으로 옮길 수 없습니다" + +#: builtin/mv.c:172 +msgid "cannot move directory over file" +msgstr "디렉터리를 파일로 옮길 수 없습니다" + +#: builtin/mv.c:181 +msgid "source directory is empty" +msgstr "원본 디렉터리가 비어 있습니다" + +#: builtin/mv.c:206 +msgid "not under version control" +msgstr "버전 컨트롤 중이 아닙니다" + +#: builtin/mv.c:209 +msgid "destination exists" +msgstr "대상이 있습니다" + +#: builtin/mv.c:217 +#, c-format +msgid "overwriting '%s'" +msgstr "'%s' 덮어쓰기" + +#: builtin/mv.c:220 +msgid "Cannot overwrite" +msgstr "덮어쓸 수 없습니다" + +#: builtin/mv.c:223 +msgid "multiple sources for the same target" +msgstr "동일한 대상에 대해 여러 개 원본" + +#: builtin/mv.c:225 +msgid "destination directory does not exist" +msgstr "대상 디렉터리가 없습니다" + +#: builtin/mv.c:232 +#, c-format +msgid "%s, source=%s, destination=%s" +msgstr "%s, 원본=%s, 대상=%s" + +#: builtin/mv.c:253 +#, c-format +msgid "Renaming %s to %s\n" +msgstr "이름 바꾸기, '%s'에서 '%s'(으)로\n" + +#: builtin/mv.c:256 builtin/remote.c:728 builtin/repack.c:365 +#, c-format +msgid "renaming '%s' failed" +msgstr "'%s'의 이름 바꾸기가 실패했습니다" + +#: builtin/name-rev.c:251 +msgid "git name-rev [<options>] <commit>..." +msgstr "git name-rev [<옵션>] <커밋>..." + +#: builtin/name-rev.c:252 +msgid "git name-rev [<options>] --all" +msgstr "git name-rev [<옵션>] --all" + +#: builtin/name-rev.c:253 +msgid "git name-rev [<options>] --stdin" +msgstr "git name-rev [<옵션>] --stdin" + +#: builtin/name-rev.c:305 +msgid "print only names (no SHA-1)" +msgstr "이름만 표시 (SHA-1 없이)" + +#: builtin/name-rev.c:306 +msgid "only use tags to name the commits" +msgstr "커밋을 지정할 때 태그만 사용합니다" + +#: builtin/name-rev.c:308 +msgid "only use refs matching <pattern>" +msgstr "<패턴>과 일치하는 레퍼런스만 사용합니다" + +#: builtin/name-rev.c:310 +msgid "list all commits reachable from all refs" +msgstr "모든 레퍼런스에서 접근 가능한 모든 커밋 목록을 표시합니다" + +#: builtin/name-rev.c:311 +msgid "read from stdin" +msgstr "표준입력에서 읽습니다" + +#: builtin/name-rev.c:312 +msgid "allow to print `undefined` names (default)" +msgstr "`정의되지 않은' 이름 표시를 허용합니다 (기본값)" + +#: builtin/name-rev.c:318 +msgid "dereference tags in the input (internal use)" +msgstr "입력의 태그 레퍼런스를 따라갑니다 (내부 사용)" + +#: builtin/notes.c:25 +msgid "git notes [--ref <notes-ref>] [list [<object>]]" +msgstr "git notes [--ref <노트-레퍼런스>] [list [<오브젝트>]]" + +#: builtin/notes.c:26 +msgid "" +"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> " +"| (-c | -C) <object>] [<object>]" +msgstr "" +"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <메시지> | -F <파" +"일> | (-c | -C) <오브젝트>] [<오브젝트>]" + +#: builtin/notes.c:27 +msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>" +msgstr "git notes [--ref <노트-레퍼런스>] copy [-f] <원본-오브젝트> <대상-오브젝트>" + +#: builtin/notes.c:28 +msgid "" +"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | " +"(-c | -C) <object>] [<object>]" +msgstr "" +"git notes [--ref <쪽지-레퍼런스>] append [--allow-empty] [-m <메시지> | -F <" +"파일> | (-c | -C) <오브젝트>] [<오브젝트>]" + +#: builtin/notes.c:29 +msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]" +msgstr "git notes [--ref <쪽지-레퍼런스>] edit [--allow-empty] [<오브젝트>]" + +#: builtin/notes.c:30 +msgid "git notes [--ref <notes-ref>] show [<object>]" +msgstr "git notes [--ref <notes-ref>] show [<오브젝트>]" + +#: builtin/notes.c:31 +msgid "" +"git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>" +msgstr "git notes [--ref <노트-레퍼런스>] merge [-v | -q] [-s <전략>] <노트-레퍼런스>" + +#: builtin/notes.c:32 +msgid "git notes merge --commit [-v | -q]" +msgstr "git notes merge --commit [-v | -q]" + +#: builtin/notes.c:33 +msgid "git notes merge --abort [-v | -q]" +msgstr "git notes merge --abort [-v | -q]" + +#: builtin/notes.c:34 +msgid "git notes [--ref <notes-ref>] remove [<object>...]" +msgstr "git notes [--ref <노트-레퍼런스>] remove [<오브젝트>...]" + +#: builtin/notes.c:35 +msgid "git notes [--ref <notes-ref>] prune [-n | -v]" +msgstr "git notes [--ref <노트-레퍼런스>] prune [-n | -v]" + +#: builtin/notes.c:36 +msgid "git notes [--ref <notes-ref>] get-ref" +msgstr "git notes [--ref <노트-레퍼런스>] get-ref" + +#: builtin/notes.c:41 +msgid "git notes [list [<object>]]" +msgstr "git notes [list [<오브젝트>]]" + +#: builtin/notes.c:46 +msgid "git notes add [<options>] [<object>]" +msgstr "git notes add [<옵션>] [<오브젝트>]" + +#: builtin/notes.c:51 +msgid "git notes copy [<options>] <from-object> <to-object>" +msgstr "git notes copy [<옵션>] <원본-오브젝트> <대상-오브젝트>" + +#: builtin/notes.c:52 +msgid "git notes copy --stdin [<from-object> <to-object>]..." +msgstr "git notes copy --stdin [<원본-오브젝트> <대상-오브젝트>]..." + +#: builtin/notes.c:57 +msgid "git notes append [<options>] [<object>]" +msgstr "git notes append [<옵션>] [<오브젝트>]" + +#: builtin/notes.c:62 +msgid "git notes edit [<object>]" +msgstr "git notes edit [<오브젝트>]" + +#: builtin/notes.c:67 +msgid "git notes show [<object>]" +msgstr "git notes show [<오브젝트>]" + +#: builtin/notes.c:72 +msgid "git notes merge [<options>] <notes-ref>" +msgstr "git notes merge [<옵션>] <쪽지-레퍼런스>" + +#: builtin/notes.c:73 +msgid "git notes merge --commit [<options>]" +msgstr "git notes merge --commit [<옵션>]" + +#: builtin/notes.c:74 +msgid "git notes merge --abort [<options>]" +msgstr "git notes merge --abort [<옵션>]" + +#: builtin/notes.c:79 +msgid "git notes remove [<object>]" +msgstr "git notes remove [<오브젝트>]" + +#: builtin/notes.c:84 +msgid "git notes prune [<options>]" +msgstr "git notes prune [<옵션>]" + +#: builtin/notes.c:89 +msgid "git notes get-ref" +msgstr "git notes get-ref" + +#: builtin/notes.c:147 +#, c-format +msgid "unable to start 'show' for object '%s'" +msgstr "'%s' 오브젝트에 대해 'show'를 시작할 수 없습니다" + +#: builtin/notes.c:151 +msgid "could not read 'show' output" +msgstr "'show' 출력을 읽을 수 없습니다" + +#: builtin/notes.c:159 +#, c-format +msgid "failed to finish 'show' for object '%s'" +msgstr "오브젝트 '%s'에 대해 'show'를 마치는데 실패했습니다" + +#: builtin/notes.c:174 builtin/tag.c:248 +#, c-format +msgid "could not create file '%s'" +msgstr "'%s' 파일을 만들 수 없습니다" + +#: builtin/notes.c:193 +msgid "Please supply the note contents using either -m or -F option" +msgstr "노트 내용을 -m 또는 -F 옵션으로 입력하십시오" + +#: builtin/notes.c:202 +msgid "unable to write note object" +msgstr "노트 오브젝트를 쓸 수 없습니다" + +#: builtin/notes.c:204 +#, c-format +msgid "The note contents have been left in %s" +msgstr "노트 내용은 %s에 남습니다" + +#: builtin/notes.c:232 builtin/tag.c:440 +#, c-format +msgid "cannot read '%s'" +msgstr "'%s'을(를) 읽을 수 없습니다" + +#: builtin/notes.c:234 builtin/tag.c:443 +#, c-format +msgid "could not open or read '%s'" +msgstr "'%s'을(를) 열거나 읽을 수 없습니다" + +#: builtin/notes.c:253 builtin/notes.c:304 builtin/notes.c:306 +#: builtin/notes.c:366 builtin/notes.c:421 builtin/notes.c:507 +#: builtin/notes.c:512 builtin/notes.c:590 builtin/notes.c:653 +#: builtin/notes.c:877 builtin/tag.c:456 +#, c-format +msgid "Failed to resolve '%s' as a valid ref." +msgstr "'%s'을(를) 올바른 레퍼런스로 알아내는데 실패했습니다." + +#: builtin/notes.c:256 +#, c-format +msgid "Failed to read object '%s'." +msgstr "'%s' 오브젝트 읽기에 실패했습니다." + +#: builtin/notes.c:260 +#, c-format +msgid "Cannot read note data from non-blob object '%s'." +msgstr "블롭이 아닌 '%s' 오브젝트에 대해 노트 데이터를 읽을 수 없습니다." + +#: builtin/notes.c:359 builtin/notes.c:414 builtin/notes.c:490 +#: builtin/notes.c:502 builtin/notes.c:578 builtin/notes.c:646 +#: builtin/notes.c:942 +msgid "too many parameters" +msgstr "파라미터가 너무 많습니다" + +#: builtin/notes.c:372 builtin/notes.c:659 +#, c-format +msgid "No note found for object %s." +msgstr "%s 오브젝트에 대해 노트가 없습니다." + +#: builtin/notes.c:393 builtin/notes.c:556 +msgid "note contents as a string" +msgstr "문자열로 노트 내용" + +#: builtin/notes.c:396 builtin/notes.c:559 +msgid "note contents in a file" +msgstr "파일 안에 노트 내용" + +#: builtin/notes.c:399 builtin/notes.c:562 +msgid "reuse and edit specified note object" +msgstr "지정한 노트 오브젝트를 재사용하고 편집합니다" + +#: builtin/notes.c:402 builtin/notes.c:565 +msgid "reuse specified note object" +msgstr "지정한 노트 오브젝트를 재사용합니다" + +#: builtin/notes.c:405 builtin/notes.c:568 +msgid "allow storing empty note" +msgstr "빈 노트 저장을 허용합니다" + +#: builtin/notes.c:406 builtin/notes.c:477 +msgid "replace existing notes" +msgstr "기존 노트를 바꿉니다" + +#: builtin/notes.c:431 +#, c-format +msgid "" +"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "노트를 추가할 수 없습니다. %s 오브젝트에 대한 기존 노트가 있습니다. 기존 노트를 덮어쓰려면 '-f' 옵션을 사용하십시오" + +#: builtin/notes.c:446 builtin/notes.c:525 +#, c-format +msgid "Overwriting existing notes for object %s\n" +msgstr "%s 오브젝트에 대한 기존 노트를 덮어씁니다\n" + +#: builtin/notes.c:457 builtin/notes.c:618 builtin/notes.c:882 +#, c-format +msgid "Removing note for object %s\n" +msgstr "%s 오브젝트에 대한 노트를 제거합니다\n" + +#: builtin/notes.c:478 +msgid "read objects from stdin" +msgstr "표준 입력에서 오브젝트를 읽습니다" + +#: builtin/notes.c:480 +msgid "load rewriting config for <command> (implies --stdin)" +msgstr "<명령>에 대한 다시쓰기 설정을 읽어들입니다 (--stdin 옵션 포함)" + +#: builtin/notes.c:498 +msgid "too few parameters" +msgstr "파라미터가 너무 적습니다" + +#: builtin/notes.c:519 +#, c-format +msgid "" +"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "노트를 복사할 수 없습니다. %s 오브젝트에 대한 기존 노트가 있습니다. 기존 노트를 덮어쓰려면 '-f' 옵션을 사용하십시오" + +#: builtin/notes.c:531 +#, c-format +msgid "Missing notes on source object %s. Cannot copy." +msgstr "원본 %s 오브젝트에 대한 노트가 없습니다. 복사할 수 없습니다." + +#: builtin/notes.c:583 +#, c-format +msgid "" +"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" +"Please use 'git notes add -f -m/-F/-c/-C' instead.\n" +msgstr "" +"-m/-F/-c/-C 옵션은 'edit' 하위 명령에 대해 사용을 권하지 않습니다.\n" +"대신에 'git notes add -f -m/-F/-c/-C' 명령을 사용하십시오.\n" + +#: builtin/notes.c:764 +msgid "General options" +msgstr "일반 옵션" + +#: builtin/notes.c:766 +msgid "Merge options" +msgstr "병합 옵션" + +#: builtin/notes.c:768 +msgid "" +"resolve notes conflicts using the given strategy (manual/ours/theirs/union/" +"cat_sort_uniq)" +msgstr "주어진 전략을 사용해 노트 충돌을 해결합니다 (manual/ours/theirs/union/cat_sort_uniq)" + +#: builtin/notes.c:770 +msgid "Committing unmerged notes" +msgstr "병합하지 않은 노트 커밋" + +#: builtin/notes.c:772 +msgid "finalize notes merge by committing unmerged notes" +msgstr "병합하지 않은 노트를 커밋해 노트 병합을 마칩니다" + +#: builtin/notes.c:774 +msgid "Aborting notes merge resolution" +msgstr "노트 병합 해결 중지" + +#: builtin/notes.c:776 +msgid "abort notes merge" +msgstr "노트 병합을 중지합니다" + +#: builtin/notes.c:853 +#, c-format +msgid "A notes merge into %s is already in-progress at %s" +msgstr "%s 위치로 노트 병합이 이미 %s에서 진행중입니다" + +#: builtin/notes.c:880 +#, c-format +msgid "Object %s has no note\n" +msgstr "%s 오브젝트에 노트가 없습니다\n" + +#: builtin/notes.c:892 +msgid "attempt to remove non-existent note is not an error" +msgstr "없는 노트를 제거하려는 시도를 오류가 아닌 것으로 취급합니다" + +#: builtin/notes.c:895 +msgid "read object names from the standard input" +msgstr "표준 입력에서 오브젝트 이름을 읽습니다" + +#: builtin/notes.c:976 +msgid "notes-ref" +msgstr "노트-레퍼런스" + +#: builtin/notes.c:977 +msgid "use notes from <notes-ref>" +msgstr "<노트-레퍼런스>에서 노트를 사용합니다" + +#: builtin/notes.c:1012 builtin/remote.c:1647 +#, c-format +msgid "Unknown subcommand: %s" +msgstr "알 수 없는 하위 명령: %s" + +#: builtin/pack-objects.c:28 +msgid "" +"git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]" +msgstr "" +"git pack-objects --stdout [<옵션>...] [< <레퍼런스목록> | < <오브젝트목록>]" + +#: builtin/pack-objects.c:29 +msgid "" +"git pack-objects [<options>...] <base-name> [< <ref-list> | < <object-list>]" +msgstr "" +"git pack-objects [<옵션>...] <베이스이름> [< <레퍼런스목록> | < <오브젝트목록" +">]" + +#: builtin/pack-objects.c:175 builtin/pack-objects.c:178 +#, c-format +msgid "deflate error (%d)" +msgstr "deflate 오류 (%d)" + +#: builtin/pack-objects.c:771 +msgid "Writing objects" +msgstr "오브젝트 쓰는 중" + +#: builtin/pack-objects.c:1011 +msgid "disabling bitmap writing, as some objects are not being packed" +msgstr "묶음에 들어있지 않은 오브젝트가 있으므로, 비트맵 쓰기를 하지 않습니다" + +#: builtin/pack-objects.c:2171 +msgid "Compressing objects" +msgstr "오브젝트 압축하는 중" + +#: builtin/pack-objects.c:2568 +#, c-format +msgid "unsupported index version %s" +msgstr "지원하지 않는 인덱스 버전 %s" + +#: builtin/pack-objects.c:2572 +#, c-format +msgid "bad index version '%s'" +msgstr "잘못된 인덱스 버전 '%s'" + +#: builtin/pack-objects.c:2602 +msgid "do not show progress meter" +msgstr "진행률을 표시하지 않습니다" + +#: builtin/pack-objects.c:2604 +msgid "show progress meter" +msgstr "진행률을 표시합니다" + +#: builtin/pack-objects.c:2606 +msgid "show progress meter during object writing phase" +msgstr "오브젝트 쓰기 단계에서 진행률을 표시합니다" + +#: builtin/pack-objects.c:2609 +msgid "similar to --all-progress when progress meter is shown" +msgstr "진행률이 표시될 때 --all-progress와 비슷합니다" + +#: builtin/pack-objects.c:2610 +msgid "version[,offset]" +msgstr "버전[,오프셋]" + +#: builtin/pack-objects.c:2611 +msgid "write the pack index file in the specified idx format version" +msgstr "지정한 버전의 인덱스 형식에 따라 묶음 인덱스 파일을 씁니다" + +#: builtin/pack-objects.c:2614 +msgid "maximum size of each output pack file" +msgstr "출력 묶음 파일의 최대 크기" + +#: builtin/pack-objects.c:2616 +msgid "ignore borrowed objects from alternate object store" +msgstr "보조 오브젝트 저장소에서 빌려온 오브젝트를 무시합니다" + +#: builtin/pack-objects.c:2618 +msgid "ignore packed objects" +msgstr "묶음 오브젝트를 무시합니다" + +#: builtin/pack-objects.c:2620 +msgid "limit pack window by objects" +msgstr "묶음 윈도우를 오브젝트 단위로 제한합니다" + +#: builtin/pack-objects.c:2622 +msgid "limit pack window by memory in addition to object limit" +msgstr "묶음 윈도우를 오브젝트 단위에 추가로 메모리 단위로 제한합니다" + +#: builtin/pack-objects.c:2624 +msgid "maximum length of delta chain allowed in the resulting pack" +msgstr "결과물 묶음에서 허용되는 최대 길이의 델타 체인" + +#: builtin/pack-objects.c:2626 +msgid "reuse existing deltas" +msgstr "기존 델타를 재사용합니다" + +#: builtin/pack-objects.c:2628 +msgid "reuse existing objects" +msgstr "기존 오브젝트를 재사용합니다" + +#: builtin/pack-objects.c:2630 +msgid "use OFS_DELTA objects" +msgstr "OFS_DELTA 오브젝트를 사용합니다" + +#: builtin/pack-objects.c:2632 +msgid "use threads when searching for best delta matches" +msgstr "최상의 델타 일치를 검색하는데 스레드를 사용합니다" + +#: builtin/pack-objects.c:2634 +msgid "do not create an empty pack output" +msgstr "빈 묶음 출력을 만들지 않습니다" + +#: builtin/pack-objects.c:2636 +msgid "read revision arguments from standard input" +msgstr "표준 입력에서 리비전 인자를 읽습니다" + +#: builtin/pack-objects.c:2638 +msgid "limit the objects to those that are not yet packed" +msgstr "묶지 않는 오브젝트 수를 제한합니다" + +#: builtin/pack-objects.c:2641 +msgid "include objects reachable from any reference" +msgstr "모든 레퍼런스에서 접근 가능한 오브젝트를 포함합니다" + +#: builtin/pack-objects.c:2644 +msgid "include objects referred by reflog entries" +msgstr "reflog 항목에서 레퍼런스할 수 있는 오브젝트를 포함합니다" + +#: builtin/pack-objects.c:2647 +msgid "include objects referred to by the index" +msgstr "인덱스에서< 레퍼런스하는 오브젝트를 포함합니다" + +#: builtin/pack-objects.c:2650 +msgid "output pack to stdout" +msgstr "묶음을 표준 출력으로 출력합니다" + +#: builtin/pack-objects.c:2652 +msgid "include tag objects that refer to objects to be packed" +msgstr "묶음에 들어갈 오브젝트를 레퍼런스하는 태그 오브젝트를 포함합니다" + +#: builtin/pack-objects.c:2654 +msgid "keep unreachable objects" +msgstr "접근 불가능 오브젝트를 보존합니다" + +#: builtin/pack-objects.c:2655 parse-options.h:142 +msgid "time" +msgstr "시각" + +#: builtin/pack-objects.c:2656 +msgid "unpack unreachable objects newer than <time>" +msgstr "<시각>보다 새로운 접근 불가능 오브젝트의 묶음을 풉니다" + +#: builtin/pack-objects.c:2659 +msgid "create thin packs" +msgstr "얇은 묶음을 만듭니다" + +#: builtin/pack-objects.c:2661 +msgid "create packs suitable for shallow fetches" +msgstr "얕은 가져오기에 적합한 묶음을 만듭니다" + +#: builtin/pack-objects.c:2663 +msgid "ignore packs that have companion .keep file" +msgstr "해당하는 .keep 파일이 있는 묶음을 무시합니다" + +#: builtin/pack-objects.c:2665 +msgid "pack compression level" +msgstr "묶음 압축 단계" + +# FIXME: graft? +#: builtin/pack-objects.c:2667 +msgid "do not hide commits by grafts" +msgstr "붙어 있는 커밋을 숨기지 않습니다" + +#: builtin/pack-objects.c:2669 +msgid "use a bitmap index if available to speed up counting objects" +msgstr "가능하면 비트맵 인덱스를 사용해 오브젝트 세기 속도를 높입니다" + +#: builtin/pack-objects.c:2671 +msgid "write a bitmap index together with the pack index" +msgstr "묶음 인덱스와 같이 비트맵 인덱스를 씁니다" + +#: builtin/pack-objects.c:2762 +msgid "Counting objects" +msgstr "오브젝트 개수 세는 중" + +#: builtin/pack-refs.c:6 +msgid "git pack-refs [<options>]" +msgstr "git pack-refs [<옵션>]" + +#: builtin/pack-refs.c:14 +msgid "pack everything" +msgstr "모두 묶습니다" + +#: builtin/pack-refs.c:15 +msgid "prune loose refs (default)" +msgstr "느슨한 레퍼런스를 잘라냅니다 (기본값)" + +#: builtin/prune-packed.c:7 +msgid "git prune-packed [-n | --dry-run] [-q | --quiet]" +msgstr "git prune-packed [-n | --dry-run] [-q | --quiet]" + +#: builtin/prune-packed.c:40 +msgid "Removing duplicate objects" +msgstr "중복된 오브젝트 제거" + +#: builtin/prune.c:11 +msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]" +msgstr "git prune [-n] [-v] [--expire <시각>] [--] [<헤드>...]" + +#: builtin/prune.c:105 builtin/worktree.c:124 +msgid "do not remove, show only" +msgstr "제거하지 않고, 보여주기만 합니다" + +#: builtin/prune.c:106 builtin/worktree.c:125 +msgid "report pruned objects" +msgstr "잘라낸 오브젝트를 알립니다" + +#: builtin/prune.c:109 builtin/worktree.c:127 +msgid "expire objects older than <time>" +msgstr "<시각>보다 오래 된 오브젝트가 만료됩니다" + +#: builtin/prune.c:123 +msgid "cannot prune in a precious-objects repo" +msgstr "precious-objects 저장소에서 잘라낼 수 없습니다" + +#: builtin/pull.c:69 +msgid "git pull [<options>] [<repository> [<refspec>...]]" +msgstr "git pull [<옵션>] [<저장소> [<레퍼런스명세>...]]" + +#: builtin/pull.c:113 +msgid "Options related to merging" +msgstr "병합 관련 옵션" + +#: builtin/pull.c:116 +msgid "incorporate changes by rebasing rather than merging" +msgstr "변경 사항을 적용할 때 병합하는 대신 리베이스합니다" + +#: builtin/pull.c:140 builtin/revert.c:105 +msgid "allow fast-forward" +msgstr "정방향 진행을 허용합니다" + +#: builtin/pull.c:146 +msgid "verify that the named commit has a valid GPG signature" +msgstr "지정한 커밋에 올바른 GPG 서명이 있는지 검증합니다" + +#: builtin/pull.c:160 +msgid "Options related to fetching" +msgstr "가져오기 관련 옵션" + +#: builtin/pull.c:268 +#, c-format +msgid "Invalid value for pull.ff: %s" +msgstr "pull.ff에 대해 잘못된 값: %s" + +#: builtin/pull.c:352 +msgid "Cannot pull with rebase: You have unstaged changes." +msgstr "리베이스로 풀을 할 수 없습니다: 스테이징하지 않은 변경 사항이 있습니다." + +#: builtin/pull.c:358 +msgid "Additionally, your index contains uncommitted changes." +msgstr "추가로, 인덱스에 커밋하지 않은 변경 사항이 있습니다." + +#: builtin/pull.c:360 +msgid "Cannot pull with rebase: Your index contains uncommitted changes." +msgstr "리베이스로 풀을 할 수 없습니다: 인덱스에 커밋하지 않은 변경 사항이 있습니다." + +#: builtin/pull.c:436 +msgid "" +"There is no candidate for rebasing against among the refs that you just " +"fetched." +msgstr "가져온 레퍼런스 중에 리베이스할 대상 후보가 없습니다." + +#: builtin/pull.c:438 +msgid "" +"There are no candidates for merging among the refs that you just fetched." +msgstr "가져온 레퍼런스 중에 병합할 대상 후보가 없습니다." + +#: builtin/pull.c:439 +msgid "" +"Generally this means that you provided a wildcard refspec which had no\n" +"matches on the remote end." +msgstr "" +"보통 이런 경우는 리모트 쪽에는 없는 와일드카드 레퍼런스명세가\n" +"주어졌을 때 일어납니다." + +#: builtin/pull.c:442 +#, c-format +msgid "" +"You asked to pull from the remote '%s', but did not specify\n" +"a branch. Because this is not the default configured remote\n" +"for your current branch, you must specify a branch on the command line." +msgstr "" +"리모트 '%s'에서 풀을 요청했지만, 브랜치를 지정하지 않았습니다.\n" +"이 리모트는 현재 브랜치에 대해 기본으로 설정된 리모트가\n" +"아니기 때문에, 명령행에서 브랜치를 지정해야 합니다." + +#: builtin/pull.c:447 +msgid "You are not currently on a branch." +msgstr "현재 어떤 브랜치 위에도 있지 않습니다." + +#: builtin/pull.c:449 builtin/pull.c:464 +msgid "Please specify which branch you want to rebase against." +msgstr "어떤 브랜치를 대상으로 리베이스할지 지정하십시오." + +#: builtin/pull.c:451 builtin/pull.c:466 +msgid "Please specify which branch you want to merge with." +msgstr "어떤 브랜치를 대상으로 병합할지 지정하십시오." + +#: builtin/pull.c:452 builtin/pull.c:467 +msgid "See git-pull(1) for details." +msgstr "자세한 정보는 git-pull(1) 페이지를 참고하십시오." + +#: builtin/pull.c:462 +msgid "There is no tracking information for the current branch." +msgstr "현재 브랜치에 추적 정보가 없습니다." + +#: builtin/pull.c:471 +#, c-format +msgid "" +"If you wish to set tracking information for this branch you can do so with:\n" +"\n" +" git branch --set-upstream-to=%s/<branch> %s\n" +msgstr "" +"이 브랜치에 대한 추적 정보를 설정하려면 다음과 같이 할 수 있습니다:\n" +"\n" +" git branch --set-upstream-to=%s/<브랜치> %s\n" + +#: builtin/pull.c:476 +#, c-format +msgid "" +"Your configuration specifies to merge with the ref '%s'\n" +"from the remote, but no such ref was fetched." +msgstr "" +"설정에서 리모트의 '%s' 레퍼런스와 병합하도록 지정했지만,\n" +"그런 레퍼런스를 가져오지 않았습니다." + +#: builtin/pull.c:830 +msgid "Updating an unborn branch with changes added to the index." +msgstr "만들어지지 않은 브랜치를 인덱스에 추가된 변경 사항으로 업데이트합니다." + +#: builtin/pull.c:859 +#, c-format +msgid "" +"fetch updated the current branch head.\n" +"fast-forwarding your working tree from\n" +"commit %s." +msgstr "" +"현재 브랜치 헤드를 업데이트했습니다.\n" +"작업 폴더를 %s 커밋에서 정방향\n" +"진행합니다." + +#: builtin/pull.c:864 +#, c-format +msgid "" +"Cannot fast-forward your working tree.\n" +"After making sure that you saved anything precious from\n" +"$ git diff %s\n" +"output, run\n" +"$ git reset --hard\n" +"to recover." +msgstr "" +"작업 폴더를 정방향 진행할 수 없습니다.\n" +"다음 명령 출력에서 중요한 사항을 저장한 다음,\n" +"$ git diff %s\n" +"다음을 실행하면\n" +"$ git reset --hard\n" +"복구됩니다." + +#: builtin/pull.c:879 +msgid "Cannot merge multiple branches into empty head." +msgstr "여러 브랜치를 빈 헤드로 병합할 수 없습니다." + +#: builtin/pull.c:883 +msgid "Cannot rebase onto multiple branches." +msgstr "여러 브랜치로 리베이스할 수 없습니다." + +#: builtin/push.c:16 +msgid "git push [<options>] [<repository> [<refspec>...]]" +msgstr "git push [<옵션>] [<저장소> [<레퍼런스명세>...]]" + +#: builtin/push.c:88 +msgid "tag shorthand without <tag>" +msgstr "<태그> 없이 태그 줄임" + +#: builtin/push.c:98 +msgid "--delete only accepts plain target ref names" +msgstr "--delete 옵션은 일반 대상 레퍼런스 이름만 받습니다" + +#: builtin/push.c:142 +msgid "" +"\n" +"To choose either option permanently, see push.default in 'git help config'." +msgstr "\n어느 한 쪽 옵션만 계속 선택하려면, 'git help config'에서 push.default를 참고하십시오." + +#: builtin/push.c:145 +#, c-format +msgid "" +"The upstream branch of your current branch does not match\n" +"the name of your current branch. To push to the upstream branch\n" +"on the remote, use\n" +"\n" +" git push %s HEAD:%s\n" +"\n" +"To push to the branch of the same name on the remote, use\n" +"\n" +" git push %s %s\n" +"%s" +msgstr "" +"현재 브랜치의 업스트림 브랜치가 현재 브랜치의 이름과\n" +"같지 않습니다. 리모트의 업스트림 브랜치로 푸시하려면\n" +"다음과 같이 하십시오.\n" +"\n" +" git push %s HEAD:%s\n" +"\n" +"리모트의 같은 이름으로 푸시하려면 다음과 같이 하십시오.\n" +"\n" +" git push %s %s\n" +"%s" + +#: builtin/push.c:160 +#, c-format +msgid "" +"You are not currently on a branch.\n" +"To push the history leading to the current (detached HEAD)\n" +"state now, use\n" +"\n" +" git push %s HEAD:<name-of-remote-branch>\n" +msgstr "" +"현재 어떤 브랜치 위에도 있지 않습니다.\n" +"지금 현재 (HEAD 분리) 상태까지의 커밋 내역을 푸시하려면\n" +"다음과 같이 하십시오.\n" +"\n" +" git push %s HEAD:<name-of-remote-branch>\n" + +#: builtin/push.c:174 +#, c-format +msgid "" +"The current branch %s has no upstream branch.\n" +"To push the current branch and set the remote as upstream, use\n" +"\n" +" git push --set-upstream %s %s\n" +msgstr "" +"현재 브랜치 %s에 업스트림 브랜치가 없습니다.\n" +"현재 브랜치를 푸시하고 해당 리모트를 업스트림으로 지정하려면\n" +"다음과 같이 하십시오.\n" +"\n" +" git push --set-upstream %s %s\n" + +#: builtin/push.c:182 +#, c-format +msgid "The current branch %s has multiple upstream branches, refusing to push." +msgstr "현재 브랜치 %s에 여러 업스트림 브랜치가 있습니다. 푸시를 거절합니다." + +#: builtin/push.c:185 +#, c-format +msgid "" +"You are pushing to remote '%s', which is not the upstream of\n" +"your current branch '%s', without telling me what to push\n" +"to update which remote branch." +msgstr "" +"'%s' 리모트로 푸시하는 중입니다. 하지만 이 리모트는 현재\n" +"'%s' 브랜치의 업스트림이 아닙니다. 어떤 리모트 브랜치에 무엇을\n" +"푸시할지 설정하지 않았습니다." + +#: builtin/push.c:208 +msgid "" +"push.default is unset; its implicit value has changed in\n" +"Git 2.0 from 'matching' to 'simple'. To squelch this message\n" +"and maintain the traditional behavior, use:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"To squelch this message and adopt the new behavior now, use:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"When push.default is set to 'matching', git will push local branches\n" +"to the remote branches that already exist with the same name.\n" +"\n" +"Since Git 2.0, Git defaults to the more conservative 'simple'\n" +"behavior, which only pushes the current branch to the corresponding\n" +"remote branch that 'git pull' uses to update the current branch.\n" +"\n" +"See 'git help config' and search for 'push.default' for further " +"information.\n" +"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" +"'current' instead of 'simple' if you sometimes use older versions of Git)" +msgstr "" +"push.default를 설정하지 않았습니다. 묵시적 값은 깃 2.0에서\n" +"'matching'에서 'simple'로 바뀌었습니다. 이 메시지를 표시하지\n" +"않고 과거의 동작을 유지하려면 다음과 같이 하십시오:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"이 메시지를 표시하지 않고 새 동작을 받아들이려면 다음과 같이\n" +"하십시오:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"push.default가 'matching'으로 설정되면, 로컬 브랜치를 이미 같은 이름이\n" +"있는 리모트 브랜치로 푸시합니다.\n" +"\n" +"깃 2.0부터 더 보수적인 'simple' 동작이 기본값입니다. 여기서는 현재\n" +"브랜치를 'git pull'에서 현재 브랜치를 업데이트할 때 사용하는 해당\n" +"리모트 브랜치로 푸시합니다.\n" +"\n" +"더 자세한 정보는 'git help config'에서 'push.default' 설명을 보십시오.\n" +"('simple' 모드는 깃 1.7.11에 추가되었습니다. 과거 버전의 깃을 사용하게\n" +"되면 비슷한 'current' 모드를 사용하십시오.)" + +#: builtin/push.c:275 +msgid "" +"You didn't specify any refspecs to push, and push.default is \"nothing\"." +msgstr "푸시할 레퍼런스명세를 지정하지 않았고, push.default 값이 'nothing'입니다." + +#: builtin/push.c:282 +msgid "" +"Updates were rejected because the tip of your current branch is behind\n" +"its remote counterpart. Integrate the remote changes (e.g.\n" +"'git pull ...') before pushing again.\n" +"See the 'Note about fast-forwards' in 'git push --help' for details." +msgstr "" +"현재 브랜치의 끝이 리모트 브랜치보다 뒤에 있으므로 업데이트가\n" +"거부되었습니다. 푸시하기 전에 ('git pull ...' 등 명령으로) 리모트\n" +"변경 사항을 포함하십시오.\n" +"자세한 정보는 'git push --help'의 \"Note about fast-forwards' 부분을\n" +"참고하십시오." + +#: builtin/push.c:288 +msgid "" +"Updates were rejected because a pushed branch tip is behind its remote\n" +"counterpart. Check out this branch and integrate the remote changes\n" +"(e.g. 'git pull ...') before pushing again.\n" +"See the 'Note about fast-forwards' in 'git push --help' for details." +msgstr "" +"현재 브랜치의 끝이 리모트 브랜치보다 뒤에 있으므로 업데이트가\n" +"거부되었습니다. 이 브랜치를 체크아웃하고 푸시하기 전에\n" +"('git pull ...' 등 명령으로) 리모트 변경 사항을 포함하십시오.\n" +"자세한 정보는 'git push --help'의 \"Note about fast-forwards' 부분을\n" +"참고하십시오." + +#: builtin/push.c:294 +msgid "" +"Updates were rejected because the remote contains work that you do\n" +"not have locally. This is usually caused by another repository pushing\n" +"to the same ref. You may want to first integrate the remote changes\n" +"(e.g., 'git pull ...') before pushing again.\n" +"See the 'Note about fast-forwards' in 'git push --help' for details." +msgstr "" +"리모트에 로컬에 없는 사항이 들어 있으므로 업데이트가\n" +"거부되었습니다. 이 상황은 보통 또 다른 저장소에서 같은\n" +"저장소로 푸시할 때 발생합니다. 푸시하기 전에\n" +"('git pull ...' 등 명령으로) 리모트 변경 사항을 먼저\n" +"포함해야 합니다.\n" +"자세한 정보는 'git push --help'의 \"Note about fast-forwards' 부분을\n" +"참고하십시오." + +#: builtin/push.c:301 +msgid "Updates were rejected because the tag already exists in the remote." +msgstr "리모트에 태그가 이미 있기 때문에 업데이트가 거부되었습니다." + +#: builtin/push.c:304 +msgid "" +"You cannot update a remote ref that points at a non-commit object,\n" +"or update a remote ref to make it point at a non-commit object,\n" +"without using the '--force' option.\n" +msgstr "" +"'--force' 옵션이 없이 커밋이 아닌 오브젝트를 가리키는 리모트\n" +"레퍼런스를 업데이트하거나, 커밋이 아닌 오브젝트를 가리키도록\n" +"업데이트할 수 없습니다.\n" + +#: builtin/push.c:363 +#, c-format +msgid "Pushing to %s\n" +msgstr "다음에 푸시: %s\n" + +#: builtin/push.c:367 +#, c-format +msgid "failed to push some refs to '%s'" +msgstr "레퍼런스를 '%s'에 푸시하는데 실패했습니다" + +#: builtin/push.c:397 +#, c-format +msgid "bad repository '%s'" +msgstr "잘못된 저장소 '%s'" + +#: builtin/push.c:398 +msgid "" +"No configured push destination.\n" +"Either specify the URL from the command-line or configure a remote " +"repository using\n" +"\n" +" git remote add <name> <url>\n" +"\n" +"and then push using the remote name\n" +"\n" +" git push <name>\n" +msgstr "" +"푸시 대상을 설정하지 않았습니다.\n" +"명령해에서 URL을 지정하거나 다음을 사용해 리모트 저장소를 설정하십시오\n" +"\n" +" git remote add <이름> <URL>\n" +"\n" +"그리고 이 리모트 이름을 사용해 푸시하십시오\n" +"\n" +" git push <name>\n" + +#: builtin/push.c:413 +msgid "--all and --tags are incompatible" +msgstr "--all 및 --tags 옵션은 호환되지 않습니다" + +#: builtin/push.c:414 +msgid "--all can't be combined with refspecs" +msgstr "--all 옵션은 레퍼런스명세와 같이 쓸 수 없습니다" + +#: builtin/push.c:419 +msgid "--mirror and --tags are incompatible" +msgstr "--mirror 및 --tags 옵션은 호환되지 않습니다" + +#: builtin/push.c:420 +msgid "--mirror can't be combined with refspecs" +msgstr "--mirror 옵션은 레퍼런스명세와 같이 쓸 수 없습니다" + +#: builtin/push.c:425 +msgid "--all and --mirror are incompatible" +msgstr "--all 및 --mirror 옵션은 호환되지 않습니다" + +#: builtin/push.c:537 +msgid "repository" +msgstr "저장소" + +#: builtin/push.c:538 builtin/send-pack.c:161 +msgid "push all refs" +msgstr "모든 레퍼런스 푸시하기" + +#: builtin/push.c:539 builtin/send-pack.c:163 +msgid "mirror all refs" +msgstr "모든 레퍼런스 미러" + +#: builtin/push.c:541 +msgid "delete refs" +msgstr "레퍼런스 삭제" + +#: builtin/push.c:542 +msgid "push tags (can't be used with --all or --mirror)" +msgstr "태그 푸시하기 (--all 또는 --mirror 옵션과 같이 쓸 수 없음)" + +#: builtin/push.c:545 builtin/send-pack.c:164 +msgid "force updates" +msgstr "강제로 업데이트" + +#: builtin/push.c:547 builtin/send-pack.c:175 +msgid "refname>:<expect" +msgstr "레퍼런스이름>:<예상" + +#: builtin/push.c:548 builtin/send-pack.c:176 +msgid "require old value of ref to be at this value" +msgstr "레퍼런스의 과거 값이 이 값이어야 합니다" + +#: builtin/push.c:550 +msgid "check|on-demand|no" +msgstr "check|on-demand|no" + +#: builtin/push.c:551 +msgid "control recursive pushing of submodules" +msgstr "재귀적 하위 모듈 푸시 방식을 설정합니다" + +#: builtin/push.c:553 builtin/send-pack.c:169 +msgid "use thin pack" +msgstr "얇은 묶음을 사용합니다" + +#: builtin/push.c:554 builtin/push.c:555 builtin/send-pack.c:158 +#: builtin/send-pack.c:159 +msgid "receive pack program" +msgstr "receive pack 프로그램" + +#: builtin/push.c:556 +msgid "set upstream for git pull/status" +msgstr "git pull/status에 대한 업스트림을 설정합니다" + +#: builtin/push.c:559 +msgid "prune locally removed refs" +msgstr "로컬에서 제거한 레퍼런스를 잘라냅니다" + +#: builtin/push.c:561 +msgid "bypass pre-push hook" +msgstr "푸시 전 후크를 건너뜁니다" + +#: builtin/push.c:562 +msgid "push missing but relevant tags" +msgstr "빠졌지만 관련된 태그를 푸시합니다" + +#: builtin/push.c:565 builtin/send-pack.c:166 +msgid "GPG sign the push" +msgstr "푸시에 GPG 서명" + +#: builtin/push.c:567 builtin/send-pack.c:170 +msgid "request atomic transaction on remote side" +msgstr "리모트 쪽에 원자 트랜잭션을 요청합니다" + +#: builtin/push.c:577 +msgid "--delete is incompatible with --all, --mirror and --tags" +msgstr "--delete 옵션은 --all, --mirror, --tags 옵션과 호환되지 않습니다" + +#: builtin/push.c:579 +msgid "--delete doesn't make sense without any refs" +msgstr "--delete 옵션은 레퍼런스 없이 앞뒤가 맞지 않습니다" + +#: builtin/read-tree.c:37 +msgid "" +"git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) " +"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--" +"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])" +msgstr "git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<접두어>) [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<파일>] (--empty | <트리-따위> [<트리-따위2> [<트리-따위3>]])" + +#: builtin/read-tree.c:110 +msgid "write resulting index to <file>" +msgstr "결과 인덱스를 <파일>에 씁니다" + +#: builtin/read-tree.c:113 +msgid "only empty the index" +msgstr "인덱스를 비우기만 합니다" + +#: builtin/read-tree.c:115 +msgid "Merging" +msgstr "병합하기" + +#: builtin/read-tree.c:117 +msgid "perform a merge in addition to a read" +msgstr "읽은 다음 병합을 수행합니다" + +#: builtin/read-tree.c:119 +msgid "3-way merge if no file level merging required" +msgstr "파일 단위 병합이 필요하지 않으면 3-방향 병합을 합니다" + +#: builtin/read-tree.c:121 +msgid "3-way merge in presence of adds and removes" +msgstr "추가와 제거가 있을 때 3-방향 병합을 합니다" + +#: builtin/read-tree.c:123 +msgid "same as -m, but discard unmerged entries" +msgstr "-m과 동일하지만, 병합되지 않은 항목을 버립니다" + +#: builtin/read-tree.c:124 +msgid "<subdirectory>/" +msgstr "<하위디렉터리>/" + +#: builtin/read-tree.c:125 +msgid "read the tree into the index under <subdirectory>/" +msgstr "트리를 <하위디렉터리>/ 아래 인덱스로 읽습니다" + +#: builtin/read-tree.c:128 +msgid "update working tree with merge result" +msgstr "작업 폴더를 병합 결과로 업데이트합니다" + +#: builtin/read-tree.c:130 +msgid "gitignore" +msgstr "gitignore" + +#: builtin/read-tree.c:131 +msgid "allow explicitly ignored files to be overwritten" +msgstr "무시하는 파일을 덮어쓰도록 명시적으로 허용합니다" + +#: builtin/read-tree.c:134 +msgid "don't check the working tree after merging" +msgstr "병합 후에 작업 폴더를 확인하지 않습니다" + +#: builtin/read-tree.c:135 +msgid "don't update the index or the work tree" +msgstr "인덱스나 작업 폴더를 업데이트하지 않습니다" + +#: builtin/read-tree.c:137 +msgid "skip applying sparse checkout filter" +msgstr "드문 체크아웃 필터 적용을 건너뜁니다" + +#: builtin/read-tree.c:139 +msgid "debug unpack-trees" +msgstr "unpack-trees 디버깅" + +#: builtin/reflog.c:428 +#, c-format +msgid "'%s' for '%s' is not a valid timestamp" +msgstr "'%s' 값이 '%s'에 대해 올바른 시각 값이 아닙니다" + +#: builtin/reflog.c:545 builtin/reflog.c:550 +#, c-format +msgid "'%s' is not a valid timestamp" +msgstr "'%s'은(는) 올바른 시각 값이 아닙니다" + +#: builtin/remote.c:12 +msgid "git remote [-v | --verbose]" +msgstr "git remote [-v | --verbose]" + +#: builtin/remote.c:13 +msgid "" +"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" +"mirror=<fetch|push>] <name> <url>" +msgstr "" +"git remote add [-t <브랜치>] [-m <master>] [-f] [--tags | --no-tags] [--" +"mirror=<fetch|push>] <이름> <url>" + +#: builtin/remote.c:14 builtin/remote.c:34 +msgid "git remote rename <old> <new>" +msgstr "git remote rename <옛이름> <새이름>" + +#: builtin/remote.c:15 builtin/remote.c:39 +msgid "git remote remove <name>" +msgstr "git remote remove <이름>" + +#: builtin/remote.c:16 builtin/remote.c:44 +msgid "git remote set-head <name> (-a | --auto | -d | --delete | <branch>)" +msgstr "git remote set-head <이름> (-a | --auto | -d | --delete | <브랜치>)" + +#: builtin/remote.c:17 +msgid "git remote [-v | --verbose] show [-n] <name>" +msgstr "git remote [-v | --verbose] show [-n] <이름>" + +#: builtin/remote.c:18 +msgid "git remote prune [-n | --dry-run] <name>" +msgstr "git remote prune [-n | --dry-run] <이름>" + +#: builtin/remote.c:19 +msgid "" +"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]" +msgstr "" +"git remote [-v | --verbose] update [-p | --prune] [(<그룹> | <리모트>)...]" + +#: builtin/remote.c:20 +msgid "git remote set-branches [--add] <name> <branch>..." +msgstr "git remote set-branches [--add] <이름> <브랜치>..." + +#: builtin/remote.c:21 builtin/remote.c:70 +msgid "git remote get-url [--push] [--all] <name>" +msgstr "git remote get-url [--push] [--all] <이름>" + +#: builtin/remote.c:22 builtin/remote.c:75 +msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]" +msgstr "git remote set-url [--push] <이름> <새url> [<옛url>]" + +#: builtin/remote.c:23 builtin/remote.c:76 +msgid "git remote set-url --add <name> <newurl>" +msgstr "git remote set-url --add <이름> <새url>" + +#: builtin/remote.c:24 builtin/remote.c:77 +msgid "git remote set-url --delete <name> <url>" +msgstr "git remote set-url --delete <이름> <url>" + +#: builtin/remote.c:29 +msgid "git remote add [<options>] <name> <url>" +msgstr "git remote add [<옵션>] <이름> <url>" + +#: builtin/remote.c:49 +msgid "git remote set-branches <name> <branch>..." +msgstr "git remote set-branches <이름> <브랜치>..." + +#: builtin/remote.c:50 +msgid "git remote set-branches --add <name> <branch>..." +msgstr "git remote set-branches --add <이름> <브랜치>..." + +#: builtin/remote.c:55 +msgid "git remote show [<options>] <name>" +msgstr "git remote show [<옵션>] <이름>" + +#: builtin/remote.c:60 +msgid "git remote prune [<options>] <name>" +msgstr "git remote prune [<옵션>] <이름>" + +#: builtin/remote.c:65 +msgid "git remote update [<options>] [<group> | <remote>]..." +msgstr "git remote update [<옵션>] [<그룹> | <리모트>]..." + +#: builtin/remote.c:94 +#, c-format +msgid "Updating %s" +msgstr "%s 업데이트 중" + +#: builtin/remote.c:126 +msgid "" +"--mirror is dangerous and deprecated; please\n" +"\t use --mirror=fetch or --mirror=push instead" +msgstr "" +"--mirror는 위험하므로 사용을 권하지 않습니다. 대신에\n" +"\t --mirror=fetch 또는 --mirror=push를 사용하십시오" + +#: builtin/remote.c:143 +#, c-format +msgid "unknown mirror argument: %s" +msgstr "알 수 없는 --mirror 옵션 인자: %s" + +#: builtin/remote.c:159 +msgid "fetch the remote branches" +msgstr "리모트 브랜치를 가져옵니다" + +#: builtin/remote.c:161 +msgid "import all tags and associated objects when fetching" +msgstr "가져올 때 모든 태그와 관련 오브젝트를 가져옵니다" + +#: builtin/remote.c:164 +msgid "or do not fetch any tag at all (--no-tags)" +msgstr "아니면 아무 태그도 가져오지 않습니다 (--no-tags)" + +#: builtin/remote.c:166 +msgid "branch(es) to track" +msgstr "추적할 브랜치" + +#: builtin/remote.c:167 +msgid "master branch" +msgstr "마스터 브랜치" + +#: builtin/remote.c:168 +msgid "push|fetch" +msgstr "push|fetch" + +#: builtin/remote.c:169 +msgid "set up remote as a mirror to push to or fetch from" +msgstr "리모트를 푸시 또는 가져올 때 사용할 미러로 설정합니다" + +#: builtin/remote.c:181 +msgid "specifying a master branch makes no sense with --mirror" +msgstr "--mirror 옵션과 같이 마스터 브랜치를 지정하면 앞뒤가 맞지 않습니다" + +#: builtin/remote.c:183 +msgid "specifying branches to track makes sense only with fetch mirrors" +msgstr "마스터 브랜치를 지정은 fetch 미러에서만 앞뒤가 맞습니다" + +#: builtin/remote.c:193 builtin/remote.c:643 +#, c-format +msgid "remote %s already exists." +msgstr "%s 리모트가 이미 있습니다." + +#: builtin/remote.c:197 builtin/remote.c:647 +#, c-format +msgid "'%s' is not a valid remote name" +msgstr "'%s'은(는) 올바른 리모트 이름이 아닙니다" + +#: builtin/remote.c:241 +#, c-format +msgid "Could not setup master '%s'" +msgstr "마스터 '%s'을(를) 설정할 수 없습니다" + +#: builtin/remote.c:341 +#, c-format +msgid "Could not get fetch map for refspec %s" +msgstr "%s 레퍼런스명세에 대한 가져오기 맵을 얻을 수 없습니다" + +#: builtin/remote.c:442 builtin/remote.c:450 +msgid "(matching)" +msgstr "(일치)" + +#: builtin/remote.c:454 +msgid "(delete)" +msgstr "(삭제)" + +#: builtin/remote.c:594 builtin/remote.c:600 builtin/remote.c:606 +#, c-format +msgid "Could not append '%s' to '%s'" +msgstr "'%s'을(를) '%s'에 추가할 수 없습니다" + +#: builtin/remote.c:636 builtin/remote.c:775 builtin/remote.c:875 +#, c-format +msgid "No such remote: %s" +msgstr "그런 리모트가 없습니다: %s" + +#: builtin/remote.c:653 +#, c-format +msgid "Could not rename config section '%s' to '%s'" +msgstr "설정 섹션을 '%s'에서 '%s'(으)로 바꿀 수 없습니다" + +#: builtin/remote.c:659 builtin/remote.c:827 +#, c-format +msgid "Could not remove config section '%s'" +msgstr "설정 섹션 '%s'을(를) 제거할 수 없습니다" + +#: builtin/remote.c:674 +#, c-format +msgid "" +"Not updating non-default fetch refspec\n" +"\t%s\n" +"\tPlease update the configuration manually if necessary." +msgstr "" +"기본값이 아닌 가져오기 레퍼런스명세를 업데이트하지 않습니다\n" +"\t%s\n" +"\t필요하면 설정을 수동으로 업데이트하십시오." + +#: builtin/remote.c:680 +#, c-format +msgid "Could not append '%s'" +msgstr "'%s'에 덧붙일 수 없습니다" + +#: builtin/remote.c:691 +#, c-format +msgid "Could not set '%s'" +msgstr "'%s'을(를) 설정할 수 없습니다" + +#: builtin/remote.c:713 +#, c-format +msgid "deleting '%s' failed" +msgstr "'%s' 삭제가 실패했습니다" + +#: builtin/remote.c:747 +#, c-format +msgid "creating '%s' failed" +msgstr "'%s' 만들기가 실패했습니다" + +#: builtin/remote.c:813 +msgid "" +"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n" +"to delete it, use:" +msgid_plural "" +"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n" +"to delete them, use:" +msgstr[0] "" +"알림: 레퍼런스/리모트/ 계층 구조 밖에 있는 일부 브랜치가 제거되지 않았습니다.\n" +"삭제하려면 다음을 사용하십시오:" + +#: builtin/remote.c:928 +#, c-format +msgid " new (next fetch will store in remotes/%s)" +msgstr " 새 항목 (다음 가져오기는 remotes/%s 아래 저장됩니다)" + +#: builtin/remote.c:931 +msgid " tracked" +msgstr " 추적됨" + +#: builtin/remote.c:933 +msgid " stale (use 'git remote prune' to remove)" +msgstr " 오래됨 (제거하려면 'git remote prune'을 사용하십시오)" + +#: builtin/remote.c:935 +msgid " ???" +msgstr " ???" + +#: builtin/remote.c:976 +#, c-format +msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch" +msgstr "잘못된 branch.%s.merge 값. 여러 개 브랜치로 리베이스할 수 없습니다" + +#: builtin/remote.c:983 +#, c-format +msgid "rebases onto remote %s" +msgstr "리베이스: 리모트 %s" + +#: builtin/remote.c:986 +#, c-format +msgid " merges with remote %s" +msgstr " 병합: 리모트 %s" + +#: builtin/remote.c:987 +msgid " and with remote" +msgstr " 그리고 리모트" + +#: builtin/remote.c:989 +#, c-format +msgid "merges with remote %s" +msgstr "병합: 리모트 %s" + +#: builtin/remote.c:990 +msgid " and with remote" +msgstr " 그리고 리모트" + +#: builtin/remote.c:1036 +msgid "create" +msgstr "만들기" + +#: builtin/remote.c:1039 +msgid "delete" +msgstr "삭제" + +#: builtin/remote.c:1043 +msgid "up to date" +msgstr "최신 상태" + +#: builtin/remote.c:1046 +msgid "fast-forwardable" +msgstr "정방향 진행 가능" + +#: builtin/remote.c:1049 +msgid "local out of date" +msgstr "로컬이 뒤떨어짐" + +#: builtin/remote.c:1056 +#, c-format +msgid " %-*s forces to %-*s (%s)" +msgstr " %-*s에서 %-*s(으)로 강제 (%s)" + +#: builtin/remote.c:1059 +#, c-format +msgid " %-*s pushes to %-*s (%s)" +msgstr " %-*s에서 %-*s(으)로 푸시 (%s)" + +#: builtin/remote.c:1063 +#, c-format +msgid " %-*s forces to %s" +msgstr " %-*s에서 %s(으)로 강제" + +#: builtin/remote.c:1066 +#, c-format +msgid " %-*s pushes to %s" +msgstr " %-*s에서 %s(으)로 푸시" + +#: builtin/remote.c:1134 +msgid "do not query remotes" +msgstr "리모트에 질의하지 않습니다" + +#: builtin/remote.c:1161 +#, c-format +msgid "* remote %s" +msgstr "* 리모트 %s" + +#: builtin/remote.c:1162 +#, c-format +msgid " Fetch URL: %s" +msgstr " 가져오기 URL: %s" + +#: builtin/remote.c:1163 builtin/remote.c:1314 +msgid "(no URL)" +msgstr "(URL 없음)" + +#: builtin/remote.c:1172 builtin/remote.c:1174 +#, c-format +msgid " Push URL: %s" +msgstr " 푸시 URL: %s" + +#: builtin/remote.c:1176 builtin/remote.c:1178 builtin/remote.c:1180 +#, c-format +msgid " HEAD branch: %s" +msgstr " HEAD 브랜치: %s" + +#: builtin/remote.c:1182 +#, c-format +msgid "" +" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n" +msgstr " HEAD 브랜치 (리모트 HEAD는 애매하고, 다음 중 하나일 수 있습니다):\n" + +#: builtin/remote.c:1194 +#, c-format +msgid " Remote branch:%s" +msgid_plural " Remote branches:%s" +msgstr[0] " 리모트 브랜치:%s" + +#: builtin/remote.c:1197 builtin/remote.c:1224 +msgid " (status not queried)" +msgstr " (상태를 질의하지 않음)" + +#: builtin/remote.c:1206 +msgid " Local branch configured for 'git pull':" +msgid_plural " Local branches configured for 'git pull':" +msgstr[0] " 'git pull'에 사용할 로컬 브랜치를 설정:" + +#: builtin/remote.c:1214 +msgid " Local refs will be mirrored by 'git push'" +msgstr " 로컬 레퍼런스를 'git push'로 미러링할 예정" + +#: builtin/remote.c:1221 +#, c-format +msgid " Local ref configured for 'git push'%s:" +msgid_plural " Local refs configured for 'git push'%s:" +msgstr[0] " 로컬 레퍼런스를 'git push'로 미러링%s:" + +#: builtin/remote.c:1242 +msgid "set refs/remotes/<name>/HEAD according to remote" +msgstr "레퍼런스/리모트/<이름>/HEAD 값을 리모트에 맞게 설정합니다" + +#: builtin/remote.c:1244 +msgid "delete refs/remotes/<name>/HEAD" +msgstr "레퍼런스/리모트/<이름>/HEAD 값을 삭제합니다" + +#: builtin/remote.c:1259 +msgid "Cannot determine remote HEAD" +msgstr "리모트 HEAD를 결정할 수 없습니다" + +#: builtin/remote.c:1261 +msgid "Multiple remote HEAD branches. Please choose one explicitly with:" +msgstr "리모트 HEAD 브랜치가 여러개입니다. 다음 중 하나를 명시적으로 지정하십시오:" + +#: builtin/remote.c:1271 +#, c-format +msgid "Could not delete %s" +msgstr "%s을(를) 삭제할 수 없습니다" + +#: builtin/remote.c:1279 +#, c-format +msgid "Not a valid ref: %s" +msgstr "올바른 레퍼런스가 아닙니다: %s" + +#: builtin/remote.c:1281 +#, c-format +msgid "Could not setup %s" +msgstr "%s을(를) 설정할 수 없습니다" + +#: builtin/remote.c:1299 +#, c-format +msgid " %s will become dangling!" +msgstr " %s의 연결이 끊어집니다!" + +#: builtin/remote.c:1300 +#, c-format +msgid " %s has become dangling!" +msgstr " %s의 연결이 끊어졌습니다!" + +#: builtin/remote.c:1310 +#, c-format +msgid "Pruning %s" +msgstr "잘라냄: %s" + +#: builtin/remote.c:1311 +#, c-format +msgid "URL: %s" +msgstr "URL: %s" + +#: builtin/remote.c:1327 +#, c-format +msgid " * [would prune] %s" +msgstr " * [잘라낼 예정] %s" + +#: builtin/remote.c:1330 +#, c-format +msgid " * [pruned] %s" +msgstr " * [잘라냄] %s" + +#: builtin/remote.c:1375 +msgid "prune remotes after fetching" +msgstr "가져온 후에 리모트를 잘라냅니다" + +#: builtin/remote.c:1441 builtin/remote.c:1498 builtin/remote.c:1566 +#, c-format +msgid "No such remote '%s'" +msgstr "그런 리모트가 없습니다 ('%s')" + +#: builtin/remote.c:1461 +msgid "add branch" +msgstr "브랜치를 추가합니다" + +#: builtin/remote.c:1468 +msgid "no remote specified" +msgstr "리모트를 지정하지 않았습니다" + +#: builtin/remote.c:1485 +msgid "query push URLs rather than fetch URLs" +msgstr "가져오기 URL이 아니라 푸시 URL을 질의합니다" + +#: builtin/remote.c:1487 +msgid "return all URLs" +msgstr "모든 URL을 리턴합니다" + +#: builtin/remote.c:1515 +#, c-format +msgid "no URLs configured for remote '%s'" +msgstr "'%s' 리모트에 대한 URL을 설정하지 않았습니다" + +#: builtin/remote.c:1541 +msgid "manipulate push URLs" +msgstr "푸시 URL을 지정합니다" + +#: builtin/remote.c:1543 +msgid "add URL" +msgstr "URL을 추가합니다" + +#: builtin/remote.c:1545 +msgid "delete URLs" +msgstr "URL을 삭제합니다" + +#: builtin/remote.c:1552 +msgid "--add --delete doesn't make sense" +msgstr "--add --delete 옵션을 둘다 쓰면 안 됩니다" + +#: builtin/remote.c:1592 +#, c-format +msgid "Invalid old URL pattern: %s" +msgstr "잘못된 오래전 URL 패턴: %s" + +#: builtin/remote.c:1600 +#, c-format +msgid "No such URL found: %s" +msgstr "그런 URL이 없습니다: %s" + +#: builtin/remote.c:1602 +msgid "Will not delete all non-push URLs" +msgstr "푸시용이 아닌 모든 URL을 삭제하지 않습니다" + +#: builtin/remote.c:1616 +msgid "be verbose; must be placed before a subcommand" +msgstr "자세히 표시합니다 (하위 명령 앞에 와야 합니다)" + +#: builtin/repack.c:17 +msgid "git repack [<options>]" +msgstr "git repack [<옵션>]" + +#: builtin/repack.c:159 +msgid "pack everything in a single pack" +msgstr "하나의 묶음 안에 모두 묶습니다" + +#: builtin/repack.c:161 +msgid "same as -a, and turn unreachable objects loose" +msgstr "-a와 동일하고, 접근 불가능 오브젝트를 느슨하게 바꿉니다" + +#: builtin/repack.c:164 +msgid "remove redundant packs, and run git-prune-packed" +msgstr "여분의 묶음을 제거하고, git-prune-packed를 실행합니다" + +#: builtin/repack.c:166 +msgid "pass --no-reuse-delta to git-pack-objects" +msgstr "git-pack-objects에 --no-reuse-delta 옵션을 넘깁니다" + +#: builtin/repack.c:168 +msgid "pass --no-reuse-object to git-pack-objects" +msgstr "git-pack-objects에 --no-reuse-object 옵션을 넘깁니다" + +#: builtin/repack.c:170 +msgid "do not run git-update-server-info" +msgstr "git-update-server-info를 실행하지 않습니다" + +#: builtin/repack.c:173 +msgid "pass --local to git-pack-objects" +msgstr "git-pack-objects에 --local 옵션을 넘깁니다" + +#: builtin/repack.c:175 +msgid "write bitmap index" +msgstr "비트맵 인덱스를 씁니다" + +#: builtin/repack.c:176 +msgid "approxidate" +msgstr "대략의시각" + +#: builtin/repack.c:177 +msgid "with -A, do not loosen objects older than this" +msgstr "-A에 추가로, 지정한 시각보다 오래된 오브젝트를 느슨하게 만들지 않습니다" + +#: builtin/repack.c:179 +msgid "size of the window used for delta compression" +msgstr "델타 압축에 사용할 윈도우 크기" + +#: builtin/repack.c:180 builtin/repack.c:184 +msgid "bytes" +msgstr "바이트수" + +#: builtin/repack.c:181 +msgid "same as the above, but limit memory size instead of entries count" +msgstr "위와 동일하지만, 항목 수 대신 메모리 크기를 제한합니다" + +#: builtin/repack.c:183 +msgid "limits the maximum delta depth" +msgstr "최대 델타 깊이를 제한합니다" + +#: builtin/repack.c:185 +msgid "maximum size of each packfile" +msgstr "묶음 파일의 최대 크기" + +#: builtin/repack.c:187 +msgid "repack objects in packs marked with .keep" +msgstr ".keep으로 표시된 묶음의 오브젝트를 다시 묶습니다" + +#: builtin/repack.c:197 +msgid "cannot delete packs in a precious-objects repo" +msgstr "precious-objects 저장소의 묶음을 삭제할 수 없습니다" + +#: builtin/repack.c:381 +#, c-format +msgid "removing '%s' failed" +msgstr "'%s' 제거가 실패했습니다" + +#: builtin/replace.c:19 +msgid "git replace [-f] <object> <replacement>" +msgstr "git replace [-f] <오브젝트> <대체이름>" + +#: builtin/replace.c:20 +msgid "git replace [-f] --edit <object>" +msgstr "git replace [-f] --edit <오브젝트>" + +#: builtin/replace.c:21 +msgid "git replace [-f] --graft <commit> [<parent>...]" +msgstr "git replace [-f] --graft <커밋> [<상위>...]" + +#: builtin/replace.c:22 +msgid "git replace -d <object>..." +msgstr "git replace -d <오브젝트>..." + +#: builtin/replace.c:23 +msgid "git replace [--format=<format>] [-l [<pattern>]]" +msgstr "git replace [--format=<형식>] [-l [<패턴>]]" + +#: builtin/replace.c:325 builtin/replace.c:363 builtin/replace.c:391 +#, c-format +msgid "Not a valid object name: '%s'" +msgstr "올바른 오브젝트 이름이 아닙니다: '%s'" + +#: builtin/replace.c:355 +#, c-format +msgid "bad mergetag in commit '%s'" +msgstr "커밋 '%s'에 잘못된 병합태그" + +#: builtin/replace.c:357 +#, c-format +msgid "malformed mergetag in commit '%s'" +msgstr "커밋 '%s'에 잘못된 형식의 병합태그" + +#: builtin/replace.c:368 +#, c-format +msgid "" +"original commit '%s' contains mergetag '%s' that is discarded; use --edit " +"instead of --graft" +msgstr "본래 커밋 '%s'에 버려진 병합태그 '%s'이(가) 들어 있습니다. --graft 대신 --edit 옵션을 사용하십시오" + +#: builtin/replace.c:401 +#, c-format +msgid "the original commit '%s' has a gpg signature." +msgstr "본래 커밋 '%s'에 GPG 서명이 있습니다." + +#: builtin/replace.c:402 +msgid "the signature will be removed in the replacement commit!" +msgstr "대체 커밋에서 서명을 제거합니다!" + +#: builtin/replace.c:408 +#, c-format +msgid "could not write replacement commit for: '%s'" +msgstr "다음에 대한 대체 커밋을 쓸 수 없습니다: '%s'" + +#: builtin/replace.c:432 +msgid "list replace refs" +msgstr "대체 레퍼런스 목록을 표시합니다" + +#: builtin/replace.c:433 +msgid "delete replace refs" +msgstr "대체 레퍼런스를 삭제합니다" + +#: builtin/replace.c:434 +msgid "edit existing object" +msgstr "현재 오브젝트를 편집합니다" + +#: builtin/replace.c:435 +msgid "change a commit's parents" +msgstr "커밋의 상위 항목을 바꿉니다" + +#: builtin/replace.c:436 +msgid "replace the ref if it exists" +msgstr "레퍼런스가 있으면 대체합니다" + +#: builtin/replace.c:437 +msgid "do not pretty-print contents for --edit" +msgstr "--edit에 대한 내용을 예쁘게 표시하지 않습니다" + +#: builtin/replace.c:438 +msgid "use this format" +msgstr "이 형식을 사용합니다" + +#: builtin/rerere.c:12 +msgid "git rerere [clear | forget <path>... | status | remaining | diff | gc]" +msgstr "git rerere [clear | forget <경로>... | status | remaining | diff | gc]" + +#: builtin/rerere.c:58 +msgid "register clean resolutions in index" +msgstr "인덱스에 깔끔한 해결을 등록합니다" + +#: builtin/reset.c:26 +msgid "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]" +msgstr "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<커밋>]" + +#: builtin/reset.c:27 +msgid "git reset [-q] <tree-ish> [--] <paths>..." +msgstr "git reset [-q] <트리-따위> [--] <경로>..." + +#: builtin/reset.c:28 +msgid "git reset --patch [<tree-ish>] [--] [<paths>...]" +msgstr "git reset --patch [<트리-따위>] [--] [<경로>...]" + +#: builtin/reset.c:34 +msgid "mixed" +msgstr "혼합" + +#: builtin/reset.c:34 +msgid "soft" +msgstr "소프트" + +#: builtin/reset.c:34 +msgid "hard" +msgstr "하드" + +#: builtin/reset.c:34 +msgid "merge" +msgstr "병합" + +#: builtin/reset.c:34 +msgid "keep" +msgstr "유지" + +#: builtin/reset.c:74 +msgid "You do not have a valid HEAD." +msgstr "올바른 HEAD가 없습니다." + +#: builtin/reset.c:76 +msgid "Failed to find tree of HEAD." +msgstr "HEAD의 트리를 찾는데 실패했습니다." + +#: builtin/reset.c:82 +#, c-format +msgid "Failed to find tree of %s." +msgstr "%s의 트리를 찾는데 실패했습니다." + +#: builtin/reset.c:100 +#, c-format +msgid "HEAD is now at %s" +msgstr "HEAD의 현재 위치는 %s입니다" + +#: builtin/reset.c:183 +#, c-format +msgid "Cannot do a %s reset in the middle of a merge." +msgstr "병합 중에 %s 리셋을 할 수 없습니다." + +#: builtin/reset.c:276 +msgid "be quiet, only report errors" +msgstr "간략히 표시, 오류만 표시합니다" + +#: builtin/reset.c:278 +msgid "reset HEAD and index" +msgstr "HEAD와 인덱스를 리셋합니다" + +#: builtin/reset.c:279 +msgid "reset only HEAD" +msgstr "HEAD만 리셋합니다" + +#: builtin/reset.c:281 builtin/reset.c:283 +msgid "reset HEAD, index and working tree" +msgstr "HEAD, 인덱스, 작업폴더를 리셋합니다" + +#: builtin/reset.c:285 +msgid "reset HEAD but keep local changes" +msgstr "HEAD를 리셋하지만 로컬 변경 사항을 남겨둡니다" + +#: builtin/reset.c:288 +msgid "record only the fact that removed paths will be added later" +msgstr "제거한 경로를 나중에 추가한다는 사실만 기록합니다" + +#: builtin/reset.c:305 +#, c-format +msgid "Failed to resolve '%s' as a valid revision." +msgstr "'%s'을(를) 올바른 리비전으로 찾는데 실패했습니다." + +#: builtin/reset.c:313 +#, c-format +msgid "Failed to resolve '%s' as a valid tree." +msgstr "'%s'을(를) 올바른 트리로 찾는데 실패했습니다." + +#: builtin/reset.c:322 +msgid "--patch is incompatible with --{hard,mixed,soft}" +msgstr "--patch 옵션은 --{hard,mixed,soft} 옵션과 호환되지 않습니다" + +#: builtin/reset.c:331 +msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." +msgstr "--mixed 옵션을 경로와 같이 쓰기는 제거될 예정입니다. 대신에 'git reset -- <경로>'를 사용하십시오." + +#: builtin/reset.c:333 +#, c-format +msgid "Cannot do %s reset with paths." +msgstr "경로와 같이 %s 리셋을 할 수 없습니다." + +#: builtin/reset.c:343 +#, c-format +msgid "%s reset is not allowed in a bare repository" +msgstr "%s 리셋은 간략한 저장소에서만 쓸 수 있습니다" + +#: builtin/reset.c:347 +msgid "-N can only be used with --mixed" +msgstr "-N 옵션은 --mixed 옵션과 같이 써야만 합니다" + +#: builtin/reset.c:364 +msgid "Unstaged changes after reset:" +msgstr "리셋 뒤에 스테이징하지 않은 변경 사항:" + +#: builtin/reset.c:370 +#, c-format +msgid "Could not reset index file to revision '%s'." +msgstr "인덱스 파일을 '%s' 리비전으로 리셋할 수 없습니다." + +#: builtin/reset.c:374 +msgid "Could not write new index file." +msgstr "새 인덱스 파일을 쓸 수 없습니다." + +#: builtin/rev-list.c:354 +msgid "rev-list does not support display of notes" +msgstr "rev-list는 노트 표시를 지원하지 않습니다" + +#: builtin/rev-parse.c:358 +msgid "git rev-parse --parseopt [<options>] -- [<args>...]" +msgstr "git rev-parse --parseopt [<옵션>] -- [<인자>...]" + +#: builtin/rev-parse.c:363 +msgid "keep the `--` passed as an arg" +msgstr "인자로 넘긴 `--`를 유지합니다" + +#: builtin/rev-parse.c:365 +msgid "stop parsing after the first non-option argument" +msgstr "첫번째 옵션이 아닌 인자 뒤에 파싱을 중지합니다" + +#: builtin/rev-parse.c:368 +msgid "output in stuck long form" +msgstr "stuck long 형식으로 출력합니다" + +#: builtin/rev-parse.c:499 +msgid "" +"git rev-parse --parseopt [<options>] -- [<args>...]\n" +" or: git rev-parse --sq-quote [<arg>...]\n" +" or: git rev-parse [<options>] [<arg>...]\n" +"\n" +"Run \"git rev-parse --parseopt -h\" for more information on the first usage." +msgstr "" +"git rev-parse --parseopt [<옵션>] -- [<인자>...]\n" +" or: git rev-parse --sq-quote [<인자>...]\n" +" or: git rev-parse [<옵션>] [<인자>...]\n" +"\n" +"첫번째 사용방법에 대해 자세히 알고 싶으면, \"git rev-parse --parseopt -h\"를\n" +"실행해 보십시오." + +#: builtin/revert.c:22 +msgid "git revert [<options>] <commit-ish>..." +msgstr "git revert [<옵션>] <커밋-따위>..." + +#: builtin/revert.c:23 +msgid "git revert <subcommand>" +msgstr "git revert <하위명령>" + +#: builtin/revert.c:28 +msgid "git cherry-pick [<options>] <commit-ish>..." +msgstr "git cherry-pick [<옵션>] <커밋-따위>..." + +#: builtin/revert.c:29 +msgid "git cherry-pick <subcommand>" +msgstr "git cherry-pick <하위명령>" + +#: builtin/revert.c:71 +#, c-format +msgid "%s: %s cannot be used with %s" +msgstr "%s: %s은(는) %s와(과) 같이 쓸 수 없습니다" + +#: builtin/revert.c:80 +msgid "end revert or cherry-pick sequence" +msgstr "되돌리기 또는 커밋 빼오기 연속을 끝냅니다" + +#: builtin/revert.c:81 +msgid "resume revert or cherry-pick sequence" +msgstr "되돌리기 또는 커밋 빼오기 연속을 계속합니다" + +#: builtin/revert.c:82 +msgid "cancel revert or cherry-pick sequence" +msgstr "되돌리기 또는 커밋 빼오기 연속을 취소합니다" + +#: builtin/revert.c:83 +msgid "don't automatically commit" +msgstr "자동으로 커밋하지 않습니다" + +#: builtin/revert.c:84 +msgid "edit the commit message" +msgstr "커밋 메시지를 편집합니다" + +#: builtin/revert.c:87 +msgid "parent number" +msgstr "이전 커밋 번호" + +#: builtin/revert.c:89 +msgid "merge strategy" +msgstr "병합 전략" + +#: builtin/revert.c:90 +msgid "option" +msgstr "옵션" + +#: builtin/revert.c:91 +msgid "option for merge strategy" +msgstr "병합 전략 옵션" + +#: builtin/revert.c:104 +msgid "append commit name" +msgstr "커밋 이름을 뒤에 붙입니다" + +#: builtin/revert.c:106 +msgid "preserve initially empty commits" +msgstr "최초 빈 커밋을 유지합니다" + +#: builtin/revert.c:107 +msgid "allow commits with empty messages" +msgstr "빈 메시지로 커밋을 허용합니다" + +#: builtin/revert.c:108 +msgid "keep redundant, empty commits" +msgstr "여분의 빈 커밋을 유지합니다" + +#: builtin/revert.c:112 +msgid "program error" +msgstr "프로그램 오류" + +#: builtin/revert.c:197 +msgid "revert failed" +msgstr "되돌리기 실패" + +#: builtin/revert.c:212 +msgid "cherry-pick failed" +msgstr "cherry-pick 실패" + +#: builtin/rm.c:17 +msgid "git rm [<options>] [--] <file>..." +msgstr "git rm [<옵션>] [--] <파일>..." + +#: builtin/rm.c:65 +msgid "" +"the following submodule (or one of its nested submodules)\n" +"uses a .git directory:" +msgid_plural "" +"the following submodules (or one of their nested submodules)\n" +"use a .git directory:" +msgstr[0] "" +"다음 하위 모듈이 (또는 그 내부 하위 모듈이) .git\n" +"디렉터리를 사용합니다:" + +#: builtin/rm.c:71 +msgid "" +"\n" +"(use 'rm -rf' if you really want to remove it including all of its history)" +msgstr "\n(정말로 그 커밋 내역까지 포함해 제거하려면 'rm -rf'를 사용하십시오)" + +#: builtin/rm.c:230 +msgid "" +"the following file has staged content different from both the\n" +"file and the HEAD:" +msgid_plural "" +"the following files have staged content different from both the\n" +"file and the HEAD:" +msgstr[0] "" +"다음 파일에 파일과 HEAD 모두 다른 스테이징한 내용이\n" +"있습니다:" + +#: builtin/rm.c:235 +msgid "" +"\n" +"(use -f to force removal)" +msgstr "" +"\n" +"(강제로 제거하려면 -f 옵션을 사용하십시오)" + +#: builtin/rm.c:239 +msgid "the following file has changes staged in the index:" +msgid_plural "the following files have changes staged in the index:" +msgstr[0] "다음 파일이 인덱스에 스테이징한 변경 사항이 있습니다:" + +#: builtin/rm.c:243 builtin/rm.c:254 +msgid "" +"\n" +"(use --cached to keep the file, or -f to force removal)" +msgstr "\n(파일을 유지하려면 --cached 옵션, 강제로 제거하려면 -f 옵션을 사용하십시오)" + +#: builtin/rm.c:251 +msgid "the following file has local modifications:" +msgid_plural "the following files have local modifications:" +msgstr[0] "다음 파일에 로컬 수정 사항이 있습니다:" + +#: builtin/rm.c:269 +msgid "do not list removed files" +msgstr "제거한 파일 목록을 표시하지 않습니다" + +#: builtin/rm.c:270 +msgid "only remove from the index" +msgstr "인덱스에서만 제거합니다" + +#: builtin/rm.c:271 +msgid "override the up-to-date check" +msgstr "최신 버전 확인을 하지 않습니다" + +#: builtin/rm.c:272 +msgid "allow recursive removal" +msgstr "재귀적 제거를 허용합니다" + +#: builtin/rm.c:274 +msgid "exit with a zero status even if nothing matched" +msgstr "아무 것도 일치하지 않으면 상태 0번으로 끝납니다" + +#: builtin/rm.c:317 +msgid "Please, stage your changes to .gitmodules or stash them to proceed" +msgstr "계속하려면 .gitmodules의 변경 사항을 스테이징하거나 stash하십시오" + +#: builtin/rm.c:335 +#, c-format +msgid "not removing '%s' recursively without -r" +msgstr "-r 옵션이 없으면 재귀적으로 '%s'을(를) 제거하지 않습니다" + +#: builtin/rm.c:374 +#, c-format +msgid "git rm: unable to remove %s" +msgstr "git rm: %s을(를) 제거할 수 없습니다" + +#: builtin/send-pack.c:18 +msgid "" +"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-" +"receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> " +"[<ref>...]\n" +" --all and explicit <ref> specification are mutually exclusive." +msgstr "" +"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<호스트>:]<디렉터리> [<레퍼런스>...]\n" +" --all 옵션과 명시적인 <레퍼런스> 명세 중 하나만 사용할 수 있습니다." + +#: builtin/send-pack.c:160 +msgid "remote name" +msgstr "리모트 이름" + +#: builtin/send-pack.c:171 +msgid "use stateless RPC protocol" +msgstr "상태 없는 RPC 프로토콜을 사용합니다" + +#: builtin/send-pack.c:172 +msgid "read refs from stdin" +msgstr "표준 입력에서 레퍼런스를 읽습니다" + +#: builtin/send-pack.c:173 +msgid "print status from remote helper" +msgstr "리모트 도움 프로그램의 상태를 표시합니다" + +#: builtin/shortlog.c:13 +msgid "git shortlog [<options>] [<revision-range>] [[--] [<path>...]]" +msgstr "git shortlog [<옵션>] [<리비전-범위>] [[--] [<경로>...]]" + +#: builtin/shortlog.c:131 +#, c-format +msgid "Missing author: %s" +msgstr "작성자 정보가 없습니다: %s" + +#: builtin/shortlog.c:230 +msgid "sort output according to the number of commits per author" +msgstr "작성자별 커밋 수에 따라 정렬합니다" + +#: builtin/shortlog.c:232 +msgid "Suppress commit descriptions, only provides commit count" +msgstr "커밋 설명을 생략하고, 커밋 수만 표시합니다" + +#: builtin/shortlog.c:234 +msgid "Show the email address of each author" +msgstr "작성자의 전자메일 주소를 표시합니다" + +#: builtin/shortlog.c:235 +msgid "w[,i1[,i2]]" +msgstr "w[,i1[,i2]]" + +#: builtin/shortlog.c:236 +msgid "Linewrap output" +msgstr "줄바꿈 출력" + +#: builtin/show-branch.c:10 +msgid "" +"git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n" +"\t\t[--current] [--color[=<when>] | --no-color] [--sparse]\n" +"\t\t[--more=<n> | --list | --independent | --merge-base]\n" +"\t\t[--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]" +msgstr "" +"git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n" +"\t\t[--current] [--color[=<시각>] | --no-color] [--sparse]\n" +"\t\t[--more=<n> | --list | --independent | --merge-base]\n" +"\t\t[--no-name | --sha1-name] [--topics] [(<리비전> | <glob>)...]" + +#: builtin/show-branch.c:14 +msgid "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]" +msgstr "git show-branch (-g | --reflog)[=<n>[,<베이스>]] [--list] [<레퍼런스>]" + +#: builtin/show-branch.c:640 +msgid "show remote-tracking and local branches" +msgstr "리모트 추적 및 로컬 브랜치를 표시합니다" + +#: builtin/show-branch.c:642 +msgid "show remote-tracking branches" +msgstr "리모트 추적 브랜치를 표시합니다" + +#: builtin/show-branch.c:644 +msgid "color '*!+-' corresponding to the branch" +msgstr "브랜치에 따른 '*!+-' 표시에 색을 입힙니다" + +#: builtin/show-branch.c:646 +msgid "show <n> more commits after the common ancestor" +msgstr "공통 이전 커밋 뒤의 <n>개의 커밋을 표시합니다" + +#: builtin/show-branch.c:648 +msgid "synonym to more=-1" +msgstr "--more=-1 옵션과 동일" + +#: builtin/show-branch.c:649 +msgid "suppress naming strings" +msgstr "이름 문자열을 표시하지 않습니다" + +#: builtin/show-branch.c:651 +msgid "include the current branch" +msgstr "현재 브랜치를 포함" + +#: builtin/show-branch.c:653 +msgid "name commits with their object names" +msgstr "커밋의 이름을 그 오브젝트 이름으로 붙입니다" + +#: builtin/show-branch.c:655 +msgid "show possible merge bases" +msgstr "가능한 병합 기준점을 표시합니다" + +#: builtin/show-branch.c:657 +msgid "show refs unreachable from any other ref" +msgstr "다른 어떤 레퍼런스에서도 접근 불가능한 레퍼런스를 표시합니다" + +#: builtin/show-branch.c:659 +msgid "show commits in topological order" +msgstr "위상 순서에 따라 커밋을 표시합니다" + +#: builtin/show-branch.c:662 +msgid "show only commits not on the first branch" +msgstr "첫 브랜치에 없는 커밋만 표시합니다" + +#: builtin/show-branch.c:664 +msgid "show merges reachable from only one tip" +msgstr "하나의 끝에서만 접근 가능한 병합을 표시합니다" + +#: builtin/show-branch.c:666 +msgid "topologically sort, maintaining date order where possible" +msgstr "가능하면 시간 순서를 유지하면서 위상 순서로 정렬" + +#: builtin/show-branch.c:669 +msgid "<n>[,<base>]" +msgstr "<n>[,<베이스>]" + +#: builtin/show-branch.c:670 +msgid "show <n> most recent ref-log entries starting at base" +msgstr "기준부터 시작해 최대 <n>개의 최근 ref-log 항목을 표시합니다" + +#: builtin/show-ref.c:10 +msgid "" +"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --" +"hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<pattern>...]" +msgstr "" +"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --" +"hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<패턴>...]" + +#: builtin/show-ref.c:11 +msgid "git show-ref --exclude-existing[=<pattern>]" +msgstr "git show-ref --exclude-existing[=<패턴>]" + +#: builtin/show-ref.c:165 +msgid "only show tags (can be combined with heads)" +msgstr "태그만 표시 (헤드와 결합 가능)" + +#: builtin/show-ref.c:166 +msgid "only show heads (can be combined with tags)" +msgstr "헤드만 표시 (태그와 결합 가능)" + +#: builtin/show-ref.c:167 +msgid "stricter reference checking, requires exact ref path" +msgstr "더 엄격한 레퍼런스 검사, 정확히 하나의 레퍼런스 경로 필요" + +#: builtin/show-ref.c:170 builtin/show-ref.c:172 +msgid "show the HEAD reference, even if it would be filtered out" +msgstr "HEAD 레퍼런스를 표시합니다 (필터링되서 제외되더라도)" + +#: builtin/show-ref.c:174 +msgid "dereference tags into object IDs" +msgstr "태그를 오브젝트 ID로 따라갑니다" + +#: builtin/show-ref.c:176 +msgid "only show SHA1 hash using <n> digits" +msgstr "SHA-1 표시에 <n>개의 숫자만 사용합니다" + +#: builtin/show-ref.c:180 +msgid "do not print results to stdout (useful with --verify)" +msgstr "표준 출력에 결과를 표시하지 않습니다 (--verify 옵션과 사용하면 좋음)" + +#: builtin/show-ref.c:182 +msgid "show refs from stdin that aren't in local repository" +msgstr "로컬 저장소에 없는 레퍼런스를 표준 입력에서 읽어 표시합니다" + +#: builtin/stripspace.c:17 +msgid "git stripspace [-s | --strip-comments]" +msgstr "git stripspace [-s | --strip-comments]" + +#: builtin/stripspace.c:18 +msgid "git stripspace [-c | --comment-lines]" +msgstr "git stripspace [-c | --comment-lines]" + +#: builtin/stripspace.c:35 +msgid "skip and remove all lines starting with comment character" +msgstr "주석 문자로 시작하는 모든 줄을 건너뛰고 제거합니다" + +#: builtin/stripspace.c:38 +msgid "prepend comment character and blank to each line" +msgstr "각 줄의 앞에 주석 문자를 붙이고 빈 줄로 만듭니다" + +#: builtin/submodule--helper.c:79 builtin/submodule--helper.c:167 +msgid "alternative anchor for relative paths" +msgstr "상대 경로에 사용할 또다른 기준" + +#: builtin/submodule--helper.c:84 +msgid "git submodule--helper list [--prefix=<path>] [<path>...]" +msgstr "git submodule--helper list [--prefix=<경로>] [<경로>...]" + +#: builtin/submodule--helper.c:114 +msgid "git submodule--helper name <path>" +msgstr "git submodule--helper name <경로>" + +#: builtin/submodule--helper.c:120 +#, c-format +msgid "no submodule mapping found in .gitmodules for path '%s'" +msgstr "경로 '%s'에 대해 .gitmodules에 있는 하위모듈 매핑이 없습니다" + +#: builtin/submodule--helper.c:170 +msgid "where the new submodule will be cloned to" +msgstr "새 하위 모듈을 복제할 대상 위치" + +#: builtin/submodule--helper.c:173 +msgid "name of the new submodule" +msgstr "새 하위 모듈 이름" + +#: builtin/submodule--helper.c:176 +msgid "url where to clone the submodule from" +msgstr "하위 모듈을 복제해 올 URL" + +#: builtin/submodule--helper.c:182 +msgid "depth for shallow clones" +msgstr "얕은 복제에 사용할 깊이" + +#: builtin/submodule--helper.c:188 +msgid "" +"git submodule--helper clone [--prefix=<path>] [--quiet] [--reference " +"<repository>] [--name <name>] [--url <url>][--depth <depth>] [--] [<path>...]" +msgstr "" +"git submodule--helper clone [--prefix=<경로>] [--quiet] [--reference <저장소" +">] [--name <이름>] [--url <URL>][--depth <깊이>] [--] [<경로>...]" + +#: builtin/submodule--helper.c:202 builtin/submodule--helper.c:208 +#: builtin/submodule--helper.c:216 +#, c-format +msgid "could not create directory '%s'" +msgstr "'%s' 디렉터리를 만들 수 없습니다" + +#: builtin/submodule--helper.c:204 +#, c-format +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "'%s'에서 하위 모듈 경로 '%s'에 복제하는데 실패했습니다" + +#: builtin/submodule--helper.c:227 +#, c-format +msgid "cannot open file '%s'" +msgstr "'%s' 파일을 열 수 없습니다" + +#: builtin/submodule--helper.c:232 +#, c-format +msgid "could not close file %s" +msgstr "%s 파일을 닫을 수 없습니다" + +#: builtin/submodule--helper.c:247 +#, c-format +msgid "could not get submodule directory for '%s'" +msgstr "'%s'에 대한 하위 모듈 디렉터리를 가져올 수 없습니다" + +#: builtin/submodule--helper.c:273 +msgid "fatal: submodule--helper subcommand must be called with a subcommand" +msgstr "" +"치명적 이상: submodule--helper 하위 명령은 하위 명령으로 호출해야 합니다" + +#: builtin/submodule--helper.c:280 +#, c-format +msgid "fatal: '%s' is not a valid submodule--helper subcommand" +msgstr "치명적 이상: '%s'은(는) 올바른 submodule--helper 하위 명령이 아닙니다" + +#: builtin/symbolic-ref.c:7 +msgid "git symbolic-ref [<options>] <name> [<ref>]" +msgstr "git symbolic-ref [<옵션>] <이름> [<레퍼런스>]" + +#: builtin/symbolic-ref.c:8 +msgid "git symbolic-ref -d [-q] <name>" +msgstr "git symbolic-ref -d [-q] <이름>" + +#: builtin/symbolic-ref.c:40 +msgid "suppress error message for non-symbolic (detached) refs" +msgstr "심볼이 아닌 (분리된) 레퍼런스에 대해 에러 메시지를 표시하지 않습니다" + +#: builtin/symbolic-ref.c:41 +msgid "delete symbolic ref" +msgstr "심볼릭 레퍼런스를 삭제합니다" + +#: builtin/symbolic-ref.c:42 +msgid "shorten ref output" +msgstr "레퍼런스 출력을 줄입니다" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:362 +msgid "reason" +msgstr "이유" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:362 +msgid "reason of the update" +msgstr "업데이트의 이유" + +#: builtin/tag.c:23 +msgid "" +"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> " +"[<head>]" +msgstr "" +"git tag [-a | -s | -u <키-ID>] [-f] [-m <메시지> | -F <파일>] <태그이름>\n" +"\t\t[<헤드>]" + +#: builtin/tag.c:24 +msgid "git tag -d <tagname>..." +msgstr "git tag -d <태그이름>..." + +#: builtin/tag.c:25 +msgid "" +"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]\n" +"\t\t[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]" +msgstr "" +"git tag -l [-n[<개수>]] [--contains <커밋>] [--points-at <오브젝트>]\n" +"\t\t[--format=<형식>] [--[no-]merged [<커밋>]] [<패턴>...]" + +#: builtin/tag.c:27 +msgid "git tag -v <tagname>..." +msgstr "git tag -v <태그이름>..." + +#: builtin/tag.c:80 +#, c-format +msgid "tag name too long: %.*s..." +msgstr "태그 이름이 너무 깁니다: %.*s..." + +#: builtin/tag.c:85 +#, c-format +msgid "tag '%s' not found." +msgstr "'%s' 태그가 없습니다." + +#: builtin/tag.c:100 +#, c-format +msgid "Deleted tag '%s' (was %s)\n" +msgstr "'%s' 태그 삭제함 (과거 %s)\n" + +#: builtin/tag.c:112 +#, c-format +msgid "could not verify the tag '%s'" +msgstr "'%s' 태그를 검증할 수 없습니다" + +#: builtin/tag.c:122 +#, c-format +msgid "" +"\n" +"Write a message for tag:\n" +" %s\n" +"Lines starting with '%c' will be ignored.\n" +msgstr "" +"\n" +"다음 태그에 대한 메시지를 쓰십시오:\n" +" %s\n" +"'%c' 문자로 시작하는 줄은 무시됩니다.\n" + +#: builtin/tag.c:126 +#, c-format +msgid "" +"\n" +"Write a message for tag:\n" +" %s\n" +"Lines starting with '%c' will be kept; you may remove them yourself if you " +"want to.\n" +msgstr "" +"\n" +"다음 태그에 대한 메시지를 쓰십시오:\n" +" %s\n" +"'%c' 문자로 시작하는 줄은 유지됩니다. 제거하려면 직접 지워야 합니다.\n" + +#: builtin/tag.c:199 +msgid "unable to sign the tag" +msgstr "태그에 서명할 수 없습니다" + +#: builtin/tag.c:201 +msgid "unable to write tag file" +msgstr "태그 파일을 쓸 수 없습니다" + +#: builtin/tag.c:226 +msgid "bad object type." +msgstr "잘못된 오브젝트 종류." + +#: builtin/tag.c:239 +msgid "tag header too big." +msgstr "태그 헤더가 너무 큽니다." + +#: builtin/tag.c:275 +msgid "no tag message?" +msgstr "태그 메시지 없음?" + +#: builtin/tag.c:281 +#, c-format +msgid "The tag message has been left in %s\n" +msgstr "태그 메시지가 %s 파일에 남아 있습니다\n" + +#: builtin/tag.c:339 +msgid "list tag names" +msgstr "태그 이름 목록을 표시합니다" + +#: builtin/tag.c:341 +msgid "print <n> lines of each tag message" +msgstr "각 태그 메시지의 <n>줄을 표시합니다" + +#: builtin/tag.c:343 +msgid "delete tags" +msgstr "태그를 삭제합니다" + +#: builtin/tag.c:344 +msgid "verify tags" +msgstr "태그를 검증합니다" + +#: builtin/tag.c:346 +msgid "Tag creation options" +msgstr "태그 만들기 옵션" + +#: builtin/tag.c:348 +msgid "annotated tag, needs a message" +msgstr "주석 달린 태그, 메시지가 필요합니다" + +#: builtin/tag.c:350 +msgid "tag message" +msgstr "태그 메시지" + +#: builtin/tag.c:352 +msgid "annotated and GPG-signed tag" +msgstr "주석 달리고 GPG 서명한 태그" + +#: builtin/tag.c:356 +msgid "use another key to sign the tag" +msgstr "태그를 서명하는데 지정한 키를 사용합니다" + +#: builtin/tag.c:357 +msgid "replace the tag if exists" +msgstr "태그가 있으면 바꿉니다" + +#: builtin/tag.c:358 builtin/update-ref.c:368 +msgid "create a reflog" +msgstr "reflog를 만듭니다" + +#: builtin/tag.c:360 +msgid "Tag listing options" +msgstr "태그 목록 보기 옵션" + +#: builtin/tag.c:361 +msgid "show tag list in columns" +msgstr "태그 목록을 여러 열로 표시합니다" + +#: builtin/tag.c:362 builtin/tag.c:363 +msgid "print only tags that contain the commit" +msgstr "해당 커밋이 들어 있는 태그만 표시합니다" + +#: builtin/tag.c:364 +msgid "print only tags that are merged" +msgstr "병합된 태그만 표시합니다" + +#: builtin/tag.c:365 +msgid "print only tags that are not merged" +msgstr "병합되지 않은 태그만 표시합니다" + +#: builtin/tag.c:370 +msgid "print only tags of the object" +msgstr "해당 오브젝트의 태그만 표시합니다" + +#: builtin/tag.c:399 +msgid "--column and -n are incompatible" +msgstr "--column 및 -n 옵션은 호환되지 않습니다" + +#: builtin/tag.c:419 +msgid "-n option is only allowed with -l." +msgstr "-n 옵션은 -l 옵션과 같이 써야 합니다." + +#: builtin/tag.c:421 +msgid "--contains option is only allowed with -l." +msgstr "--contains 옵션은 -l 옵션과 같이 써야 합니다." + +#: builtin/tag.c:423 +msgid "--points-at option is only allowed with -l." +msgstr "--points-at 옵션은 -l 옵션과 같이 써야 합니다." + +#: builtin/tag.c:425 +msgid "--merged and --no-merged option are only allowed with -l" +msgstr "--merged 및 --no-merged 옵션은 -l 옵션과 같이 써야 합니다." + +#: builtin/tag.c:433 +msgid "only one -F or -m option is allowed." +msgstr "하나의 -F 또는 -m 옵션만 쓸 수 있습니다." + +#: builtin/tag.c:453 +msgid "too many params" +msgstr "파라미터가 너무 많습니다" + +#: builtin/tag.c:459 +#, c-format +msgid "'%s' is not a valid tag name." +msgstr "'%s'은9는) 올바른 태그 이름이 아닙니다." + +#: builtin/tag.c:464 +#, c-format +msgid "tag '%s' already exists" +msgstr "태그 '%s'이(가) 이미 있습니다" + +#: builtin/tag.c:489 +#, c-format +msgid "Updated tag '%s' (was %s)\n" +msgstr "태그 '%s' 업데이트 (과거 %s)\n" + +#: builtin/unpack-objects.c:490 +msgid "Unpacking objects" +msgstr "오브젝트 묶음 푸는 중" + +#: builtin/update-index.c:70 +#, c-format +msgid "failed to create directory %s" +msgstr "%s 디렉터리 만들기 실패했습니다" + +#: builtin/update-index.c:76 +#, c-format +msgid "failed to stat %s" +msgstr "%s에 stat()하는데 실패했습니다" + +#: builtin/update-index.c:86 +#, c-format +msgid "failed to create file %s" +msgstr "%s 파일을 만드는데 실패했습니다" + +#: builtin/update-index.c:94 +#, c-format +msgid "failed to delete file %s" +msgstr "%s 파일을 삭제하는데 실패했습니다" + +#: builtin/update-index.c:101 builtin/update-index.c:203 +#, c-format +msgid "failed to delete directory %s" +msgstr "%s 디렉터리를 삭제하는데 실패했습니다" + +#: builtin/update-index.c:124 +#, c-format +msgid "Testing " +msgstr "테스트중 " + +#: builtin/update-index.c:136 +msgid "directory stat info does not change after adding a new file" +msgstr "새 파일을 추가한 후에 디렉터리 정보가 바뀌지 않았습니다" + +#: builtin/update-index.c:149 +msgid "directory stat info does not change after adding a new directory" +msgstr "새 디렉터리를 추가한 후에 디렉터리 정보가 바뀌지 않았습니다" + +#: builtin/update-index.c:162 +msgid "directory stat info changes after updating a file" +msgstr "파일을 업데이트한 후에 디렉터리 정보가 바뀌지 않았습니다" + +#: builtin/update-index.c:173 +msgid "directory stat info changes after adding a file inside subdirectory" +msgstr "하위 디렉터리에 파일을 추가한 후에 디렉터리 정보가 바뀌지 않았습니다" + +#: builtin/update-index.c:184 +msgid "directory stat info does not change after deleting a file" +msgstr "파일을 삭제한 후에 디렉터리 정보가 바뀌지 않았습니다" + +#: builtin/update-index.c:197 +msgid "directory stat info does not change after deleting a directory" +msgstr "디렉터리를 삭제한 후에 디렉터리 정보가 바뀌지 않았습니다" + +#: builtin/update-index.c:204 +msgid " OK" +msgstr " 오케이" + +#: builtin/update-index.c:564 +msgid "git update-index [<options>] [--] [<file>...]" +msgstr "git update-index [<옵션>] [--] [<파일>...]" + +#: builtin/update-index.c:918 +msgid "continue refresh even when index needs update" +msgstr "인덱스에 업데이트가 필요하더라도 새로 고침을 계속합니다" + +#: builtin/update-index.c:921 +msgid "refresh: ignore submodules" +msgstr "새로 고침: 하위 모듈 무시" + +#: builtin/update-index.c:924 +msgid "do not ignore new files" +msgstr "새 파일을 무시할 수 않습니다" + +#: builtin/update-index.c:926 +msgid "let files replace directories and vice-versa" +msgstr "디렉터리를 파일로, 또는 그 반대로 바꿀 수 있게 허용합니다" + +#: builtin/update-index.c:928 +msgid "notice files missing from worktree" +msgstr "작업폴더에서 알림 파일이 없습니다" + +#: builtin/update-index.c:930 +msgid "refresh even if index contains unmerged entries" +msgstr "인덱스에 병합하지 않은 항목이 있어도 새로 고칩니다" + +#: builtin/update-index.c:933 +msgid "refresh stat information" +msgstr "파일 정보를 새로 고칩니다" + +#: builtin/update-index.c:937 +msgid "like --refresh, but ignore assume-unchanged setting" +msgstr "--refresh와 동일하지만, assume-unchanged 설정을 무시합니다" + +#: builtin/update-index.c:941 +msgid "<mode>,<object>,<path>" +msgstr "<모드>,<오브젝트>,<경로>" + +#: builtin/update-index.c:942 +msgid "add the specified entry to the index" +msgstr "지정한 항목을 인덱스에 추가합니다" + +#: builtin/update-index.c:946 +msgid "(+/-)x" +msgstr "(+/-)x" + +#: builtin/update-index.c:947 +msgid "override the executable bit of the listed files" +msgstr "목록의 파일에서 실행 가능 비트를 바꿉니다" + +#: builtin/update-index.c:951 +msgid "mark files as \"not changing\"" +msgstr "파일을 \"바꾸지 않음\"으로 표시합니다" + +#: builtin/update-index.c:954 +msgid "clear assumed-unchanged bit" +msgstr "바꾸지 않음으로 가정 (assumed-unchanged) 비트를 지웁니다" + +#: builtin/update-index.c:957 +msgid "mark files as \"index-only\"" +msgstr "파일을 인덱스 전용으로 (\"index-only\") 표시합니다" + +#: builtin/update-index.c:960 +msgid "clear skip-worktree bit" +msgstr "작업폴더 건너뛰기 (skip-worktree) 비트를 지웁니다" + +#: builtin/update-index.c:963 +msgid "add to index only; do not add content to object database" +msgstr "인덱스에만 추가합니다. 내용을 오브젝트 데이터베이스에 추가하지 않습니다" + +#: builtin/update-index.c:965 +msgid "remove named paths even if present in worktree" +msgstr "작업 폴더에 있어도 해당 경로를 제거합니다" + +#: builtin/update-index.c:967 +msgid "with --stdin: input lines are terminated by null bytes" +msgstr "--stdin과 같이 사용: 입력 줄은 NUL 바이트로 끝납니다" + +#: builtin/update-index.c:969 +msgid "read list of paths to be updated from standard input" +msgstr "표준 입력에서 업데이트할 경로의 목록을 읽습니다" + +#: builtin/update-index.c:973 +msgid "add entries from standard input to the index" +msgstr "표준 입력에서 읽은 항목을 인덱스에 추가합니다" + +#: builtin/update-index.c:977 +msgid "repopulate stages #2 and #3 for the listed paths" +msgstr "경로 목록에 대해 #2 및 #3 스테이징을 다시 합니다" + +#: builtin/update-index.c:981 +msgid "only update entries that differ from HEAD" +msgstr "HEAD와 다른 항목만 업데이트합니다" + +#: builtin/update-index.c:985 +msgid "ignore files missing from worktree" +msgstr "작업 폴더에 없는 파일을 무시합니다" + +#: builtin/update-index.c:988 +msgid "report actions to standard output" +msgstr "표준 출력에 동작을 알립니다" + +#: builtin/update-index.c:990 +msgid "(for porcelains) forget saved unresolved conflicts" +msgstr "저장한 해결되지 않은 충돌을 무시합니다 (사용자용 명령 용도)" + +#: builtin/update-index.c:994 +msgid "write index in this format" +msgstr "인덱스를 이 형식으로 씁니다" + +#: builtin/update-index.c:996 +msgid "enable or disable split index" +msgstr "스플릿 인덱스를 켜거나 끕니다" + +#: builtin/update-index.c:998 +msgid "enable/disable untracked cache" +msgstr "추적하지 않는 캐시 사용을 켜거나 끕니다" + +#: builtin/update-index.c:1000 +msgid "enable untracked cache without testing the filesystem" +msgstr "파일 시스템 테스트 없이 추적하지 않는 캐시를 사용합니다" + +#: builtin/update-ref.c:9 +msgid "git update-ref [<options>] -d <refname> [<old-val>]" +msgstr "git update-ref [<옵션>] -d <레퍼런스이름> [<과거-값>]" + +#: builtin/update-ref.c:10 +msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]" +msgstr "git update-ref [<옵션>] <레퍼런스이름> <새-값> [<과거-값>]" + +#: builtin/update-ref.c:11 +msgid "git update-ref [<options>] --stdin [-z]" +msgstr "git update-ref [<옵션>] --stdin [-z]" + +#: builtin/update-ref.c:363 +msgid "delete the reference" +msgstr "레퍼런스를 삭제합니다" + +#: builtin/update-ref.c:365 +msgid "update <refname> not the one it points to" +msgstr "<레퍼런스이름>을 가리키지 않는 항목으로 업데이트합니다" + +#: builtin/update-ref.c:366 +msgid "stdin has NUL-terminated arguments" +msgstr "표준 입력에 NUL로 끝나는 인자가 있습니다" + +#: builtin/update-ref.c:367 +msgid "read updates from stdin" +msgstr "표준 입력에서 업데이트를 읽습니다" + +#: builtin/update-server-info.c:6 +msgid "git update-server-info [--force]" +msgstr "git update-server-info [--force]" + +#: builtin/update-server-info.c:14 +msgid "update the info files from scratch" +msgstr "바닥부터 정보 파일을 업데이트합니다" + +#: builtin/verify-commit.c:17 +msgid "git verify-commit [-v | --verbose] <commit>..." +msgstr "git verify-commit [-v | --verbose] <커밋>..." + +#: builtin/verify-commit.c:72 +msgid "print commit contents" +msgstr "커밋 내용을 표시합니다" + +#: builtin/verify-commit.c:73 builtin/verify-tag.c:84 +msgid "print raw gpg status output" +msgstr "원본 GPG 상태를 출력합니다" + +#: builtin/verify-pack.c:54 +msgid "git verify-pack [-v | --verbose] [-s | --stat-only] <pack>..." +msgstr "git verify-pack [-v | --verbose] [-s | --stat-only] <묶음>..." + +#: builtin/verify-pack.c:64 +msgid "verbose" +msgstr "자세히 표시" + +#: builtin/verify-pack.c:66 +msgid "show statistics only" +msgstr "통계만 표시" + +#: builtin/verify-tag.c:17 +msgid "git verify-tag [-v | --verbose] <tag>..." +msgstr "git verify-tag [-v | --verbose] <태그>..." + +#: builtin/verify-tag.c:83 +msgid "print tag contents" +msgstr "태그 내용 표시" + +#: builtin/worktree.c:15 +msgid "git worktree add [<options>] <path> [<branch>]" +msgstr "git worktree add [<옵션>] <경로> [<브랜치>]" + +#: builtin/worktree.c:16 +msgid "git worktree prune [<options>]" +msgstr "git worktree prune [<옵션>]" + +#: builtin/worktree.c:17 +msgid "git worktree list [<options>]" +msgstr "git worktree list [<옵션>]" + +#: builtin/worktree.c:39 +#, c-format +msgid "Removing worktrees/%s: not a valid directory" +msgstr "worktrees/%s 제거: 올바른 디렉터리가 아닙나다" + +#: builtin/worktree.c:45 +#, c-format +msgid "Removing worktrees/%s: gitdir file does not exist" +msgstr "worktrees/%s 제거: gitdir 파일이 없습니다" + +#: builtin/worktree.c:50 +#, c-format +msgid "Removing worktrees/%s: unable to read gitdir file (%s)" +msgstr "worktrees/%s 제거: gitdir 파일을 읽을 수 없습니다 (%s)" + +#: builtin/worktree.c:61 +#, c-format +msgid "Removing worktrees/%s: invalid gitdir file" +msgstr "worktrees/%s 제거: gitdir 파일이 올바르지 않습니다" + +#: builtin/worktree.c:77 +#, c-format +msgid "Removing worktrees/%s: gitdir file points to non-existent location" +msgstr "worktrees/%s 제거: gitdir 파일이 없는 위치를 가리킵니다" + +#: builtin/worktree.c:112 +#, c-format +msgid "failed to remove: %s" +msgstr "제거에 실패했습니다: %s" + +#: builtin/worktree.c:201 +#, c-format +msgid "'%s' already exists" +msgstr "'%s'이(가) 이미 있습니다" + +#: builtin/worktree.c:235 +#, c-format +msgid "could not create directory of '%s'" +msgstr "'%s'의 디렉터리를 만들 수 없습니다" + +#: builtin/worktree.c:271 +#, c-format +msgid "Preparing %s (identifier %s)" +msgstr "%s 준비 중 (ID %s)" + +#: builtin/worktree.c:319 +msgid "checkout <branch> even if already checked out in other worktree" +msgstr "다른 작업 폴더에서 체크아웃했더라도 <브랜치>를 체크아웃합니다" + +#: builtin/worktree.c:321 +msgid "create a new branch" +msgstr "새 브랜치를 만듭니다" + +#: builtin/worktree.c:323 +msgid "create or reset a branch" +msgstr "브랜치를 만들거나 리셋합니다" + +#: builtin/worktree.c:324 +msgid "detach HEAD at named commit" +msgstr "HEAD를 해당 커밋에서 분리합니다" + +#: builtin/worktree.c:331 +msgid "-b, -B, and --detach are mutually exclusive" +msgstr "-b, -B, --detach 옵션 중 하나만 쓸 수 있습니다" + +#: builtin/write-tree.c:13 +msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]" +msgstr "git write-tree [--missing-ok] [--prefix=<접두어>/]" + +#: builtin/write-tree.c:26 +msgid "<prefix>/" +msgstr "<접두어>/" + +#: builtin/write-tree.c:27 +msgid "write tree object for a subdirectory <prefix>" +msgstr "하위 디렉터리 <접두어>에 대해 트리 오브젝트를 씁니다" + +#: builtin/write-tree.c:30 +msgid "only useful for debugging" +msgstr "디버깅 용도로만 사용" + +#: credential-cache--daemon.c:255 +msgid "print debugging messages to stderr" +msgstr "디버깅 메시지를 표준오류로 출력합니다" + +#: git.c:14 +msgid "" +"'git help -a' and 'git help -g' list available subcommands and some\n" +"concept guides. See 'git help <command>' or 'git help <concept>'\n" +"to read about a specific subcommand or concept." +msgstr "" +"'git help -a' 및 'git help -g' 명령을 실행하면 하위 명령어와 개념 설명서의\n" +"목록을 볼 수 있습니다. 특정 하위 명령어나 개념에 대해 읽어 보려면 'git help\n" +"<명령>' 또는 'git help <개념>' 명령을 실행하십시오." + +#: common-cmds.h:9 +msgid "start a working area (see also: git help tutorial)" +msgstr "작업 공간 시작 (참고: git help tutorial)" + +#: common-cmds.h:10 +msgid "work on the current change (see also: git help everyday)" +msgstr "변경 사항에 대한 작업 (참고: git help everyday)" + +#: common-cmds.h:11 +msgid "examine the history and state (see also: git help revisions)" +msgstr "커밋 내역과 상태 보기 (참고: git help revisions)" + +#: common-cmds.h:12 +msgid "grow, mark and tweak your common history" +msgstr "커밋 내역을 키우고, 표시하고, 조작하기" + +#: common-cmds.h:13 +msgid "collaborate (see also: git help workflows)" +msgstr "협동 작업 (참고: git help workflows)" + +#: common-cmds.h:17 +msgid "Add file contents to the index" +msgstr "파일 내용을 인덱스에 추가합니다" + +#: common-cmds.h:18 +msgid "Use binary search to find the commit that introduced a bug" +msgstr "이진 탐색으로 버그를 만들어낸 커밋을 찾습니다" + +#: common-cmds.h:19 +msgid "List, create, or delete branches" +msgstr "브랜치를 만들거나, 삭제하거나, 목록을 출력합니다" + +#: common-cmds.h:20 +msgid "Switch branches or restore working tree files" +msgstr "브랜치를 전환하거나 작업 파일을 복구합니다" + +#: common-cmds.h:21 +msgid "Clone a repository into a new directory" +msgstr "저장소를 복제해 새 디렉터리로 가져 옵니다" + +#: common-cmds.h:22 +msgid "Record changes to the repository" +msgstr "바뀐 사항을 저장소에 기록합니다." + +#: common-cmds.h:23 +msgid "Show changes between commits, commit and working tree, etc" +msgstr "커밋과 커밋 사이, 커밋과 작업 내용 사이 등의 바뀐 점을 봅니다" + +#: common-cmds.h:24 +msgid "Download objects and refs from another repository" +msgstr "다른 저장소에서 오브젝트와 레퍼런스를 다운로드합니다" + +#: common-cmds.h:25 +msgid "Print lines matching a pattern" +msgstr "패턴과 일치하는 줄을 표시합니다" + +#: common-cmds.h:26 +msgid "Create an empty Git repository or reinitialize an existing one" +msgstr "빈 깃 저장소를 만들거나 기존 저장소를 다시 초기화합니다" + +#: common-cmds.h:27 +msgid "Show commit logs" +msgstr "커밋 기록을 표시합니다" + +#: common-cmds.h:28 +msgid "Join two or more development histories together" +msgstr "여러 개의 개발 내역을 하나로 합칩니다" + +#: common-cmds.h:29 +msgid "Move or rename a file, a directory, or a symlink" +msgstr "파일, 디렉터리, 심볼릭 링크를 옮기거나 이름을 바꿉니다" + +#: common-cmds.h:30 +msgid "Fetch from and integrate with another repository or a local branch" +msgstr "다른 저장소 또는 다른 로컬 브랜치에서 가져오거나 통합합니다" + +#: common-cmds.h:31 +msgid "Update remote refs along with associated objects" +msgstr "원격 레퍼런스 및 그와 관련된 오브젝트를 업데이트합니다" + +#: common-cmds.h:32 +msgid "Forward-port local commits to the updated upstream head" +msgstr "로컬 커밋을 업데이트된 업스트림 head 다음에 맞춰 넣습니다" + +#: common-cmds.h:33 +msgid "Reset current HEAD to the specified state" +msgstr "현재 HEAD를 지정한 상태로 재설정화합니다" + +#: common-cmds.h:34 +msgid "Remove files from the working tree and from the index" +msgstr "파일을 작업 폴더에서 제거하고 인덱스에서도 제거합니다" + +#: common-cmds.h:35 +msgid "Show various types of objects" +msgstr "여러가지 종류의 오브젝트를 표시합니다" + +#: common-cmds.h:36 +msgid "Show the working tree status" +msgstr "작업 폴더 상태를 표시합니다" + +#: common-cmds.h:37 +msgid "Create, list, delete or verify a tag object signed with GPG" +msgstr "태그를 만들거나, 표시하거나, 삭제하거나, GPG 서명을 검증합니다" + +#: parse-options.h:145 +msgid "expiry-date" +msgstr "만료-시각" + +#: parse-options.h:160 +msgid "no-op (backward compatibility)" +msgstr "아무 동작도 하지 않음 (호환용)" + +#: parse-options.h:237 +msgid "be more verbose" +msgstr "더 자세히 표시합니다" + +#: parse-options.h:239 +msgid "be more quiet" +msgstr "더 간략히 표시합니다" + +#: parse-options.h:245 +msgid "use <n> digits to display SHA-1s" +msgstr "SHA-1 표시에 <n>개의 숫자를 사용합니다" + +#: rerere.h:38 +msgid "update the index with reused conflict resolution if possible" +msgstr "가능하면 인덱스를 재사용한 충돌 해결로 업데이트합니다" + +#: git-bisect.sh:55 +msgid "You need to start by \"git bisect start\"" +msgstr "\"git bisect start\" 명령으로 시작해야 합니다" + +#. TRANSLATORS: Make sure to include [Y] and [n] in your +#. translation. The program will only accept English input +#. at this point. +#: git-bisect.sh:61 +msgid "Do you want me to do it for you [Y/n]? " +msgstr "지금 하시겠습니까 [Y/n]? " + +#: git-bisect.sh:122 +#, sh-format +msgid "unrecognised option: '$arg'" +msgstr "알 수 없는 옵션: '$arg'" + +#: git-bisect.sh:126 +#, sh-format +msgid "'$arg' does not appear to be a valid revision" +msgstr "'$arg'은(는) 올바른 리비전처럼 보이지 않습니다" + +#: git-bisect.sh:155 +msgid "Bad HEAD - I need a HEAD" +msgstr "잘못된 HEAD - HEAD가 필요합니다" + +#: git-bisect.sh:168 +#, sh-format +msgid "" +"Checking out '$start_head' failed. Try 'git bisect reset <valid-branch>'." +msgstr "" +"'$start_head' 받아오기가 실패했습니다. 'git bisect reset <valid-branch>'를 " +"해 보십시오." + +#: git-bisect.sh:178 +msgid "won't bisect on cg-seek'ed tree" +msgstr "cg-seek한 트리에서 bisect를 할 수 없습니다" + +#: git-bisect.sh:182 +msgid "Bad HEAD - strange symbolic ref" +msgstr "잘못된 HEAD - 심볼릭 레퍼런스가 잘못되었습니다" + +#: git-bisect.sh:234 +#, sh-format +msgid "Bad bisect_write argument: $state" +msgstr "잘못된 bisect_write 인자: $state" + +#: git-bisect.sh:263 +#, sh-format +msgid "Bad rev input: $arg" +msgstr "잘못된 리비전 입력: $arg" + +#: git-bisect.sh:278 +msgid "Please call 'bisect_state' with at least one argument." +msgstr "'bisect_state' 호출은 최소한 하나의 인자를 써야 합니다." + +#: git-bisect.sh:290 +#, sh-format +msgid "Bad rev input: $rev" +msgstr "잘못된 리비전 입력: $rev" + +#: git-bisect.sh:299 +#, sh-format +msgid "'git bisect $TERM_BAD' can take only one argument." +msgstr "'git bisect $TERM_BAD' 명령은 하나의 인자만 쓸 수 있습니다." + +#: git-bisect.sh:322 +#, sh-format +msgid "Warning: bisecting only with a $TERM_BAD commit." +msgstr "경고: 하나의 $TERM_BAD 커밋에 대해서만 이등분." + +#. TRANSLATORS: Make sure to include [Y] and [n] in your +#. translation. The program will only accept English input +#. at this point. +#: git-bisect.sh:328 +msgid "Are you sure [Y/n]? " +msgstr "확실합니까 [Y/n]? " + +#: git-bisect.sh:340 +#, sh-format +msgid "" +"You need to give me at least one $bad_syn and one $good_syn revision.\n" +"(You can use \"git bisect $bad_syn\" and \"git bisect $good_syn\" for that.)" +msgstr "" +"최소한 하나의 $bad_syn 및 하나의 $good_syn 리비전을 넘겨야 합니다.\n" +"(\"git bisect $bad_syn\" 및 \"git bisect $good_syn\" 명령을 실행하면 됩니다.)" + +#: git-bisect.sh:343 +#, sh-format +msgid "" +"You need to start by \"git bisect start\".\n" +"You then need to give me at least one $good_syn and one $bad_syn revision.\n" +"(You can use \"git bisect $bad_syn\" and \"git bisect $good_syn\" for that.)" +msgstr "" +"\"git bisect start\"를 실행해야 합니다.\n" +"그 다음 최소한 하나의 $good_syn 및 하나의 $bad_syn 리비전을 넘겨야 합니다\n" +"(\"git bisect $bad_syn\" 및 \"git bisect $good_syn\" 명령을 실행하면 됩니다.)" + +#: git-bisect.sh:414 git-bisect.sh:546 +msgid "We are not bisecting." +msgstr "이등분하는 중입니다." + +#: git-bisect.sh:421 +#, sh-format +msgid "'$invalid' is not a valid commit" +msgstr "'$invalid'은(는) 올바른 커밋이 아닙니다" + +#: git-bisect.sh:430 +#, sh-format +msgid "" +"Could not check out original HEAD '$branch'.\n" +"Try 'git bisect reset <commit>'." +msgstr "" +"본래의 HEAD '$branch'을(를) 체크아웃할 수 없습니다.\n" +"'git bisect reset <커밋>'을 해 보십시오" + +#: git-bisect.sh:458 +msgid "No logfile given" +msgstr "로그 파일이 주어지지 않았습니다" + +#: git-bisect.sh:459 +#, sh-format +msgid "cannot read $file for replaying" +msgstr "다시 재생할 $file 파일을 읽을 수 없습니다" + +#: git-bisect.sh:480 +msgid "?? what are you talking about?" +msgstr "?? 무슨 소리인지 모르겠습니다?" + +#: git-bisect.sh:492 +#, sh-format +msgid "running $command" +msgstr "실행: $command" + +#: git-bisect.sh:499 +#, sh-format +msgid "" +"bisect run failed:\n" +"exit code $res from '$command' is < 0 or >= 128" +msgstr "" +"이등분 실행이 실패했습니다:\n" +"'$command' 명령에서 상태 코드 '$res'이(가) 0보다 작거나 128보다 큽니다" + +#: git-bisect.sh:525 +msgid "bisect run cannot continue any more" +msgstr "이등분 실행을 계속 할 수 없습니다" + +#: git-bisect.sh:531 +#, sh-format +msgid "" +"bisect run failed:\n" +"'bisect_state $state' exited with error code $res" +msgstr "" +"이등분 실행이 실패했습니다:\n" +"'bisect_state $state' 명령에서 상태 코드가 '$res'입니다" + +#: git-bisect.sh:538 +msgid "bisect run success" +msgstr "이등분 실행 성공" + +#: git-bisect.sh:565 +msgid "please use two different terms" +msgstr "두 다른 용어를 사용하십시오" + +#: git-bisect.sh:575 +#, sh-format +msgid "'$term' is not a valid term" +msgstr "'$term'이(가) 올바른 용어가 아닙니다" + +#: git-bisect.sh:578 +#, sh-format +msgid "can't use the builtin command '$term' as a term" +msgstr "내부 명령어 '$term'을(를) 용어로 사용할 수 없습니다" + +#: git-bisect.sh:587 git-bisect.sh:593 +#, sh-format +msgid "can't change the meaning of term '$term'" +msgstr "용어 '$term'의 의미를 바꿀 수 없습니다" + +#: git-bisect.sh:606 +#, sh-format +msgid "Invalid command: you're currently in a $TERM_BAD/$TERM_GOOD bisect." +msgstr "잘못된 명령어: 현재 $TERM_BAD/$TERM_GOOD 이등분 중입니다." + +#: git-bisect.sh:636 +msgid "no terms defined" +msgstr "용어를 정의하지 않았습니다" + +#: git-bisect.sh:653 +#, sh-format +msgid "" +"invalid argument $arg for 'git bisect terms'.\n" +"Supported options are: --term-good|--term-old and --term-bad|--term-new." +msgstr "" +"'git bisect terms'에 대해 잘못된 인자 '$arg'.\n" +"지원하는 옵션은: --term-good|--term-old 및 --term-bad|--term-new." + +#: git-rebase.sh:57 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" +"이 문제를 해결하면, \"\"git rebase --continue\"를 실행하십시오.\n" +"이 패치를 건너뛰려면, 대신에 \"git rebase --skip\"을 실행하십시오.\n" +"원래 브랜치를 체크아웃하고 리베이스를 중지하려면, \"git rebase --abort\"를 실행하십시오." + +#: git-rebase.sh:165 +msgid "Applied autostash." +msgstr "자동스태시 적용." + +#: git-rebase.sh:168 +#, sh-format +msgid "Cannot store $stash_sha1" +msgstr "\"$stash_sha1\"을(를) 저장할 수 없습니다" + +#: git-rebase.sh:169 +msgid "" +"Applying autostash resulted in conflicts.\n" +"Your changes are safe in the stash.\n" +"You can run \"git stash pop\" or \"git stash drop\" at any time.\n" +msgstr "" +"자동스태시 적용에 충돌이 발생했습니다.\n" +"변경 사항은 스태시 안에 안전하게 들어 있습니다.\n" +"언제든지 \"git stash pop\" 또는 \"git stash drop\"을 실행할 수 있습니다.\n" + +#: git-rebase.sh:208 +msgid "The pre-rebase hook refused to rebase." +msgstr "리베이스 전 후크에서 리베이스를 거부했습니다." + +#: git-rebase.sh:213 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "git-am이 진행 중인 것처럼 보입니다. 리베이스할 수 없습니다." + +#: git-rebase.sh:354 +msgid "The --exec option must be used with the --interactive option" +msgstr "--exec 옵션은 --interactive 옵션과 같이 사용해야 합니다" + +#: git-rebase.sh:359 +msgid "No rebase in progress?" +msgstr "리베이스가 진행 중이지 않습니다" + +#: git-rebase.sh:370 +msgid "The --edit-todo action can only be used during interactive rebase." +msgstr "--edit-todo 동작은 대화형 리베이스에서만 사용할 수 있습니다." + +#: git-rebase.sh:377 +msgid "Cannot read HEAD" +msgstr "HEAD를 읽을 수 없습니다" + +#: git-rebase.sh:380 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"모든 병합 충돌을 편집하고 git add\n" +"명령으로 해결되었다고 표시해야 합니다" + +#: git-rebase.sh:398 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "'$head_name' 위치로 돌아갈 수 없습니다" + +#: git-rebase.sh:417 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"이미 '$state_dir_base' 디렉터리가 있는 것으로 보아, 이미\n" +"또 다른 리베이스 중에 있는 것 같습니다. 그러한 경우에는\n" +"다음을 시도해 보십시오:\n" +"\t$cmd_live_rebase\n" +"리베이스 중이 아니라면 다음을 시도하고,\n" +"\t$cmd_clear_stale_rebase\n" +"이 명령을 다시 실행하십시오. 중요한 사항이 남아 있을 경우를\n" +"대비해 여기서 멈춥니다." + +#: git-rebase.sh:468 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "잘못된 업스트림 $upstream_name" + +#: git-rebase.sh:492 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: 여러 개의 병합 베이스가 있습니다" + +#: git-rebase.sh:495 git-rebase.sh:499 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: 병합 베이스가 없습니다" + +#: git-rebase.sh:504 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "올바른 커밋을 가리키지 않습니다: $onto_name" + +#: git-rebase.sh:527 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "치명적 이상: 그런 브랜치가 없습니다: $branch_name" + +#: git-rebase.sh:560 +msgid "Cannot autostash" +msgstr "자동 스태시를 할 수 없습니다" + +#: git-rebase.sh:565 +#, sh-format +msgid "Created autostash: $stash_abbrev" +msgstr "자동 스태시를 만들었습니다: $stash_abbrev" + +#: git-rebase.sh:569 +msgid "Please commit or stash them." +msgstr "커밋하거나 스태시에 넣으십시오." + +#: git-rebase.sh:589 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "현재 브랜치가 ($branch_name) 최신 상태입니다." + +#: git-rebase.sh:593 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "현재 브랜치가 ($branch_name) 최신 상태입니다. 강제 리베이스합니다." + +#: git-rebase.sh:604 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "변경 사항 '$mb'에서 '$onto'(으)로:" + +#: git-rebase.sh:613 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "작업 사항을 다시 넣기 위해 먼저 헤드를 뒤로 돌립니다..." + +#: git-rebase.sh:623 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "$branch_name 브랜치를 $onto_name 위치로 정방향 진행합니다." + +#: git-stash.sh:51 +msgid "git stash clear with parameters is unimplemented" +msgstr "git stash clear 명령을 파라미터와 같이 쓰기는 구현되지 않았습니다" + +#: git-stash.sh:74 +msgid "You do not have the initial commit yet" +msgstr "아직 최초 커밋이 없습니다" + +#: git-stash.sh:89 +msgid "Cannot save the current index state" +msgstr "현재 인덱스 상태를 저장할 수 없습니다" + +#: git-stash.sh:124 git-stash.sh:137 +msgid "Cannot save the current worktree state" +msgstr "현재 작업 폴더 상태를 저장할 수 없습니다" + +#: git-stash.sh:141 +msgid "No changes selected" +msgstr "변경 사항을 선택하지 않았습니다" + +#: git-stash.sh:144 +msgid "Cannot remove temporary index (can't happen)" +msgstr "임시 인덱스를 제거할 수 없습니다 (일어날 수 없는 상황)" + +#: git-stash.sh:157 +msgid "Cannot record working tree state" +msgstr "작업 폴더 상태를 기록할 수 없습니다" + +#: git-stash.sh:189 +#, sh-format +msgid "Cannot update $ref_stash with $w_commit" +msgstr "$ref_stash을(를) $w_commit(으)로 업데이트할 수 없습니다" + +#. TRANSLATORS: $option is an invalid option, like +#. `--blah-blah'. The 7 spaces at the beginning of the +#. second line correspond to "error: ". So you should line +#. up the second line with however many characters the +#. translation of "error: " takes in your language. E.g. in +#. English this is: +#. +#. $ git stash save --blah-blah 2>&1 | head -n 2 +#. error: unknown option for 'stash save': --blah-blah +#. To provide a message, use git stash save -- '--blah-blah' +#: git-stash.sh:239 +#, sh-format +msgid "" +"error: unknown option for 'stash save': $option\n" +" To provide a message, use git stash save -- '$option'" +msgstr "" +"오류: 'stash save'에 대해 알 수 없는 옵션: $option\n" +" 메시지를 넘기려면, 다음과 같이 쓰십시오: git stash save -- '$option'" + +#: git-stash.sh:260 +msgid "No local changes to save" +msgstr "저장할 로컬 변경 사항이 없습니다" + +#: git-stash.sh:264 +msgid "Cannot initialize stash" +msgstr "스태시를 초기화할 수 없습니다" + +#: git-stash.sh:268 +msgid "Cannot save the current status" +msgstr "현재 상태를 저장할 수 없습니다" + +#: git-stash.sh:286 +msgid "Cannot remove worktree changes" +msgstr "작업폴더 변경 사항을 제거할 수 없습니다" + +#: git-stash.sh:405 +#, sh-format +msgid "unknown option: $opt" +msgstr "알 수 없는 옵션: $opt" + +#: git-stash.sh:415 +msgid "No stash found." +msgstr "스태시가 없습니다." + +#: git-stash.sh:422 +#, sh-format +msgid "Too many revisions specified: $REV" +msgstr "너무 많은 리비전을 지정했습니다: $REV" + +#: git-stash.sh:428 +#, sh-format +msgid "$reference is not a valid reference" +msgstr "$reference은(는) 올바른 레퍼런스가 아닙니다" + +#: git-stash.sh:456 +#, sh-format +msgid "'$args' is not a stash-like commit" +msgstr "'$args'은(는) 스태시 커밋이 아닙니다" + +#: git-stash.sh:467 +#, sh-format +msgid "'$args' is not a stash reference" +msgstr "'$args'은(는) 스태시 레퍼런스가 아닙니다" + +#: git-stash.sh:475 +msgid "unable to refresh index" +msgstr "인덱스를 새로 고칠 수 없습니다" + +#: git-stash.sh:479 +msgid "Cannot apply a stash in the middle of a merge" +msgstr "병합 도중에 스태시를 적용할 수 없습니다" + +#: git-stash.sh:487 +msgid "Conflicts in index. Try without --index." +msgstr "인덱스에 충돌. --index 없이 시도해 보십시오." + +#: git-stash.sh:489 +msgid "Could not save index tree" +msgstr "인덱스 트리를 저장할 수 없습니다" + +#: git-stash.sh:523 +msgid "Cannot unstage modified files" +msgstr "수정한 파일을 스테이지에서 뺄 수 없습니다" + +#: git-stash.sh:538 +msgid "Index was not unstashed." +msgstr "인덱스가 스태시에서 빠졌습니다." + +#: git-stash.sh:561 +#, sh-format +msgid "Dropped ${REV} ($s)" +msgstr "${REV} 지움 ($s)" + +#: git-stash.sh:562 +#, sh-format +msgid "${REV}: Could not drop stash entry" +msgstr "${REV}: 스태시 항목을 지울 수 없습니다" + +#: git-stash.sh:570 +msgid "No branch name specified" +msgstr "브랜치 이름을 지정하지 않았습니다" + +#: git-stash.sh:642 +msgid "(To restore them type \"git stash apply\")" +msgstr "(복구하려면 \"git stash apply\"를 실행하십시오)" + +#: git-submodule.sh:104 +#, sh-format +msgid "cannot strip one component off url '$remoteurl'" +msgstr "'$remoteurl' URL에서 하나의 항목을 잘라낼 수 없습니다" + +#: git-submodule.sh:281 +msgid "Relative path can only be used from the toplevel of the working tree" +msgstr "상대 경로는 작업 폴더의 최상위에서만 쓸 수 있습니다" + +#: git-submodule.sh:291 +#, sh-format +msgid "repo URL: '$repo' must be absolute or begin with ./|../" +msgstr "저장소 URL: '$repo' 값은 절대 경로거나 ./ 또는 ../로 시작해야 합니다." + +#: git-submodule.sh:308 +#, sh-format +msgid "'$sm_path' already exists in the index" +msgstr "'$sm_path'은(는) 이미 인덱스에 있습니다" + +#: git-submodule.sh:312 +#, sh-format +msgid "" +"The following path is ignored by one of your .gitignore files:\n" +"$sm_path\n" +"Use -f if you really want to add it." +msgstr "" +"다음 경로는 .gitignore 파일에서 무시합니다:\n" +"$sm_path\n" +"정말로 추가하려면 -f 옵션을 사용하십시오." + +#: git-submodule.sh:330 +#, sh-format +msgid "Adding existing repo at '$sm_path' to the index" +msgstr "'$sm_path'의 기존 저장소를 인덱스에 추가합니다" + +#: git-submodule.sh:332 +#, sh-format +msgid "'$sm_path' already exists and is not a valid git repo" +msgstr "'$sm_path'이(가) 이미 있고 올바른 git 저장소가 아닙니다" + +#: git-submodule.sh:340 +#, sh-format +msgid "A git directory for '$sm_name' is found locally with remote(s):" +msgstr "'$sm_name'에 대한 깃 디렉터리가 로컬에서 리모트가 있는 채로 있습니다:" + +#: git-submodule.sh:342 +#, sh-format +msgid "" +"If you want to reuse this local git directory instead of cloning again from" +msgstr "다시 복제하지 않고 이 로컬 깃 디렉터리를 재활용하려면" + +#: git-submodule.sh:344 +#, sh-format +msgid "" +"use the '--force' option. If the local git directory is not the correct repo" +msgstr "" +"'--force' 옵션을 사용하십시오. 로컬 깃 디렉터리가 올바른 저장소가 아니거나" + +#: git-submodule.sh:345 +#, sh-format +msgid "" +"or you are unsure what this means choose another name with the '--name' " +"option." +msgstr "무슨 의미인지 잘 모르겠다면 '--name' 옵션으로 다른 이름을 쓰십시오." + +#: git-submodule.sh:347 +#, sh-format +msgid "Reactivating local git directory for submodule '$sm_name'." +msgstr "로컬 깃 디렉터리를 '$sm_name' 하위모듈로 다시 활성화합니다." + +#: git-submodule.sh:359 +#, sh-format +msgid "Unable to checkout submodule '$sm_path'" +msgstr "'$sm_path' 하위 모듈을 체크아웃할 수 없습니다" + +#: git-submodule.sh:364 +#, sh-format +msgid "Failed to add submodule '$sm_path'" +msgstr "'$sm_path' 하위 모듈을 추가하는데 실패했습니다" + +#: git-submodule.sh:373 +#, sh-format +msgid "Failed to register submodule '$sm_path'" +msgstr "'$sm_path' 하위 모듈을 등록하는데 실패했습니다" + +#: git-submodule.sh:417 +#, sh-format +msgid "Entering '$prefix$displaypath'" +msgstr "'$prefix$displaypath' 입력" + +#: git-submodule.sh:437 +#, sh-format +msgid "Stopping at '$prefix$displaypath'; script returned non-zero status." +msgstr "'$prefix$displaypath' 위치에서 멈춤. 스크립트에서 0이 아닌 상태를 리턴했습니다." + +#: git-submodule.sh:483 +#, sh-format +msgid "No url found for submodule path '$displaypath' in .gitmodules" +msgstr ".gitmodules에서 하위 모듈 경로 '$displaypath'에 대한 URL이 없습니다" + +#: git-submodule.sh:492 +#, sh-format +msgid "Failed to register url for submodule path '$displaypath'" +msgstr "하위 모듈 경로 '$displaypath'에 대한 URL을 등록하는데 실패했습니다" + +#: git-submodule.sh:494 +#, sh-format +msgid "Submodule '$name' ($url) registered for path '$displaypath'" +msgstr "'$displaypath' 경로에 ($url) 대해 등록된 '$name' 하위 모듈" + +#: git-submodule.sh:511 +#, sh-format +msgid "Failed to register update mode for submodule path '$displaypath'" +msgstr "하위 모듈 경로 '$displaypath'에 대해 업데이트 모드를 등록하는데 실패했습니다" + +#: git-submodule.sh:549 +#, sh-format +msgid "Use '.' if you really want to deinitialize all submodules" +msgstr "정말로 모든 하위 모듈 초기화를 해제하려면 '.'을 사용하십시오" + +#: git-submodule.sh:566 +#, sh-format +msgid "Submodule work tree '$displaypath' contains a .git directory" +msgstr "하위 모듈 작업 폴더에 ('$displaypath') .git 디렉터리가 들어 있습니다" + +#: git-submodule.sh:567 +#, sh-format +msgid "" +"(use 'rm -rf' if you really want to remove it including all of its history)" +msgstr "(정말로 그 커밋 내역까지 포함해 제거하려면 'rm -rf'를 사용하십시오)" + +#: git-submodule.sh:573 +#, sh-format +msgid "" +"Submodule work tree '$displaypath' contains local modifications; use '-f' to " +"discard them" +msgstr "하위 모듈 작업 폴더에 ('$displaypath') 로컬 수정 사항이 있습니다. 버리려면 '-f'를 사용하십시오" + +#: git-submodule.sh:576 +#, sh-format +msgid "Cleared directory '$displaypath'" +msgstr "'$displaypath' 디렉터리를 지웁니다" + +#: git-submodule.sh:577 +#, sh-format +msgid "Could not remove submodule work tree '$displaypath'" +msgstr "하위 모듈 디렉터리를 ('$displaypath') 제거할 수 없습니다" + +#: git-submodule.sh:580 +#, sh-format +msgid "Could not create empty submodule directory '$displaypath'" +msgstr "빈 하위 모듈 디렉터리를 ('$displaypath') 만들 수 없습니다" + +#: git-submodule.sh:589 +#, sh-format +msgid "Submodule '$name' ($url) unregistered for path '$displaypath'" +msgstr "'$name' 하위 모듈이 ($url) '$displaypath' 경로에 대해 등록되지 않았습니다" + +#: git-submodule.sh:705 +#, sh-format +msgid "" +"Submodule path '$displaypath' not initialized\n" +"Maybe you want to use 'update --init'?" +msgstr "" +"하위 모듈 경로가 ('$displaypath') 초기화되지 않았습니다\n" +"아마도 'update --init'이 필요합니다?" + +#: git-submodule.sh:718 +#, sh-format +msgid "Unable to find current revision in submodule path '$displaypath'" +msgstr "하위 모듈 경로에서 ('$displaypath') 현재 리비전을 찾을 수 없습니다" + +#: git-submodule.sh:727 +#, sh-format +msgid "Unable to fetch in submodule path '$sm_path'" +msgstr "하위 모듈 경로 '$sm_path'에서 가져올 수 없습니다" + +#: git-submodule.sh:751 +#, sh-format +msgid "Unable to fetch in submodule path '$displaypath'" +msgstr "하위 모듈 경로 '$displaypath'에서 가져올 수 없습니다" + +#: git-submodule.sh:765 +#, sh-format +msgid "Unable to checkout '$sha1' in submodule path '$displaypath'" +msgstr "하위 모듈 경로 '$displaypath'에서 '$sha1'을(를) 체크아웃할 수 없습니다" + +#: git-submodule.sh:766 +#, sh-format +msgid "Submodule path '$displaypath': checked out '$sha1'" +msgstr "하위 모듈 경로 '$displaypath': '$sha1' 체크아웃" + +#: git-submodule.sh:770 +#, sh-format +msgid "Unable to rebase '$sha1' in submodule path '$displaypath'" +msgstr "하위 모듈 경로 '$displaypath'에서 '$sha1'을(를) 리베이스할 수 없습니다" + +#: git-submodule.sh:771 +#, sh-format +msgid "Submodule path '$displaypath': rebased into '$sha1'" +msgstr "하위 모듈 경로 '$displaypath': '$sha1'(으)로 리베이스" + +#: git-submodule.sh:776 +#, sh-format +msgid "Unable to merge '$sha1' in submodule path '$displaypath'" +msgstr "하위 모듈 경로 '$displaypath'에서 '$sha1' 병합할 수 없습니다" + +#: git-submodule.sh:777 +#, sh-format +msgid "Submodule path '$displaypath': merged in '$sha1'" +msgstr "하위 모듈 경로 '$displaypath': '$sha1'에서 병합" + +#: git-submodule.sh:782 +#, sh-format +msgid "" +"Execution of '$command $sha1' failed in submodule path '$prefix$sm_path'" +msgstr "하위 모듈 경로 '$prefix$sm_path'에서 '$command $sha1' 실행이 실패했습니다" + +#: git-submodule.sh:783 +#, sh-format +msgid "Submodule path '$prefix$sm_path': '$command $sha1'" +msgstr "하위 모듈 경로 '$prefix$sm_path': '$command $sha1'" + +#: git-submodule.sh:813 +#, sh-format +msgid "Failed to recurse into submodule path '$displaypath'" +msgstr "재귀적으로 하위 모듈 경로 '$displaypath'에 들어가는데 실패했습니다" + +#: git-submodule.sh:921 +msgid "The --cached option cannot be used with the --files option" +msgstr "--cached 옵션은 --files 옵션과 같이 쓸 수 없습니다" + +#: git-submodule.sh:973 +#, sh-format +msgid "unexpected mode $mod_dst" +msgstr "예상치 못한 모드 $mod_dst" + +#: git-submodule.sh:993 +#, sh-format +msgid " Warn: $display_name doesn't contain commit $sha1_src" +msgstr " 경고: '$display_name'에 '$sha1_src' 커밋이 들어있지 않습니다" + +#: git-submodule.sh:996 +#, sh-format +msgid " Warn: $display_name doesn't contain commit $sha1_dst" +msgstr " 경고: '$display_name'에 '$sha1_dst' 커밋이 들어있지 않습니다" + +#: git-submodule.sh:999 +#, sh-format +msgid " Warn: $display_name doesn't contain commits $sha1_src and $sha1_dst" +msgstr " 경고: '$display_name'에 '$sha1_src' 및 '$sha1_dst' 커밋이 들어있지 않습니다" + +#: git-submodule.sh:1024 +msgid "blob" +msgstr "블롭" + +#: git-submodule.sh:1142 +#, sh-format +msgid "Failed to recurse into submodule path '$sm_path'" +msgstr "재귀적으로 하위 모듈 경로 '$sm_path'에 들어가는데 실패했습니다" + +#: git-submodule.sh:1206 +#, sh-format +msgid "Synchronizing submodule url for '$displaypath'" +msgstr "하위 모듈 URL을 '$displaypath'에 대해 동기화" diff --git a/progress.c b/progress.c index 353bd37416..76a88c573f 100644 --- a/progress.c +++ b/progress.c @@ -247,7 +247,7 @@ void stop_progress_msg(struct progress **p_progress, const char *msg) size_t len = strlen(msg) + 5; struct throughput *tp = progress->throughput; - bufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1); + bufp = (len < sizeof(buf)) ? buf : xmallocz(len); if (tp) { unsigned int rate = !tp->avg_misecs ? 0 : tp->avg_bytes / tp->avg_misecs; diff --git a/reachable.c b/reachable.c index 43616d49c7..ed35201896 100644 --- a/reachable.c +++ b/reachable.c @@ -43,15 +43,14 @@ static int add_one_ref(const char *path, const struct object_id *oid, * The traversal will have already marked us as SEEN, so we * only need to handle any progress reporting here. */ -static void mark_object(struct object *obj, const struct name_path *path, - const char *name, void *data) +static void mark_object(struct object *obj, const char *name, void *data) { update_progress(data); } static void mark_commit(struct commit *c, void *data) { - mark_object(&c->object, NULL, NULL, data); + mark_object(&c->object, NULL, data); } struct recent_data { diff --git a/read-cache.c b/read-cache.c index 84616c8e21..d9fb78bc55 100644 --- a/read-cache.c +++ b/read-cache.c @@ -327,7 +327,7 @@ int ie_match_stat(const struct index_state *istate, * by definition never matches what is in the work tree until it * actually gets added. */ - if (ce->ce_flags & CE_INTENT_TO_ADD) + if (ce_intent_to_add(ce)) return DATA_CHANGED | TYPE_CHANGED | MODE_CHANGED; changed = ce_match_stat_basic(ce, st); @@ -1237,7 +1237,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, if (cache_errno == ENOENT) fmt = deleted_fmt; - else if (ce->ce_flags & CE_INTENT_TO_ADD) + else if (ce_intent_to_add(ce)) fmt = added_fmt; /* must be before other checks */ else if (changed & TYPE_CHANGED) fmt = typechange_fmt; @@ -1519,6 +1519,28 @@ static void check_ce_order(struct index_state *istate) } } +static void tweak_untracked_cache(struct index_state *istate) +{ + switch (git_config_get_untracked_cache()) { + case -1: /* keep: do nothing */ + break; + case 0: /* false */ + remove_untracked_cache(istate); + break; + case 1: /* true */ + add_untracked_cache(istate); + break; + default: /* unknown value: do nothing */ + break; + } +} + +static void post_read_index_from(struct index_state *istate) +{ + check_ce_order(istate); + tweak_untracked_cache(istate); +} + /* remember to discard_cache() before reading a different cache! */ int do_read_index(struct index_state *istate, const char *path, int must_exist) { @@ -1622,9 +1644,10 @@ int read_index_from(struct index_state *istate, const char *path) return istate->cache_nr; ret = do_read_index(istate, path, 0); + split_index = istate->split_index; if (!split_index || is_null_sha1(split_index->base_sha1)) { - check_ce_order(istate); + post_read_index_from(istate); return ret; } @@ -1642,7 +1665,7 @@ int read_index_from(struct index_state *istate, const char *path) sha1_to_hex(split_index->base_sha1)), sha1_to_hex(split_index->base->sha1)); merge_base_index(istate); - check_ce_order(istate); + post_read_index_from(istate); return ret; } diff --git a/ref-filter.c b/ref-filter.c index 7bef7f8dac..bb79d6b9cc 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -16,14 +16,162 @@ typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type; +struct align { + align_type position; + unsigned int width; +}; + +/* + * An atom is a valid field atom listed below, possibly prefixed with + * a "*" to denote deref_tag(). + * + * We parse given format string and sort specifiers, and make a list + * of properties that we need to extract out of objects. ref_array_item + * structure will hold an array of values extracted that can be + * indexed with the "atom number", which is an index into this + * array. + */ +static struct used_atom { + const char *name; + cmp_type type; + union { + char color[COLOR_MAXLEN]; + struct align align; + enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT } + remote_ref; + struct { + enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB } option; + unsigned int nlines; + } contents; + enum { O_FULL, O_SHORT } objectname; + } u; +} *used_atom; +static int used_atom_cnt, need_tagged, need_symref; +static int need_color_reset_at_eol; + +static void color_atom_parser(struct used_atom *atom, const char *color_value) +{ + if (!color_value) + die(_("expected format: %%(color:<color>)")); + if (color_parse(color_value, atom->u.color) < 0) + die(_("unrecognized color: %%(color:%s)"), color_value); +} + +static void remote_ref_atom_parser(struct used_atom *atom, const char *arg) +{ + if (!arg) + atom->u.remote_ref = RR_NORMAL; + else if (!strcmp(arg, "short")) + atom->u.remote_ref = RR_SHORTEN; + else if (!strcmp(arg, "track")) + atom->u.remote_ref = RR_TRACK; + else if (!strcmp(arg, "trackshort")) + atom->u.remote_ref = RR_TRACKSHORT; + else + die(_("unrecognized format: %%(%s)"), atom->name); +} + +static void body_atom_parser(struct used_atom *atom, const char *arg) +{ + if (arg) + die("%%(body) does not take arguments"); + atom->u.contents.option = C_BODY_DEP; +} + +static void subject_atom_parser(struct used_atom *atom, const char *arg) +{ + if (arg) + die("%%(subject) does not take arguments"); + atom->u.contents.option = C_SUB; +} + +static void contents_atom_parser(struct used_atom *atom, const char *arg) +{ + if (!arg) + atom->u.contents.option = C_BARE; + else if (!strcmp(arg, "body")) + atom->u.contents.option = C_BODY; + else if (!strcmp(arg, "signature")) + atom->u.contents.option = C_SIG; + else if (!strcmp(arg, "subject")) + atom->u.contents.option = C_SUB; + else if (skip_prefix(arg, "lines=", &arg)) { + atom->u.contents.option = C_LINES; + if (strtoul_ui(arg, 10, &atom->u.contents.nlines)) + die(_("positive value expected contents:lines=%s"), arg); + } else + die(_("unrecognized %%(contents) argument: %s"), arg); +} + +static void objectname_atom_parser(struct used_atom *atom, const char *arg) +{ + if (!arg) + atom->u.objectname = O_FULL; + else if (!strcmp(arg, "short")) + atom->u.objectname = O_SHORT; + else + die(_("unrecognized %%(objectname) argument: %s"), arg); +} + +static align_type parse_align_position(const char *s) +{ + if (!strcmp(s, "right")) + return ALIGN_RIGHT; + else if (!strcmp(s, "middle")) + return ALIGN_MIDDLE; + else if (!strcmp(s, "left")) + return ALIGN_LEFT; + return -1; +} + +static void align_atom_parser(struct used_atom *atom, const char *arg) +{ + struct align *align = &atom->u.align; + struct string_list params = STRING_LIST_INIT_DUP; + int i; + unsigned int width = ~0U; + + if (!arg) + die(_("expected format: %%(align:<width>,<position>)")); + + align->position = ALIGN_LEFT; + + string_list_split(¶ms, arg, ',', -1); + for (i = 0; i < params.nr; i++) { + const char *s = params.items[i].string; + int position; + + if (skip_prefix(s, "position=", &s)) { + position = parse_align_position(s); + if (position < 0) + die(_("unrecognized position:%s"), s); + align->position = position; + } else if (skip_prefix(s, "width=", &s)) { + if (strtoul_ui(s, 10, &width)) + die(_("unrecognized width:%s"), s); + } else if (!strtoul_ui(s, 10, &width)) + ; + else if ((position = parse_align_position(s)) >= 0) + align->position = position; + else + die(_("unrecognized %%(align) argument: %s"), s); + } + + if (width == ~0U) + die(_("positive width expected with the %%(align) atom")); + align->width = width; + string_list_clear(¶ms, 0); +} + static struct { const char *name; cmp_type cmp_type; + void (*parser)(struct used_atom *atom, const char *arg); } valid_atom[] = { { "refname" }, { "objecttype" }, { "objectsize", FIELD_ULONG }, - { "objectname" }, + { "objectname", FIELD_STR, objectname_atom_parser }, { "tree" }, { "parent" }, { "numparent", FIELD_ULONG }, @@ -44,31 +192,21 @@ static struct { { "taggerdate", FIELD_TIME }, { "creator" }, { "creatordate", FIELD_TIME }, - { "subject" }, - { "body" }, - { "contents" }, - { "upstream" }, - { "push" }, + { "subject", FIELD_STR, subject_atom_parser }, + { "body", FIELD_STR, body_atom_parser }, + { "contents", FIELD_STR, contents_atom_parser }, + { "upstream", FIELD_STR, remote_ref_atom_parser }, + { "push", FIELD_STR, remote_ref_atom_parser }, { "symref" }, { "flag" }, { "HEAD" }, - { "color" }, - { "align" }, + { "color", FIELD_STR, color_atom_parser }, + { "align", FIELD_STR, align_atom_parser }, { "end" }, }; #define REF_FORMATTING_STATE_INIT { 0, NULL } -struct align { - align_type position; - unsigned int width; -}; - -struct contents { - unsigned int lines; - struct object_id oid; -}; - struct ref_formatting_stack { struct ref_formatting_stack *prev; struct strbuf output; @@ -85,33 +223,18 @@ struct atom_value { const char *s; union { struct align align; - struct contents contents; } u; void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state); unsigned long ul; /* used for sorting when not FIELD_STR */ }; /* - * An atom is a valid field atom listed above, possibly prefixed with - * a "*" to denote deref_tag(). - * - * We parse given format string and sort specifiers, and make a list - * of properties that we need to extract out of objects. ref_array_item - * structure will hold an array of values extracted that can be - * indexed with the "atom number", which is an index into this - * array. - */ -static const char **used_atom; -static cmp_type *used_atom_type; -static int used_atom_cnt, need_tagged, need_symref; -static int need_color_reset_at_eol; - -/* * Used to parse format string and sort specifiers */ int parse_ref_filter_atom(const char *atom, const char *ep) { const char *sp; + const char *arg; int i, at; sp = atom; @@ -122,24 +245,24 @@ int parse_ref_filter_atom(const char *atom, const char *ep) /* Do we have the atom already used elsewhere? */ for (i = 0; i < used_atom_cnt; i++) { - int len = strlen(used_atom[i]); - if (len == ep - atom && !memcmp(used_atom[i], atom, len)) + int len = strlen(used_atom[i].name); + if (len == ep - atom && !memcmp(used_atom[i].name, atom, len)) return i; } /* Is the atom a valid one? */ for (i = 0; i < ARRAY_SIZE(valid_atom); i++) { int len = strlen(valid_atom[i].name); + /* * If the atom name has a colon, strip it and everything after * it off - it specifies the format for this entry, and * shouldn't be used for checking against the valid_atom * table. */ - const char *formatp = strchr(sp, ':'); - if (!formatp || ep < formatp) - formatp = ep; - if (len == formatp - sp && !memcmp(valid_atom[i].name, sp, len)) + arg = memchr(sp, ':', ep - sp); + if (len == (arg ? arg : ep) - sp && + !memcmp(valid_atom[i].name, sp, len)) break; } @@ -150,12 +273,16 @@ int parse_ref_filter_atom(const char *atom, const char *ep) at = used_atom_cnt; used_atom_cnt++; REALLOC_ARRAY(used_atom, used_atom_cnt); - REALLOC_ARRAY(used_atom_type, used_atom_cnt); - used_atom[at] = xmemdupz(atom, ep - atom); - used_atom_type[at] = valid_atom[i].cmp_type; + used_atom[at].name = xmemdupz(atom, ep - atom); + used_atom[at].type = valid_atom[i].cmp_type; + if (arg) + arg = used_atom[at].name + (arg - atom) + 1; + memset(&used_atom[at].u, 0, sizeof(used_atom[at].u)); + if (valid_atom[i].parser) + valid_atom[i].parser(&used_atom[at], arg); if (*atom == '*') need_tagged = 1; - if (!strcmp(used_atom[at], "symref")) + if (!strcmp(used_atom[at].name, "symref")) need_symref = 1; return at; } @@ -258,22 +385,6 @@ static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_sta pop_stack_element(&state->stack); } -static int match_atom_name(const char *name, const char *atom_name, const char **val) -{ - const char *body; - - if (!skip_prefix(name, atom_name, &body)) - return 0; /* doesn't even begin with "atom_name" */ - if (!body[0]) { - *val = NULL; /* %(atom_name) and no customization */ - return 1; - } - if (body[0] != ':') - return 0; /* "atom_namefoo" is not "atom_name" or "atom_name:..." */ - *val = body + 1; /* "atom_name:val" */ - return 1; -} - /* * In a format string, find the next occurrence of %(atom). */ @@ -315,7 +426,7 @@ int verify_ref_format(const char *format) at = parse_ref_filter_atom(sp + 2, ep); cp = ep + 1; - if (skip_prefix(used_atom[at], "color:", &color)) + if (skip_prefix(used_atom[at].name, "color:", &color)) need_color_reset_at_eol = !!strcmp(color, "reset"); } return 0; @@ -340,15 +451,17 @@ static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned lo } static int grab_objectname(const char *name, const unsigned char *sha1, - struct atom_value *v) + struct atom_value *v, struct used_atom *atom) { - if (!strcmp(name, "objectname")) { - v->s = xstrdup(sha1_to_hex(sha1)); - return 1; - } - if (!strcmp(name, "objectname:short")) { - v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV)); - return 1; + if (starts_with(name, "objectname")) { + if (atom->u.objectname == O_SHORT) { + v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV)); + return 1; + } else if (atom->u.objectname == O_FULL) { + v->s = xstrdup(sha1_to_hex(sha1)); + return 1; + } else + die("BUG: unknown %%(objectname) option"); } return 0; } @@ -359,7 +472,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object int i; for (i = 0; i < used_atom_cnt; i++) { - const char *name = used_atom[i]; + const char *name = used_atom[i].name; struct atom_value *v = &val[i]; if (!!deref != (*name == '*')) continue; @@ -372,7 +485,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object v->s = xstrfmt("%lu", sz); } else if (deref) - grab_objectname(name, obj->oid.hash, v); + grab_objectname(name, obj->oid.hash, v, &used_atom[i]); } } @@ -383,7 +496,7 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob struct tag *tag = (struct tag *) obj; for (i = 0; i < used_atom_cnt; i++) { - const char *name = used_atom[i]; + const char *name = used_atom[i].name; struct atom_value *v = &val[i]; if (!!deref != (*name == '*')) continue; @@ -405,7 +518,7 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object struct commit *commit = (struct commit *) obj; for (i = 0; i < used_atom_cnt; i++) { - const char *name = used_atom[i]; + const char *name = used_atom[i].name; struct atom_value *v = &val[i]; if (!!deref != (*name == '*')) continue; @@ -535,7 +648,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru const char *wholine = NULL; for (i = 0; i < used_atom_cnt; i++) { - const char *name = used_atom[i]; + const char *name = used_atom[i].name; struct atom_value *v = &val[i]; if (!!deref != (*name == '*')) continue; @@ -573,7 +686,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru if (!wholine) return; for (i = 0; i < used_atom_cnt; i++) { - const char *name = used_atom[i]; + const char *name = used_atom[i].name; struct atom_value *v = &val[i]; if (!!deref != (*name == '*')) continue; @@ -663,20 +776,16 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj unsigned long sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0; for (i = 0; i < used_atom_cnt; i++) { - const char *name = used_atom[i]; + struct used_atom *atom = &used_atom[i]; + const char *name = atom->name; struct atom_value *v = &val[i]; - const char *valp = NULL; if (!!deref != (*name == '*')) continue; if (deref) name++; if (strcmp(name, "subject") && strcmp(name, "body") && - strcmp(name, "contents") && - strcmp(name, "contents:subject") && - strcmp(name, "contents:body") && - strcmp(name, "contents:signature") && - !starts_with(name, "contents:lines=")) + !starts_with(name, "contents")) continue; if (!subpos) find_subpos(buf, sz, @@ -684,28 +793,23 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj &bodypos, &bodylen, &nonsiglen, &sigpos, &siglen); - if (!strcmp(name, "subject")) - v->s = copy_subject(subpos, sublen); - else if (!strcmp(name, "contents:subject")) + if (atom->u.contents.option == C_SUB) v->s = copy_subject(subpos, sublen); - else if (!strcmp(name, "body")) + else if (atom->u.contents.option == C_BODY_DEP) v->s = xmemdupz(bodypos, bodylen); - else if (!strcmp(name, "contents:body")) + else if (atom->u.contents.option == C_BODY) v->s = xmemdupz(bodypos, nonsiglen); - else if (!strcmp(name, "contents:signature")) + else if (atom->u.contents.option == C_SIG) v->s = xmemdupz(sigpos, siglen); - else if (!strcmp(name, "contents")) - v->s = xstrdup(subpos); - else if (skip_prefix(name, "contents:lines=", &valp)) { + else if (atom->u.contents.option == C_LINES) { struct strbuf s = STRBUF_INIT; const char *contents_end = bodylen + bodypos - siglen; - if (strtoul_ui(valp, 10, &v->u.contents.lines)) - die(_("positive value expected contents:lines=%s"), valp); /* Size is the length of the message after removing the signature */ - append_lines(&s, subpos, contents_end - subpos, v->u.contents.lines); + append_lines(&s, subpos, contents_end - subpos, atom->u.contents.nlines); v->s = strbuf_detach(&s, NULL); - } + } else if (atom->u.contents.option == C_BARE) + v->s = xstrdup(subpos); } } @@ -763,6 +867,66 @@ static inline char *copy_advance(char *dst, const char *src) return dst; } +static const char *strip_ref_components(const char *refname, const char *nr_arg) +{ + char *end; + long nr = strtol(nr_arg, &end, 10); + long remaining = nr; + const char *start = refname; + + if (nr < 1 || *end != '\0') + die(":strip= requires a positive integer argument"); + + while (remaining) { + switch (*start++) { + case '\0': + die("ref '%s' does not have %ld components to :strip", + refname, nr); + case '/': + remaining--; + break; + } + } + return start; +} + +static void fill_remote_ref_details(struct used_atom *atom, const char *refname, + struct branch *branch, const char **s) +{ + int num_ours, num_theirs; + if (atom->u.remote_ref == RR_SHORTEN) + *s = shorten_unambiguous_ref(refname, warn_ambiguous_refs); + else if (atom->u.remote_ref == RR_TRACK) { + if (stat_tracking_info(branch, &num_ours, + &num_theirs, NULL)) + return; + + if (!num_ours && !num_theirs) + *s = ""; + else if (!num_ours) + *s = xstrfmt("[behind %d]", num_theirs); + else if (!num_theirs) + *s = xstrfmt("[ahead %d]", num_ours); + else + *s = xstrfmt("[ahead %d, behind %d]", + num_ours, num_theirs); + } else if (atom->u.remote_ref == RR_TRACKSHORT) { + if (stat_tracking_info(branch, &num_ours, + &num_theirs, NULL)) + return; + + if (!num_ours && !num_theirs) + *s = "="; + else if (!num_ours) + *s = "<"; + else if (!num_theirs) + *s = ">"; + else + *s = "<>"; + } else /* RR_NORMAL */ + *s = refname; +} + /* * Parse the object referred by ref, and grab needed value. */ @@ -786,12 +950,12 @@ static void populate_value(struct ref_array_item *ref) /* Fill in specials first */ for (i = 0; i < used_atom_cnt; i++) { - const char *name = used_atom[i]; + struct used_atom *atom = &used_atom[i]; + const char *name = used_atom[i].name; struct atom_value *v = &ref->value[i]; int deref = 0; const char *refname; const char *formatp; - const char *valp; struct branch *branch = NULL; v->handler = append_atom; @@ -814,8 +978,9 @@ static void populate_value(struct ref_array_item *ref) branch = branch_get(branch_name); refname = branch_get_upstream(branch, NULL); - if (!refname) - continue; + if (refname) + fill_remote_ref_details(atom, refname, branch, &v->s); + continue; } else if (starts_with(name, "push")) { const char *branch_name; if (!skip_prefix(ref->refname, "refs/heads/", @@ -826,14 +991,10 @@ static void populate_value(struct ref_array_item *ref) refname = branch_get_push(branch, NULL); if (!refname) continue; - } else if (match_atom_name(name, "color", &valp)) { - char color[COLOR_MAXLEN] = ""; - - if (!valp) - die(_("expected format: %%(color:<color>)")); - if (color_parse(valp, color) < 0) - die(_("unable to parse format")); - v->s = xstrdup(color); + fill_remote_ref_details(atom, refname, branch, &v->s); + continue; + } else if (starts_with(name, "color:")) { + v->s = atom->u.color; continue; } else if (!strcmp(name, "flag")) { char buf[256], *cp = buf; @@ -848,7 +1009,7 @@ static void populate_value(struct ref_array_item *ref) v->s = xstrdup(buf + 1); } continue; - } else if (!deref && grab_objectname(name, ref->objectname, v)) { + } else if (!deref && grab_objectname(name, ref->objectname, v, atom)) { continue; } else if (!strcmp(name, "HEAD")) { const char *head; @@ -861,43 +1022,8 @@ static void populate_value(struct ref_array_item *ref) else v->s = " "; continue; - } else if (match_atom_name(name, "align", &valp)) { - struct align *align = &v->u.align; - struct strbuf **s, **to_free; - int width = -1; - - if (!valp) - die(_("expected format: %%(align:<width>,<position>)")); - - /* - * TODO: Implement a function similar to strbuf_split_str() - * which would omit the separator from the end of each value. - */ - s = to_free = strbuf_split_str(valp, ',', 0); - - align->position = ALIGN_LEFT; - - while (*s) { - /* Strip trailing comma */ - if (s[1]) - strbuf_setlen(s[0], s[0]->len - 1); - if (!strtoul_ui(s[0]->buf, 10, (unsigned int *)&width)) - ; - else if (!strcmp(s[0]->buf, "left")) - align->position = ALIGN_LEFT; - else if (!strcmp(s[0]->buf, "right")) - align->position = ALIGN_RIGHT; - else if (!strcmp(s[0]->buf, "middle")) - align->position = ALIGN_MIDDLE; - else - die(_("improper format entered align:%s"), s[0]->buf); - s++; - } - - if (width < 0) - die(_("positive width expected with the %%(align) atom")); - align->width = width; - strbuf_list_free(to_free); + } else if (starts_with(name, "align")) { + v->u.align = atom->u.align; v->handler = align_atom_handler; continue; } else if (!strcmp(name, "end")) { @@ -908,49 +1034,15 @@ static void populate_value(struct ref_array_item *ref) formatp = strchr(name, ':'); if (formatp) { - int num_ours, num_theirs; + const char *arg; formatp++; if (!strcmp(formatp, "short")) refname = shorten_unambiguous_ref(refname, warn_ambiguous_refs); - else if (!strcmp(formatp, "track") && - (starts_with(name, "upstream") || - starts_with(name, "push"))) { - - if (stat_tracking_info(branch, &num_ours, - &num_theirs, NULL)) - continue; - - if (!num_ours && !num_theirs) - v->s = ""; - else if (!num_ours) - v->s = xstrfmt("[behind %d]", num_theirs); - else if (!num_theirs) - v->s = xstrfmt("[ahead %d]", num_ours); - else - v->s = xstrfmt("[ahead %d, behind %d]", - num_ours, num_theirs); - continue; - } else if (!strcmp(formatp, "trackshort") && - (starts_with(name, "upstream") || - starts_with(name, "push"))) { - assert(branch); - - if (stat_tracking_info(branch, &num_ours, - &num_theirs, NULL)) - continue; - - if (!num_ours && !num_theirs) - v->s = "="; - else if (!num_ours) - v->s = "<"; - else if (!num_theirs) - v->s = ">"; - else - v->s = "<>"; - continue; - } else + else if (skip_prefix(formatp, "strip=", &arg)) + refname = strip_ref_components(refname, arg); + else die("unknown %.*s format %s", (int)(formatp - name), name, formatp); } @@ -1229,10 +1321,8 @@ static struct ref_array_item *new_ref_array_item(const char *refname, const unsigned char *objectname, int flag) { - size_t len = strlen(refname); - struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1); - memcpy(ref->refname, refname, len); - ref->refname[len] = '\0'; + struct ref_array_item *ref; + FLEX_ALLOC_STR(ref, refname, refname); hashcpy(ref->objectname, objectname); ref->flag = flag; @@ -1445,7 +1535,7 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru { struct atom_value *va, *vb; int cmp; - cmp_type cmp_type = used_atom_type[s->atom]; + cmp_type cmp_type = used_atom[s->atom].type; get_ref_atom_value(a, s->atom, &va); get_ref_atom_value(b, s->atom, &vb); diff --git a/reflog-walk.c b/reflog-walk.c index 85b8a54241..0ebd1da5ce 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -221,6 +221,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) struct commit_info *commit_info = get_commit_info(commit, &info->reflogs, 0); struct commit_reflog *commit_reflog; + struct object *logobj; struct reflog_info *reflog; info->last_commit_reflog = NULL; @@ -232,15 +233,20 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) commit->parents = NULL; return; } - - reflog = &commit_reflog->reflogs->items[commit_reflog->recno]; info->last_commit_reflog = commit_reflog; - commit_reflog->recno--; - commit_info->commit = (struct commit *)parse_object(reflog->osha1); - if (!commit_info->commit) { + + do { + reflog = &commit_reflog->reflogs->items[commit_reflog->recno]; + commit_reflog->recno--; + logobj = parse_object(reflog->osha1); + } while (commit_reflog->recno && (logobj && logobj->type != OBJ_COMMIT)); + + if (!logobj || logobj->type != OBJ_COMMIT) { + commit_info->commit = NULL; commit->parents = NULL; return; } + commit_info->commit = (struct commit *)logobj; commit->parents = xcalloc(1, sizeof(struct commit_list)); commit->parents->item = commit_info->commit; @@ -124,7 +124,7 @@ int refname_is_safe(const char *refname) char *buf; int result; - buf = xmalloc(strlen(refname) + 1); + buf = xmallocz(strlen(refname)); /* * Does the refname try to escape refs/? * For example: refs/foo/../bar is safe but refs/foo/../../bar @@ -761,10 +761,8 @@ void ref_transaction_free(struct ref_transaction *transaction) static struct ref_update *add_update(struct ref_transaction *transaction, const char *refname) { - size_t len = strlen(refname) + 1; - struct ref_update *update = xcalloc(1, sizeof(*update) + len); - - memcpy((char *)update->refname, refname, len); /* includes NUL */ + struct ref_update *update; + FLEX_ALLOC_STR(update, refname, refname); ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc); transaction->updates[transaction->nr++] = update; return update; @@ -908,7 +906,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict) /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */ total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1; - scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len); + scanf_fmts = xmalloc(st_add(st_mult(nr_rules, sizeof(char *)), total_len)); offset = 0; for (i = 0; i < nr_rules; i++) { @@ -304,7 +304,7 @@ extern char *shorten_unambiguous_ref(const char *refname, int strict); /** rename ref, return 0 on success **/ extern int rename_ref(const char *oldref, const char *newref, const char *logmsg); -extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg); +extern int create_symref(const char *refname, const char *target, const char *logmsg); enum action_on_err { UPDATE_REFS_MSG_ON_ERR, diff --git a/refs/files-backend.c b/refs/files-backend.c index c648b5e853..81f68f846b 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -199,17 +199,14 @@ static struct ref_entry *create_ref_entry(const char *refname, const unsigned char *sha1, int flag, int check_name) { - int len; struct ref_entry *ref; if (check_name && check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) die("Reference has invalid format: '%s'", refname); - len = strlen(refname) + 1; - ref = xmalloc(sizeof(struct ref_entry) + len); + FLEX_ALLOC_STR(ref, name, refname); hashcpy(ref->u.value.oid.hash, sha1); oidclr(&ref->u.value.peeled); - memcpy(ref->name, refname, len); ref->flag = flag; return ref; } @@ -268,9 +265,7 @@ static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache, int incomplete) { struct ref_entry *direntry; - direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1); - memcpy(direntry->name, dirname, len); - direntry->name[len] = '\0'; + FLEX_ALLOC_MEM(direntry, name, dirname, len); direntry->u.subdir.ref_cache = ref_cache; direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0); return direntry; @@ -933,25 +928,22 @@ static void clear_loose_ref_cache(struct ref_cache *refs) } } +/* + * Create a new submodule ref cache and add it to the internal + * set of caches. + */ static struct ref_cache *create_ref_cache(const char *submodule) { - int len; struct ref_cache *refs; if (!submodule) submodule = ""; - len = strlen(submodule) + 1; - refs = xcalloc(1, sizeof(struct ref_cache) + len); - memcpy(refs->name, submodule, len); + FLEX_ALLOC_STR(refs, name, submodule); + refs->next = submodule_ref_caches; + submodule_ref_caches = refs; return refs; } -/* - * Return a pointer to a ref_cache for the specified submodule. For - * the main repository, use submodule==NULL. The returned structure - * will be allocated and initialized but not necessarily populated; it - * should not be freed. - */ -static struct ref_cache *get_ref_cache(const char *submodule) +static struct ref_cache *lookup_ref_cache(const char *submodule) { struct ref_cache *refs; @@ -961,10 +953,20 @@ static struct ref_cache *get_ref_cache(const char *submodule) for (refs = submodule_ref_caches; refs; refs = refs->next) if (!strcmp(submodule, refs->name)) return refs; + return NULL; +} - refs = create_ref_cache(submodule); - refs->next = submodule_ref_caches; - submodule_ref_caches = refs; +/* + * Return a pointer to a ref_cache for the specified submodule. For + * the main repository, use submodule==NULL. The returned structure + * will be allocated and initialized but not necessarily populated; it + * should not be freed. + */ +static struct ref_cache *get_ref_cache(const char *submodule) +{ + struct ref_cache *refs = lookup_ref_cache(submodule); + if (!refs) + refs = create_ref_cache(submodule); return refs; } @@ -1336,16 +1338,24 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs, int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1) { int len = strlen(path), retval; - char *submodule; + struct strbuf submodule = STRBUF_INIT; struct ref_cache *refs; while (len && path[len-1] == '/') len--; if (!len) return -1; - submodule = xstrndup(path, len); - refs = get_ref_cache(submodule); - free(submodule); + + strbuf_add(&submodule, path, len); + refs = lookup_ref_cache(submodule.buf); + if (!refs) { + if (!is_nonbare_repository_dir(&submodule)) { + strbuf_release(&submodule); + return -1; + } + refs = create_ref_cache(submodule.buf); + } + strbuf_release(&submodule); retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0); return retval; @@ -1840,12 +1850,17 @@ static int verify_lock(struct ref_lock *lock, if (read_ref_full(lock->ref_name, mustexist ? RESOLVE_REF_READING : 0, lock->old_oid.hash, NULL)) { - int save_errno = errno; - strbuf_addf(err, "can't verify ref %s", lock->ref_name); - errno = save_errno; - return -1; + if (old_sha1) { + int save_errno = errno; + strbuf_addf(err, "can't verify ref %s", lock->ref_name); + errno = save_errno; + return -1; + } else { + hashclr(lock->old_oid.hash); + return 0; + } } - if (hashcmp(lock->old_oid.hash, old_sha1)) { + if (old_sha1 && hashcmp(lock->old_oid.hash, old_sha1)) { strbuf_addf(err, "ref %s is at %s but expected %s", lock->ref_name, sha1_to_hex(lock->old_oid.hash), @@ -1882,7 +1897,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, const char *orig_refname = refname; struct ref_lock *lock; int last_errno = 0; - int type, lflags; + int type; + int lflags = 0; int mustexist = (old_sha1 && !is_null_sha1(old_sha1)); int resolve_flags = 0; int attempts_remaining = 3; @@ -1893,10 +1909,11 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, if (mustexist) resolve_flags |= RESOLVE_REF_READING; - if (flags & REF_DELETING) { + if (flags & REF_DELETING) resolve_flags |= RESOLVE_REF_ALLOW_BAD_NAME; - if (flags & REF_NODEREF) - resolve_flags |= RESOLVE_REF_NO_RECURSE; + if (flags & REF_NODEREF) { + resolve_flags |= RESOLVE_REF_NO_RECURSE; + lflags |= LOCK_NO_DEREF; } refname = resolve_ref_unsafe(refname, resolve_flags, @@ -1932,6 +1949,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, goto error_return; } + + if (flags & REF_NODEREF) + refname = orig_refname; + /* * If the ref did not exist and we are creating it, make sure * there is no existing packed ref whose name begins with our @@ -1947,11 +1968,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, lock->lk = xcalloc(1, sizeof(struct lock_file)); - lflags = 0; - if (flags & REF_NODEREF) { - refname = orig_refname; - lflags |= LOCK_NO_DEREF; - } lock->ref_name = xstrdup(refname); lock->orig_ref_name = xstrdup(orig_refname); strbuf_git_path(&ref_file, "%s", refname); @@ -1985,7 +2001,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, goto error_return; } } - if (old_sha1 && verify_lock(lock, old_sha1, mustexist, err)) { + if (verify_lock(lock, old_sha1, mustexist, err)) { last_errno = errno; goto error_return; } @@ -2173,10 +2189,9 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data) /* Schedule the loose reference for pruning if requested. */ if ((cb->flags & PACK_REFS_PRUNE)) { - int namelen = strlen(entry->name) + 1; - struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen); + struct ref_to_prune *n; + FLEX_ALLOC_STR(n, name, entry->name); hashcpy(n->sha1, entry->u.value.oid.hash); - memcpy(n->name, entry->name, namelen); /* includes NUL */ n->next = cb->ref_to_prune; cb->ref_to_prune = n; } @@ -2811,73 +2826,72 @@ static int commit_ref_update(struct ref_lock *lock, return 0; } -int create_symref(const char *ref_target, const char *refs_heads_master, - const char *logmsg) +static int create_ref_symlink(struct ref_lock *lock, const char *target) { - char *lockpath = NULL; - char ref[1000]; - int fd, len, written; - char *git_HEAD = git_pathdup("%s", ref_target); - unsigned char old_sha1[20], new_sha1[20]; - struct strbuf err = STRBUF_INIT; - - if (logmsg && read_ref(ref_target, old_sha1)) - hashclr(old_sha1); - - if (safe_create_leading_directories(git_HEAD) < 0) - return error("unable to create directory for %s", git_HEAD); - + int ret = -1; #ifndef NO_SYMLINK_HEAD - if (prefer_symlink_refs) { - unlink(git_HEAD); - if (!symlink(refs_heads_master, git_HEAD)) - goto done; + char *ref_path = get_locked_file_path(lock->lk); + unlink(ref_path); + ret = symlink(target, ref_path); + free(ref_path); + + if (ret) fprintf(stderr, "no symlink - falling back to symbolic ref\n"); - } #endif + return ret; +} - len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master); - if (sizeof(ref) <= len) { - error("refname too long: %s", refs_heads_master); - goto error_free_return; - } - lockpath = mkpathdup("%s.lock", git_HEAD); - fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666); - if (fd < 0) { - error("Unable to open %s for writing", lockpath); - goto error_free_return; - } - written = write_in_full(fd, ref, len); - if (close(fd) != 0 || written != len) { - error("Unable to write to %s", lockpath); - goto error_unlink_return; - } - if (rename(lockpath, git_HEAD) < 0) { - error("Unable to create %s", git_HEAD); - goto error_unlink_return; - } - if (adjust_shared_perm(git_HEAD)) { - error("Unable to fix permissions on %s", lockpath); - error_unlink_return: - unlink_or_warn(lockpath); - error_free_return: - free(lockpath); - free(git_HEAD); - return -1; +static void update_symref_reflog(struct ref_lock *lock, const char *refname, + const char *target, const char *logmsg) +{ + struct strbuf err = STRBUF_INIT; + unsigned char new_sha1[20]; + if (logmsg && !read_ref(target, new_sha1) && + log_ref_write(refname, lock->old_oid.hash, new_sha1, logmsg, 0, &err)) { + error("%s", err.buf); + strbuf_release(&err); } - free(lockpath); +} -#ifndef NO_SYMLINK_HEAD - done: -#endif - if (logmsg && !read_ref(refs_heads_master, new_sha1) && - log_ref_write(ref_target, old_sha1, new_sha1, logmsg, 0, &err)) { +static int create_symref_locked(struct ref_lock *lock, const char *refname, + const char *target, const char *logmsg) +{ + if (prefer_symlink_refs && !create_ref_symlink(lock, target)) { + update_symref_reflog(lock, refname, target, logmsg); + return 0; + } + + if (!fdopen_lock_file(lock->lk, "w")) + return error("unable to fdopen %s: %s", + lock->lk->tempfile.filename.buf, strerror(errno)); + + update_symref_reflog(lock, refname, target, logmsg); + + /* no error check; commit_ref will check ferror */ + fprintf(lock->lk->tempfile.fp, "ref: %s\n", target); + if (commit_ref(lock) < 0) + return error("unable to write symref for %s: %s", refname, + strerror(errno)); + return 0; +} + +int create_symref(const char *refname, const char *target, const char *logmsg) +{ + struct strbuf err = STRBUF_INIT; + struct ref_lock *lock; + int ret; + + lock = lock_ref_sha1_basic(refname, NULL, NULL, NULL, REF_NODEREF, NULL, + &err); + if (!lock) { error("%s", err.buf); strbuf_release(&err); + return -1; } - free(git_HEAD); - return 0; + ret = create_symref_locked(lock, refname, target, logmsg); + unlock_ref(lock); + return ret; } int reflog_exists(const char *refname) diff --git a/remote-curl.c b/remote-curl.c index f404faf0f4..15e48e25fb 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -119,6 +119,19 @@ static int set_option(const char *name, const char *value) else return -1; return 0; + +#if LIBCURL_VERSION_NUM >= 0x070a08 + } else if (!strcmp(name, "family")) { + if (!strcmp(value, "ipv4")) + git_curl_ipresolve = CURL_IPRESOLVE_V4; + else if (!strcmp(value, "ipv6")) + git_curl_ipresolve = CURL_IPRESOLVE_V6; + else if (!strcmp(value, "all")) + git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER; + else + return -1; + return 0; +#endif /* LIBCURL_VERSION_NUM >= 0x070a08 */ } else { return 1 /* unsupported */; } @@ -439,8 +452,20 @@ static int run_slot(struct active_request_slot *slot, err = run_one_slot(slot, results); if (err != HTTP_OK && err != HTTP_REAUTH) { - error("RPC failed; result=%d, HTTP code = %ld", - results->curl_result, results->http_code); + struct strbuf msg = STRBUF_INIT; + if (results->http_code && results->http_code != 200) + strbuf_addf(&msg, "HTTP %ld", results->http_code); + if (results->curl_result != CURLE_OK) { + if (msg.len) + strbuf_addch(&msg, ' '); + strbuf_addf(&msg, "curl %d", results->curl_result); + if (curl_errorstr[0]) { + strbuf_addch(&msg, ' '); + strbuf_addstr(&msg, curl_errorstr); + } + } + error("RPC failed; %s", msg.buf); + strbuf_release(&msg); } return err; @@ -696,9 +721,10 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads) static int fetch_dumb(int nr_heads, struct ref **to_fetch) { struct walker *walker; - char **targets = xmalloc(nr_heads * sizeof(char*)); + char **targets; int ret, i; + ALLOC_ARRAY(targets, nr_heads); if (options.depth) die("dumb http transport does not support --depth"); for (i = 0; i < nr_heads; i++) @@ -827,7 +853,7 @@ static void parse_fetch(struct strbuf *buf) die("http transport does not support %s", buf->buf); strbuf_reset(buf); - if (strbuf_getline(buf, stdin, '\n') == EOF) + if (strbuf_getline_lf(buf, stdin) == EOF) return; if (!*buf->buf) break; @@ -845,23 +871,22 @@ static void parse_fetch(struct strbuf *buf) static int push_dav(int nr_spec, char **specs) { - const char **argv = xmalloc((10 + nr_spec) * sizeof(char*)); - int argc = 0, i; + struct child_process child = CHILD_PROCESS_INIT; + size_t i; - argv[argc++] = "http-push"; - argv[argc++] = "--helper-status"; + child.git_cmd = 1; + argv_array_push(&child.args, "http-push"); + argv_array_push(&child.args, "--helper-status"); if (options.dry_run) - argv[argc++] = "--dry-run"; + argv_array_push(&child.args, "--dry-run"); if (options.verbosity > 1) - argv[argc++] = "--verbose"; - argv[argc++] = url.buf; + argv_array_push(&child.args, "--verbose"); + argv_array_push(&child.args, url.buf); for (i = 0; i < nr_spec; i++) - argv[argc++] = specs[i]; - argv[argc++] = NULL; + argv_array_push(&child.args, specs[i]); - if (run_command_v_opt(argv, RUN_GIT_CMD)) - die("git-%s failed", argv[0]); - free(argv); + if (run_command(&child)) + die("git-http-push failed"); return 0; } @@ -940,7 +965,7 @@ static void parse_push(struct strbuf *buf) die("http transport does not support %s", buf->buf); strbuf_reset(buf); - if (strbuf_getline(buf, stdin, '\n') == EOF) + if (strbuf_getline_lf(buf, stdin) == EOF) goto free_specs; if (!*buf->buf) break; @@ -990,7 +1015,7 @@ int main(int argc, const char **argv) do { const char *arg; - if (strbuf_getline(&buf, stdin, '\n') == EOF) { + if (strbuf_getline_lf(&buf, stdin) == EOF) { if (ferror(stdin)) error("remote-curl: error reading command stream from git"); return 1; diff --git a/remote-testsvn.c b/remote-testsvn.c index f599c372c6..f05ff45298 100644 --- a/remote-testsvn.c +++ b/remote-testsvn.c @@ -154,7 +154,7 @@ static void check_or_regenerate_marks(int latestrev) fclose(marksfile); } else { strbuf_addf(&sb, ":%d ", latestrev); - while (strbuf_getline(&line, marksfile, '\n') != EOF) { + while (strbuf_getline_lf(&line, marksfile) != EOF) { if (starts_with(line.buf, sb.buf)) { found++; break; @@ -322,7 +322,7 @@ int main(int argc, char **argv) marksfilename = marksfilename_sb.buf; while (1) { - if (strbuf_getline(&buf, stdin, '\n') == EOF) { + if (strbuf_getline_lf(&buf, stdin) == EOF) { if (ferror(stdin)) die("Error reading command stream"); else @@ -256,7 +256,7 @@ static void read_remotes_file(struct remote *remote) if (!f) return; remote->origin = REMOTE_REMOTES; - while (strbuf_getline(&buf, f, '\n') != EOF) { + while (strbuf_getline(&buf, f) != EOF) { const char *v; strbuf_rtrim(&buf); @@ -281,7 +281,7 @@ static void read_branches_file(struct remote *remote) if (!f) return; - strbuf_getline(&buf, f, '\n'); + strbuf_getline_lf(&buf, f); fclose(f); strbuf_trim(&buf); if (!buf.len) { @@ -318,93 +318,88 @@ static void read_branches_file(struct remote *remote) static int handle_config(const char *key, const char *value, void *cb) { const char *name; + int namelen; const char *subkey; struct remote *remote; struct branch *branch; - if (starts_with(key, "branch.")) { - name = key + 7; - subkey = strrchr(name, '.'); - if (!subkey) + if (parse_config_key(key, "branch", &name, &namelen, &subkey) >= 0) { + if (!name) return 0; - branch = make_branch(name, subkey - name); - if (!strcmp(subkey, ".remote")) { + branch = make_branch(name, namelen); + if (!strcmp(subkey, "remote")) { return git_config_string(&branch->remote_name, key, value); - } else if (!strcmp(subkey, ".pushremote")) { + } else if (!strcmp(subkey, "pushremote")) { return git_config_string(&branch->pushremote_name, key, value); - } else if (!strcmp(subkey, ".merge")) { + } else if (!strcmp(subkey, "merge")) { if (!value) return config_error_nonbool(key); add_merge(branch, xstrdup(value)); } return 0; } - if (starts_with(key, "url.")) { + if (parse_config_key(key, "url", &name, &namelen, &subkey) >= 0) { struct rewrite *rewrite; - name = key + 4; - subkey = strrchr(name, '.'); - if (!subkey) + if (!name) return 0; - if (!strcmp(subkey, ".insteadof")) { - rewrite = make_rewrite(&rewrites, name, subkey - name); + if (!strcmp(subkey, "insteadof")) { + rewrite = make_rewrite(&rewrites, name, namelen); if (!value) return config_error_nonbool(key); add_instead_of(rewrite, xstrdup(value)); - } else if (!strcmp(subkey, ".pushinsteadof")) { - rewrite = make_rewrite(&rewrites_push, name, subkey - name); + } else if (!strcmp(subkey, "pushinsteadof")) { + rewrite = make_rewrite(&rewrites_push, name, namelen); if (!value) return config_error_nonbool(key); add_instead_of(rewrite, xstrdup(value)); } } - if (!starts_with(key, "remote.")) + if (parse_config_key(key, "remote", &name, &namelen, &subkey) < 0) return 0; - name = key + 7; /* Handle remote.* variables */ - if (!strcmp(name, "pushdefault")) + if (!name && !strcmp(subkey, "pushdefault")) return git_config_string(&pushremote_name, key, value); + if (!name) + return 0; /* Handle remote.<name>.* variables */ if (*name == '/') { warning("Config remote shorthand cannot begin with '/': %s", name); return 0; } - subkey = strrchr(name, '.'); - if (!subkey) - return 0; - remote = make_remote(name, subkey - name); + remote = make_remote(name, namelen); remote->origin = REMOTE_CONFIG; - if (!strcmp(subkey, ".mirror")) + if (!strcmp(subkey, "mirror")) remote->mirror = git_config_bool(key, value); - else if (!strcmp(subkey, ".skipdefaultupdate")) + else if (!strcmp(subkey, "skipdefaultupdate")) remote->skip_default_update = git_config_bool(key, value); - else if (!strcmp(subkey, ".skipfetchall")) + else if (!strcmp(subkey, "skipfetchall")) remote->skip_default_update = git_config_bool(key, value); - else if (!strcmp(subkey, ".prune")) + else if (!strcmp(subkey, "prune")) remote->prune = git_config_bool(key, value); - else if (!strcmp(subkey, ".url")) { + else if (!strcmp(subkey, "url")) { const char *v; if (git_config_string(&v, key, value)) return -1; add_url(remote, v); - } else if (!strcmp(subkey, ".pushurl")) { + } else if (!strcmp(subkey, "pushurl")) { const char *v; if (git_config_string(&v, key, value)) return -1; add_pushurl(remote, v); - } else if (!strcmp(subkey, ".push")) { + } else if (!strcmp(subkey, "push")) { const char *v; if (git_config_string(&v, key, value)) return -1; add_push_refspec(remote, v); - } else if (!strcmp(subkey, ".fetch")) { + } else if (!strcmp(subkey, "fetch")) { const char *v; if (git_config_string(&v, key, value)) return -1; add_fetch_refspec(remote, v); - } else if (!strcmp(subkey, ".receivepack")) { + } else if (!strcmp(subkey, "receivepack")) { const char *v; if (git_config_string(&v, key, value)) return -1; @@ -412,7 +407,7 @@ static int handle_config(const char *key, const char *value, void *cb) remote->receivepack = v; else error("more than one receivepack given, using the first"); - } else if (!strcmp(subkey, ".uploadpack")) { + } else if (!strcmp(subkey, "uploadpack")) { const char *v; if (git_config_string(&v, key, value)) return -1; @@ -420,15 +415,18 @@ static int handle_config(const char *key, const char *value, void *cb) remote->uploadpack = v; else error("more than one uploadpack given, using the first"); - } else if (!strcmp(subkey, ".tagopt")) { + } else if (!strcmp(subkey, "tagopt")) { if (!strcmp(value, "--no-tags")) remote->fetch_tags = -1; else if (!strcmp(value, "--tags")) remote->fetch_tags = 2; - } else if (!strcmp(subkey, ".proxy")) { + } else if (!strcmp(subkey, "proxy")) { return git_config_string((const char **)&remote->http_proxy, key, value); - } else if (!strcmp(subkey, ".vcs")) { + } else if (!strcmp(subkey, "proxyauthmethod")) { + return git_config_string((const char **)&remote->http_proxy_authmethod, + key, value); + } else if (!strcmp(subkey, "vcs")) { return git_config_string(&remote->foreign_vcs, key, value); } return 0; @@ -715,18 +713,9 @@ struct remote *pushremote_get(const char *name) return remote_get_1(name, pushremote_for_branch); } -int remote_is_configured(const char *name) +int remote_is_configured(struct remote *remote) { - struct remotes_hash_key lookup; - struct hashmap_entry lookup_entry; - read_config(); - - init_remotes_hash(); - lookup.str = name; - lookup.len = strlen(name); - hashmap_entry_init(&lookup_entry, memhash(name, lookup.len)); - - return hashmap_get(&remotes_hash, &lookup_entry, &lookup) != NULL; + return remote && remote->origin; } int for_each_remote(each_remote_fn fn, void *priv) @@ -928,7 +917,7 @@ static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen, const char *name) { size_t len = strlen(name); - struct ref *ref = xcalloc(1, sizeof(struct ref) + prefixlen + len + 1); + struct ref *ref = xcalloc(1, st_add4(sizeof(*ref), prefixlen, len, 1)); memcpy(ref->name, prefix, prefixlen); memcpy(ref->name + prefixlen, name, len); return ref; @@ -945,9 +934,9 @@ struct ref *copy_ref(const struct ref *ref) size_t len; if (!ref) return NULL; - len = strlen(ref->name); - cpy = xmalloc(sizeof(struct ref) + len + 1); - memcpy(cpy, ref, sizeof(struct ref) + len + 1); + len = st_add3(sizeof(struct ref), strlen(ref->name), 1); + cpy = xmalloc(len); + memcpy(cpy, ref, len); cpy->next = NULL; cpy->symref = xstrdup_or_null(ref->symref); cpy->remote_status = xstrdup_or_null(ref->remote_status); @@ -1545,11 +1534,8 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, } /* - * Bypass the usual "must fast-forward" check but - * replace it with a weaker "the old value must be - * this value we observed". If the remote ref has - * moved and is now different from what we expect, - * reject any push. + * If the remote ref has moved and is now different + * from what we expect, reject any push. * * It also is an error if the user told us to check * with the remote-tracking branch to find the value @@ -1560,10 +1546,14 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, if (ref->expect_old_no_trackback || oidcmp(&ref->old_oid, &ref->old_oid_expect)) reject_reason = REF_STATUS_REJECT_STALE; + else + /* If the ref isn't stale then force the update. */ + force_ref_update = 1; } /* - * The usual "must fast-forward" rules. + * If the update isn't already rejected then check + * the usual "must fast-forward" rules. * * Decide whether an individual refspec A:B can be * pushed. The push will succeed if any of the @@ -1582,7 +1572,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, * passing the --force argument */ - else if (!ref->deletion && !is_null_oid(&ref->old_oid)) { + if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) { if (starts_with(ref->name, "refs/tags/")) reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS; else if (!has_object_file(&ref->old_oid)) @@ -2132,16 +2122,13 @@ static int one_local_ref(const char *refname, const struct object_id *oid, { struct ref ***local_tail = cb_data; struct ref *ref; - int len; /* we already know it starts with refs/ to get here */ if (check_refname_format(refname + 5, 0)) return 0; - len = strlen(refname) + 1; - ref = xcalloc(1, sizeof(*ref) + len); + ref = alloc_ref(refname); oidcpy(&ref->new_oid, oid); - memcpy(ref->name, refname, len); **local_tail = ref; *local_tail = &ref->next; return 0; @@ -5,6 +5,7 @@ #include "hashmap.h" enum { + REMOTE_UNCONFIGURED = 0, REMOTE_CONFIG, REMOTE_REMOTES, REMOTE_BRANCHES @@ -54,11 +55,12 @@ struct remote { * for curl remotes only */ char *http_proxy; + char *http_proxy_authmethod; }; struct remote *remote_get(const char *name); struct remote *pushremote_get(const char *name); -int remote_is_configured(const char *name); +int remote_is_configured(struct remote *remote); typedef int each_remote_fn(struct remote *remote, void *priv); int for_each_remote(each_remote_fn fn, void *priv); @@ -48,7 +48,7 @@ static int has_rerere_resolution(const struct rerere_id *id) static struct rerere_id *new_rerere_id_hex(char *hex) { struct rerere_id *id = xmalloc(sizeof(*id)); - strcpy(id->hex, hex); + xsnprintf(id->hex, sizeof(id->hex), "%s", hex); return id; } @@ -904,7 +904,7 @@ int rerere_forget(struct pathspec *pathspec) static struct rerere_id *dirname_to_id(const char *name) { static struct rerere_id id; - strcpy(id.hex, name); + xsnprintf(id.hex, sizeof(id.hex), "%s", name); return &id; } diff --git a/revision.c b/revision.c index 0a282f533b..8b2dfe3160 100644 --- a/revision.c +++ b/revision.c @@ -25,69 +25,13 @@ volatile show_early_output_fn_t show_early_output; static const char *term_bad; static const char *term_good; -char *path_name(const struct name_path *path, const char *name) -{ - const struct name_path *p; - char *n, *m; - int nlen = strlen(name); - int len = nlen + 1; - - for (p = path; p; p = p->up) { - if (p->elem_len) - len += p->elem_len + 1; - } - n = xmalloc(len); - m = n + len - (nlen + 1); - memcpy(m, name, nlen + 1); - for (p = path; p; p = p->up) { - if (p->elem_len) { - m -= p->elem_len + 1; - memcpy(m, p->elem, p->elem_len); - m[p->elem_len] = '/'; - } - } - return n; -} - -static int show_path_component_truncated(FILE *out, const char *name, int len) -{ - int cnt; - for (cnt = 0; cnt < len; cnt++) { - int ch = name[cnt]; - if (!ch || ch == '\n') - return -1; - fputc(ch, out); - } - return len; -} - -static int show_path_truncated(FILE *out, const struct name_path *path) -{ - int emitted, ours; - - if (!path) - return 0; - emitted = show_path_truncated(out, path->up); - if (emitted < 0) - return emitted; - if (emitted) - fputc('/', out); - ours = show_path_component_truncated(out, path->elem, path->elem_len); - if (ours < 0) - return ours; - return ours || emitted; -} - -void show_object_with_name(FILE *out, struct object *obj, - const struct name_path *path, const char *component) +void show_object_with_name(FILE *out, struct object *obj, const char *name) { - struct name_path leaf; - leaf.up = (struct name_path *)path; - leaf.elem = component; - leaf.elem_len = strlen(component); + const char *p; fprintf(out, "%s ", oid_to_hex(&obj->oid)); - show_path_truncated(out, &leaf); + for (p = name; *p && *p != '\n'; p++) + fputc(*p, out); fputc('\n', out); } @@ -540,7 +484,7 @@ struct treesame_state { static struct treesame_state *initialise_treesame(struct rev_info *revs, struct commit *commit) { unsigned n = commit_list_count(commit->parents); - struct treesame_state *st = xcalloc(1, sizeof(*st) + n); + struct treesame_state *st = xcalloc(1, st_add(sizeof(*st), n)); st->nparents = n; add_decoration(&revs->treesame, &commit->object, st); return st; @@ -1635,10 +1579,7 @@ static void append_prune_data(struct cmdline_pathspec *prune, const char **av) static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb, struct cmdline_pathspec *prune) { - while (strbuf_getwholeline(sb, stdin, '\n') != EOF) { - int len = sb->len; - if (len && sb->buf[len - 1] == '\n') - sb->buf[--len] = '\0'; + while (strbuf_getline(sb, stdin) != EOF) { ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc); prune->path[prune->nr++] = xstrdup(sb->buf); } @@ -1655,10 +1596,8 @@ static void read_revisions_from_stdin(struct rev_info *revs, warn_on_object_refname_ambiguity = 0; strbuf_init(&sb, 1000); - while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) { + while (strbuf_getline(&sb, stdin) != EOF) { int len = sb.len; - if (len && sb.buf[len - 1] == '\n') - sb.buf[--len] = '\0'; if (!len) break; if (sb.buf[0] == '-') { @@ -2049,7 +1988,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--ignore-missing")) { revs->ignore_missing = 1; } else { - int opts = diff_opt_parse(&revs->diffopt, argv, argc); + int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix); if (!opts) unkv[(*unkc)++] = arg; return opts; diff --git a/revision.h b/revision.h index 23857c0ed1..dca0d38171 100644 --- a/revision.h +++ b/revision.h @@ -257,16 +257,9 @@ extern void put_revision_mark(const struct rev_info *revs, extern void mark_parents_uninteresting(struct commit *commit); extern void mark_tree_uninteresting(struct tree *tree); -struct name_path { - struct name_path *up; - int elem_len; - const char *elem; -}; - -char *path_name(const struct name_path *path, const char *name); +char *path_name(struct strbuf *path, const char *name); -extern void show_object_with_name(FILE *, struct object *, - const struct name_path *, const char *); +extern void show_object_with_name(FILE *, struct object *, const char *); extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name); diff --git a/run-command.c b/run-command.c index 13fa452e8c..863dad52f1 100644 --- a/run-command.c +++ b/run-command.c @@ -3,6 +3,8 @@ #include "exec_cmd.h" #include "sigchain.h" #include "argv-array.h" +#include "thread-utils.h" +#include "strbuf.h" void child_process_init(struct child_process *child) { @@ -158,50 +160,41 @@ int sane_execvp(const char *file, char * const argv[]) return -1; } -static const char **prepare_shell_cmd(const char **argv) +static const char **prepare_shell_cmd(struct argv_array *out, const char **argv) { - int argc, nargc = 0; - const char **nargv; - - for (argc = 0; argv[argc]; argc++) - ; /* just counting */ - /* +1 for NULL, +3 for "sh -c" plus extra $0 */ - nargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3)); - - if (argc < 1) + if (!argv[0]) die("BUG: shell command is empty"); if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) { #ifndef GIT_WINDOWS_NATIVE - nargv[nargc++] = SHELL_PATH; + argv_array_push(out, SHELL_PATH); #else - nargv[nargc++] = "sh"; + argv_array_push(out, "sh"); #endif - nargv[nargc++] = "-c"; - - if (argc < 2) - nargv[nargc++] = argv[0]; - else { - struct strbuf arg0 = STRBUF_INIT; - strbuf_addf(&arg0, "%s \"$@\"", argv[0]); - nargv[nargc++] = strbuf_detach(&arg0, NULL); - } - } + argv_array_push(out, "-c"); - for (argc = 0; argv[argc]; argc++) - nargv[nargc++] = argv[argc]; - nargv[nargc] = NULL; + /* + * If we have no extra arguments, we do not even need to + * bother with the "$@" magic. + */ + if (!argv[1]) + argv_array_push(out, argv[0]); + else + argv_array_pushf(out, "%s \"$@\"", argv[0]); + } - return nargv; + argv_array_pushv(out, argv); + return out->argv; } #ifndef GIT_WINDOWS_NATIVE static int execv_shell_cmd(const char **argv) { - const char **nargv = prepare_shell_cmd(argv); - trace_argv_printf(nargv, "trace: exec:"); - sane_execvp(nargv[0], (char **)nargv); - free(nargv); + struct argv_array nargv = ARGV_ARRAY_INIT; + prepare_shell_cmd(&nargv, argv); + trace_argv_printf(nargv.argv, "trace: exec:"); + sane_execvp(nargv.argv[0], (char **)nargv.argv); + argv_array_clear(&nargv); return -1; } #endif @@ -245,7 +238,7 @@ static int wait_or_whine(pid_t pid, const char *argv0, int in_signal) error("waitpid is confused (%s)", argv0); } else if (WIFSIGNALED(status)) { code = WTERMSIG(status); - if (code != SIGINT && code != SIGQUIT) + if (code != SIGINT && code != SIGQUIT && code != SIGPIPE) error("%s died of signal %d", argv0, code); /* * This return value is chosen so that code & 0xff @@ -455,6 +448,7 @@ fail_pipe: { int fhin = 0, fhout = 1, fherr = 2; const char **sargv = cmd->argv; + struct argv_array nargv = ARGV_ARRAY_INIT; if (cmd->no_stdin) fhin = open("/dev/null", O_RDWR); @@ -480,9 +474,9 @@ fail_pipe: fhout = dup(cmd->out); if (cmd->git_cmd) - cmd->argv = prepare_git_cmd(cmd->argv); + cmd->argv = prepare_git_cmd(&nargv, cmd->argv); else if (cmd->use_shell) - cmd->argv = prepare_shell_cmd(cmd->argv); + cmd->argv = prepare_shell_cmd(&nargv, cmd->argv); cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env, cmd->dir, fhin, fhout, fherr); @@ -492,9 +486,7 @@ fail_pipe: if (cmd->clean_on_exit && cmd->pid >= 0) mark_child_for_cleanup(cmd->pid); - if (cmd->git_cmd) - free(cmd->argv); - + argv_array_clear(&nargv); cmd->argv = sargv; if (fhin != 0) close(fhin); @@ -633,6 +625,11 @@ int in_async(void) return !pthread_equal(main_thread, pthread_self()); } +void NORETURN async_exit(int code) +{ + pthread_exit((void *)(intptr_t)code); +} + #else static struct { @@ -678,6 +675,11 @@ int in_async(void) return process_is_async; } +void NORETURN async_exit(int code) +{ + exit(code); +} + #endif int start_async(struct async *async) @@ -865,3 +867,336 @@ int capture_command(struct child_process *cmd, struct strbuf *buf, size_t hint) close(cmd->out); return finish_command(cmd); } + +enum child_state { + GIT_CP_FREE, + GIT_CP_WORKING, + GIT_CP_WAIT_CLEANUP, +}; + +struct parallel_processes { + void *data; + + int max_processes; + int nr_processes; + + get_next_task_fn get_next_task; + start_failure_fn start_failure; + task_finished_fn task_finished; + + struct { + enum child_state state; + struct child_process process; + struct strbuf err; + void *data; + } *children; + /* + * The struct pollfd is logically part of *children, + * but the system call expects it as its own array. + */ + struct pollfd *pfd; + + unsigned shutdown : 1; + + int output_owner; + struct strbuf buffered_output; /* of finished children */ +}; + +static int default_start_failure(struct child_process *cp, + struct strbuf *err, + void *pp_cb, + void *pp_task_cb) +{ + int i; + + strbuf_addstr(err, "Starting a child failed:"); + for (i = 0; cp->argv[i]; i++) + strbuf_addf(err, " %s", cp->argv[i]); + + return 0; +} + +static int default_task_finished(int result, + struct child_process *cp, + struct strbuf *err, + void *pp_cb, + void *pp_task_cb) +{ + int i; + + if (!result) + return 0; + + strbuf_addf(err, "A child failed with return code %d:", result); + for (i = 0; cp->argv[i]; i++) + strbuf_addf(err, " %s", cp->argv[i]); + + return 0; +} + +static void kill_children(struct parallel_processes *pp, int signo) +{ + int i, n = pp->max_processes; + + for (i = 0; i < n; i++) + if (pp->children[i].state == GIT_CP_WORKING) + kill(pp->children[i].process.pid, signo); +} + +static struct parallel_processes *pp_for_signal; + +static void handle_children_on_signal(int signo) +{ + kill_children(pp_for_signal, signo); + sigchain_pop(signo); + raise(signo); +} + +static void pp_init(struct parallel_processes *pp, + int n, + get_next_task_fn get_next_task, + start_failure_fn start_failure, + task_finished_fn task_finished, + void *data) +{ + int i; + + if (n < 1) + n = online_cpus(); + + pp->max_processes = n; + + trace_printf("run_processes_parallel: preparing to run up to %d tasks", n); + + pp->data = data; + if (!get_next_task) + die("BUG: you need to specify a get_next_task function"); + pp->get_next_task = get_next_task; + + pp->start_failure = start_failure ? start_failure : default_start_failure; + pp->task_finished = task_finished ? task_finished : default_task_finished; + + pp->nr_processes = 0; + pp->output_owner = 0; + pp->shutdown = 0; + pp->children = xcalloc(n, sizeof(*pp->children)); + pp->pfd = xcalloc(n, sizeof(*pp->pfd)); + strbuf_init(&pp->buffered_output, 0); + + for (i = 0; i < n; i++) { + strbuf_init(&pp->children[i].err, 0); + child_process_init(&pp->children[i].process); + pp->pfd[i].events = POLLIN | POLLHUP; + pp->pfd[i].fd = -1; + } + + pp_for_signal = pp; + sigchain_push_common(handle_children_on_signal); +} + +static void pp_cleanup(struct parallel_processes *pp) +{ + int i; + + trace_printf("run_processes_parallel: done"); + for (i = 0; i < pp->max_processes; i++) { + strbuf_release(&pp->children[i].err); + child_process_clear(&pp->children[i].process); + } + + free(pp->children); + free(pp->pfd); + + /* + * When get_next_task added messages to the buffer in its last + * iteration, the buffered output is non empty. + */ + fputs(pp->buffered_output.buf, stderr); + strbuf_release(&pp->buffered_output); + + sigchain_pop_common(); +} + +/* returns + * 0 if a new task was started. + * 1 if no new jobs was started (get_next_task ran out of work, non critical + * problem with starting a new command) + * <0 no new job was started, user wishes to shutdown early. Use negative code + * to signal the children. + */ +static int pp_start_one(struct parallel_processes *pp) +{ + int i, code; + + for (i = 0; i < pp->max_processes; i++) + if (pp->children[i].state == GIT_CP_FREE) + break; + if (i == pp->max_processes) + die("BUG: bookkeeping is hard"); + + code = pp->get_next_task(&pp->children[i].process, + &pp->children[i].err, + pp->data, + &pp->children[i].data); + if (!code) { + strbuf_addbuf(&pp->buffered_output, &pp->children[i].err); + strbuf_reset(&pp->children[i].err); + return 1; + } + pp->children[i].process.err = -1; + pp->children[i].process.stdout_to_stderr = 1; + pp->children[i].process.no_stdin = 1; + + if (start_command(&pp->children[i].process)) { + code = pp->start_failure(&pp->children[i].process, + &pp->children[i].err, + pp->data, + &pp->children[i].data); + strbuf_addbuf(&pp->buffered_output, &pp->children[i].err); + strbuf_reset(&pp->children[i].err); + if (code) + pp->shutdown = 1; + return code; + } + + pp->nr_processes++; + pp->children[i].state = GIT_CP_WORKING; + pp->pfd[i].fd = pp->children[i].process.err; + return 0; +} + +static void pp_buffer_stderr(struct parallel_processes *pp, int output_timeout) +{ + int i; + + while ((i = poll(pp->pfd, pp->max_processes, output_timeout)) < 0) { + if (errno == EINTR) + continue; + pp_cleanup(pp); + die_errno("poll"); + } + + /* Buffer output from all pipes. */ + for (i = 0; i < pp->max_processes; i++) { + if (pp->children[i].state == GIT_CP_WORKING && + pp->pfd[i].revents & (POLLIN | POLLHUP)) { + int n = strbuf_read_once(&pp->children[i].err, + pp->children[i].process.err, 0); + if (n == 0) { + close(pp->children[i].process.err); + pp->children[i].state = GIT_CP_WAIT_CLEANUP; + } else if (n < 0) + if (errno != EAGAIN) + die_errno("read"); + } + } +} + +static void pp_output(struct parallel_processes *pp) +{ + int i = pp->output_owner; + if (pp->children[i].state == GIT_CP_WORKING && + pp->children[i].err.len) { + fputs(pp->children[i].err.buf, stderr); + strbuf_reset(&pp->children[i].err); + } +} + +static int pp_collect_finished(struct parallel_processes *pp) +{ + int i, code; + int n = pp->max_processes; + int result = 0; + + while (pp->nr_processes > 0) { + for (i = 0; i < pp->max_processes; i++) + if (pp->children[i].state == GIT_CP_WAIT_CLEANUP) + break; + if (i == pp->max_processes) + break; + + code = finish_command(&pp->children[i].process); + + code = pp->task_finished(code, &pp->children[i].process, + &pp->children[i].err, pp->data, + &pp->children[i].data); + + if (code) + result = code; + if (code < 0) + break; + + pp->nr_processes--; + pp->children[i].state = GIT_CP_FREE; + pp->pfd[i].fd = -1; + child_process_init(&pp->children[i].process); + + if (i != pp->output_owner) { + strbuf_addbuf(&pp->buffered_output, &pp->children[i].err); + strbuf_reset(&pp->children[i].err); + } else { + fputs(pp->children[i].err.buf, stderr); + strbuf_reset(&pp->children[i].err); + + /* Output all other finished child processes */ + fputs(pp->buffered_output.buf, stderr); + strbuf_reset(&pp->buffered_output); + + /* + * Pick next process to output live. + * NEEDSWORK: + * For now we pick it randomly by doing a round + * robin. Later we may want to pick the one with + * the most output or the longest or shortest + * running process time. + */ + for (i = 0; i < n; i++) + if (pp->children[(pp->output_owner + i) % n].state == GIT_CP_WORKING) + break; + pp->output_owner = (pp->output_owner + i) % n; + } + } + return result; +} + +int run_processes_parallel(int n, + get_next_task_fn get_next_task, + start_failure_fn start_failure, + task_finished_fn task_finished, + void *pp_cb) +{ + int i, code; + int output_timeout = 100; + int spawn_cap = 4; + struct parallel_processes pp; + + pp_init(&pp, n, get_next_task, start_failure, task_finished, pp_cb); + while (1) { + for (i = 0; + i < spawn_cap && !pp.shutdown && + pp.nr_processes < pp.max_processes; + i++) { + code = pp_start_one(&pp); + if (!code) + continue; + if (code < 0) { + pp.shutdown = 1; + kill_children(&pp, -code); + } + break; + } + if (!pp.nr_processes) + break; + pp_buffer_stderr(&pp, output_timeout); + pp_output(&pp); + code = pp_collect_finished(&pp); + if (code) { + pp.shutdown = 1; + if (code < 0) + kill_children(&pp, -code); + } + } + + pp_cleanup(&pp); + return 0; +} diff --git a/run-command.h b/run-command.h index 12bb26c2a6..42917e8618 100644 --- a/run-command.h +++ b/run-command.h @@ -121,5 +121,86 @@ struct async { int start_async(struct async *async); int finish_async(struct async *async); int in_async(void); +void NORETURN async_exit(int code); + +/** + * This callback should initialize the child process and preload the + * error channel if desired. The preloading of is useful if you want to + * have a message printed directly before the output of the child process. + * pp_cb is the callback cookie as passed to run_processes_parallel. + * You can store a child process specific callback cookie in pp_task_cb. + * + * Even after returning 0 to indicate that there are no more processes, + * this function will be called again until there are no more running + * child processes. + * + * Return 1 if the next child is ready to run. + * Return 0 if there are currently no more tasks to be processed. + * To send a signal to other child processes for abortion, + * return the negative signal number. + */ +typedef int (*get_next_task_fn)(struct child_process *cp, + struct strbuf *err, + void *pp_cb, + void **pp_task_cb); + +/** + * This callback is called whenever there are problems starting + * a new process. + * + * You must not write to stdout or stderr in this function. Add your + * message to the strbuf err instead, which will be printed without + * messing up the output of the other parallel processes. + * + * pp_cb is the callback cookie as passed into run_processes_parallel, + * pp_task_cb is the callback cookie as passed into get_next_task_fn. + * + * Return 0 to continue the parallel processing. To abort return non zero. + * To send a signal to other child processes for abortion, return + * the negative signal number. + */ +typedef int (*start_failure_fn)(struct child_process *cp, + struct strbuf *err, + void *pp_cb, + void *pp_task_cb); + +/** + * This callback is called on every child process that finished processing. + * + * You must not write to stdout or stderr in this function. Add your + * message to the strbuf err instead, which will be printed without + * messing up the output of the other parallel processes. + * + * pp_cb is the callback cookie as passed into run_processes_parallel, + * pp_task_cb is the callback cookie as passed into get_next_task_fn. + * + * Return 0 to continue the parallel processing. To abort return non zero. + * To send a signal to other child processes for abortion, return + * the negative signal number. + */ +typedef int (*task_finished_fn)(int result, + struct child_process *cp, + struct strbuf *err, + void *pp_cb, + void *pp_task_cb); + +/** + * Runs up to n processes at the same time. Whenever a process can be + * started, the callback get_next_task_fn is called to obtain the data + * required to start another child process. + * + * The children started via this function run in parallel. Their output + * (both stdout and stderr) is routed to stderr in a manner that output + * from different tasks does not interleave. + * + * If start_failure_fn or task_finished_fn are NULL, default handlers + * will be used. The default handlers will print an error message on + * error without issuing an emergency stop. + */ +int run_processes_parallel(int n, + get_next_task_fn, + start_failure_fn, + task_finished_fn, + void *pp_cb); #endif diff --git a/sequencer.c b/sequencer.c index 8c58fa2f4d..e66f2fe0f0 100644 --- a/sequencer.c +++ b/sequencer.c @@ -124,42 +124,33 @@ static const char *action_name(const struct replay_opts *opts) struct commit_message { char *parent_label; - const char *label; - const char *subject; + char *label; + char *subject; const char *message; }; static int get_message(struct commit *commit, struct commit_message *out) { const char *abbrev, *subject; - int abbrev_len, subject_len; - char *q; - - if (!git_commit_encoding) - git_commit_encoding = "UTF-8"; + int subject_len; - out->message = logmsg_reencode(commit, NULL, git_commit_encoding); + out->message = logmsg_reencode(commit, NULL, get_commit_output_encoding()); abbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV); - abbrev_len = strlen(abbrev); subject_len = find_commit_subject(out->message, &subject); - out->parent_label = xmalloc(strlen("parent of ") + abbrev_len + - strlen("... ") + subject_len + 1); - q = out->parent_label; - q = mempcpy(q, "parent of ", strlen("parent of ")); - out->label = q; - q = mempcpy(q, abbrev, abbrev_len); - q = mempcpy(q, "... ", strlen("... ")); - out->subject = q; - q = mempcpy(q, subject, subject_len); - *q = '\0'; + out->subject = xmemdupz(subject, subject_len); + out->label = xstrfmt("%s... %s", abbrev, out->subject); + out->parent_label = xstrfmt("parent of %s", out->label); + return 0; } static void free_message(struct commit *commit, struct commit_message *msg) { free(msg->parent_label); + free(msg->label); + free(msg->subject); unuse_commit_buffer(commit, msg->message); } @@ -886,7 +877,7 @@ static int sequencer_rollback(struct replay_opts *opts) if (!f) return error(_("cannot open %s: %s"), git_path_head_file(), strerror(errno)); - if (strbuf_getline(&buf, f, '\n')) { + if (strbuf_getline_lf(&buf, f)) { error(_("cannot read %s: %s"), git_path_head_file(), ferror(f) ? strerror(errno) : _("unexpected end of file")); fclose(f); @@ -88,7 +88,7 @@ char *prefix_path_gently(const char *prefix, int len, const char *orig = path; char *sanitized; if (is_absolute_path(orig)) { - sanitized = xmalloc(strlen(path) + 1); + sanitized = xmallocz(strlen(path)); if (remaining_prefix) *remaining_prefix = 0; if (normalize_path_copy_len(sanitized, path, remaining_prefix)) { @@ -139,9 +139,7 @@ int check_filename(const char *prefix, const char *arg) if (arg[2] == '\0') /* ":/" is root dir, always exists */ return 1; name = arg + 2; - } else if (!no_wildcard(arg)) - return 1; - else if (prefix) + } else if (prefix) name = prefix_filename(prefix, strlen(prefix), arg); else name = arg; @@ -202,7 +200,7 @@ void verify_filename(const char *prefix, { if (*arg == '-') die("bad flag '%s' used after filename", arg); - if (check_filename(prefix, arg)) + if (check_filename(prefix, arg) || !no_wildcard(arg)) return; die_verify_filename(prefix, arg, diagnose_misspelt_rev); } @@ -312,6 +310,23 @@ done: return ret; } +int is_nonbare_repository_dir(struct strbuf *path) +{ + int ret = 0; + int gitfile_error; + size_t orig_path_len = path->len; + assert(orig_path_len != 0); + strbuf_complete(path, '/'); + strbuf_addstr(path, ".git"); + if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf)) + ret = 1; + if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED || + gitfile_error == READ_GITFILE_ERR_READ_FAILED) + ret = 1; + strbuf_setlen(path, orig_path_len); + return ret; +} + int is_inside_git_dir(void) { if (inside_git_dir < 0) @@ -434,17 +449,6 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok) return ret; } -static void update_linked_gitdir(const char *gitfile, const char *gitdir) -{ - struct strbuf path = STRBUF_INIT; - struct stat st; - - strbuf_addf(&path, "%s/gitdir", gitdir); - if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL)) - write_file(path.buf, "%s", gitfile); - strbuf_release(&path); -} - /* * Try to read the location of the git directory from the .git file, * return path to git directory if found. @@ -482,14 +486,13 @@ const char *read_gitfile_gently(const char *path, int *return_error_code) error_code = READ_GITFILE_ERR_OPEN_FAILED; goto cleanup_return; } - buf = xmalloc(st.st_size + 1); + buf = xmallocz(st.st_size); len = read_in_full(fd, buf, st.st_size); close(fd); if (len != st.st_size) { error_code = READ_GITFILE_ERR_READ_FAILED; goto cleanup_return; } - buf[len] = '\0'; if (!starts_with(buf, "gitdir: ")) { error_code = READ_GITFILE_ERR_INVALID_FORMAT; goto cleanup_return; @@ -514,7 +517,6 @@ const char *read_gitfile_gently(const char *path, int *return_error_code) error_code = READ_GITFILE_ERR_NOT_A_REPO; goto cleanup_return; } - update_linked_gitdir(path, dir); path = real_path(dir); cleanup_return: diff --git a/sha1_file.c b/sha1_file.c index 73ccd49a46..02517009c1 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -253,7 +253,7 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base, { struct alternate_object_database *ent; struct alternate_object_database *alt; - int pfxlen, entlen; + size_t pfxlen, entlen; struct strbuf pathbuf = STRBUF_INIT; if (!is_absolute_path(entry) && relative_base) { @@ -273,8 +273,8 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base, while (pfxlen && pathbuf.buf[pfxlen-1] == '/') pfxlen -= 1; - entlen = pfxlen + 43; /* '/' + 2 hex + '/' + 38 hex + NUL */ - ent = xmalloc(sizeof(*ent) + entlen); + entlen = st_add(pfxlen, 43); /* '/' + 2 hex + '/' + 38 hex + NUL */ + ent = xmalloc(st_add(sizeof(*ent), entlen)); memcpy(ent->base, pathbuf.buf, pfxlen); strbuf_release(&pathbuf); @@ -396,7 +396,7 @@ void add_to_alternates_file(const char *reference) struct strbuf line = STRBUF_INIT; int found = 0; - while (strbuf_getline(&line, in, '\n') != EOF) { + while (strbuf_getline(&line, in) != EOF) { if (!strcmp(reference, line.buf)) { found = 1; break; @@ -1134,7 +1134,7 @@ unsigned char *use_pack(struct packed_git *p, static struct packed_git *alloc_packed_git(int extra) { - struct packed_git *p = xmalloc(sizeof(*p) + extra); + struct packed_git *p = xmalloc(st_add(sizeof(*p), extra)); memset(p, 0, sizeof(*p)); p->pack_fd = -1; return p; @@ -1168,7 +1168,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local) * ".pack" is long enough to hold any suffix we're adding (and * the use xsnprintf double-checks that) */ - alloc = path_len + strlen(".pack") + 1; + alloc = st_add3(path_len, strlen(".pack"), 1); p = alloc_packed_git(alloc); memcpy(p->pack_name, path, path_len); @@ -1196,7 +1196,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local) struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path) { const char *path = sha1_pack_name(sha1); - int alloc = strlen(path) + 1; + size_t alloc = st_add(strlen(path), 1); struct packed_git *p = alloc_packed_git(alloc); memcpy(p->pack_name, path, alloc); /* includes NUL */ @@ -1413,10 +1413,12 @@ static void mark_bad_packed_object(struct packed_git *p, { unsigned i; for (i = 0; i < p->num_bad_objects; i++) - if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i)) + if (!hashcmp(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i)) return; - p->bad_object_sha1 = xrealloc(p->bad_object_sha1, 20 * (p->num_bad_objects + 1)); - hashcpy(p->bad_object_sha1 + 20 * p->num_bad_objects, sha1); + p->bad_object_sha1 = xrealloc(p->bad_object_sha1, + st_mult(GIT_SHA1_RAWSZ, + st_add(p->num_bad_objects, 1))); + hashcpy(p->bad_object_sha1 + GIT_SHA1_RAWSZ * p->num_bad_objects, sha1); p->num_bad_objects++; } @@ -1942,7 +1944,7 @@ static enum object_type packed_to_object_type(struct packed_git *p, /* Push the object we're going to leave behind */ if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) { poi_stack_alloc = alloc_nr(poi_stack_nr); - poi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc); + ALLOC_ARRAY(poi_stack, poi_stack_alloc); memcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr); } else { ALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc); @@ -2308,7 +2310,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset, if (delta_stack_nr >= delta_stack_alloc && delta_stack == small_delta_stack) { delta_stack_alloc = alloc_nr(delta_stack_nr); - delta_stack = xmalloc(sizeof(*delta_stack)*delta_stack_alloc); + ALLOC_ARRAY(delta_stack, delta_stack_alloc); memcpy(delta_stack, small_delta_stack, sizeof(*delta_stack)*delta_stack_nr); } else { diff --git a/sha1_name.c b/sha1_name.c index 892db21813..3acf221f92 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -87,9 +87,8 @@ static void find_short_object_filename(int len, const char *hex_pfx, struct disa * object databases including our own. */ const char *objdir = get_object_directory(); - int objdir_len = strlen(objdir); - int entlen = objdir_len + 43; - fakeent = xmalloc(sizeof(*fakeent) + entlen); + size_t objdir_len = strlen(objdir); + fakeent = xmalloc(st_add3(sizeof(*fakeent), objdir_len, 43)); memcpy(fakeent->base, objdir, objdir_len); fakeent->name = fakeent->base + objdir_len + 1; fakeent->name[-1] = '/'; @@ -848,8 +847,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l * through history and returning the first commit whose message starts * the given regular expression. * - * For future extension, ':/!' is reserved. If you want to match a message - * beginning with a '!', you have to repeat the exclamation mark. + * For negative-matching, prefix the pattern-part with '!-', like: ':/!-WIP'. + * + * For a literal '!' character at the beginning of a pattern, you have to repeat + * that, like: ':/!!foo' + * + * For future extension, all other sequences beginning with ':/!' are reserved. */ /* Remember to update object flag allocation in object.h */ @@ -878,16 +881,22 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1, { struct commit_list *backup = NULL, *l; int found = 0; + int negative = 0; regex_t regex; if (prefix[0] == '!') { - if (prefix[1] != '!') - die ("Invalid search pattern: %s", prefix); prefix++; + + if (prefix[0] == '-') { + prefix++; + negative = 1; + } else if (prefix[0] != '!') { + return -1; + } } if (regcomp(®ex, prefix, REG_EXTENDED)) - die("Invalid search pattern: %s", prefix); + return -1; for (l = list; l; l = l->next) { l->item->object.flags |= ONELINE_SEEN; @@ -903,7 +912,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1, continue; buf = get_commit_buffer(commit, NULL); p = strstr(buf, "\n\n"); - matches = p && !regexec(®ex, p + 2, 0, NULL, 0); + matches = negative ^ (p && !regexec(®ex, p + 2, 0, NULL, 0)); unuse_commit_buffer(commit, buf); if (matches) { @@ -315,8 +315,8 @@ void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa) info->shallow = sa; if (!sa) return; - info->ours = xmalloc(sizeof(*info->ours) * sa->nr); - info->theirs = xmalloc(sizeof(*info->theirs) * sa->nr); + ALLOC_ARRAY(info->ours, sa->nr); + ALLOC_ARRAY(info->theirs, sa->nr); for (i = 0; i < sa->nr; i++) { if (has_sha1_file(sa->sha1[i])) { struct commit_graft *graft; @@ -389,7 +389,7 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1, unsigned int i, nr; struct commit_list *head = NULL; int bitmap_nr = (info->nr_bits + 31) / 32; - int bitmap_size = bitmap_nr * sizeof(uint32_t); + size_t bitmap_size = st_mult(bitmap_nr, sizeof(uint32_t)); uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */ uint32_t *bitmap = paint_alloc(info); struct commit *c = lookup_commit_reference_gently(sha1, 1); @@ -487,7 +487,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, struct paint_info pi; trace_printf_key(&trace_shallow, "shallow: assign_shallow_commits_to_refs\n"); - shallow = xmalloc(sizeof(*shallow) * (info->nr_ours + info->nr_theirs)); + ALLOC_ARRAY(shallow, info->nr_ours + info->nr_theirs); for (i = 0; i < info->nr_ours; i++) shallow[nr_shallow++] = info->ours[i]; for (i = 0; i < info->nr_theirs; i++) @@ -88,7 +88,7 @@ static void run_shell(void) int count; fprintf(stderr, "git> "); - if (strbuf_getline(&line, stdin, '\n') == EOF) { + if (strbuf_getline_lf(&line, stdin) == EOF) { fprintf(stderr, "\n"); strbuf_release(&line); break; diff --git a/show-index.c b/show-index.c index d9e4903fed..acf8d5445a 100644 --- a/show-index.c +++ b/show-index.c @@ -50,7 +50,8 @@ int main(int argc, char **argv) unsigned char sha1[20]; uint32_t crc; uint32_t off; - } *entries = xmalloc(nr * sizeof(entries[0])); + } *entries; + ALLOC_ARRAY(entries, nr); for (i = 0; i < nr; i++) if (fread(entries[i].sha1, 20, 1, stdin) != 1) die("unable to read sha1 %u/%u", i, nr); diff --git a/sigchain.c b/sigchain.c index faa375d5d8..2ac43bbd28 100644 --- a/sigchain.c +++ b/sigchain.c @@ -50,3 +50,12 @@ void sigchain_push_common(sigchain_fun f) sigchain_push(SIGQUIT, f); sigchain_push(SIGPIPE, f); } + +void sigchain_pop_common(void) +{ + sigchain_pop(SIGPIPE); + sigchain_pop(SIGQUIT); + sigchain_pop(SIGTERM); + sigchain_pop(SIGHUP); + sigchain_pop(SIGINT); +} diff --git a/sigchain.h b/sigchain.h index 618083bce0..138b20f54b 100644 --- a/sigchain.h +++ b/sigchain.h @@ -7,5 +7,6 @@ int sigchain_push(int sig, sigchain_fun f); int sigchain_pop(int sig); void sigchain_push_common(sigchain_fun f); +void sigchain_pop_common(void); #endif /* SIGCHAIN_H */ @@ -384,6 +384,17 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) return sb->len - oldlen; } +ssize_t strbuf_read_once(struct strbuf *sb, int fd, size_t hint) +{ + ssize_t cnt; + + strbuf_grow(sb, hint ? hint : 8192); + cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); + if (cnt > 0) + strbuf_setlen(sb, sb->len + cnt); + return cnt; +} + #define STRBUF_MAXLINK (2*PATH_MAX) int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint) @@ -501,15 +512,37 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) } #endif -int strbuf_getline(struct strbuf *sb, FILE *fp, int term) +static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term) { if (strbuf_getwholeline(sb, fp, term)) return EOF; - if (sb->buf[sb->len-1] == term) - strbuf_setlen(sb, sb->len-1); + if (sb->buf[sb->len - 1] == term) + strbuf_setlen(sb, sb->len - 1); return 0; } +int strbuf_getline(struct strbuf *sb, FILE *fp) +{ + if (strbuf_getwholeline(sb, fp, '\n')) + return EOF; + if (sb->buf[sb->len - 1] == '\n') { + strbuf_setlen(sb, sb->len - 1); + if (sb->len && sb->buf[sb->len - 1] == '\r') + strbuf_setlen(sb, sb->len - 1); + } + return 0; +} + +int strbuf_getline_lf(struct strbuf *sb, FILE *fp) +{ + return strbuf_getdelim(sb, fp, '\n'); +} + +int strbuf_getline_nul(struct strbuf *sb, FILE *fp) +{ + return strbuf_getdelim(sb, fp, '\0'); +} + int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term) { strbuf_reset(sb); @@ -685,7 +718,7 @@ char *xstrdup_tolower(const char *string) size_t len, i; len = strlen(string); - result = xmalloc(len + 1); + result = xmallocz(len); for (i = 0; i < len; i++) result[i] = tolower(string[i]); result[i] = '\0'; @@ -354,8 +354,8 @@ extern void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm * * NOTE: The buffer is rewound if the read fails. If -1 is returned, * `errno` must be consulted, like you would do for `read(3)`. - * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the - * same behaviour as well. + * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline_*()` + * family of functions have the same behaviour as well. */ extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); @@ -367,6 +367,14 @@ extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); /** + * Read the contents of a given file descriptor partially by using only one + * attempt of xread. The third argument can be used to give a hint about the + * file size, to avoid reallocs. Returns the number of new bytes appended to + * the sb. + */ +extern ssize_t strbuf_read_once(struct strbuf *, int fd, size_t hint); + +/** * Read the contents of a file, specified by its path. The third argument * can be used to give a hint about the file size, to avoid reallocs. */ @@ -379,14 +387,31 @@ extern ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint); /** - * Read a line from a FILE *, overwriting the existing contents - * of the strbuf. The second argument specifies the line - * terminator character, typically `'\n'`. + * Read a line from a FILE *, overwriting the existing contents of + * the strbuf. The strbuf_getline*() family of functions share + * this signature, but have different line termination conventions. + * * Reading stops after the terminator or at EOF. The terminator * is removed from the buffer before returning. Returns 0 unless * there was nothing left before EOF, in which case it returns `EOF`. */ -extern int strbuf_getline(struct strbuf *, FILE *, int); +typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *); + +/* Uses LF as the line terminator */ +extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp); + +/* Uses NUL as the line terminator */ +extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp); + +/* + * Similar to strbuf_getline_lf(), but additionally treats a CR that + * comes immediately before the LF as part of the terminator. + * This is the most friendly version to be used to read "text" files + * that can come from platforms whose native text format is CRLF + * terminated. + */ +extern int strbuf_getline(struct strbuf *, FILE *); + /** * Like `strbuf_getline`, but keeps the trailing terminator (if diff --git a/submodule-config.c b/submodule-config.c index fe8ceabf30..92502b594d 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -427,8 +427,8 @@ static const struct submodule *config_from(struct submodule_cache *cache, parameter.commit_sha1 = commit_sha1; parameter.gitmodules_sha1 = sha1; parameter.overwrite = 0; - git_config_from_buf(parse_config, rev.buf, config, config_size, - ¶meter); + git_config_from_mem(parse_config, "submodule-blob", rev.buf, + config, config_size, ¶meter); free(config); switch (lookup_type) { diff --git a/submodule.c b/submodule.c index 14e76247bf..24fb81ac62 100644 --- a/submodule.c +++ b/submodule.c @@ -12,6 +12,7 @@ #include "sha1-array.h" #include "argv-array.h" #include "blob.h" +#include "thread-utils.h" static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND; static struct string_list changed_submodule_paths; @@ -68,7 +69,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath) strbuf_addstr(&entry, "submodule."); strbuf_addstr(&entry, submodule->name); strbuf_addstr(&entry, ".path"); - if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) { + if (git_config_set_in_file_gently(".gitmodules", entry.buf, newpath) < 0) { /* Maybe the user already did that, don't error out here */ warning(_("Could not update .gitmodules entry %s"), entry.buf); strbuf_release(&entry); @@ -122,7 +123,7 @@ static int add_submodule_odb(const char *path) struct strbuf objects_directory = STRBUF_INIT; struct alternate_object_database *alt_odb; int ret = 0; - int alloc; + size_t alloc; strbuf_git_path_submodule(&objects_directory, path, "objects/"); if (!is_directory(objects_directory.buf)) { @@ -137,8 +138,8 @@ static int add_submodule_odb(const char *path) objects_directory.len)) goto done; - alloc = objects_directory.len + 42; /* for "12/345..." sha1 */ - alt_odb = xmalloc(sizeof(*alt_odb) + alloc); + alloc = st_add(objects_directory.len, 42); /* for "12/345..." sha1 */ + alt_odb = xmalloc(st_add(sizeof(*alt_odb), alloc)); alt_odb->next = alt_odb_list; xsnprintf(alt_odb->base, alloc, "%s", objects_directory.buf); alt_odb->name = alt_odb->base + objects_directory.len; @@ -610,37 +611,28 @@ static void calculate_changed_submodule_paths(void) initialized_fetch_ref_tips = 0; } -int fetch_populated_submodules(const struct argv_array *options, - const char *prefix, int command_line_option, - int quiet) +struct submodule_parallel_fetch { + int count; + struct argv_array args; + const char *work_tree; + const char *prefix; + int command_line_option; + int quiet; + int result; +}; +#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0} + +static int get_next_submodule(struct child_process *cp, + struct strbuf *err, void *data, void **task_cb) { - int i, result = 0; - struct child_process cp = CHILD_PROCESS_INIT; - struct argv_array argv = ARGV_ARRAY_INIT; - const char *work_tree = get_git_work_tree(); - if (!work_tree) - goto out; - - if (read_cache() < 0) - die("index file corrupt"); - - argv_array_push(&argv, "fetch"); - for (i = 0; i < options->argc; i++) - argv_array_push(&argv, options->argv[i]); - argv_array_push(&argv, "--recurse-submodules-default"); - /* default value, "--submodule-prefix" and its value are added later */ - - cp.env = local_repo_env; - cp.git_cmd = 1; - cp.no_stdin = 1; - - calculate_changed_submodule_paths(); + int ret = 0; + struct submodule_parallel_fetch *spf = data; - for (i = 0; i < active_nr; i++) { + for (; spf->count < active_nr; spf->count++) { struct strbuf submodule_path = STRBUF_INIT; struct strbuf submodule_git_dir = STRBUF_INIT; struct strbuf submodule_prefix = STRBUF_INIT; - const struct cache_entry *ce = active_cache[i]; + const struct cache_entry *ce = active_cache[spf->count]; const char *git_dir, *default_argv; const struct submodule *submodule; @@ -652,7 +644,7 @@ int fetch_populated_submodules(const struct argv_array *options, submodule = submodule_from_name(null_sha1, ce->name); default_argv = "yes"; - if (command_line_option == RECURSE_SUBMODULES_DEFAULT) { + if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) { if (submodule && submodule->fetch_recurse != RECURSE_SUBMODULES_NONE) { @@ -675,40 +667,101 @@ int fetch_populated_submodules(const struct argv_array *options, default_argv = "on-demand"; } } - } else if (command_line_option == RECURSE_SUBMODULES_ON_DEMAND) { + } else if (spf->command_line_option == RECURSE_SUBMODULES_ON_DEMAND) { if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name)) continue; default_argv = "on-demand"; } - strbuf_addf(&submodule_path, "%s/%s", work_tree, ce->name); + strbuf_addf(&submodule_path, "%s/%s", spf->work_tree, ce->name); strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf); - strbuf_addf(&submodule_prefix, "%s%s/", prefix, ce->name); + strbuf_addf(&submodule_prefix, "%s%s/", spf->prefix, ce->name); git_dir = read_gitfile(submodule_git_dir.buf); if (!git_dir) git_dir = submodule_git_dir.buf; if (is_directory(git_dir)) { - if (!quiet) - printf("Fetching submodule %s%s\n", prefix, ce->name); - cp.dir = submodule_path.buf; - argv_array_push(&argv, default_argv); - argv_array_push(&argv, "--submodule-prefix"); - argv_array_push(&argv, submodule_prefix.buf); - cp.argv = argv.argv; - if (run_command(&cp)) - result = 1; - argv_array_pop(&argv); - argv_array_pop(&argv); - argv_array_pop(&argv); + child_process_init(cp); + cp->dir = strbuf_detach(&submodule_path, NULL); + cp->env = local_repo_env; + cp->git_cmd = 1; + if (!spf->quiet) + strbuf_addf(err, "Fetching submodule %s%s\n", + spf->prefix, ce->name); + argv_array_init(&cp->args); + argv_array_pushv(&cp->args, spf->args.argv); + argv_array_push(&cp->args, default_argv); + argv_array_push(&cp->args, "--submodule-prefix"); + argv_array_push(&cp->args, submodule_prefix.buf); + ret = 1; } strbuf_release(&submodule_path); strbuf_release(&submodule_git_dir); strbuf_release(&submodule_prefix); + if (ret) { + spf->count++; + return 1; + } } - argv_array_clear(&argv); + return 0; +} + +static int fetch_start_failure(struct child_process *cp, + struct strbuf *err, + void *cb, void *task_cb) +{ + struct submodule_parallel_fetch *spf = cb; + + spf->result = 1; + + return 0; +} + +static int fetch_finish(int retvalue, struct child_process *cp, + struct strbuf *err, void *cb, void *task_cb) +{ + struct submodule_parallel_fetch *spf = cb; + + if (retvalue) + spf->result = 1; + + return 0; +} + +int fetch_populated_submodules(const struct argv_array *options, + const char *prefix, int command_line_option, + int quiet, int max_parallel_jobs) +{ + int i; + struct submodule_parallel_fetch spf = SPF_INIT; + + spf.work_tree = get_git_work_tree(); + spf.command_line_option = command_line_option; + spf.quiet = quiet; + spf.prefix = prefix; + + if (!spf.work_tree) + goto out; + + if (read_cache() < 0) + die("index file corrupt"); + + argv_array_push(&spf.args, "fetch"); + for (i = 0; i < options->argc; i++) + argv_array_push(&spf.args, options->argv[i]); + argv_array_push(&spf.args, "--recurse-submodules-default"); + /* default value, "--submodule-prefix" and its value are added later */ + + calculate_changed_submodule_paths(); + run_processes_parallel(max_parallel_jobs, + get_next_submodule, + fetch_start_failure, + fetch_finish, + &spf); + + argv_array_clear(&spf.args); out: string_list_clear(&changed_submodule_paths, 1); - return result; + return spf.result; } unsigned is_submodule_modified(const char *path, int ignore_untracked) @@ -1034,11 +1087,9 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir) /* Update core.worktree setting */ strbuf_reset(&file_name); strbuf_addf(&file_name, "%s/config", git_dir); - if (git_config_set_in_file(file_name.buf, "core.worktree", - relative_path(real_work_tree, git_dir, - &rel_path))) - die(_("Could not set core.worktree in %s"), - file_name.buf); + git_config_set_in_file(file_name.buf, "core.worktree", + relative_path(real_work_tree, git_dir, + &rel_path)); strbuf_release(&file_name); strbuf_release(&rel_path); diff --git a/submodule.h b/submodule.h index ddff512109..e06eaa5ebb 100644 --- a/submodule.h +++ b/submodule.h @@ -32,7 +32,7 @@ void set_config_fetch_recurse_submodules(int value); void check_for_new_submodule_commits(unsigned char new_sha1[20]); int fetch_populated_submodules(const struct argv_array *options, const char *prefix, int command_line_option, - int quiet); + int quiet, int max_parallel_jobs); unsigned is_submodule_modified(const char *path, int ignore_untracked); int submodule_uses_gitfile(const char *path); int ok_to_remove_submodule(const char *path); diff --git a/t/Makefile b/t/Makefile index 43b15e36ae..18e2b28b26 100644 --- a/t/Makefile +++ b/t/Makefile @@ -27,7 +27,6 @@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY)) T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) -TSVN = $(sort $(wildcard t91[0-9][0-9]-*.sh)) TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh)) THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh))) @@ -77,11 +76,6 @@ aggregate-results: echo "$$f"; \ done | '$(SHELL_PATH_SQ)' ./aggregate-results.sh -# we can test NO_OPTIMIZE_COMMITS independently of LC_ALL -full-svn-test: - $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C - $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8 - gitweb-test: $(MAKE) $(TGITWEB) diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh index bc4b3412fb..340534c064 100644 --- a/t/lib-git-daemon.sh +++ b/t/lib-git-daemon.sh @@ -23,6 +23,11 @@ then test_done fi +if test_have_prereq !PIPE +then + test_skip_or_die $GIT_TEST_GIT_DAEMON "file system does not support FIFOs" +fi + LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-${this_test#t}} GIT_DAEMON_PID= diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index b0ec12ff6c..6a50b8793e 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -186,3 +186,15 @@ start_svnserve () { --listen-host 127.0.0.1 & } +prepare_a_utf8_locale () { + a_utf8_locale=$(locale -a | sed -n '/\.[uU][tT][fF]-*8$/{ + p + q +}') + if test -n "$a_utf8_locale" + then + test_set_prereq UTF8 + else + say "# UTF-8 locale not available, some tests are skipped" + fi +} diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index e9714467d0..f9f3e5fd82 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -98,8 +98,8 @@ then test_skip_or_die $GIT_TEST_HTTPD "no web server found at '$LIB_HTTPD_PATH'" fi -HTTPD_VERSION=`$LIB_HTTPD_PATH -v | \ - sed -n 's/^Server version: Apache\/\([0-9]*\)\..*$/\1/p; q'` +HTTPD_VERSION=$($LIB_HTTPD_PATH -v | \ + sed -n 's/^Server version: Apache\/\([0-9]*\)\..*$/\1/p; q') if test -n "$HTTPD_VERSION" then diff --git a/t/perf/p7300-clean.sh b/t/perf/p7300-clean.sh index ec94cdd657..7c1888a27e 100755 --- a/t/perf/p7300-clean.sh +++ b/t/perf/p7300-clean.sh @@ -28,4 +28,8 @@ test_perf 'clean many untracked sub dirs, ignore nested git' ' git clean -n -q -f -f -d 100000_sub_dirs/ ' +test_perf 'ls-files -o' ' + git ls-files -o +' + test_done diff --git a/t/t0001-init.sh b/t/t0001-init.sh index f91bbcfc85..295aa5949a 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -87,6 +87,23 @@ test_expect_success 'plain nested in bare through aliased command' ' check_config bare-ancestor-aliased.git/plain-nested/.git false unset ' +test_expect_success 'No extra GIT_* on alias scripts' ' + ( + env | sed -ne "/^GIT_/s/=.*//p" && + echo GIT_PREFIX && # setup.c + echo GIT_TEXTDOMAINDIR # wrapper-for-bin.sh + ) | sort | uniq >expected && + cat <<-\EOF >script && + #!/bin/sh + env | sed -ne "/^GIT_/s/=.*//p" | sort >actual + exit 0 + EOF + chmod 755 script && + git config alias.script \!./script && + ( mkdir sub && cd sub && git script ) && + test_cmp expected actual +' + test_expect_success 'plain with GIT_WORK_TREE' ' mkdir plain-wt && test_must_fail env GIT_WORK_TREE="$(pwd)/plain-wt" git init plain-wt diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh index 4ef5ed484c..89544dd833 100755 --- a/t/t0008-ignores.sh +++ b/t/t0008-ignores.sh @@ -5,7 +5,7 @@ test_description=check-ignore . ./test-lib.sh init_vars () { - global_excludes="$(pwd)/global-excludes" + global_excludes="global-excludes" } enable_global_excludes () { diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index 718efa04d3..7bac2bcf26 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -252,4 +252,20 @@ test_expect_success "filter: smudge empty file" ' test_cmp expected filtered-empty-in-repo ' +test_expect_success 'disable filter with empty override' ' + test_config_global filter.disable.smudge false && + test_config_global filter.disable.clean false && + test_config filter.disable.smudge false && + test_config filter.disable.clean false && + + echo "*.disable filter=disable" >.gitattributes && + + echo test >test.disable && + git -c filter.disable.clean= add test.disable 2>err && + test_must_be_empty err && + rm -f test.disable && + git -c filter.disable.smudge= checkout -- test.disable 2>err && + test_must_be_empty err +' + test_done diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh index b343651504..f33962b178 100755 --- a/t/t0027-auto-crlf.sh +++ b/t/t0027-auto-crlf.sh @@ -21,56 +21,45 @@ compare_ws_file () { pfx=$1 exp=$2.expect act=$pfx.actual.$3 - tr '\015\000' QN <"$2" >"$exp" && - tr '\015\000' QN <"$3" >"$act" && - test_cmp $exp $act && - rm $exp $act + tr '\015\000abcdef0123456789' QN00000000000000000 <"$2" >"$exp" && + tr '\015\000abcdef0123456789' QN00000000000000000 <"$3" >"$act" && + test_cmp "$exp" "$act" && + rm "$exp" "$act" } create_gitattributes () { - attr=$1 - case "$attr" in - auto) - echo "*.txt text=auto" >.gitattributes - ;; - text) - echo "*.txt text" >.gitattributes - ;; - -text) - echo "*.txt -text" >.gitattributes - ;; - crlf) - echo "*.txt eol=crlf" >.gitattributes - ;; - lf) - echo "*.txt eol=lf" >.gitattributes - ;; - "") - echo >.gitattributes - ;; - *) - echo >&2 invalid attribute: $attr - exit 1 - ;; - esac + { + while test "$#" != 0 + do + case "$1" in + auto) echo '*.txt text=auto' ;; + ident) echo '*.txt ident' ;; + text) echo '*.txt text' ;; + -text) echo '*.txt -text' ;; + crlf) echo '*.txt eol=crlf' ;; + lf) echo '*.txt eol=lf' ;; + "") ;; + *) + echo >&2 invalid attribute: "$1" + exit 1 + ;; + esac && + shift + done + } >.gitattributes } create_NNO_files () { - lfname=$1 - crlfname=$2 - lfmixcrlf=$3 - lfmixcr=$4 - crlfnul=$5 for crlf in false true input do for attr in "" auto text -text lf crlf do pfx=NNO_${crlf}_attr_${attr} && - cp $lfname ${pfx}_LF.txt && - cp $crlfname ${pfx}_CRLF.txt && - cp $lfmixcrlf ${pfx}_CRLF_mix_LF.txt && - cp $lfmixcr ${pfx}_LF_mix_CR.txt && - cp $crlfnul ${pfx}_CRLF_nul.txt + cp CRLF_mix_LF ${pfx}_LF.txt && + cp CRLF_mix_LF ${pfx}_CRLF.txt && + cp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt && + cp CRLF_mix_LF ${pfx}_LF_mix_CR.txt && + cp CRLF_mix_LF ${pfx}_CRLF_nul.txt done done } @@ -96,7 +85,7 @@ commit_check_warn () { crlfnul=$7 pfx=crlf_${crlf}_attr_${attr} create_gitattributes "$attr" && - for f in LF CRLF repoMIX LF_mix_CR CRLF_mix_LF LF_nul CRLF_nul + for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul CRLF_nul do fname=${pfx}_$f.txt && cp $f $fname && @@ -149,6 +138,46 @@ commit_chk_wrnNNO () { ' } +stats_ascii () { + case "$1" in + LF) + echo lf + ;; + CRLF) + echo crlf + ;; + CRLF_mix_LF) + echo mixed + ;; + LF_mix_CR|CRLF_nul|LF_nul|CRLF_mix_CR) + echo "-text" + ;; + *) + echo error_invalid $1 + ;; + esac + +} + + +# contruct the attr/ returned by git ls-files --eol +# Take none (=empty), one or two args +attr_ascii () { + case $1,$2 in + -text,*) echo "-text" ;; + text,) echo "text" ;; + text,lf) echo "text eol=lf" ;; + text,crlf) echo "text eol=crlf" ;; + auto,) echo "text=auto" ;; + auto,lf) echo "text=auto eol=lf" ;; + auto,crlf) echo "text=auto eol=crlf" ;; + lf,) echo "text eol=lf" ;; + crlf,) echo "text eol=crlf" ;; + ,) echo "" ;; + *) echo invalid_attr "$1,$2" ;; + esac +} + check_files_in_repo () { crlf=$1 attr=$2 @@ -192,59 +221,108 @@ check_in_repo_NNO () { } checkout_files () { - eol=$1 - crlf=$2 - attr=$3 - lfname=$4 - crlfname=$5 - lfmixcrlf=$6 - lfmixcr=$7 - crlfnul=$8 - create_gitattributes $attr && + attr=$1 ; shift + ident=$1; shift + aeol=$1 ; shift + crlf=$1 ; shift + ceol=$1 ; shift + lfname=$1 ; shift + crlfname=$1 ; shift + lfmixcrlf=$1 ; shift + lfmixcr=$1 ; shift + crlfnul=$1 ; shift + create_gitattributes "$attr" "$ident" && git config core.autocrlf $crlf && - pfx=eol_${eol}_crlf_${crlf}_attr_${attr}_ && - src=crlf_false_attr__ && + pfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ && for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul do - rm $src$f.txt && - if test -z "$eol"; then - git checkout $src$f.txt + rm crlf_false_attr__$f.txt && + if test -z "$ceol"; then + git checkout crlf_false_attr__$f.txt else - git -c core.eol=$eol checkout $src$f.txt + git -c core.eol=$ceol checkout crlf_false_attr__$f.txt fi done - test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF" " - compare_ws_file $pfx $lfname ${src}LF.txt + test_expect_success "ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol" ' + test_when_finished "rm expect actual" && + sort <<-EOF >expect && + i/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt + i/mixed w/$(stats_ascii $lfmixcrlf) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF_mix_LF.txt + i/lf w/$(stats_ascii $lfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__LF.txt + i/-text w/$(stats_ascii $lfmixcr) attr/$(attr_ascii $attr $aeol) crlf_false_attr__LF_mix_CR.txt + i/-text w/$(stats_ascii $crlfnul) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF_nul.txt + i/-text w/$(stats_ascii $crlfnul) attr/$(attr_ascii $attr $aeol) crlf_false_attr__LF_nul.txt + EOF + git ls-files --eol crlf_false_attr__* | + sed -e "s/ / /g" -e "s/ */ /g" | + sort >actual && + test_cmp expect actual + ' + test_expect_success "checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF" " + compare_ws_file $pfx $lfname crlf_false_attr__LF.txt " - test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=CRLF" " - compare_ws_file $pfx $crlfname ${src}CRLF.txt + test_expect_success "checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF" " + compare_ws_file $pfx $crlfname crlf_false_attr__CRLF.txt " - test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=CRLF_mix_LF" " - compare_ws_file $pfx $lfmixcrlf ${src}CRLF_mix_LF.txt + test_expect_success "checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF" " + compare_ws_file $pfx $lfmixcrlf crlf_false_attr__CRLF_mix_LF.txt " - test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF_mix_CR" " - compare_ws_file $pfx $lfmixcr ${src}LF_mix_CR.txt + test_expect_success "checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR" " + compare_ws_file $pfx $lfmixcr crlf_false_attr__LF_mix_CR.txt " - test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF_nul" " - compare_ws_file $pfx $crlfnul ${src}LF_nul.txt + test_expect_success "checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul" " + compare_ws_file $pfx $crlfnul crlf_false_attr__LF_nul.txt " } -####### +# Test control characters +# NUL SOH CR EOF==^Z +test_expect_success 'ls-files --eol -o Text/Binary' ' + test_when_finished "rm expect actual TeBi_*" && + STRT=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA && + STR=$STRT$STRT$STRT$STRT && + printf "${STR}BBB\001" >TeBi_127_S && + printf "${STR}BBBB\001">TeBi_128_S && + printf "${STR}BBB\032" >TeBi_127_E && + printf "\032${STR}BBB" >TeBi_E_127 && + printf "${STR}BBBB\000">TeBi_128_N && + printf "${STR}BBB\012">TeBi_128_L && + printf "${STR}BBB\015">TeBi_127_C && + printf "${STR}BB\015\012" >TeBi_126_CL && + printf "${STR}BB\015\012\015" >TeBi_126_CLC && + sort <<-\EOF >expect && + i/ w/-text TeBi_127_S + i/ w/none TeBi_128_S + i/ w/none TeBi_127_E + i/ w/-text TeBi_E_127 + i/ w/-text TeBi_128_N + i/ w/lf TeBi_128_L + i/ w/-text TeBi_127_C + i/ w/crlf TeBi_126_CL + i/ w/-text TeBi_126_CLC + EOF + git ls-files --eol -o | + sed -n -e "/TeBi_/{s!attr/[ ]*!!g + s! ! !g + s! *! !g + p + }" | sort >actual && + test_cmp expect actual +' + test_expect_success 'setup master' ' echo >.gitattributes && git checkout -b master && git add .gitattributes && git commit -m "add .gitattributes" "" && - printf "line1\nline2\nline3" >LF && - printf "line1\r\nline2\r\nline3" >CRLF && - printf "line1\r\nline2\nline3" >repoMIX && - printf "line1\r\nline2\nline3" >CRLF_mix_LF && - printf "line1\nline2\rline3" >LF_mix_CR && - printf "line1\r\nline2\rline3" >CRLF_mix_CR && - printf "line1Q\r\nline2\r\nline3" | q_to_nul >CRLF_nul && - printf "line1Q\nline2\nline3" | q_to_nul >LF_nul && + printf "\$Id: 0000000000000000000000000000000000000000 \$\nLINEONE\nLINETWO\nLINETHREE" >LF && + printf "\$Id: 0000000000000000000000000000000000000000 \$\r\nLINEONE\r\nLINETWO\r\nLINETHREE" >CRLF && + printf "\$Id: 0000000000000000000000000000000000000000 \$\nLINEONE\r\nLINETWO\nLINETHREE" >CRLF_mix_LF && + printf "\$Id: 0000000000000000000000000000000000000000 \$\nLINEONE\nLINETWO\rLINETHREE" >LF_mix_CR && + printf "\$Id: 0000000000000000000000000000000000000000 \$\r\nLINEONE\r\nLINETWO\rLINETHREE" >CRLF_mix_CR && + printf "\$Id: 0000000000000000000000000000000000000000 \$\r\nLINEONEQ\r\nLINETWO\r\nLINETHREE" | q_to_nul >CRLF_nul && + printf "\$Id: 0000000000000000000000000000000000000000 \$\nLINEONEQ\nLINETWO\nLINETHREE" | q_to_nul >LF_nul && create_NNO_files CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF && git -c core.autocrlf=false add NNO_*.txt && git commit -m "mixed line endings" && @@ -385,23 +463,18 @@ check_in_repo_NNO input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF # How to read the table below: # - checkout_files will check multiple files with a combination of settings # and attributes (core.autocrlf=input is forbidden with core.eol=crlf) -# - parameter $1 : core.eol lf | crlf -# - parameter $2 : core.autocrlf false | true | input -# - parameter $3 : text in .gitattributs "" (empty) | auto | text | -text -# - parameter $4 : reference for a file with only LF in the repo -# - parameter $5 : reference for a file with only CRLF in the repo -# - parameter $6 : reference for a file with mixed LF and CRLF in the repo -# - parameter $7 : reference for a file with LF and CR in the repo (does somebody uses this ?) -# - parameter $8 : reference for a file with CRLF and a NUL (should be handled as binary when auto) - -# What we have in the repo: -# ----------------- EOL in repo ---------------- -# LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -# settings with checkout: -# core. core. .gitattr -# eol acrlf -# ---------------------------------------------- -# What we want to have in the working tree: +# +# - parameter $1 : text in .gitattributs "" (empty) | auto | text | -text +# - parameter $2 : ident "" | i (i == ident) +# - parameter $3 : eol in .gitattributs "" (empty) | lf | crlf +# - parameter $4 : core.autocrlf false | true | input +# - parameter $5 : core.eol "" | lf | crlf | "native" +# - parameter $6 : reference for a file with only LF in the repo +# - parameter $7 : reference for a file with only CRLF in the repo +# - parameter $8 : reference for a file with mixed LF and CRLF in the repo +# - parameter $9 : reference for a file with LF and CR in the repo +# - parameter $10 : reference for a file with CRLF and a NUL (should be handled as binary when auto) + if test_have_prereq NATIVE_CRLF then MIX_CRLF_LF=CRLF @@ -416,68 +489,104 @@ LFNUL=LF_nul fi export CRLF_MIX_LF_CR MIX NL -checkout_files lf false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf false "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul -checkout_files lf input "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf false "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files lf input "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf input "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf input "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files lf false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files lf true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files lf input "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul - -checkout_files crlf false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files crlf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files crlf false "auto" CRLF CRLF CRLF LF_mix_CR LF_nul -checkout_files crlf true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul -checkout_files crlf false "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files crlf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files crlf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files crlf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files crlf false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files crlf true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files crlf false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files crlf true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul - -checkout_files "" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" false "auto" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul -checkout_files "" true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul -checkout_files "" input "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" false "text" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL -checkout_files "" true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files "" input "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" input "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" input "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files "" false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files "" true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files "" input "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul - -checkout_files native false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files native true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files native false "auto" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul -checkout_files native true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul -checkout_files native false "text" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL -checkout_files native true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files native false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files native true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files native false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files native true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul -checkout_files native false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -checkout_files native true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files "" "" "" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" false crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" false lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" false native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" input lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" true crlf CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" true lf CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" "" "" true native CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" false crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" false lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" false native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" input lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" true "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" true crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" true lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" ident "" true native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" "" "" false "" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul +checkout_files "auto" "" "" false crlf CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files "auto" "" "" false lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" "" "" false native $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul +checkout_files "auto" "" "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" "" "" input lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" "" "" true "" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files "auto" "" "" true crlf CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files "auto" "" "" true lf CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files "auto" "" "" true native CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files "auto" ident "" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" false crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" false lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" false native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" input lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" true "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" true crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" true lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "auto" ident "" true native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + +for id in "" ident; +do + checkout_files "crlf" "$id" "" false "" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" false crlf CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" false lf CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" false native CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" input "" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" input lf CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" true "" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" true crlf CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" true lf CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "crlf" "$id" "" true native CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "lf" "$id" "" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" false crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" false lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" false native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" input lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" true "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" true crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" true lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "lf" "$id" "" true native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "text" "$id" "" false "" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL + checkout_files "text" "$id" "" false crlf CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "text" "$id" "" false lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "text" "$id" "" false native $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL + checkout_files "text" "$id" "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "text" "$id" "" input lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "text" "$id" "" true "" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "text" "$id" "" true crlf CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "text" "$id" "" true lf CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "text" "$id" "" true native CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files "-text" "$id" "" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" false crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" false lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" false native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" input lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" true "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" true crlf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" true lf LF CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files "-text" "$id" "" true native LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +done + +# Should be the last test case: remove some files from the worktree +test_expect_success 'ls-files --eol -d -z' ' + rm crlf_false_attr__CRLF.txt crlf_false_attr__CRLF_mix_LF.txt crlf_false_attr__LF.txt .gitattributes && + cat >expect <<-\EOF && + i/crlf w/ crlf_false_attr__CRLF.txt + i/lf w/ .gitattributes + i/lf w/ crlf_false_attr__LF.txt + i/mixed w/ crlf_false_attr__CRLF_mix_LF.txt + EOF + git ls-files --eol -d | + sed -e "s!attr/[^ ]*!!g" -e "s/ / /g" -e "s/ */ /g" | + sort >actual && + test_cmp expect actual +' test_done diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 627ef854d5..8532a028e7 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -36,12 +36,21 @@ if test $rootoff = 2; then rootoff= # we are on Unix else rootoff=$(($rootoff-1)) + # In MSYS2, the root directory "/" is translated into a Windows + # directory *with* trailing slash. Let's test for that and adjust + # our expected longest ancestor length accordingly. + case "$(test-path-utils print_path /)" in + */) rootslash=1;; + *) rootslash=0;; + esac fi ancestor() { # We do some math with the expected ancestor length. expected=$3 if test -n "$rootoff" && test "x$expected" != x-1; then + expected=$(($expected-$rootslash)) + test $expected -lt 0 || expected=$(($expected+$rootoff)) fi test_expect_success "longest ancestor: $1 $2 => $expected" \ @@ -59,6 +68,9 @@ case $(uname -s) in ;; esac +test_expect_success basename 'test-path-utils basename' +test_expect_success dirname 'test-path-utils dirname' + norm_path "" "" norm_path . "" norm_path ./ "" diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh index 9acf628726..12228b4aa6 100755 --- a/t/t0061-run-command.sh +++ b/t/t0061-run-command.sh @@ -47,4 +47,57 @@ test_expect_success POSIXPERM,SANITY 'unreadable directory in PATH' ' test_cmp expect actual ' +cat >expect <<-EOF +preloaded output of a child +Hello +World +preloaded output of a child +Hello +World +preloaded output of a child +Hello +World +preloaded output of a child +Hello +World +EOF + +test_expect_success 'run_command runs in parallel with more jobs available than tasks' ' + test-run-command run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual && + test_cmp expect actual +' + +test_expect_success 'run_command runs in parallel with as many jobs as tasks' ' + test-run-command run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual && + test_cmp expect actual +' + +test_expect_success 'run_command runs in parallel with more tasks than jobs available' ' + test-run-command run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual && + test_cmp expect actual +' + +cat >expect <<-EOF +preloaded output of a child +asking for a quick stop +preloaded output of a child +asking for a quick stop +preloaded output of a child +asking for a quick stop +EOF + +test_expect_success 'run_command is asked to abort gracefully' ' + test-run-command run-command-abort 3 false 2>actual && + test_cmp expect actual +' + +cat >expect <<-EOF +no further jobs available +EOF + +test_expect_success 'run_command outputs ' ' + test-run-command run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual && + test_cmp expect actual +' + test_done diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh index f8457f9d14..b7e9b4fc5b 100755 --- a/t/t1100-commit-tree-options.sh +++ b/t/t1100-commit-tree-options.sh @@ -35,11 +35,11 @@ test_expect_success \ GIT_COMMITTER_NAME="Committer Name" \ GIT_COMMITTER_EMAIL="committer@email" \ GIT_COMMITTER_DATE="2005-05-26 23:30" \ - TZ=GMT git commit-tree `cat treeid` >commitid 2>/dev/null' + TZ=GMT git commit-tree $(cat treeid) >commitid 2>/dev/null' test_expect_success \ 'read commit' \ - 'git cat-file commit `cat commitid` >commit' + 'git cat-file commit $(cat commitid) >commit' test_expect_success \ 'compare commit' \ diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 52678e7d0a..8867ce10f8 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -700,12 +700,18 @@ test_expect_success 'invalid unit' ' git config aninvalid.unit >actual && test_cmp expect actual && cat >expect <<-\EOF && - fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit + fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in file .git/config: invalid unit EOF test_must_fail git config --int --get aninvalid.unit 2>actual && test_i18ncmp expect actual ' +test_expect_success 'invalid stdin config' ' + echo "fatal: bad config line 1 in standard input " >expect && + echo "[broken" | test_must_fail git config --list --file - >output 2>&1 && + test_cmp expect output +' + cat > expect << EOF true false @@ -957,13 +963,15 @@ Qsection.sub=section.val4 Qsection.sub=section.val5Q EOF test_expect_success '--null --list' ' - git config --null --list | nul_to_q >result && + git config --null --list >result.raw && + nul_to_q <result.raw >result && echo >>result && test_cmp expect result ' test_expect_success '--null --get-regexp' ' - git config --null --get-regexp "val[0-9]" | nul_to_q >result && + git config --null --get-regexp "val[0-9]" >result.raw && + nul_to_q <result.raw >result && echo >>result && test_cmp expect result ' @@ -1201,4 +1209,151 @@ test_expect_success POSIXPERM,PERL 'preserves existing permissions' ' "die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600" ' +test_expect_success 'set up --show-origin tests' ' + INCLUDE_DIR="$HOME/include" && + mkdir -p "$INCLUDE_DIR" && + cat >"$INCLUDE_DIR"/absolute.include <<-\EOF && + [user] + absolute = include + EOF + cat >"$INCLUDE_DIR"/relative.include <<-\EOF && + [user] + relative = include + EOF + cat >"$HOME"/.gitconfig <<-EOF && + [user] + global = true + override = global + [include] + path = "$INCLUDE_DIR/absolute.include" + EOF + cat >.git/config <<-\EOF + [user] + local = true + override = local + [include] + path = ../include/relative.include + EOF +' + +test_expect_success '--show-origin with --list' ' + cat >expect <<-EOF && + file:$HOME/.gitconfig user.global=true + file:$HOME/.gitconfig user.override=global + file:$HOME/.gitconfig include.path=$INCLUDE_DIR/absolute.include + file:$INCLUDE_DIR/absolute.include user.absolute=include + file:.git/config user.local=true + file:.git/config user.override=local + file:.git/config include.path=../include/relative.include + file:.git/../include/relative.include user.relative=include + command line: user.cmdline=true + EOF + git -c user.cmdline=true config --list --show-origin >output && + test_cmp expect output +' + +test_expect_success '--show-origin with --list --null' ' + cat >expect <<-EOF && + file:$HOME/.gitconfigQuser.global + trueQfile:$HOME/.gitconfigQuser.override + globalQfile:$HOME/.gitconfigQinclude.path + $INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute + includeQfile:.git/configQuser.local + trueQfile:.git/configQuser.override + localQfile:.git/configQinclude.path + ../include/relative.includeQfile:.git/../include/relative.includeQuser.relative + includeQcommand line:Quser.cmdline + trueQ + EOF + git -c user.cmdline=true config --null --list --show-origin >output.raw && + nul_to_q <output.raw >output && + # The here-doc above adds a newline that the --null output would not + # include. Add it here to make the two comparable. + echo >>output && + test_cmp expect output +' + +test_expect_success '--show-origin with single file' ' + cat >expect <<-\EOF && + file:.git/config user.local=true + file:.git/config user.override=local + file:.git/config include.path=../include/relative.include + EOF + git config --local --list --show-origin >output && + test_cmp expect output +' + +test_expect_success '--show-origin with --get-regexp' ' + cat >expect <<-EOF && + file:$HOME/.gitconfig user.global true + file:.git/config user.local true + EOF + git config --show-origin --get-regexp "user\.[g|l].*" >output && + test_cmp expect output +' + +test_expect_success '--show-origin getting a single key' ' + cat >expect <<-\EOF && + file:.git/config local + EOF + git config --show-origin user.override >output && + test_cmp expect output +' + +test_expect_success 'set up custom config file' ' + CUSTOM_CONFIG_FILE="file\" (dq) and spaces.conf" && + cat >"$CUSTOM_CONFIG_FILE" <<-\EOF + [user] + custom = true + EOF +' + +test_expect_success '--show-origin escape special file name characters' ' + cat >expect <<-\EOF && + file:"file\" (dq) and spaces.conf" user.custom=true + EOF + git config --file "$CUSTOM_CONFIG_FILE" --show-origin --list >output && + test_cmp expect output +' + +test_expect_success '--show-origin stdin' ' + cat >expect <<-\EOF && + standard input: user.custom=true + EOF + git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output && + test_cmp expect output +' + +test_expect_success '--show-origin stdin with file include' ' + cat >"$INCLUDE_DIR"/stdin.include <<-EOF && + [user] + stdin = include + EOF + cat >expect <<-EOF && + file:$INCLUDE_DIR/stdin.include include + EOF + echo "[include]path=\"$INCLUDE_DIR\"/stdin.include" \ + | git config --show-origin --includes --file - user.stdin >output && + test_cmp expect output +' + +test_expect_success '--show-origin blob' ' + cat >expect <<-\EOF && + blob:a9d9f9e555b5c6f07cbe09d3f06fe3df11e09c08 user.custom=true + EOF + blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") && + git config --blob=$blob --show-origin --list >output && + test_cmp expect output +' + +test_expect_success '--show-origin blob ref' ' + cat >expect <<-\EOF && + blob:"master:file\" (dq) and spaces.conf" user.custom=true + EOF + git add "$CUSTOM_CONFIG_FILE" && + git commit -m "new config file" && + git config --blob=master:"$CUSTOM_CONFIG_FILE" --show-origin --list >output && + test_cmp expect output +' + test_done diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh index 91235b76ba..005d66dbef 100755 --- a/t/t1308-config-set.sh +++ b/t/t1308-config-set.sh @@ -195,14 +195,14 @@ test_expect_success 'proper error on error in default config files' ' cp .git/config .git/config.old && test_when_finished "mv .git/config.old .git/config" && echo "[" >>.git/config && - echo "fatal: bad config file line 34 in .git/config" >expect && + echo "fatal: bad config line 34 in file .git/config" >expect && test_expect_code 128 test-config get_value foo.bar 2>actual && test_cmp expect actual ' test_expect_success 'proper error on error in custom config files' ' echo "[" >>syntax-error && - echo "fatal: bad config file line 1 in syntax-error" >expect && + echo "fatal: bad config line 1 in file syntax-error" >expect && test_expect_code 128 test-config configset_get_value foo.bar syntax-error 2>actual && test_cmp expect actual ' @@ -218,4 +218,15 @@ test_expect_success 'check line errors for malformed values' ' test_i18ngrep "fatal: .*alias\.br.*\.git/config.*line 2" result ' +test_expect_success 'error on modifying repo config without repo' ' + mkdir no-repo && + ( + GIT_CEILING_DIRECTORIES=$(pwd) && + export GIT_CEILING_DIRECTORIES && + cd no-repo && + test_must_fail git config a.b c 2>err && + grep "not in a git directory" err + ) +' + test_done diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh index 1f0dff3a0b..417eecc3af 100755 --- a/t/t1401-symbolic-ref.sh +++ b/t/t1401-symbolic-ref.sh @@ -29,7 +29,7 @@ reset_to_sane test_expect_success 'symbolic-ref refuses bare sha1' ' echo content >file && git add file && git commit -m one && - test_must_fail git symbolic-ref HEAD `git rev-parse HEAD` + test_must_fail git symbolic-ref HEAD $(git rev-parse HEAD) ' reset_to_sane @@ -114,4 +114,19 @@ test_expect_success 'symbolic-ref writes reflog entry' ' test_cmp expect actual ' +test_expect_success 'symbolic-ref does not create ref d/f conflicts' ' + git checkout -b df && + test_commit df && + test_must_fail git symbolic-ref refs/heads/df/conflict refs/heads/df && + git pack-refs --all --prune && + test_must_fail git symbolic-ref refs/heads/df/conflict refs/heads/df +' + +test_expect_success 'symbolic-ref handles existing pointer to invalid name' ' + head=$(git rev-parse HEAD) && + git symbolic-ref HEAD refs/heads/outer && + git update-ref refs/heads/outer/inner $head && + git symbolic-ref HEAD refs/heads/unrelated +' + test_done diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index b79049f6f6..c623824b4d 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -62,18 +62,18 @@ test_expect_success setup ' git add . && test_tick && git commit -m rabbit && - H=`git rev-parse --verify HEAD` && - A=`git rev-parse --verify HEAD:A` && - B=`git rev-parse --verify HEAD:A/B` && - C=`git rev-parse --verify HEAD:C` && - D=`git rev-parse --verify HEAD:A/D` && - E=`git rev-parse --verify HEAD:A/B/E` && + H=$(git rev-parse --verify HEAD) && + A=$(git rev-parse --verify HEAD:A) && + B=$(git rev-parse --verify HEAD:A/B) && + C=$(git rev-parse --verify HEAD:C) && + D=$(git rev-parse --verify HEAD:A/D) && + E=$(git rev-parse --verify HEAD:A/B/E) && check_fsck && test_chmod +x C && git add C && test_tick && git commit -m dragon && - L=`git rev-parse --verify HEAD` && + L=$(git rev-parse --verify HEAD) && check_fsck && rm -f C A/B/E && @@ -81,15 +81,15 @@ test_expect_success setup ' echo horse >A/G && git add F A/G && test_tick && git commit -a -m sheep && - F=`git rev-parse --verify HEAD:F` && - G=`git rev-parse --verify HEAD:A/G` && - I=`git rev-parse --verify HEAD:A` && - J=`git rev-parse --verify HEAD` && + F=$(git rev-parse --verify HEAD:F) && + G=$(git rev-parse --verify HEAD:A/G) && + I=$(git rev-parse --verify HEAD:A) && + J=$(git rev-parse --verify HEAD) && check_fsck && rm -f A/G && test_tick && git commit -a -m monkey && - K=`git rev-parse --verify HEAD` && + K=$(git rev-parse --verify HEAD) && check_fsck && check_have A B C D E F G H I J K L && @@ -325,4 +325,17 @@ test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' ' test_cmp expect actual ' +test_expect_success 'no segfaults for reflog containing non-commit sha1s' ' + git update-ref --create-reflog -m "Creating ref" \ + refs/tests/tree-in-reflog HEAD && + git update-ref -m "Forcing tree" refs/tests/tree-in-reflog HEAD^{tree} && + git update-ref -m "Restoring to commit" refs/tests/tree-in-reflog HEAD && + git reflog refs/tests/tree-in-reflog +' + +test_expect_failure 'reflog with non-commit entries displays all entries' ' + git reflog refs/tests/tree-in-reflog >actual && + test_line_count = 3 actual +' + test_done diff --git a/t/t1501-worktree.sh b/t/t1501-work-tree.sh index cc5b870e58..cc5b870e58 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-work-tree.sh diff --git a/t/t1508-at-combinations.sh b/t/t1508-at-combinations.sh index 078e1195df..4a9964e9dc 100755 --- a/t/t1508-at-combinations.sh +++ b/t/t1508-at-combinations.sh @@ -35,7 +35,10 @@ test_expect_success 'setup' ' git checkout -b upstream-branch && test_commit upstream-one && test_commit upstream-two && - git checkout -b @/at-test && + if test_have_prereq !MINGW + then + git checkout -b @/at-test + fi && git checkout -b @@/at-test && git checkout -b @at-test && git checkout -b old-branch && @@ -64,6 +67,7 @@ check "@{-1}@{u}@{1}" commit master-one check "@" commit new-two check "@@{u}" ref refs/heads/upstream-branch check "@@/at-test" ref refs/heads/@@/at-test +test_have_prereq MINGW || check "@/at-test" ref refs/heads/@/at-test check "@at-test" ref refs/heads/@at-test nonsense "@{u}@{-1}" diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-work-tree.sh index 553a3f601b..553a3f601b 100755 --- a/t/t1509-root-worktree.sh +++ b/t/t1509-root-work-tree.sh diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh index 15973f2094..e0a49a651f 100755 --- a/t/t1511-rev-parse-caret.sh +++ b/t/t1511-rev-parse-caret.sh @@ -6,11 +6,11 @@ test_description='tests for ref^{stuff}' test_expect_success 'setup' ' echo blob >a-blob && - git tag -a -m blob blob-tag `git hash-object -w a-blob` && + git tag -a -m blob blob-tag $(git hash-object -w a-blob) && mkdir a-tree && echo moreblobs >a-tree/another-blob && git add . && - TREE_SHA1=`git write-tree` && + TREE_SHA1=$(git write-tree) && git tag -a -m tree tree-tag "$TREE_SHA1" && git commit -m Initial && git tag -a -m commit commit-tag && @@ -18,7 +18,18 @@ test_expect_success 'setup' ' git checkout master && echo modified >>a-blob && git add -u && - git commit -m Modified + git commit -m Modified && + git branch modref && + echo changed! >>a-blob && + git add -u && + git commit -m !Exp && + git branch expref && + echo changed >>a-blob && + git add -u && + git commit -m Changed && + echo changed-again >>a-blob && + git add -u && + git commit -m Changed-again ' test_expect_success 'ref^{non-existent}' ' @@ -77,4 +88,44 @@ test_expect_success 'ref^{/Initial}' ' test_cmp expected actual ' +test_expect_success 'ref^{/!Exp}' ' + test_must_fail git rev-parse master^{/!Exp} +' + +test_expect_success 'ref^{/!}' ' + test_must_fail git rev-parse master^{/!} +' + +test_expect_success 'ref^{/!!Exp}' ' + git rev-parse expref >expected && + git rev-parse master^{/!!Exp} >actual && + test_cmp expected actual +' + +test_expect_success 'ref^{/!-}' ' + test_must_fail git rev-parse master^{/!-} +' + +test_expect_success 'ref^{/!-.}' ' + test_must_fail git rev-parse master^{/!-.} +' + +test_expect_success 'ref^{/!-non-existent}' ' + git rev-parse master >expected && + git rev-parse master^{/!-non-existent} >actual && + test_cmp expected actual +' + +test_expect_success 'ref^{/!-Changed}' ' + git rev-parse expref >expected && + git rev-parse master^{/!-Changed} >actual && + test_cmp expected actual +' + +test_expect_success 'ref^{/!-!Exp}' ' + git rev-parse modref >expected && + git rev-parse expref^{/!-!Exp} >actual && + test_cmp expected actual +' + test_done diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh index 4a155c8d09..e221167cfb 100755 --- a/t/t1512-rev-parse-disambiguation.sh +++ b/t/t1512-rev-parse-disambiguation.sh @@ -275,19 +275,19 @@ test_expect_success 'rev-parse --disambiguate' ' test_expect_success 'ambiguous 40-hex ref' ' TREE=$(git mktree </dev/null) && - REF=`git rev-parse HEAD` && + REF=$(git rev-parse HEAD) && VAL=$(git commit-tree $TREE </dev/null) && git update-ref refs/heads/$REF $VAL && - test `git rev-parse $REF 2>err` = $REF && + test $(git rev-parse $REF 2>err) = $REF && grep "refname.*${REF}.*ambiguous" err ' test_expect_success 'ambiguous short sha1 ref' ' TREE=$(git mktree </dev/null) && - REF=`git rev-parse --short HEAD` && + REF=$(git rev-parse --short HEAD) && VAL=$(git commit-tree $TREE </dev/null) && git update-ref refs/heads/$REF $VAL && - test `git rev-parse $REF 2>err` = $VAL && + test $(git rev-parse $REF 2>err) = $VAL && grep "refname.*${REF}.*ambiguous" err ' diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index 193d55c3f4..8aef49f236 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -55,7 +55,7 @@ test_expect_success 'disable split index' ' EOF test_cmp ls-files.expect ls-files.actual && - BASE=`test-dump-split-index .git/index | grep "^own" | sed "s/own/base/"` && + BASE=$(test-dump-split-index .git/index | grep "^own" | sed "s/own/base/") && test-dump-split-index .git/index | sed "/^own/d" >actual && cat >expect <<EOF && not a split index diff --git a/t/t2011-checkout-invalid-head.sh b/t/t2011-checkout-invalid-head.sh index 300f8bf25c..c5501b008c 100755 --- a/t/t2011-checkout-invalid-head.sh +++ b/t/t2011-checkout-invalid-head.sh @@ -19,4 +19,43 @@ test_expect_success 'checkout master from invalid HEAD' ' git checkout master -- ' +test_expect_success 'checkout notices failure to lock HEAD' ' + test_when_finished "rm -f .git/HEAD.lock" && + >.git/HEAD.lock && + test_must_fail git checkout -b other +' + +test_expect_success 'create ref directory/file conflict scenario' ' + git update-ref refs/heads/outer/inner master && + + # do not rely on symbolic-ref to get a known state, + # as it may use the same code we are testing + reset_to_df () { + echo "ref: refs/heads/outer" >.git/HEAD + } +' + +test_expect_success 'checkout away from d/f HEAD (unpacked, to branch)' ' + reset_to_df && + git checkout master +' + +test_expect_success 'checkout away from d/f HEAD (unpacked, to detached)' ' + reset_to_df && + git checkout --detach master +' + +test_expect_success 'pack refs' ' + git pack-refs --all --prune +' + +test_expect_success 'checkout away from d/f HEAD (packed, to branch)' ' + reset_to_df && + git checkout master +' + +test_expect_success 'checkout away from d/f HEAD (packed, to detached)' ' + reset_to_df && + git checkout --detach master +' test_done diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh index 199b22d85e..b99d5192a9 100755 --- a/t/t2019-checkout-ambiguous-ref.sh +++ b/t/t2019-checkout-ambiguous-ref.sh @@ -56,30 +56,4 @@ test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' ' test_i18ngrep ! "^HEAD is now at" stderr ' -test_expect_success 'wildcard ambiguation, paths win' ' - git init ambi && - ( - cd ambi && - echo a >a.c && - git add a.c && - echo b >a.c && - git checkout "*.c" && - echo a >expect && - test_cmp expect a.c - ) -' - -test_expect_success !MINGW 'wildcard ambiguation, refs lose' ' - git init ambi2 && - ( - cd ambi2 && - echo a >"*.c" && - git add . && - test_must_fail git show :"*.c" && - git show :"*.c" -- >actual && - echo a >expect && - test_cmp expect actual - ) -' - test_done diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh index 3694174989..cbfa41ec61 100755 --- a/t/t2025-worktree-add.sh +++ b/t/t2025-worktree-add.sh @@ -123,10 +123,10 @@ test_expect_success 'checkout from a bare repo without "add"' ' test_expect_success 'checkout with grafts' ' test_when_finished rm .git/info/grafts && test_commit abc && - SHA1=`git rev-parse HEAD` && + SHA1=$(git rev-parse HEAD) && test_commit def && test_commit xyz && - echo "`git rev-parse HEAD` $SHA1" >.git/info/grafts && + echo "$(git rev-parse HEAD) $SHA1" >.git/info/grafts && cat >expected <<-\EOF && xyz abc @@ -193,6 +193,21 @@ test_expect_success '"add" -B/--detach mutually exclusive' ' test_must_fail git worktree add -B poodle --detach bamboo master ' +test_expect_success '"add -B" fails if the branch is checked out' ' + git rev-parse newmaster >before && + test_must_fail git worktree add -B newmaster bamboo master && + git rev-parse newmaster >after && + test_cmp before after +' + +test_expect_success 'add -B' ' + git worktree add -B poodle bamboo2 master^ && + git -C bamboo2 symbolic-ref HEAD >actual && + echo refs/heads/poodle >expected && + test_cmp expected actual && + test_cmp_rev master^ poodle +' + test_expect_success 'local clone from linked checkout' ' git clone --local here here-clone && ( cd here-clone && git fsck ) diff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh index 75ebb1b4a0..1b1b65a6b0 100755 --- a/t/t2027-worktree-list.sh +++ b/t/t2027-worktree-list.sh @@ -8,6 +8,16 @@ test_expect_success 'setup' ' test_commit init ' +test_expect_success 'rev-parse --git-common-dir on main worktree' ' + git rev-parse --git-common-dir >actual && + echo .git >expected && + test_cmp expected actual && + mkdir sub && + git -C sub rev-parse --git-common-dir >actual2 && + echo sub/.git >expected2 && + test_cmp expected2 actual2 +' + test_expect_success '"list" all worktrees from main' ' echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect && test_when_finished "rm -rf here && git worktree prune" && diff --git a/t/t2102-update-index-symlinks.sh b/t/t2102-update-index-symlinks.sh index 4d0d0a3515..22f2c730ae 100755 --- a/t/t2102-update-index-symlinks.sh +++ b/t/t2102-update-index-symlinks.sh @@ -23,7 +23,7 @@ git update-index symlink' test_expect_success \ 'the index entry must still be a symbolic link' ' -case "`git ls-files --stage --cached symlink`" in +case "$(git ls-files --stage --cached symlink)" in 120000" "*symlink) echo pass;; *) echo fail; git ls-files --stage --cached symlink; (exit 1);; esac' diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index 88be904c09..c525656b2c 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -65,6 +65,13 @@ test_expect_success '--no-empty-directory hides empty directory' ' test_cmp expected3 output ' +test_expect_success 'ls-files --others handles non-submodule .git' ' + mkdir not-a-submodule && + echo foo >not-a-submodule/.git && + git ls-files -o >output && + test_cmp expected1 output +' + test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' ' git init super && git init sub && diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index da257c020f..d043078da5 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -175,13 +175,10 @@ test_expect_success 'negated exclude matches can override previous ones' ' grep "^a.1" output ' -test_expect_success 'excluded directory overrides content patterns' ' +test_expect_success 'excluded directory does not override content patterns' ' git ls-files --others --exclude="one" --exclude="!one/a.1" >output && - if grep "^one/a.1" output - then - false - fi + grep "^one/a.1" output ' test_expect_success 'negated directory doesn'\''t affect content patterns' ' @@ -305,29 +302,4 @@ test_expect_success 'ls-files with "**" patterns and no slashes' ' test_cmp expect actual ' -test_expect_success 'negative patterns' ' - git init reinclude && - ( - cd reinclude && - cat >.gitignore <<-\EOF && - /fooo - /foo - !foo/bar/bar - EOF - mkdir fooo && - cat >fooo/.gitignore <<-\EOF && - !/* - EOF - mkdir -p foo/bar && - touch abc foo/def foo/bar/ghi foo/bar/bar && - git ls-files -o --exclude-standard >../actual && - cat >../expected <<-\EOF && - .gitignore - abc - foo/bar/bar - EOF - test_cmp ../expected ../actual - ) -' - test_done diff --git a/t/t3007-ls-files-other-negative.sh b/t/t3007-ls-files-other-negative.sh new file mode 100755 index 0000000000..0797b86ad0 --- /dev/null +++ b/t/t3007-ls-files-other-negative.sh @@ -0,0 +1,153 @@ +#!/bin/sh + +test_description='test re-include patterns' + +. ./test-lib.sh + +test_expect_success 'setup' ' + mkdir -p fooo foo/bar tmp && + touch abc foo/def foo/bar/ghi foo/bar/bar +' + +test_expect_success 'no match, do not enter subdir and waste cycles' ' + cat >.gitignore <<-\EOF && + /tmp + /foo + !fooo/bar/bar + EOF + GIT_TRACE_EXCLUDE="$(pwd)/tmp/trace" git ls-files -o --exclude-standard >tmp/actual && + ! grep "enter .foo/.\$" tmp/trace && + cat >tmp/expected <<-\EOF && + .gitignore + abc + EOF + test_cmp tmp/expected tmp/actual +' + +test_expect_success 'match, excluded by literal pathname pattern' ' + cat >.gitignore <<-\EOF && + /tmp + /fooo + /foo + !foo/bar/bar + EOF + cat >fooo/.gitignore <<-\EOF && + !/* + EOF git ls-files -o --exclude-standard >tmp/actual && + cat >tmp/expected <<-\EOF && + .gitignore + abc + foo/bar/bar + EOF + test_cmp tmp/expected tmp/actual +' + +test_expect_success 'match, excluded by wildcard pathname pattern' ' + cat >.gitignore <<-\EOF && + /tmp + /fooo + /fo? + !foo/bar/bar + EOF + git ls-files -o --exclude-standard >tmp/actual && + cat >tmp/expected <<-\EOF && + .gitignore + abc + foo/bar/bar + EOF + test_cmp tmp/expected tmp/actual +' + +test_expect_success 'match, excluded by literal basename pattern' ' + cat >.gitignore <<-\EOF && + /tmp + /fooo + foo + !foo/bar/bar + EOF + git ls-files -o --exclude-standard >tmp/actual && + cat >tmp/expected <<-\EOF && + .gitignore + abc + foo/bar/bar + EOF + test_cmp tmp/expected tmp/actual +' + +test_expect_success 'match, excluded by wildcard basename pattern' ' + cat >.gitignore <<-\EOF && + /tmp + /fooo + fo? + !foo/bar/bar + EOF + git ls-files -o --exclude-standard >tmp/actual && + cat >tmp/expected <<-\EOF && + .gitignore + abc + foo/bar/bar + EOF + test_cmp tmp/expected tmp/actual +' + +test_expect_success 'match, excluded by literal mustbedir, basename pattern' ' + cat >.gitignore <<-\EOF && + /tmp + /fooo + foo/ + !foo/bar/bar + EOF + git ls-files -o --exclude-standard >tmp/actual && + cat >tmp/expected <<-\EOF && + .gitignore + abc + foo/bar/bar + EOF + test_cmp tmp/expected tmp/actual +' + +test_expect_success 'match, excluded by literal mustbedir, pathname pattern' ' + cat >.gitignore <<-\EOF && + /tmp + /fooo + /foo/ + !foo/bar/bar + EOF + git ls-files -o --exclude-standard >tmp/actual && + cat >tmp/expected <<-\EOF && + .gitignore + abc + foo/bar/bar + EOF + test_cmp tmp/expected tmp/actual +' + +test_expect_success 'prepare for nested negatives' ' + cat >.git/info/exclude <<-\EOF && + /.gitignore + /tmp + /foo + /abc + EOF + git ls-files -o --exclude-standard >tmp/actual && + test_must_be_empty tmp/actual && + mkdir -p 1/2/3/4 && + touch 1/f 1/2/f 1/2/3/f 1/2/3/4/f +' + +test_expect_success 'match, literal pathname, nested negatives' ' + cat >.gitignore <<-\EOF && + /1 + !1/2 + 1/2/3 + !1/2/3/4 + EOF + git ls-files -o --exclude-standard >tmp/actual && + cat >tmp/expected <<-\EOF && + 1/2/3/4/f + 1/2/f + EOF + test_cmp tmp/expected tmp/actual +' + +test_done diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index 6224187632..f7b0e599f1 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -263,7 +263,7 @@ test_expect_success 'setup 8' ' test_ln_s_add e a && test_tick && git commit -m "rename a->e, symlink a->e" && - oln=`printf e | git hash-object --stdin` + oln=$(printf e | git hash-object --stdin) ' test_expect_success 'setup 9' ' diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-space-options.sh index 4029c9c8c0..b56180ee4a 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-space-options.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='merge-recursive options +test_description='merge-recursive space options * [master] Clarify ! [remote] Remove cruft diff --git a/t/t3034-merge-recursive-rename-options.sh b/t/t3034-merge-recursive-rename-options.sh new file mode 100755 index 0000000000..b9c4028496 --- /dev/null +++ b/t/t3034-merge-recursive-rename-options.sh @@ -0,0 +1,312 @@ +#!/bin/sh + +test_description='merge-recursive rename options + +Test rename detection by examining rename/delete conflicts. + +* (HEAD -> rename) rename +| * (master) delete +|/ +* base + +git diff --name-status base master +D 0-old +D 1-old +D 2-old +D 3-old + +git diff --name-status -M01 base rename +R025 0-old 0-new +R050 1-old 1-new +R075 2-old 2-new +R100 3-old 3-new + +Actual similarity indices are parsed from diff output. We rely on the fact that +they are rounded down (see, e.g., Documentation/diff-generate-patch.txt, which +mentions this in a different context). +' + +. ./test-lib.sh + +get_expected_stages () { + git checkout rename -- $1-new && + git ls-files --stage $1-new >expected-stages-undetected-$1 && + sed "s/ 0 / 2 /" <expected-stages-undetected-$1 \ + >expected-stages-detected-$1 && + git read-tree -u --reset HEAD +} + +rename_detected () { + git ls-files --stage $1-old $1-new >stages-actual-$1 && + test_cmp expected-stages-detected-$1 stages-actual-$1 +} + +rename_undetected () { + git ls-files --stage $1-old $1-new >stages-actual-$1 && + test_cmp expected-stages-undetected-$1 stages-actual-$1 +} + +check_common () { + git ls-files --stage >stages-actual && + test_line_count = 4 stages-actual +} + +check_threshold_0 () { + check_common && + rename_detected 0 && + rename_detected 1 && + rename_detected 2 && + rename_detected 3 +} + +check_threshold_1 () { + check_common && + rename_undetected 0 && + rename_detected 1 && + rename_detected 2 && + rename_detected 3 +} + +check_threshold_2 () { + check_common && + rename_undetected 0 && + rename_undetected 1 && + rename_detected 2 && + rename_detected 3 +} + +check_exact_renames () { + check_common && + rename_undetected 0 && + rename_undetected 1 && + rename_undetected 2 && + rename_detected 3 +} + +check_no_renames () { + check_common && + rename_undetected 0 && + rename_undetected 1 && + rename_undetected 2 && + rename_undetected 3 +} + +test_expect_success 'setup repo' ' + cat <<-\EOF >3-old && + 33a + 33b + 33c + 33d + EOF + sed s/33/22/ <3-old >2-old && + sed s/33/11/ <3-old >1-old && + sed s/33/00/ <3-old >0-old && + git add [0-3]-old && + git commit -m base && + git rm [0-3]-old && + git commit -m delete && + git checkout -b rename HEAD^ && + cp 3-old 3-new && + sed 1,1s/./x/ <2-old >2-new && + sed 1,2s/./x/ <1-old >1-new && + sed 1,3s/./x/ <0-old >0-new && + git add [0-3]-new && + git rm [0-3]-old && + git commit -m rename && + get_expected_stages 0 && + get_expected_stages 1 && + get_expected_stages 2 && + get_expected_stages 3 && + check_50="false" && + tail="HEAD^ -- HEAD master" +' + +test_expect_success 'setup thresholds' ' + git diff --name-status -M01 HEAD^ HEAD >diff-output && + test_debug "cat diff-output" && + test_line_count = 4 diff-output && + grep "R[0-9][0-9][0-9] \([0-3]\)-old \1-new" diff-output \ + >grep-output && + test_cmp diff-output grep-output && + th0=$(sed -n "s/R\(...\) 0-old 0-new/\1/p" <diff-output) && + th1=$(sed -n "s/R\(...\) 1-old 1-new/\1/p" <diff-output) && + th2=$(sed -n "s/R\(...\) 2-old 2-new/\1/p" <diff-output) && + th3=$(sed -n "s/R\(...\) 3-old 3-new/\1/p" <diff-output) && + test "$th0" -lt "$th1" && + test "$th1" -lt "$th2" && + test "$th2" -lt "$th3" && + test "$th3" = 100 && + if test 50 -le "$th0" + then + check_50=check_threshold_0 + elif test 50 -le "$th1" + then + check_50=check_threshold_1 + elif test 50 -le "$th2" + then + check_50=check_threshold_2 + fi && + th0="$th0%" && + th1="$th1%" && + th2="$th2%" && + th3="$th3%" +' + +test_expect_success 'assumption for tests: rename detection with diff' ' + git diff --name-status -M$th0 --diff-filter=R HEAD^ HEAD \ + >diff-output-0 && + git diff --name-status -M$th1 --diff-filter=R HEAD^ HEAD \ + >diff-output-1 && + git diff --name-status -M$th2 --diff-filter=R HEAD^ HEAD \ + >diff-output-2 && + git diff --name-status -M100% --diff-filter=R HEAD^ HEAD \ + >diff-output-3 && + test_line_count = 4 diff-output-0 && + test_line_count = 3 diff-output-1 && + test_line_count = 2 diff-output-2 && + test_line_count = 1 diff-output-3 +' + +test_expect_success 'default similarity threshold is 50%' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive $tail && + $check_50 +' + +test_expect_success 'low rename threshold' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=$th0 $tail && + check_threshold_0 +' + +test_expect_success 'medium rename threshold' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=$th1 $tail && + check_threshold_1 +' + +test_expect_success 'high rename threshold' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=$th2 $tail && + check_threshold_2 +' + +test_expect_success 'exact renames only' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=100% $tail && + check_exact_renames +' + +test_expect_success 'rename threshold is truncated' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=200% $tail && + check_exact_renames +' + +test_expect_success 'disabled rename detection' ' + git read-tree --reset -u HEAD && + git merge-recursive --no-renames $tail && + check_no_renames +' + +test_expect_success 'last wins in --find-renames=<m> --find-renames=<n>' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive \ + --find-renames=$th0 --find-renames=$th2 $tail && + check_threshold_2 +' + +test_expect_success '--find-renames resets threshold' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive \ + --find-renames=$th0 --find-renames $tail && + $check_50 +' + +test_expect_success 'last wins in --no-renames --find-renames' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --no-renames --find-renames $tail && + $check_50 +' + +test_expect_success 'last wins in --find-renames --no-renames' ' + git read-tree --reset -u HEAD && + git merge-recursive --find-renames --no-renames $tail && + check_no_renames +' + +test_expect_success 'assumption for further tests: trivial merge succeeds' ' + git read-tree --reset -u HEAD && + git merge-recursive HEAD -- HEAD HEAD && + git diff --quiet --cached && + git merge-recursive --find-renames=$th0 HEAD -- HEAD HEAD && + git diff --quiet --cached && + git merge-recursive --find-renames=$th2 HEAD -- HEAD HEAD && + git diff --quiet --cached && + git merge-recursive --find-renames=100% HEAD -- HEAD HEAD && + git diff --quiet --cached && + git merge-recursive --no-renames HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success '--find-renames rejects negative argument' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=-25 \ + HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success '--find-renames rejects non-numbers' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=0xf \ + HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success 'rename-threshold=<n> is a synonym for find-renames=<n>' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --rename-threshold=$th0 $tail && + check_threshold_0 +' + +test_expect_success 'last wins in --no-renames --rename-threshold=<n>' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --no-renames --rename-threshold=$th0 $tail && + check_threshold_0 +' + +test_expect_success 'last wins in --rename-threshold=<n> --no-renames' ' + git read-tree --reset -u HEAD && + git merge-recursive --rename-threshold=$th0 --no-renames $tail && + check_no_renames +' + +test_expect_success '--rename-threshold=<n> rejects negative argument' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --rename-threshold=-25 \ + HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success '--rename-threshold=<n> rejects non-numbers' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --rename-threshold=0xf \ + HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success 'last wins in --rename-threshold=<m> --find-renames=<n>' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive \ + --rename-threshold=$th0 --find-renames=$th2 $tail && + check_threshold_2 +' + +test_expect_success 'last wins in --find-renames=<m> --rename-threshold=<n>' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive \ + --find-renames=$th2 --rename-threshold=$th0 $tail && + check_threshold_0 +' + +test_done diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index eb73c06a4e..325114f8fe 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -28,7 +28,7 @@ test_expect_success \ echo Mi >path2/baz/b && find path? \( -type f -o -type l \) -print | xargs git update-index --add && - tree=`git write-tree` && + tree=$(git write-tree) && echo $tree' test_output () { diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh index 026f9f89d9..425d858938 100755 --- a/t/t3101-ls-tree-dirname.sh +++ b/t/t3101-ls-tree-dirname.sh @@ -35,7 +35,7 @@ test_expect_success 'setup' ' echo 222 >path3/2.txt && find *.txt path* \( -type f -o -type l \) -print | xargs git update-index --add && - tree=`git write-tree` && + tree=$(git write-tree) && echo $tree ' diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index cdaf6f64ec..a897248490 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -446,6 +446,13 @@ test_expect_success '--set-upstream-to fails on a non-ref' ' test_must_fail git branch --set-upstream-to HEAD^{} ' +test_expect_success '--set-upstream-to fails on locked config' ' + test_when_finished "rm -f .git/config.lock" && + >.git/config.lock && + git branch locked && + test_must_fail git branch --set-upstream-to locked +' + test_expect_success 'use --set-upstream-to modify HEAD' ' test_config branch.master.remote foo && test_config branch.master.merge foo && @@ -466,6 +473,13 @@ test_expect_success '--unset-upstream should fail if given a non-existent branch test_must_fail git branch --unset-upstream i-dont-exist ' +test_expect_success '--unset-upstream should fail if config is locked' ' + test_when_finished "rm -f .git/config.lock" && + git branch --set-upstream-to locked && + >.git/config.lock && + test_must_fail git branch --unset-upstream +' + test_expect_success 'test --unset-upstream on HEAD' ' git branch my14 && test_config branch.master.remote foo && @@ -579,7 +593,7 @@ test_expect_success 'avoid ambiguous track' ' git config remote.ambi1.fetch refs/heads/lalala:refs/heads/master && git config remote.ambi2.url lilili && git config remote.ambi2.fetch refs/heads/lilili:refs/heads/master && - git branch all1 master && + test_must_fail git branch all1 master && test -z "$(git config branch.all1.merge)" ' diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index d3913f9088..4261403cf6 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -176,4 +176,12 @@ test_expect_success 'git branch --points-at option' ' test_cmp expect actual ' +test_expect_success 'ambiguous branch/tag not marked' ' + git tag ambiguous && + git branch ambiguous && + echo " ambiguous" >expect && + git branch --list ambiguous >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh index db244d2f88..9b182a0c32 100755 --- a/t/t3210-pack-refs.sh +++ b/t/t3210-pack-refs.sh @@ -27,7 +27,7 @@ SHA1= test_expect_success \ 'see if git show-ref works as expected' \ 'git branch a && - SHA1=`cat .git/refs/heads/a` && + SHA1=$(cat .git/refs/heads/a) && echo "$SHA1 refs/heads/a" >expect && git show-ref a >result && test_cmp expect result' diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh index 9a146f1335..04de03cad0 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -13,6 +13,7 @@ tree, index, and tree objects. HT=' ' +test_have_prereq MINGW || echo 2>/dev/null > "Name with an${HT}HT" if ! test -f "Name with an${HT}HT" then diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index cd70274ea5..2d200fdf36 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -83,6 +83,16 @@ test_expect_success 'edit existing notes' ' test_must_fail git notes show HEAD^ ' +test_expect_success 'show notes from treeish' ' + test "b3" = "$(git notes --ref commits^{tree} show)" && + test "b4" = "$(git notes --ref commits@{1} show)" +' + +test_expect_success 'cannot edit notes from non-ref' ' + test_must_fail git notes --ref commits^{tree} edit && + test_must_fail git notes --ref commits@{1} edit +' + test_expect_success 'cannot "git notes add -m" where notes already exists' ' test_must_fail git notes add -m "b2" && test_path_is_missing .git/NOTES_EDITMSG && diff --git a/t/t3308-notes-merge.sh b/t/t3308-notes-merge.sh index 24d82b49bb..19aed7ec95 100755 --- a/t/t3308-notes-merge.sh +++ b/t/t3308-notes-merge.sh @@ -18,7 +18,9 @@ test_expect_success setup ' git notes add -m "Notes on 1st commit" 1st && git notes add -m "Notes on 2nd commit" 2nd && git notes add -m "Notes on 3rd commit" 3rd && - git notes add -m "Notes on 4th commit" 4th + git notes add -m "Notes on 4th commit" 4th && + # Copy notes to remote-notes + git fetch . refs/notes/*:refs/remote-notes/origin/* ' commit_sha1=$(git rev-parse 1st^{commit}) @@ -66,7 +68,9 @@ test_expect_success 'verify initial notes (x)' ' ' cp expect_notes_x expect_notes_y +cp expect_notes_x expect_notes_v cp expect_log_x expect_log_y +cp expect_log_x expect_log_v test_expect_success 'fail to merge empty notes ref into empty notes ref (z => y)' ' test_must_fail git -c "core.notesRef=refs/notes/y" notes merge z @@ -84,16 +88,12 @@ test_expect_success 'fail to merge into various non-notes refs' ' test_must_fail git -c "core.notesRef=refs/notes/foo^{bar" notes merge x ' -test_expect_success 'fail to merge various non-note-trees' ' - git config core.notesRef refs/notes/y && - test_must_fail git notes merge refs/notes && - test_must_fail git notes merge refs/notes/ && - test_must_fail git notes merge refs/notes/dir && - test_must_fail git notes merge refs/notes/dir/ && - test_must_fail git notes merge refs/heads/master && - test_must_fail git notes merge x: && - test_must_fail git notes merge x:foo && - test_must_fail git notes merge foo^{bar +test_expect_success 'merge non-notes ref into empty notes ref (remote-notes/origin/x => v)' ' + git config core.notesRef refs/notes/v && + git notes merge refs/remote-notes/origin/x && + verify_notes v && + # refs/remote-notes/origin/x and v should point to the same notes commit + test "$(git rev-parse refs/remote-notes/origin/x)" = "$(git rev-parse refs/notes/v)" ' test_expect_success 'merge notes into empty notes ref (x => y)' ' diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh index 3968020e64..1f5122b632 100755 --- a/t/t3403-rebase-skip.sh +++ b/t/t3403-rebase-skip.sh @@ -67,7 +67,7 @@ test_expect_success 'rebase --skip with --merge' ' ' test_expect_success 'merge and reference trees equal' ' - test -z "`git diff-tree skip-merge skip-reference`" + test -z "$(git diff-tree skip-merge skip-reference)" ' test_expect_success 'moved back to branch correctly' ' diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh index b7dff09d06..9cce5ae881 100755 --- a/t/t3511-cherry-pick-x.sh +++ b/t/t3511-cherry-pick-x.sh @@ -77,7 +77,7 @@ test_expect_success setup ' test_expect_success 'cherry-pick -x inserts blank line after one line subject' ' pristine_detach initial && - sha1=`git rev-parse mesg-one-line^0` && + sha1=$(git rev-parse mesg-one-line^0) && git cherry-pick -x mesg-one-line && cat <<-EOF >expect && $mesg_one_line @@ -114,7 +114,7 @@ test_expect_success 'cherry-pick -s inserts blank line after non-conforming foot test_expect_success 'cherry-pick -x inserts blank line when conforming footer not found' ' pristine_detach initial && - sha1=`git rev-parse mesg-no-footer^0` && + sha1=$(git rev-parse mesg-no-footer^0) && git cherry-pick -x mesg-no-footer && cat <<-EOF >expect && $mesg_no_footer @@ -139,7 +139,7 @@ test_expect_success 'cherry-pick -s inserts blank line when conforming footer no test_expect_success 'cherry-pick -x -s inserts blank line when conforming footer not found' ' pristine_detach initial && - sha1=`git rev-parse mesg-no-footer^0` && + sha1=$(git rev-parse mesg-no-footer^0) && git cherry-pick -x -s mesg-no-footer && cat <<-EOF >expect && $mesg_no_footer @@ -164,7 +164,7 @@ test_expect_success 'cherry-pick -s adds sob when last sob doesnt match committe test_expect_success 'cherry-pick -x -s adds sob when last sob doesnt match committer' ' pristine_detach initial && - sha1=`git rev-parse mesg-with-footer^0` && + sha1=$(git rev-parse mesg-with-footer^0) && git cherry-pick -x -s mesg-with-footer && cat <<-EOF >expect && $mesg_with_footer @@ -187,7 +187,7 @@ test_expect_success 'cherry-pick -s refrains from adding duplicate trailing sob' test_expect_success 'cherry-pick -x -s adds sob even when trailing sob exists for committer' ' pristine_detach initial && - sha1=`git rev-parse mesg-with-footer-sob^0` && + sha1=$(git rev-parse mesg-with-footer-sob^0) && git cherry-pick -x -s mesg-with-footer-sob && cat <<-EOF >expect && $mesg_with_footer_sob @@ -200,7 +200,7 @@ test_expect_success 'cherry-pick -x -s adds sob even when trailing sob exists fo test_expect_success 'cherry-pick -x treats "(cherry picked from..." line as part of footer' ' pristine_detach initial && - sha1=`git rev-parse mesg-with-cherry-footer^0` && + sha1=$(git rev-parse mesg-with-cherry-footer^0) && git cherry-pick -x mesg-with-cherry-footer && cat <<-EOF >expect && $mesg_with_cherry_footer @@ -223,7 +223,7 @@ test_expect_success 'cherry-pick -s treats "(cherry picked from..." line as part test_expect_success 'cherry-pick -x -s treats "(cherry picked from..." line as part of footer' ' pristine_detach initial && - sha1=`git rev-parse mesg-with-cherry-footer^0` && + sha1=$(git rev-parse mesg-with-cherry-footer^0) && git cherry-pick -x -s mesg-with-cherry-footer && cat <<-EOF >expect && $mesg_with_cherry_footer diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 9d90d2c935..d046d98aec 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -14,7 +14,7 @@ test_expect_success \ git add -- foo bar baz 'space embedded' -q && git commit -m 'add normal files'" -if touch -- 'tab embedded' 'newline +if test_have_prereq !MINGW && touch -- 'tab embedded' 'newline embedded' 2>/dev/null then test_set_prereq FUNNYNAMES @@ -115,7 +115,7 @@ test_expect_success '"rm" command printed' ' git add test-file && git commit -m "add file for rm test" && git rm test-file > rm-output && - test `grep "^rm " rm-output | wc -l` = 1 && + test $(grep "^rm " rm-output | wc -l) = 1 && rm -f test-file rm-output && git commit -m "remove file from rm test" ' @@ -125,7 +125,7 @@ test_expect_success '"rm" command suppressed with --quiet' ' git add test-file && git commit -m "add file for rm --quiet test" && git rm --quiet test-file > rm-output && - test `wc -l < rm-output` = 0 && + test $(wc -l < rm-output) = 0 && rm -f test-file rm-output && git commit -m "remove file from rm --quiet test" ' diff --git a/t/t3700-add.sh b/t/t3700-add.sh index f7ff1f555d..f14a665356 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -25,7 +25,7 @@ test_expect_success \ echo foo >xfoo1 && chmod 755 xfoo1 && git add xfoo1 && - case "`git ls-files --stage xfoo1`" in + case "$(git ls-files --stage xfoo1)" in 100644" "*xfoo1) echo pass;; *) echo fail; git ls-files --stage xfoo1; (exit 1);; esac' @@ -33,7 +33,7 @@ test_expect_success \ test_expect_success 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo1 && test_ln_s_add foo xfoo1 && - case "`git ls-files --stage xfoo1`" in + case "$(git ls-files --stage xfoo1)" in 120000" "*xfoo1) echo pass;; *) echo fail; git ls-files --stage xfoo1; (exit 1);; esac @@ -45,7 +45,7 @@ test_expect_success \ echo foo >xfoo2 && chmod 755 xfoo2 && git update-index --add xfoo2 && - case "`git ls-files --stage xfoo2`" in + case "$(git ls-files --stage xfoo2)" in 100644" "*xfoo2) echo pass;; *) echo fail; git ls-files --stage xfoo2; (exit 1);; esac' @@ -53,7 +53,7 @@ test_expect_success \ test_expect_success 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo2 && test_ln_s_add foo xfoo2 && - case "`git ls-files --stage xfoo2`" in + case "$(git ls-files --stage xfoo2)" in 120000" "*xfoo2) echo pass;; *) echo fail; git ls-files --stage xfoo2; (exit 1);; esac @@ -63,7 +63,7 @@ test_expect_success \ 'git update-index --add: Test that executable bit is not used...' \ 'git config core.filemode 0 && test_ln_s_add xfoo2 xfoo3 && # runs git update-index --add - case "`git ls-files --stage xfoo3`" in + case "$(git ls-files --stage xfoo3)" in 120000" "*xfoo3) echo pass;; *) echo fail; git ls-files --stage xfoo3; (exit 1);; esac' @@ -173,14 +173,14 @@ test_expect_success 'git add with filemode=0, symlinks=0 prefers stage 2 over st test_expect_success 'git add --refresh' ' >foo && git add foo && git commit -a -m "commit all" && - test -z "`git diff-index HEAD -- foo`" && + test -z "$(git diff-index HEAD -- foo)" && git read-tree HEAD && - case "`git diff-index HEAD -- foo`" in + case "$(git diff-index HEAD -- foo)" in :100644" "*"M foo") echo pass;; *) echo fail; (exit 1);; esac && git add --refresh -- foo && - test -z "`git diff-index HEAD -- foo`" + test -z "$(git diff-index HEAD -- foo)" ' test_expect_success 'git add --refresh with pathspec' ' diff --git a/t/t3703-add-magic-pathspec.sh b/t/t3703-add-magic-pathspec.sh index 5115de7036..3ef525a559 100755 --- a/t/t3703-add-magic-pathspec.sh +++ b/t/t3703-add-magic-pathspec.sh @@ -38,7 +38,7 @@ cat >expected <<EOF add 'sub/foo' EOF -if mkdir ":" 2>/dev/null +if test_have_prereq !MINGW && mkdir ":" 2>/dev/null then test_set_prereq COLON_DIR fi diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh index 892f567844..f528008c36 100755 --- a/t/t3902-quoted.sh +++ b/t/t3902-quoted.sh @@ -12,6 +12,7 @@ GN='純' HT=' ' DQ='"' +test_have_prereq MINGW || echo foo 2>/dev/null > "Name and an${HT}HT" if ! test -f "Name and an${HT}HT" then diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 646c4750ec..3b99434e3e 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -1445,4 +1445,19 @@ test_expect_success 'From line has expected format' ' test_cmp from filtered ' +test_expect_success 'format-patch format.outputDirectory option' ' + test_config format.outputDirectory patches && + rm -fr patches && + git format-patch master..side && + test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l) +' + +test_expect_success 'format-patch -o overrides format.outputDirectory' ' + test_config format.outputDirectory patches && + rm -fr patches patchset && + git format-patch master..side -o patchset && + test_path_is_missing patches && + test_path_is_dir patchset +' + test_done diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index cd543ecc54..9c48e5c2c9 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -13,6 +13,7 @@ P1='pathname with HT' P2='pathname with SP' P3='pathname with LF' +test_have_prereq !MINGW && echo 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1" || { skip_all='Your filesystem does not allow tabs in filenames' test_done diff --git a/t/t4056-diff-order.sh b/t/t4056-diff-order.sh index c0460bb0e5..43dd474a12 100755 --- a/t/t4056-diff-order.sh +++ b/t/t4056-diff-order.sh @@ -68,6 +68,12 @@ test_expect_success POSIXPERM,SANITY 'unreadable orderfile' ' test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD ' +test_expect_success "orderfile using option from subdir with --output" ' + mkdir subdir && + git -C subdir diff -O../order_file_1 --output ../actual --name-only HEAD^..HEAD && + test_cmp expect_1 actual +' + for i in 1 2 do test_expect_success "orderfile using option ($i)" ' diff --git a/t/t4135-apply-weird-filenames.sh b/t/t4135-apply-weird-filenames.sh index bf5dc57286..27cb0009fb 100755 --- a/t/t4135-apply-weird-filenames.sh +++ b/t/t4135-apply-weird-filenames.sh @@ -19,7 +19,8 @@ test_expect_success 'setup' ' test_when_finished "rm -f \"tab embedded.txt\"" && test_when_finished "rm -f '\''\"quoteembedded\".txt'\''" && - if touch -- "tab embedded.txt" '\''"quoteembedded".txt'\'' + if test_have_prereq !MINGW && + touch -- "tab embedded.txt" '\''"quoteembedded".txt'\'' then test_set_prereq FUNNYNAMES fi diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index 7600a3e3e8..f5e63670fa 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -120,6 +120,12 @@ test_expect_success !MINGW 'shortlog from non-git directory' ' test_cmp expect out ' +test_expect_success !MINGW 'shortlog can read --format=raw output' ' + git log --format=raw HEAD >log && + GIT_DIR=non-existing git shortlog -w <log >out && + test_cmp expect out +' + test_expect_success 'shortlog should add newline when input line matches wraplen' ' cat >expect <<\EOF && A U Thor (2): @@ -172,22 +178,6 @@ test_expect_success !MINGW 'shortlog encoding' ' git shortlog HEAD~2.. > out && test_cmp expect out' -test_expect_success 'shortlog ignores commits with missing authors' ' - git commit --allow-empty -m normal && - git commit --allow-empty -m soon-to-be-broken && - git cat-file commit HEAD >commit.tmp && - sed "/^author/d" commit.tmp >broken.tmp && - commit=$(git hash-object -w -t commit --stdin <broken.tmp) && - git update-ref HEAD $commit && - cat >expect <<-\EOF && - A U Thor (1): - normal - - EOF - git shortlog HEAD~2.. >actual && - test_cmp expect actual -' - test_expect_success 'shortlog with revision pseudo options' ' git shortlog --all && git shortlog --branches && diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index e97cfb2ab8..85b3df5e33 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -9,9 +9,9 @@ test_description='git mailinfo and git mailsplit test' test_expect_success 'split sample box' \ 'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last && - last=`cat last` && + last=$(cat last) && echo total is $last && - test `cat last` = 17' + test $(cat last) = 17' check_mailinfo () { mail=$1 opt=$2 @@ -23,7 +23,7 @@ check_mailinfo () { } -for mail in `echo 00*` +for mail in 00* do test_expect_success "mailinfo $mail" ' check_mailinfo $mail "" && @@ -47,11 +47,11 @@ test_expect_success 'split box with rfc2047 samples' \ 'mkdir rfc2047 && git mailsplit -orfc2047 "$TEST_DIRECTORY"/t5100/rfc2047-samples.mbox \ >rfc2047/last && - last=`cat rfc2047/last` && + last=$(cat rfc2047/last) && echo total is $last && - test `cat rfc2047/last` = 11' + test $(cat rfc2047/last) = 11' -for mail in `echo rfc2047/00*` +for mail in rfc2047/00* do test_expect_success "mailinfo $mail" ' git mailinfo -u $mail-msg $mail-patch <$mail >$mail-info && diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 20c1961515..fc2be63e02 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -8,7 +8,7 @@ test_description='git pack-object ' . ./test-lib.sh -TRASH=`pwd` +TRASH=$(pwd) test_expect_success \ 'setup' \ @@ -20,8 +20,8 @@ test_expect_success \ test-genrandom "seed b" 2097152 > b_big && git update-index --add a a_big b b_big c && cat c >d && echo foo >>d && git update-index --add d && - tree=`git write-tree` && - commit=`git commit-tree $tree </dev/null` && { + tree=$(git write-tree) && + commit=$(git commit-tree $tree </dev/null) && { echo $tree && echo $commit && git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\) .*/\\1/" @@ -29,7 +29,7 @@ test_expect_success \ git diff-tree --root -p $commit && while read object do - t=`git cat-file -t $object` && + t=$(git cat-file -t $object) && git cat-file $t $object || return 1 done <obj-list } >expect' @@ -147,7 +147,7 @@ test_expect_success \ git diff-tree --root -p $commit && while read object do - t=`git cat-file -t $object` && + t=$(git cat-file -t $object) && git cat-file $t $object || return 1 done <obj-list } >current && @@ -162,7 +162,7 @@ test_expect_success \ git diff-tree --root -p $commit && while read object do - t=`git cat-file -t $object` && + t=$(git cat-file -t $object) && git cat-file $t $object || return 1 done <obj-list } >current && @@ -177,7 +177,7 @@ test_expect_success \ git diff-tree --root -p $commit && while read object do - t=`git cat-file -t $object` && + t=$(git cat-file -t $object) && git cat-file $t $object || return 1 done <obj-list } >current && @@ -252,8 +252,8 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted sum of the index file itself' \ - 'l=`wc -c <test-3.idx` && - l=`expr $l - 20` && + 'l=$(wc -c <test-3.idx) && + l=$(expr $l - 20) && cat test-1-${packname_1}.pack >test-3.pack && printf "%20s" "" | dd of=test-3.idx count=20 bs=1 conv=notrunc seek=$l && if git verify-pack test-3.pack diff --git a/t/t5301-sliding-window.sh b/t/t5301-sliding-window.sh index 2fc5af6007..cae8c2e882 100755 --- a/t/t5301-sliding-window.sh +++ b/t/t5301-sliding-window.sh @@ -16,12 +16,12 @@ test_expect_success \ git update-index --add $i || return 1 done && echo d >d && cat c >>d && git update-index --add d && - tree=`git write-tree` && - commit1=`git commit-tree $tree </dev/null` && + tree=$(git write-tree) && + commit1=$(git commit-tree $tree </dev/null) && git update-ref HEAD $commit1 && git repack -a -d && - test "`git count-objects`" = "0 objects, 0 kilobytes" && - pack1=`ls .git/objects/pack/*.pack` && + test "$(git count-objects)" = "0 objects, 0 kilobytes" && + pack1=$(ls .git/objects/pack/*.pack) && test -f "$pack1"' test_expect_success \ @@ -43,11 +43,11 @@ test_expect_success \ 'repack -a -d, packedGit{WindowSize,Limit} == 1 page' \ 'git config core.packedGitWindowSize 512 && git config core.packedGitLimit 512 && - commit2=`git commit-tree $tree -p $commit1 </dev/null` && + commit2=$(git commit-tree $tree -p $commit1 </dev/null) && git update-ref HEAD $commit2 && git repack -a -d && - test "`git count-objects`" = "0 objects, 0 kilobytes" && - pack2=`ls .git/objects/pack/*.pack` && + test "$(git count-objects)" = "0 objects, 0 kilobytes" && + pack2=$(ls .git/objects/pack/*.pack) && test -f "$pack2" && test "$pack1" \!= "$pack2"' diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 3dc5ec4dd3..c2fc584dac 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -14,21 +14,21 @@ test_expect_success \ i=1 && while test $i -le 100 do - iii=`printf '%03i' $i` + iii=$(printf '%03i' $i) test-genrandom "bar" 200 > wide_delta_$iii && test-genrandom "baz $iii" 50 >> wide_delta_$iii && test-genrandom "foo"$i 100 > deep_delta_$iii && - test-genrandom "foo"`expr $i + 1` 100 >> deep_delta_$iii && - test-genrandom "foo"`expr $i + 2` 100 >> deep_delta_$iii && + test-genrandom "foo"$(expr $i + 1) 100 >> deep_delta_$iii && + test-genrandom "foo"$(expr $i + 2) 100 >> deep_delta_$iii && echo $iii >file_$iii && test-genrandom "$iii" 8192 >>file_$iii && git update-index --add file_$iii deep_delta_$iii wide_delta_$iii && - i=`expr $i + 1` || return 1 + i=$(expr $i + 1) || return 1 done && { echo 101 && test-genrandom 100 8192; } >file_101 && git update-index --add file_101 && - tree=`git write-tree` && - commit=`git commit-tree $tree </dev/null` && { + tree=$(git write-tree) && + commit=$(git commit-tree $tree </dev/null) && { echo $tree && git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\) .*/\\1/" } >obj-list && @@ -152,10 +152,10 @@ test_expect_success \ '[index v1] 2) create a stealth corruption in a delta base reference' \ '# This test assumes file_101 is a delta smaller than 16 bytes. # It should be against file_100 but we substitute its base for file_099 - sha1_101=`git hash-object file_101` && - sha1_099=`git hash-object file_099` && - offs_101=`index_obj_offset 1.idx $sha1_101` && - nr_099=`index_obj_nr 1.idx $sha1_099` && + sha1_101=$(git hash-object file_101) && + sha1_099=$(git hash-object file_099) && + offs_101=$(index_obj_offset 1.idx $sha1_101) && + nr_099=$(index_obj_nr 1.idx $sha1_099) && chmod +w ".git/objects/pack/pack-${pack1}.pack" && dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \ if=".git/objects/pack/pack-${pack1}.idx" \ @@ -193,10 +193,10 @@ test_expect_success \ '[index v2] 2) create a stealth corruption in a delta base reference' \ '# This test assumes file_101 is a delta smaller than 16 bytes. # It should be against file_100 but we substitute its base for file_099 - sha1_101=`git hash-object file_101` && - sha1_099=`git hash-object file_099` && - offs_101=`index_obj_offset 1.idx $sha1_101` && - nr_099=`index_obj_nr 1.idx $sha1_099` && + sha1_101=$(git hash-object file_101) && + sha1_099=$(git hash-object file_099) && + offs_101=$(index_obj_offset 1.idx $sha1_101) && + nr_099=$(index_obj_nr 1.idx $sha1_099) && chmod +w ".git/objects/pack/pack-${pack1}.pack" && dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \ if=".git/objects/pack/pack-${pack1}.idx" \ @@ -222,11 +222,11 @@ test_expect_success \ 'rm -f .git/objects/pack/* && git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && git verify-pack ".git/objects/pack/pack-${pack1}.pack" && - obj=`git hash-object file_001` && - nr=`index_obj_nr ".git/objects/pack/pack-${pack1}.idx" $obj` && + obj=$(git hash-object file_001) && + nr=$(index_obj_nr ".git/objects/pack/pack-${pack1}.idx" $obj) && chmod +w ".git/objects/pack/pack-${pack1}.idx" && printf xxxx | dd of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ - bs=1 count=4 seek=$((8 + 256 * 4 + `wc -l <obj-list` * 20 + $nr * 4)) && + bs=1 count=4 seek=$((8 + 256 * 4 + $(wc -l <obj-list) * 20 + $nr * 4)) && ( while read obj do git cat-file -p $obj >/dev/null || exit 1 done <obj-list ) && diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 663b02bbb1..5940ce2084 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -32,23 +32,23 @@ create_test_files() { create_new_pack() { rm -rf .git && git init && - blob_1=`git hash-object -t blob -w file_1` && - blob_2=`git hash-object -t blob -w file_2` && - blob_3=`git hash-object -t blob -w file_3` && - pack=`printf "$blob_1\n$blob_2\n$blob_3\n" | - git pack-objects $@ .git/objects/pack/pack` && + blob_1=$(git hash-object -t blob -w file_1) && + blob_2=$(git hash-object -t blob -w file_2) && + blob_3=$(git hash-object -t blob -w file_3) && + pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" | + git pack-objects $@ .git/objects/pack/pack) && pack=".git/objects/pack/pack-${pack}" && git verify-pack -v ${pack}.pack } do_repack() { - pack=`printf "$blob_1\n$blob_2\n$blob_3\n" | - git pack-objects $@ .git/objects/pack/pack` && + pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" | + git pack-objects $@ .git/objects/pack/pack) && pack=".git/objects/pack/pack-${pack}" } do_corrupt_object() { - ofs=`git show-index < ${pack}.idx | grep $1 | cut -f1 -d" "` && + ofs=$(git show-index < ${pack}.idx | grep $1 | cut -f1 -d" ") && ofs=$(($ofs + $2)) && chmod +w ${pack}.pack && dd of=${pack}.pack bs=1 conv=notrunc seek=$ofs && diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index def203c724..133b5842b1 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -266,7 +266,7 @@ EOF ' test_expect_success 'prune .git/shallow' ' - SHA1=`echo hi|git commit-tree HEAD^{tree}` && + SHA1=$(echo hi|git commit-tree HEAD^{tree}) && echo $SHA1 >.git/shallow && git prune --dry-run >out && grep $SHA1 .git/shallow && diff --git a/t/t5305-include-tag.sh b/t/t5305-include-tag.sh index 21517c70cd..f314ad5079 100755 --- a/t/t5305-include-tag.sh +++ b/t/t5305-include-tag.sh @@ -3,20 +3,20 @@ test_description='git pack-object --include-tag' . ./test-lib.sh -TRASH=`pwd` +TRASH=$(pwd) test_expect_success setup ' echo c >d && git update-index --add d && - tree=`git write-tree` && - commit=`git commit-tree $tree </dev/null` && + tree=$(git write-tree) && + commit=$(git commit-tree $tree </dev/null) && echo "object $commit" >sig && echo "type commit" >>sig && echo "tag mytag" >>sig && echo "tagger $(git var GIT_COMMITTER_IDENT)" >>sig && echo >>sig && echo "our test tag" >>sig && - tag=`git mktag <sig` && + tag=$(git mktag <sig) && rm d sig && git update-ref refs/tags/mytag $tag && { echo $tree && diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 3a9b77576f..e5f83bf5e4 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -14,7 +14,7 @@ test_description='Testing multi_ack pack fetching' add () { name=$1 && text="$@" && - branch=`echo $name | sed -e 's/^\(.\).*$/\1/'` && + branch=$(echo $name | sed -e 's/^\(.\).*$/\1/') && parents="" && shift && @@ -50,18 +50,18 @@ pull_to_client () { case "$heads" in *B*) echo $BTIP > .git/refs/heads/B;; esac && - git symbolic-ref HEAD refs/heads/`echo $heads \ - | sed -e "s/^\(.\).*$/\1/"` && + git symbolic-ref HEAD refs/heads/$(echo $heads \ + | sed -e "s/^\(.\).*$/\1/") && git fsck --full && mv .git/objects/pack/pack-* . && - p=`ls -1 pack-*.pack` && + p=$(ls -1 pack-*.pack) && git unpack-objects <$p && git fsck --full && - idx=`echo pack-*.idx` && - pack_count=`git show-index <$idx | wc -l` && + idx=$(echo pack-*.idx) && + pack_count=$(git show-index <$idx | wc -l) && test $pack_count = $count && rm -f pack-* ) @@ -132,13 +132,13 @@ test_expect_success 'single given branch clone' ' test_expect_success 'clone shallow depth 1' ' git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0 && - test "`git --git-dir=shallow0/.git rev-list --count HEAD`" = 1 + test "$(git --git-dir=shallow0/.git rev-list --count HEAD)" = 1 ' test_expect_success 'clone shallow depth 1 with fsck' ' git config --global fetch.fsckobjects true && git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0fsck && - test "`git --git-dir=shallow0fsck/.git rev-list --count HEAD`" = 1 && + test "$(git --git-dir=shallow0fsck/.git rev-list --count HEAD)" = 1 && git config --global --unset fetch.fsckobjects ' @@ -147,7 +147,7 @@ test_expect_success 'clone shallow' ' ' test_expect_success 'clone shallow depth count' ' - test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 2 + test "$(git --git-dir=shallow/.git rev-list --count HEAD)" = 2 ' test_expect_success 'clone shallow object count' ' @@ -273,7 +273,7 @@ test_expect_success 'additional simple shallow deepenings' ' ' test_expect_success 'clone shallow depth count' ' - test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 11 + test "$(git --git-dir=shallow/.git rev-list --count HEAD)" = 11 ' test_expect_success 'clone shallow object count' ' diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 89224edcc5..a3e12d295a 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -101,7 +101,10 @@ test_expect_success 'push with receive.fsckobjects' ' git config transfer.fsckobjects false ) && test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act && - test_cmp exp act + { + test_cmp exp act || + ! test -s act + } ' test_expect_success 'push with transfer.fsckobjects' ' diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index dfaf9d9f68..dd2e6ce34e 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -51,6 +51,11 @@ test_expect_success setup ' git clone one test ' +test_expect_success 'add remote whose URL agrees with url.<...>.insteadOf' ' + test_config url.git@host.com:team/repo.git.insteadOf myremote && + git remote add myremote git@host.com:team/repo.git +' + test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' ' ( cd test && @@ -85,7 +90,7 @@ test_expect_success C_LOCALE_OUTPUT 'check remote-tracking' ' test_expect_success 'remote forces tracking branches' ' ( cd test && - case `git config remote.second.fetch` in + case $(git config remote.second.fetch) in +*) true ;; *) false ;; esac @@ -139,6 +144,39 @@ test_expect_success 'remove remote protects local branches' ' ) ' +test_expect_success 'remove errors out early when deleting non-existent branch' ' + ( + cd test && + echo "fatal: No such remote: foo" >expect && + test_must_fail git remote rm foo 2>actual && + test_i18ncmp expect actual + ) +' + +test_expect_success 'rename errors out early when deleting non-existent branch' ' + ( + cd test && + echo "fatal: No such remote: foo" >expect && + test_must_fail git remote rename foo bar 2>actual && + test_i18ncmp expect actual + ) +' + +test_expect_success 'add existing foreign_vcs remote' ' + test_config remote.foo.vcs bar && + echo "fatal: remote foo already exists." >expect && + test_must_fail git remote add foo bar 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'add existing foreign_vcs remote' ' + test_config remote.foo.vcs bar && + test_config remote.bar.vcs bar && + echo "fatal: remote bar already exists." >expect && + test_must_fail git remote rename foo bar 2>actual && + test_i18ncmp expect actual +' + cat >test/expect <<EOF * remote origin Fetch URL: $(pwd)/one @@ -932,6 +970,15 @@ test_expect_success 'get-url on new remote' ' echo foo | get_url_test --push --all someremote ' +test_expect_success 'remote set-url with locked config' ' + test_when_finished "rm -f .git/config.lock" && + git config --get-all remote.someremote.url >expect && + >.git/config.lock && + test_must_fail git remote set-url someremote baz && + git config --get-all remote.someremote.url >actual && + cmp expect actual +' + test_expect_success 'remote set-url bar' ' git remote set-url someremote bar && echo bar >expect && diff --git a/t/t5506-remote-groups.sh b/t/t5506-remote-groups.sh index 530b01678e..83d5558c0e 100755 --- a/t/t5506-remote-groups.sh +++ b/t/t5506-remote-groups.sh @@ -20,7 +20,7 @@ update_repos() { } repo_fetched() { - if test "`git log -1 --pretty=format:%s $1 --`" = "`cat mark`"; then + if test "$(git log -1 --pretty=format:%s $1 --)" = "$(cat mark)"; then echo >&2 "repo was fetched: $1" return 0 fi diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 0ba9db0884..0c10c856a9 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -7,7 +7,7 @@ test_description='Per branch config variables affects "git fetch". . ./test-lib.sh -D=`pwd` +D=$(pwd) test_bundle_object_count () { git verify-pack -v "$1" >verify.out && @@ -64,8 +64,8 @@ test_expect_success "fetch test" ' cd two && git fetch && test -f .git/refs/heads/one && - mine=`git rev-parse refs/heads/one` && - his=`cd ../one && git rev-parse refs/heads/master` && + mine=$(git rev-parse refs/heads/one) && + his=$(cd ../one && git rev-parse refs/heads/master) && test "z$mine" = "z$his" ' @@ -75,8 +75,8 @@ test_expect_success "fetch test for-merge" ' git fetch && test -f .git/refs/heads/two && test -f .git/refs/heads/one && - master_in_two=`cd ../two && git rev-parse master` && - one_in_two=`cd ../two && git rev-parse one` && + master_in_two=$(cd ../two && git rev-parse master) && + one_in_two=$(cd ../two && git rev-parse one) && { echo "$one_in_two " echo "$master_in_two not-for-merge" @@ -314,42 +314,6 @@ test_expect_success 'bundle should be able to create a full history' ' ' -! rsync --help > /dev/null 2> /dev/null && -say 'Skipping rsync tests because rsync was not found' || { -test_expect_success 'fetch via rsync' ' - git pack-refs && - mkdir rsynced && - (cd rsynced && - git init --bare && - git fetch "rsync:../.git" master:refs/heads/master && - git gc --prune && - test $(git rev-parse master) = $(cd .. && git rev-parse master) && - git fsck --full) -' - -test_expect_success 'push via rsync' ' - mkdir rsynced2 && - (cd rsynced2 && - git init) && - (cd rsynced && - git push "rsync:../rsynced2/.git" master) && - (cd rsynced2 && - git gc --prune && - test $(git rev-parse master) = $(cd .. && git rev-parse master) && - git fsck --full) -' - -test_expect_success 'push via rsync' ' - mkdir rsynced3 && - (cd rsynced3 && - git init) && - git push --all "rsync:rsynced3/.git" && - (cd rsynced3 && - test $(git rev-parse master) = $(cd .. && git rev-parse master) && - git fsck --full) -' -} - test_expect_success 'fetch with a non-applying branch.<name>.merge' ' git config branch.master.remote yeti && git config branch.master.merge refs/heads/bigfoot && @@ -708,4 +672,17 @@ test_expect_success 'fetching a one-level ref works' ' ) ' +test_expect_success 'fetching with auto-gc does not lock up' ' + write_script askyesno <<-\EOF && + echo "$*" && + false + EOF + git clone "file://$D" auto-gc && + test_commit test2 && + cd auto-gc && + git config gc.autoPackLimit 1 && + GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 && + ! grep "Should I try again" fetch.out +' + test_done diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index aadaac515e..819b9ddd0f 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -163,4 +163,49 @@ test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs' grep refs/tags/magic actual ' +test_expect_success 'ls-remote --symref' ' + cat >expect <<-\EOF && + ref: refs/heads/master HEAD + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a HEAD + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/master + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/remotes/origin/HEAD + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/remotes/origin/master + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/tags/mark + EOF + git ls-remote --symref >actual && + test_cmp expect actual +' + +test_expect_success 'ls-remote with filtered symref (refname)' ' + cat >expect <<-\EOF && + ref: refs/heads/master HEAD + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a HEAD + EOF + git ls-remote --symref . HEAD >actual && + test_cmp expect actual +' + +test_expect_failure 'ls-remote with filtered symref (--heads)' ' + git symbolic-ref refs/heads/foo refs/tags/mark && + cat >expect <<-\EOF && + ref: refs/tags/mark refs/heads/foo + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/foo + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/master + EOF + git ls-remote --symref --heads . >actual && + test_cmp expect actual +' + +test_expect_success 'ls-remote --symref omits filtered-out matches' ' + cat >expect <<-\EOF && + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/foo + 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/master + EOF + git ls-remote --symref --heads . >actual && + test_cmp expect actual && + git ls-remote --symref . "refs/heads/*" >actual && + test_cmp expect actual +' + + test_done diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index dbb927dec8..36b0dbc01c 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -128,8 +128,8 @@ do case "$cmd" in '' | '#'*) continue ;; esac - test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'` - pfx=`printf "%04d" $test_count` + test=$(echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g') + pfx=$(printf "%04d" $test_count) expect_f="$TEST_DIRECTORY/t5515/fetch.$test" actual_f="$pfx-fetch.$test" expect_r="$TEST_DIRECTORY/t5515/refs.$test" diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 0a87e195ea..26b2cafc47 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -16,7 +16,7 @@ This test checks the following functionality: . ./test-lib.sh -D=`pwd` +D=$(pwd) mk_empty () { repo_name="$1" @@ -422,7 +422,7 @@ test_expect_success 'push tag with non-existent, incomplete dest' ' test_expect_success 'push sha1 with non-existent, incomplete dest' ' mk_test testrepo && - test_must_fail git push testrepo `git rev-parse master`:foo + test_must_fail git push testrepo $(git rev-parse master):foo ' diff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh index 12a5dfb17e..02f160aae0 100755 --- a/t/t5517-push-mirror.sh +++ b/t/t5517-push-mirror.sh @@ -4,7 +4,7 @@ test_description='pushing to a mirror repository' . ./test-lib.sh -D=`pwd` +D=$(pwd) invert () { if "$@"; then diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index a0013ee32f..c952d5ef5c 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -326,6 +326,16 @@ test_expect_success 'pull.rebase=preserve rebases and merges keep-merge' ' test "$(git rev-parse HEAD^2)" = "$(git rev-parse keep-merge)" ' +test_expect_success 'pull.rebase=interactive' ' + write_script "$TRASH_DIRECTORY/fake-editor" <<-\EOF && + echo I was here >fake.out && + false + EOF + test_set_editor "$TRASH_DIRECTORY/fake-editor" && + test_must_fail git pull --rebase=interactive . copy && + test "I was here" = "$(cat fake.out)" +' + test_expect_success 'pull.rebase=invalid fails' ' git reset --hard before-preserve-rebase && test_config pull.rebase invalid && diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh index 8e9b204e02..bcff460d0a 100755 --- a/t/t5522-pull-symlink.sh +++ b/t/t5522-pull-symlink.sh @@ -54,7 +54,7 @@ test_expect_success SYMLINKS 'pulling from real subdir' ' # git rev-parse --show-cdup printed a path relative to # clone-repo/subdir/, not subdir-link/. Git rev-parse --show-cdup # used the correct .git, but when the git pull shell script did -# "cd `git rev-parse --show-cdup`", it ended up in the wrong +# "cd $(git rev-parse --show-cdup)", it ended up in the wrong # directory. A POSIX shell's "cd" works a little differently # than chdir() in C; "cd -P" is much closer to chdir(). # diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index a4532b00d6..1241146227 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -16,7 +16,8 @@ add_upstream_commit() { git add subfile && git commit -m new subfile && head2=$(git rev-parse --short HEAD) && - echo "From $pwd/submodule" > ../expect.err && + echo "Fetching submodule submodule" > ../expect.err && + echo "From $pwd/submodule" >> ../expect.err && echo " $head1..$head2 master -> origin/master" >> ../expect.err ) && ( @@ -27,6 +28,7 @@ add_upstream_commit() { git add deepsubfile && git commit -m new deepsubfile && head2=$(git rev-parse --short HEAD) && + echo "Fetching submodule submodule/subdir/deepsubmodule" >> ../expect.err echo "From $pwd/deepsubmodule" >> ../expect.err && echo " $head1..$head2 master -> origin/master" >> ../expect.err ) @@ -56,9 +58,7 @@ test_expect_success setup ' ( cd downstream && git submodule update --init --recursive - ) && - echo "Fetching submodule submodule" > expect.out && - echo "Fetching submodule submodule/subdir/deepsubmodule" >> expect.out + ) ' test_expect_success "fetch --recurse-submodules recurses into submodules" ' @@ -67,10 +67,21 @@ test_expect_success "fetch --recurse-submodules recurses into submodules" ' cd downstream && git fetch --recurse-submodules >../actual.out 2>../actual.err ) && - test_i18ncmp expect.out actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err actual.err ' +test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" ' + add_upstream_commit && + ( + cd downstream && + GIT_TRACE=$(pwd)/../trace.out git fetch --recurse-submodules -j2 2>../actual.err + ) && + test_must_be_empty actual.out && + test_i18ncmp expect.err actual.err && + grep "2 tasks" trace.out +' + test_expect_success "fetch alone only fetches superproject" ' add_upstream_commit && ( @@ -96,7 +107,7 @@ test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses i git config -f .gitmodules submodule.submodule.fetchRecurseSubmodules true && git fetch >../actual.out 2>../actual.err ) && - test_i18ncmp expect.out actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err actual.err ' @@ -127,7 +138,7 @@ test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setti git config --unset -f .gitmodules submodule.submodule.fetchRecurseSubmodules && git config --unset submodule.submodule.fetchRecurseSubmodules ) && - test_i18ncmp expect.out actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err actual.err ' @@ -140,13 +151,22 @@ test_expect_success "--quiet propagates to submodules" ' ! test -s actual.err ' +test_expect_success "--quiet propagates to parallel submodules" ' + ( + cd downstream && + git fetch --recurse-submodules -j 2 --quiet >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + test_expect_success "--dry-run propagates to submodules" ' add_upstream_commit && ( cd downstream && git fetch --recurse-submodules --dry-run >../actual.out 2>../actual.err ) && - test_i18ncmp expect.out actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err actual.err ' @@ -155,7 +175,7 @@ test_expect_success "Without --dry-run propagates to submodules" ' cd downstream && git fetch --recurse-submodules >../actual.out 2>../actual.err ) && - test_i18ncmp expect.out actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err actual.err ' @@ -166,7 +186,7 @@ test_expect_success "recurseSubmodules=true propagates into submodules" ' git config fetch.recurseSubmodules true git fetch >../actual.out 2>../actual.err ) && - test_i18ncmp expect.out actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err actual.err ' @@ -180,7 +200,7 @@ test_expect_success "--recurse-submodules overrides config in submodule" ' ) && git fetch --recurse-submodules >../actual.out 2>../actual.err ) && - test_i18ncmp expect.out actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err actual.err ' @@ -214,16 +234,15 @@ test_expect_success "Recursion stops when no new submodule commits are fetched" git add submodule && git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && - echo "Fetching submodule submodule" > expect.out.sub && echo "From $pwd/." > expect.err.sub && echo " $head1..$head2 master -> origin/master" >>expect.err.sub && - head -2 expect.err >> expect.err.sub && + head -3 expect.err >> expect.err.sub && ( cd downstream && git fetch >../actual.out 2>../actual.err ) && test_i18ncmp expect.err.sub actual.err && - test_i18ncmp expect.out.sub actual.out + test_must_be_empty actual.out ' test_expect_success "Recursion doesn't happen when new superproject commits don't change any submodules" ' @@ -269,7 +288,7 @@ test_expect_success "Recursion picks up config in submodule" ' ) ) && test_i18ncmp expect.err.sub actual.err && - test_i18ncmp expect.out actual.out + test_must_be_empty actual.out ' test_expect_success "Recursion picks up all submodules when necessary" ' @@ -285,7 +304,8 @@ test_expect_success "Recursion picks up all submodules when necessary" ' git add subdir/deepsubmodule && git commit -m "new deepsubmodule" head2=$(git rev-parse --short HEAD) && - echo "From $pwd/submodule" > ../expect.err.sub && + echo "Fetching submodule submodule" > ../expect.err.sub && + echo "From $pwd/submodule" >> ../expect.err.sub && echo " $head1..$head2 master -> origin/master" >> ../expect.err.sub ) && head1=$(git rev-parse --short HEAD) && @@ -295,13 +315,13 @@ test_expect_success "Recursion picks up all submodules when necessary" ' echo "From $pwd/." > expect.err.2 && echo " $head1..$head2 master -> origin/master" >> expect.err.2 && cat expect.err.sub >> expect.err.2 && - tail -2 expect.err >> expect.err.2 && + tail -3 expect.err >> expect.err.2 && ( cd downstream && git fetch >../actual.out 2>../actual.err ) && test_i18ncmp expect.err.2 actual.err && - test_i18ncmp expect.out actual.out + test_must_be_empty actual.out ' test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" ' @@ -317,7 +337,8 @@ test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no ne git add subdir/deepsubmodule && git commit -m "new deepsubmodule" && head2=$(git rev-parse --short HEAD) && - echo "From $pwd/submodule" > ../expect.err.sub && + echo Fetching submodule submodule > ../expect.err.sub && + echo "From $pwd/submodule" >> ../expect.err.sub && echo " $head1..$head2 master -> origin/master" >> ../expect.err.sub ) && ( @@ -335,7 +356,7 @@ test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necess git add submodule && git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && - tail -2 expect.err > expect.err.deepsub && + tail -3 expect.err > expect.err.deepsub && echo "From $pwd/." > expect.err && echo " $head1..$head2 master -> origin/master" >>expect.err && cat expect.err.sub >> expect.err && @@ -354,7 +375,7 @@ test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necess git config --unset -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive ) ) && - test_i18ncmp expect.out actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err actual.err ' @@ -388,7 +409,7 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.2 && echo " $head1..$head2 master -> origin/master" >>expect.err.2 && - head -2 expect.err >> expect.err.2 && + head -3 expect.err >> expect.err.2 && ( cd downstream && git config fetch.recurseSubmodules on-demand && @@ -399,7 +420,7 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config cd downstream && git config --unset fetch.recurseSubmodules ) && - test_i18ncmp expect.out.sub actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err.2 actual.err ' @@ -416,7 +437,7 @@ test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' override head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.2 && echo " $head1..$head2 master -> origin/master" >>expect.err.2 && - head -2 expect.err >> expect.err.2 && + head -3 expect.err >> expect.err.2 && ( cd downstream && git config submodule.submodule.fetchRecurseSubmodules on-demand && @@ -427,7 +448,7 @@ test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' override cd downstream && git config --unset submodule.submodule.fetchRecurseSubmodules ) && - test_i18ncmp expect.out.sub actual.out && + test_must_be_empty actual.out && test_i18ncmp expect.err.2 actual.err ' diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh index 3932e797f7..4f6e32b04c 100755 --- a/t/t5530-upload-pack-error.sh +++ b/t/t5530-upload-pack-error.sh @@ -4,7 +4,7 @@ test_description='errors in upload-pack' . ./test-lib.sh -D=`pwd` +D=$(pwd) corrupt_repo () { object_sha1=$(git rev-parse "$1") && diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh index 5531bd1af4..d75ef0ea2b 100755 --- a/t/t5532-fetch-proxy.sh +++ b/t/t5532-fetch-proxy.sh @@ -15,7 +15,7 @@ test_expect_success 'setup remote repo' ' cat >proxy <<'EOF' #!/bin/sh echo >&2 "proxying for $*" -cmd=`"$PERL_PATH" -e ' +cmd=$("$PERL_PATH" -e ' read(STDIN, $buf, 4); my $n = hex($buf) - 4; read(STDIN, $buf, $n); @@ -23,7 +23,7 @@ cmd=`"$PERL_PATH" -e ' # drop absolute-path on repo name $cmd =~ s{ /}{ }; print $cmd; -'` +') echo >&2 "Running '$cmd'" exec $cmd EOF diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh index c402d8d3d7..c7320121ec 100755 --- a/t/t5533-push-cas.sh +++ b/t/t5533-push-cas.sh @@ -25,7 +25,8 @@ test_expect_success 'push to update (protected)' ' ( cd dst && test_commit D && - test_must_fail git push --force-with-lease=master:master origin master + test_must_fail git push --force-with-lease=master:master origin master 2>err && + grep "stale info" err ) && git ls-remote . refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -37,7 +38,8 @@ test_expect_success 'push to update (protected, forced)' ' ( cd dst && test_commit D && - git push --force --force-with-lease=master:master origin master + git push --force --force-with-lease=master:master origin master 2>err && + grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -101,7 +103,8 @@ test_expect_success 'push to update (allowed, tracking)' ' ( cd dst && test_commit D && - git push --force-with-lease=master origin master + git push --force-with-lease=master origin master 2>err && + ! grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -114,7 +117,8 @@ test_expect_success 'push to update (allowed even though no-ff)' ' cd dst && git reset --hard HEAD^ && test_commit D && - git push --force-with-lease=master origin master + git push --force-with-lease=master origin master 2>err && + grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -147,7 +151,8 @@ test_expect_success 'push to delete (allowed)' ' setup_srcdst_basic && ( cd dst && - git push --force-with-lease=master origin :master + git push --force-with-lease=master origin :master 2>err && + grep deleted err ) && >expect && git ls-remote src refs/heads/master >actual && diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh index a980574682..df8d2f095a 100755 --- a/t/t5537-fetch-shallow.sh +++ b/t/t5537-fetch-shallow.sh @@ -98,7 +98,7 @@ EOF test_expect_success 'fetch something upstream has but hidden by clients shallow boundaries' ' # the blob "1" is available in .git but hidden by the # shallow2/.git/shallow and it should be resent - ! git --git-dir=shallow2/.git cat-file blob `echo 1|git hash-object --stdin` >/dev/null && + ! git --git-dir=shallow2/.git cat-file blob $(echo 1|git hash-object --stdin) >/dev/null && echo 1 >1.t && git add 1.t && git commit -m add-1-back && @@ -114,7 +114,7 @@ add-1-back EOF test_cmp expect actual ) && - git --git-dir=shallow2/.git cat-file blob `echo 1|git hash-object --stdin` >/dev/null + git --git-dir=shallow2/.git cat-file blob $(echo 1|git hash-object --stdin) >/dev/null ' diff --git a/t/t5538-push-shallow.sh b/t/t5538-push-shallow.sh index ceee95b8a4..ecbf84d21c 100755 --- a/t/t5538-push-shallow.sh +++ b/t/t5538-push-shallow.sh @@ -104,7 +104,7 @@ EOF ' test_expect_success 'push from full to shallow' ' - ! git --git-dir=shallow2/.git cat-file blob `echo 1|git hash-object --stdin` && + ! git --git-dir=shallow2/.git cat-file blob $(echo 1|git hash-object --stdin) && commit 1 && git push shallow2/.git +master:refs/remotes/top/master && ( @@ -117,7 +117,7 @@ test_expect_success 'push from full to shallow' ' 3 EOF test_cmp expect actual && - git cat-file blob `echo 1|git hash-object --stdin` >/dev/null + git cat-file blob $(echo 1|git hash-object --stdin) >/dev/null ) ' test_done diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index 87a7aa04ae..64146352ae 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -132,7 +132,7 @@ test_expect_success 'fetch packed objects' ' test_expect_success 'fetch notices corrupt pack' ' cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git && (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git && - p=`ls objects/pack/pack-*.pack` && + p=$(ls objects/pack/pack-*.pack) && chmod u+w $p && printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc ) && @@ -140,14 +140,14 @@ test_expect_success 'fetch notices corrupt pack' ' (cd repo_bad1.git && git --bare init && test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad1.git && - test 0 = `ls objects/pack/pack-*.pack | wc -l` + test 0 = $(ls objects/pack/pack-*.pack | wc -l) ) ' test_expect_success 'fetch notices corrupt idx' ' cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git && (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git && - p=`ls objects/pack/pack-*.idx` && + p=$(ls objects/pack/pack-*.idx) && chmod u+w $p && printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc ) && @@ -155,7 +155,7 @@ test_expect_success 'fetch notices corrupt idx' ' (cd repo_bad2.git && git --bare init && test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad2.git && - test 0 = `ls objects/pack | wc -l` + test 0 = $(ls objects/pack | wc -l) ) ' diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh index b7e283252d..225a022e8a 100755 --- a/t/t5570-git-daemon.sh +++ b/t/t5570-git-daemon.sh @@ -6,6 +6,12 @@ test_description='test fetching over git protocol' . "$TEST_DIRECTORY"/lib-git-daemon.sh start_git_daemon +check_verbose_connect () { + grep -F "Looking up 127.0.0.1 ..." stderr && + grep -F "Connecting to 127.0.0.1 (port " stderr && + grep -F "done." stderr +} + test_expect_success 'setup repository' ' git config push.default matching && echo content >file && @@ -24,7 +30,8 @@ test_expect_success 'create git-accessible bare repository' ' ' test_expect_success 'clone git repository' ' - git clone "$GIT_DAEMON_URL/repo.git" clone && + git clone -v "$GIT_DAEMON_URL/repo.git" clone 2>stderr && + check_verbose_connect && test_cmp file clone/file ' @@ -32,10 +39,21 @@ test_expect_success 'fetch changes via git protocol' ' echo content >>file && git commit -a -m two && git push public && - (cd clone && git pull) && + (cd clone && git pull -v) 2>stderr && + check_verbose_connect && test_cmp file clone/file ' +test_expect_success 'no-op fetch -v stderr is as expected' ' + (cd clone && git fetch -v) 2>stderr && + check_verbose_connect +' + +test_expect_success 'no-op fetch without "-v" is quiet' ' + (cd clone && git fetch) 2>stderr && + ! test -s stderr +' + test_expect_success 'remote detects correct HEAD' ' git push public master:other && (cd clone && @@ -57,7 +75,7 @@ test_expect_success 'prepare pack objects' ' test_expect_success 'fetch notices corrupt pack' ' cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git && (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git && - p=`ls objects/pack/pack-*.pack` && + p=$(ls objects/pack/pack-*.pack) && chmod u+w $p && printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc ) && @@ -65,14 +83,14 @@ test_expect_success 'fetch notices corrupt pack' ' (cd repo_bad1.git && git --bare init && test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad1.git" && - test 0 = `ls objects/pack/pack-*.pack | wc -l` + test 0 = $(ls objects/pack/pack-*.pack | wc -l) ) ' test_expect_success 'fetch notices corrupt idx' ' cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git && (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git && - p=`ls objects/pack/pack-*.idx` && + p=$(ls objects/pack/pack-*.idx) && chmod u+w $p && printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc ) && @@ -80,7 +98,7 @@ test_expect_success 'fetch notices corrupt idx' ' (cd repo_bad2.git && git --bare init && test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad2.git" && - test 0 = `ls objects/pack | wc -l` + test 0 = $(ls objects/pack | wc -l) ) ' diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 9b34f3c615..c1efb8e445 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -4,6 +4,9 @@ test_description=clone . ./test-lib.sh +X= +test_have_prereq !MINGW || X=.exe + test_expect_success setup ' rm -fr .git && @@ -65,6 +68,29 @@ test_expect_success 'clone respects GIT_WORK_TREE' ' ' +test_expect_success 'clone from hooks' ' + + test_create_repo r0 && + cd r0 && + test_commit initial && + cd .. && + git init r1 && + cd r1 && + cat >.git/hooks/pre-commit <<-\EOF && + #!/bin/sh + git clone ../r0 ../r2 + exit 1 + EOF + chmod u+x .git/hooks/pre-commit && + : >file && + git add file && + test_must_fail git commit -m invoke-hook && + cd .. && + test_cmp r0/.git/HEAD r2/.git/HEAD && + test_cmp r0/initial.t r2/initial.t + +' + test_expect_success 'clone creates intermediate directories' ' git clone src long/path/to/dst && @@ -221,7 +247,7 @@ test_expect_success 'clone separate gitdir' ' ' test_expect_success 'clone separate gitdir: output' ' - echo "gitdir: `pwd`/realgitdir" >expected && + echo "gitdir: $(pwd)/realgitdir" >expected && test_cmp expected dst/.git ' @@ -282,14 +308,9 @@ test_expect_success 'clone checking out a tag' ' setup_ssh_wrapper () { test_expect_success 'setup ssh wrapper' ' - write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF && - echo >>"$TRASH_DIRECTORY/ssh-output" "ssh: $*" && - # throw away all but the last argument, which should be the - # command - while test $# -gt 1; do shift; done - eval "$1" - EOF - GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" && + cp "$GIT_BUILD_DIR/test-fake-ssh$X" \ + "$TRASH_DIRECTORY/ssh-wrapper$X" && + GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper$X" && export GIT_SSH && export TRASH_DIRECTORY && >"$TRASH_DIRECTORY"/ssh-output @@ -297,8 +318,8 @@ setup_ssh_wrapper () { } copy_ssh_wrapper_as () { - cp "$TRASH_DIRECTORY/ssh-wrapper" "$1" && - GIT_SSH="$1" && + cp "$TRASH_DIRECTORY/ssh-wrapper$X" "${1%$X}$X" && + GIT_SSH="${1%$X}$X" && export GIT_SSH } diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh index dfa1bf79c5..4320082b1b 100755 --- a/t/t5700-clone-reference.sh +++ b/t/t5700-clone-reference.sh @@ -6,7 +6,7 @@ test_description='test clone --reference' . ./test-lib.sh -base_dir=`pwd` +base_dir=$(pwd) U=$base_dir/UPLOAD_LOG diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh index 5a6e49d18d..9cd2626dba 100755 --- a/t/t5710-info-alternate.sh +++ b/t/t5710-info-alternate.sh @@ -21,7 +21,7 @@ test_valid_repo() { test_line_count = 0 fsck.log } -base_dir=`pwd` +base_dir=$(pwd) test_expect_success 'preparing first repository' \ 'test_create_repo A && cd A && diff --git a/t/t5900-repo-selection.sh b/t/t5900-repo-selection.sh index 3d5b418bb4..14e59c5b3e 100755 --- a/t/t5900-repo-selection.sh +++ b/t/t5900-repo-selection.sh @@ -15,7 +15,7 @@ make_tree() { make_bare() { git init --bare "$1" && (cd "$1" && - tree=`git hash-object -w -t tree /dev/null` && + tree=$(git hash-object -w -t tree /dev/null) && commit=$(echo "$1" | git commit-tree $tree) && git update-ref HEAD $commit ) diff --git a/t/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh index 8efcd13079..05ddc69cf2 100755 --- a/t/t6001-rev-list-graft.sh +++ b/t/t6001-rev-list-graft.sh @@ -10,15 +10,15 @@ test_expect_success setup ' echo >subdir/fileB fileB && git add fileA subdir/fileB && git commit -a -m "Initial in one history." && - A0=`git rev-parse --verify HEAD` && + A0=$(git rev-parse --verify HEAD) && echo >fileA fileA modified && git commit -a -m "Second in one history." && - A1=`git rev-parse --verify HEAD` && + A1=$(git rev-parse --verify HEAD) && echo >subdir/fileB fileB modified && git commit -a -m "Third in one history." && - A2=`git rev-parse --verify HEAD` && + A2=$(git rev-parse --verify HEAD) && rm -f .git/refs/heads/master .git/index && @@ -26,15 +26,15 @@ test_expect_success setup ' echo >subdir/fileB fileB again && git add fileA subdir/fileB && git commit -a -m "Initial in alternate history." && - B0=`git rev-parse --verify HEAD` && + B0=$(git rev-parse --verify HEAD) && echo >fileA fileA modified in alternate history && git commit -a -m "Second in alternate history." && - B1=`git rev-parse --verify HEAD` && + B1=$(git rev-parse --verify HEAD) && echo >subdir/fileB fileB modified in alternate history && git commit -a -m "Third in alternate history." && - B2=`git rev-parse --verify HEAD` && + B2=$(git rev-parse --verify HEAD) && : done ' diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh index 43ad772484..3bf2759eae 100755 --- a/t/t6002-rev-list-bisect.sh +++ b/t/t6002-rev-list-bisect.sh @@ -27,9 +27,9 @@ test_bisection_diff() # Test if bisection size is close to half of list size within # tolerance. # - _bisect_err=`expr $_list_size - $_bisection_size \* 2` - test "$_bisect_err" -lt 0 && _bisect_err=`expr 0 - $_bisect_err` - _bisect_err=`expr $_bisect_err / 2` ; # floor + _bisect_err=$(expr $_list_size - $_bisection_size \* 2) + test "$_bisect_err" -lt 0 && _bisect_err=$(expr 0 - $_bisect_err) + _bisect_err=$(expr $_bisect_err / 2) ; # floor test_expect_success \ "bisection diff $_bisect_option $_head $* <= $_max_diff" \ diff --git a/t/t6015-rev-list-show-all-parents.sh b/t/t6015-rev-list-show-all-parents.sh index 8b146fb432..3c73c93ba6 100755 --- a/t/t6015-rev-list-show-all-parents.sh +++ b/t/t6015-rev-list-show-all-parents.sh @@ -6,11 +6,11 @@ test_description='--show-all --parents does not rewrite TREESAME commits' test_expect_success 'set up --show-all --parents test' ' test_commit one foo.txt && - commit1=`git rev-list -1 HEAD` && + commit1=$(git rev-list -1 HEAD) && test_commit two bar.txt && - commit2=`git rev-list -1 HEAD` && + commit2=$(git rev-list -1 HEAD) && test_commit three foo.txt && - commit3=`git rev-list -1 HEAD` + commit3=$(git rev-list -1 HEAD) ' test_expect_success '--parents rewrites TREESAME parents correctly' ' diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh index 190ee903cf..20aee43f95 100755 --- a/t/t6023-merge-file.sh +++ b/t/t6023-merge-file.sh @@ -346,4 +346,17 @@ test_expect_success 'conflict at EOF without LF resolved by --union' \ printf "line1\nline2\nline3x\nline3y" >expect.txt && test_cmp expect.txt output.txt' +test_expect_success 'conflict sections match existing line endings' ' + printf "1\\r\\n2\\r\\n3" >crlf-orig.txt && + printf "1\\r\\n2\\r\\n4" >crlf-diff1.txt && + printf "1\\r\\n2\\r\\n5" >crlf-diff2.txt && + test_must_fail git -c core.eol=crlf merge-file -p \ + crlf-diff1.txt crlf-orig.txt crlf-diff2.txt >crlf.txt && + test $(tr "\015" Q <crlf.txt | grep "^[<=>].*Q$" | wc -l) = 3 && + test $(tr "\015" Q <crlf.txt | grep "[345]Q$" | wc -l) = 3 && + test_must_fail git -c core.eol=crlf merge-file -p \ + nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >nolf.txt && + test $(tr "\015" Q <nolf.txt | grep "^[<=>].*Q$" | wc -l) = 0 +' + test_done diff --git a/t/t6032-merge-large-rename.sh b/t/t6032-merge-large-rename.sh index 0f79268917..80777386dc 100755 --- a/t/t6032-merge-large-rename.sh +++ b/t/t6032-merge-large-rename.sh @@ -20,7 +20,7 @@ test_expect_success 'setup (initial)' ' make_text() { echo $1: $2 - for i in `count 20`; do + for i in $(count 20); do echo $1: $i done echo $1: $3 diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 4d5a25eedf..c630aba657 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -351,11 +351,15 @@ test_expect_success 'test --format long' ' test_cmp expected actual ' -test_expect_success 'setup a fake editor' ' - write_script fakeeditor <<-\EOF +test_expect_success 'setup fake editors' ' + write_script fakeeditor <<-\EOF && sed -e "s/A U Thor/A fake Thor/" "$1" >"$1.new" mv "$1.new" "$1" EOF + write_script failingfakeeditor <<-\EOF + ./fakeeditor "$@" + false + EOF ' test_expect_success '--edit with and without already replaced object' ' @@ -372,7 +376,7 @@ test_expect_success '--edit with and without already replaced object' ' test_expect_success '--edit and change nothing or command failed' ' git replace -d "$PARA3" && test_must_fail env GIT_EDITOR=true git replace --edit "$PARA3" && - test_must_fail env GIT_EDITOR="./fakeeditor;false" git replace --edit "$PARA3" && + test_must_fail env GIT_EDITOR="./failingfakeeditor" git replace --edit "$PARA3" && GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" && git replace -l | grep "$PARA3" && git cat-file commit "$PARA3" | grep "A fake Thor" diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh index e1e1b1fa38..d51595cf6b 100755 --- a/t/t6132-pathspec-exclude.sh +++ b/t/t6132-pathspec-exclude.sh @@ -7,7 +7,7 @@ test_description='test case exclude pathspec' test_expect_success 'setup' ' for p in file sub/file sub/sub/file sub/file2 sub/sub/sub/file sub2/file; do if echo $p | grep /; then - mkdir -p `dirname $p` + mkdir -p $(dirname $p) fi && : >$p && git add $p && diff --git a/t/t6133-pathspec-rev-dwim.sh b/t/t6133-pathspec-rev-dwim.sh new file mode 100755 index 0000000000..a290ffca0d --- /dev/null +++ b/t/t6133-pathspec-rev-dwim.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +test_description='test dwim of revs versus pathspecs in revision parser' +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit base && + echo content >"br[ack]ets" && + git add . && + test_tick && + git commit -m brackets +' + +test_expect_success 'non-rev wildcard dwims to pathspec' ' + git log -- "*.t" >expect && + git log "*.t" >actual && + test_cmp expect actual +' + +test_expect_success 'tree:path with metacharacters dwims to rev' ' + git show "HEAD:br[ack]ets" -- >expect && + git show "HEAD:br[ack]ets" >actual && + test_cmp expect actual +' + +test_expect_success '^{foo} with metacharacters dwims to rev' ' + git log "HEAD^{/b.*}" -- >expect && + git log "HEAD^{/b.*}" >actual && + test_cmp expect actual +' + +test_expect_success '@{foo} with metacharacters dwims to rev' ' + git log "HEAD@{now [or thereabouts]}" -- >expect && + git log "HEAD@{now [or thereabouts]}" >actual && + test_cmp expect actual +' + +test_expect_success ':/*.t from a subdir dwims to a pathspec' ' + mkdir subdir && + ( + cd subdir && + git log -- ":/*.t" >expect && + git log ":/*.t" >actual && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 03873b09d1..19a2823025 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -49,11 +49,17 @@ test_atom() { } test_atom head refname refs/heads/master +test_atom head refname:short master +test_atom head refname:strip=1 heads/master +test_atom head refname:strip=2 master test_atom head upstream refs/remotes/origin/master +test_atom head upstream:short origin/master test_atom head push refs/remotes/myfork/master +test_atom head push:short myfork/master test_atom head objecttype commit test_atom head objectsize 171 test_atom head objectname $(git rev-parse refs/heads/master) +test_atom head objectname:short $(git rev-parse --short refs/heads/master) test_atom head tree $(git rev-parse refs/heads/master^{tree}) test_atom head parent '' test_atom head numparent 0 @@ -86,11 +92,13 @@ test_atom head contents 'Initial test_atom head HEAD '*' test_atom tag refname refs/tags/testtag +test_atom tag refname:short testtag test_atom tag upstream '' test_atom tag push '' test_atom tag objecttype tag test_atom tag objectsize 154 test_atom tag objectname $(git rev-parse refs/tags/testtag) +test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag) test_atom tag tree '' test_atom tag parent '' test_atom tag numparent '' @@ -126,6 +134,16 @@ test_expect_success 'Check invalid atoms names are errors' ' test_must_fail git for-each-ref --format="%(INVALID)" refs/heads ' +test_expect_success 'arguments to :strip must be positive integers' ' + test_must_fail git for-each-ref --format="%(refname:strip=0)" && + test_must_fail git for-each-ref --format="%(refname:strip=-1)" && + test_must_fail git for-each-ref --format="%(refname:strip=foo)" +' + +test_expect_success 'stripping refnames too far gives an error' ' + test_must_fail git for-each-ref --format="%(refname:strip=3)" +' + test_expect_success 'Check format specifiers are ignored in naming date atoms' ' git for-each-ref --format="%(authordate)" refs/heads && git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads && @@ -338,47 +356,14 @@ for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do " done -cat >expected <<\EOF -master -testtag -EOF - -test_expect_success 'Check short refname format' ' - (git for-each-ref --format="%(refname:short)" refs/heads && - git for-each-ref --format="%(refname:short)" refs/tags) >actual && - test_cmp expected actual -' - -cat >expected <<EOF -origin/master -EOF - -test_expect_success 'Check short upstream format' ' - git for-each-ref --format="%(upstream:short)" refs/heads >actual && - test_cmp expected actual -' - test_expect_success 'setup for upstream:track[short]' ' test_commit two ' -cat >expected <<EOF -[ahead 1] -EOF - -test_expect_success 'Check upstream:track format' ' - git for-each-ref --format="%(upstream:track)" refs/heads >actual && - test_cmp expected actual -' - -cat >expected <<EOF -> -EOF - -test_expect_success 'Check upstream:trackshort format' ' - git for-each-ref --format="%(upstream:trackshort)" refs/heads >actual && - test_cmp expected actual -' +test_atom head upstream:track '[ahead 1]' +test_atom head upstream:trackshort '>' +test_atom head push:track '[ahead 1]' +test_atom head push:trackshort '>' test_expect_success 'Check that :track[short] cannot be used with other atoms' ' test_must_fail git for-each-ref --format="%(refname:track)" 2>/dev/null && @@ -398,21 +383,6 @@ test_expect_success 'Check that :track[short] works when upstream is invalid' ' test_cmp expected actual ' -test_expect_success '%(push) supports tracking specifiers, too' ' - echo "[ahead 1]" >expected && - git for-each-ref --format="%(push:track)" refs/heads >actual && - test_cmp expected actual -' - -cat >expected <<EOF -$(git rev-parse --short HEAD) -EOF - -test_expect_success 'Check short objectname format' ' - git for-each-ref --format="%(objectname:short)" refs/heads >actual && - test_cmp expected actual -' - test_expect_success 'Check for invalid refname format' ' test_must_fail git for-each-ref --format="%(refname:INVALID)" ' diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index fe4796cc9c..bcf472bf51 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -133,6 +133,48 @@ test_expect_success 'right alignment' ' test_cmp expect actual ' +cat >expect <<-\EOF +| refname is refs/heads/master |refs/heads/master +| refname is refs/heads/side |refs/heads/side +| refname is refs/odd/spot |refs/odd/spot +| refname is refs/tags/double-tag |refs/tags/double-tag +| refname is refs/tags/four |refs/tags/four +| refname is refs/tags/one |refs/tags/one +| refname is refs/tags/signed-tag |refs/tags/signed-tag +| refname is refs/tags/three |refs/tags/three +| refname is refs/tags/two |refs/tags/two +EOF + +test_align_permutations() { + while read -r option + do + test_expect_success "align:$option" ' + git for-each-ref --format="|%(align:$option)refname is %(refname)%(end)|%(refname)" >actual && + test_cmp expect actual + ' + done +} + +test_align_permutations <<-\EOF + middle,42 + 42,middle + position=middle,42 + 42,position=middle + middle,width=42 + width=42,middle + position=middle,width=42 + width=42,position=middle +EOF + +# Last one wins (silently) when multiple arguments of the same type are given + +test_align_permutations <<-\EOF + 32,width=42,middle + width=30,42,middle + width=42,position=right,middle + 42,right,position=middle +EOF + # Individual atoms inside %(align:...) and %(end) must not be quoted. test_expect_success 'alignment with format quote' " diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 7b56081137..51dd2b4e0e 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -156,11 +156,11 @@ test_expect_success "Michael Cassar's test case" ' echo b > partA/outline.txt && echo c > papers/unsorted/_another && git add papers partA && - T1=`git write-tree` && + T1=$(git write-tree) && git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf && - T=`git write-tree` && + T=$(git write-tree) && git ls-tree -r $T | verbose grep partA/outline.txt ' diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 869e0bf073..cb8fbd8e5e 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -333,6 +333,14 @@ test_expect_success 'prune empty collapsed merges' ' test_cmp expect actual ' +test_expect_success 'prune empty works even without index/tree filters' ' + git rev-list HEAD >expect && + git commit --allow-empty -m empty && + git filter-branch -f --prune-empty HEAD && + git rev-list HEAD >actual && + test_cmp expect actual +' + test_expect_success '--remap-to-ancestor with filename filters' ' git checkout master && git reset --hard A && @@ -387,7 +395,7 @@ test_expect_success 'setup submodule' ' git branch original HEAD ' -orig_head=`git show-ref --hash --head HEAD` +orig_head=$(git show-ref --hash --head HEAD) test_expect_success 'rewrite submodule with another content' ' git filter-branch --tree-filter "test -d submod && { @@ -396,7 +404,7 @@ test_expect_success 'rewrite submodule with another content' ' mkdir submod && : > submod/file } || :" HEAD && - test $orig_head != `git show-ref --hash --head HEAD` + test $orig_head != $(git show-ref --hash --head HEAD) ' test_expect_success 'replace submodule revision' ' @@ -405,7 +413,7 @@ test_expect_success 'replace submodule revision' ' "if git ls-files --error-unmatch -- submod > /dev/null 2>&1 then git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 submod fi" HEAD && - test $orig_head != `git show-ref --hash --head HEAD` + test $orig_head != $(git show-ref --hash --head HEAD) ' test_expect_success 'filter commit message without trailing newline' ' diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 3dd2f51e49..cf3469b142 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -23,8 +23,8 @@ test_expect_success 'listing all tags in an empty tree should succeed' ' ' test_expect_success 'listing all tags in an empty tree should output nothing' ' - test `git tag -l | wc -l` -eq 0 && - test `git tag | wc -l` -eq 0 + test $(git tag -l | wc -l) -eq 0 && + test $(git tag | wc -l) -eq 0 ' test_expect_success 'looking for a tag in an empty tree should fail' \ @@ -72,8 +72,8 @@ test_expect_success 'listing all tags if one exists should succeed' ' ' test_expect_success 'listing all tags if one exists should output that tag' ' - test `git tag -l` = mytag && - test `git tag` = mytag + test $(git tag -l) = mytag && + test $(git tag) = mytag ' # pattern matching: @@ -83,7 +83,7 @@ test_expect_success 'listing a tag using a matching pattern should succeed' \ test_expect_success \ 'listing a tag using a matching pattern should output that tag' \ - 'test `git tag -l mytag` = mytag' + 'test $(git tag -l mytag) = mytag' # todo: git tag -l now returns always zero, when fixed, change this test test_expect_success \ @@ -92,7 +92,7 @@ test_expect_success \ test_expect_success \ 'listing tags using a non-matching pattern should output nothing' \ - 'test `git tag -l xxx | wc -l` -eq 0' + 'test $(git tag -l xxx | wc -l) -eq 0' # special cases for creating tags: @@ -102,13 +102,13 @@ test_expect_success \ test_expect_success \ 'trying to create a tag with a non-valid name should fail' ' - test `git tag -l | wc -l` -eq 1 && + test $(git tag -l | wc -l) -eq 1 && test_must_fail git tag "" && test_must_fail git tag .othertag && test_must_fail git tag "other tag" && test_must_fail git tag "othertag^" && test_must_fail git tag "other~tag" && - test `git tag -l | wc -l` -eq 1 + test $(git tag -l | wc -l) -eq 1 ' test_expect_success 'creating a tag using HEAD directly should succeed' ' @@ -1558,4 +1558,12 @@ test_expect_success '--no-merged show unmerged tags' ' test_cmp expect actual ' +test_expect_success 'ambiguous branch/tags not marked' ' + git tag ambiguous && + git branch ambiguous && + echo ambiguous >expect && + git tag -l ambiguous >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index 6ea7ac4c41..e4fc5c826c 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -424,7 +424,7 @@ test_expect_success TTY 'command-specific pager works for external commands' ' echo "foo:initial" >expect && >actual && test_config pager.external "sed s/^/foo:/ >actual" && - test_terminal git --exec-path="`pwd`" external log --format=%s -1 && + test_terminal git --exec-path="$(pwd)" external log --format=%s -1 && test_cmp expect actual ' diff --git a/t/t7008-grep-binary.sh b/t/t7008-grep-binary.sh index b146406e9c..9c9c378119 100755 --- a/t/t7008-grep-binary.sh +++ b/t/t7008-grep-binary.sh @@ -141,7 +141,8 @@ test_expect_success 'grep respects not-binary diff attribute' ' test_cmp expect actual && echo "b diff" >.gitattributes && echo "b:binQary" >expect && - git grep bin b | nul_to_q >actual && + git grep bin b >actual.raw && + nul_to_q <actual.raw >actual && test_cmp expect actual ' diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh index 0e8d0d42f2..a971884cfd 100755 --- a/t/t7063-status-untracked-cache.sh +++ b/t/t7063-status-untracked-cache.sh @@ -8,10 +8,8 @@ avoid_racy() { sleep 1 } -# It's fine if git update-index returns an error code other than one, -# it'll be caught in the first test. test_lazy_prereq UNTRACKED_CACHE ' - { git update-index --untracked-cache; ret=$?; } && + { git update-index --test-untracked-cache; ret=$?; } && test $ret -ne 1 ' @@ -20,6 +18,10 @@ if ! test_have_prereq UNTRACKED_CACHE; then test_done fi +test_expect_success 'core.untrackedCache is unset' ' + test_must_fail git config --get core.untrackedCache +' + test_expect_success 'setup' ' git init worktree && cd worktree && @@ -32,13 +34,13 @@ test_expect_success 'setup' ' test_expect_success 'untracked cache is empty' ' test-dump-untracked-cache >../actual && - cat >../expect <<EOF && + cat >../expect-empty <<EOF && info/exclude 0000000000000000000000000000000000000000 core.excludesfile 0000000000000000000000000000000000000000 exclude_per_dir .gitignore flags 00000006 EOF - test_cmp ../expect ../actual + test_cmp ../expect-empty ../actual ' cat >../status.expect <<EOF && @@ -508,7 +510,7 @@ EOF test_expect_success 'verify untracked cache dump (sparse/subdirs)' ' test-dump-untracked-cache >../actual && - cat >../expect <<EOF && + cat >../expect-from-test-dump <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 exclude_per_dir .gitignore @@ -527,7 +529,7 @@ file /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid two EOF - test_cmp ../expect ../actual + test_cmp ../expect-from-test-dump ../actual ' test_expect_success 'test sparse status again with untracked cache and subdir' ' @@ -571,4 +573,77 @@ EOF test_cmp ../status.expect ../status.actual ' +test_expect_success '--no-untracked-cache removes the cache' ' + git update-index --no-untracked-cache && + test-dump-untracked-cache >../actual && + echo "no untracked cache" >../expect-no-uc && + test_cmp ../expect-no-uc ../actual +' + +test_expect_success 'git status does not change anything' ' + git status && + test-dump-untracked-cache >../actual && + test_cmp ../expect-no-uc ../actual +' + +test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' ' + git config core.untrackedCache true && + test-dump-untracked-cache >../actual && + test_cmp ../expect-no-uc ../actual && + git status && + test-dump-untracked-cache >../actual && + test_cmp ../expect-from-test-dump ../actual +' + +test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' ' + git update-index --no-untracked-cache && + test-dump-untracked-cache >../actual && + test_cmp ../expect-no-uc ../actual && + git update-index --untracked-cache && + test-dump-untracked-cache >../actual && + test_cmp ../expect-empty ../actual +' + +test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' ' + git config core.untrackedCache false && + test-dump-untracked-cache >../actual && + test_cmp ../expect-empty ../actual && + git status && + test-dump-untracked-cache >../actual && + test_cmp ../expect-no-uc ../actual +' + +test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' ' + git update-index --untracked-cache && + test-dump-untracked-cache >../actual && + test_cmp ../expect-empty ../actual +' + +test_expect_success 'setting core.untrackedCache to keep' ' + git config core.untrackedCache keep && + git update-index --untracked-cache && + test-dump-untracked-cache >../actual && + test_cmp ../expect-empty ../actual && + git status && + test-dump-untracked-cache >../actual && + test_cmp ../expect-from-test-dump ../actual && + git update-index --no-untracked-cache && + test-dump-untracked-cache >../actual && + test_cmp ../expect-no-uc ../actual && + git update-index --force-untracked-cache && + test-dump-untracked-cache >../actual && + test_cmp ../expect-empty ../actual && + git status && + test-dump-untracked-cache >../actual && + test_cmp ../expect-from-test-dump ../actual +' + +test_expect_success 'test ident field is working' ' + mkdir ../other_worktree && + cp -R done dthree dtwo four three ../other_worktree && + GIT_WORK_TREE=../other_worktree git status 2>../err && + echo "warning: Untracked cache is disabled on this system or location." >../expect && + test_cmp ../expect ../err +' + test_done diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh index 1eef93c2b2..afe36a533c 100755 --- a/t/t7103-reset-bare.sh +++ b/t/t7103-reset-bare.sh @@ -63,7 +63,7 @@ test_expect_success '"mixed" reset is not allowed in bare' ' test_expect_success '"soft" reset is allowed in bare' ' git reset --soft HEAD^ && - test "`git show --pretty=format:%s | head -n 1`" = "one" + test "$(git show --pretty=format:%s | head -n 1)" = "one" ' test_done diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 540771ca41..be82a75e54 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -999,5 +999,30 @@ test_expect_success 'submodule add clone shallow submodule' ' ) ' +test_expect_success 'submodule helper list is not confused by common prefixes' ' + mkdir -p dir1/b && + ( + cd dir1/b && + git init && + echo hi >testfile2 && + git add . && + git commit -m "test1" + ) && + mkdir -p dir2/b && + ( + cd dir2/b && + git init && + echo hello >testfile1 && + git add . && + git commit -m "test2" + ) && + git submodule add /dir1/b dir1/b && + git submodule add /dir2/b dir2/b && + git commit -m "first submodule commit" && + git submodule--helper list dir1/b |cut -c51- >actual && + echo "dir1/b" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index dda3929d99..68ea31d693 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -14,8 +14,8 @@ submodule and "git submodule update --rebase/--merge" does not detach the HEAD. compare_head() { - sha_master=`git rev-list --max-count=1 master` - sha_head=`git rev-list --max-count=1 HEAD` + sha_master=$(git rev-list --max-count=1 master) + sha_head=$(git rev-list --max-count=1 HEAD) test "$sha_master" = "$sha_head" } diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh index b770b2f04d..eaea19b8f2 100755 --- a/t/t7408-submodule-reference.sh +++ b/t/t7408-submodule-reference.sh @@ -6,7 +6,7 @@ test_description='test clone --reference' . ./test-lib.sh -base_dir=`pwd` +base_dir=$(pwd) U=$base_dir/UPLOAD_LOG diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-work-tree.sh index c20717181e..c20717181e 100755 --- a/t/t7409-submodule-detached-worktree.sh +++ b/t/t7409-submodule-detached-work-tree.sh diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh index 1f53ea8090..8728db61d3 100755 --- a/t/t7504-commit-msg-hook.sh +++ b/t/t7504-commit-msg-hook.sh @@ -179,7 +179,7 @@ EOF chmod +x "$HOOK" commit_msg_is () { - test "`git log --pretty=format:%s%b -1`" = "$1" + test "$(git log --pretty=format:%s%b -1)" = "$1" } test_expect_success 'hook edits commit message' ' diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh index 03dce09cfe..b13f72975e 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -53,7 +53,7 @@ test_expect_success 'with hook (-m)' ' echo "more" >> file && git add file && git commit -m "more" && - test "`git log -1 --pretty=format:%s`" = "message (no editor)" + test "$(git log -1 --pretty=format:%s)" = "message (no editor)" ' @@ -62,7 +62,7 @@ test_expect_success 'with hook (-m editor)' ' echo "more" >> file && git add file && GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -m "more more" && - test "`git log -1 --pretty=format:%s`" = message + test "$(git log -1 --pretty=format:%s)" = message ' @@ -71,7 +71,7 @@ test_expect_success 'with hook (-t)' ' echo "more" >> file && git add file && git commit -t "$(git rev-parse --git-dir)/template" && - test "`git log -1 --pretty=format:%s`" = template + test "$(git log -1 --pretty=format:%s)" = template ' @@ -80,7 +80,7 @@ test_expect_success 'with hook (-F)' ' echo "more" >> file && git add file && (echo more | git commit -F -) && - test "`git log -1 --pretty=format:%s`" = "message (no editor)" + test "$(git log -1 --pretty=format:%s)" = "message (no editor)" ' @@ -89,17 +89,17 @@ test_expect_success 'with hook (-F editor)' ' echo "more" >> file && git add file && (echo more more | GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -F -) && - test "`git log -1 --pretty=format:%s`" = message + test "$(git log -1 --pretty=format:%s)" = message ' test_expect_success 'with hook (-C)' ' - head=`git rev-parse HEAD` && + head=$(git rev-parse HEAD) && echo "more" >> file && git add file && git commit -C $head && - test "`git log -1 --pretty=format:%s`" = "$head (no editor)" + test "$(git log -1 --pretty=format:%s)" = "$head (no editor)" ' @@ -108,27 +108,27 @@ test_expect_success 'with hook (editor)' ' echo "more more" >> file && git add file && GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit && - test "`git log -1 --pretty=format:%s`" = default + test "$(git log -1 --pretty=format:%s)" = default ' test_expect_success 'with hook (--amend)' ' - head=`git rev-parse HEAD` && + head=$(git rev-parse HEAD) && echo "more" >> file && git add file && GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --amend && - test "`git log -1 --pretty=format:%s`" = "$head" + test "$(git log -1 --pretty=format:%s)" = "$head" ' test_expect_success 'with hook (-c)' ' - head=`git rev-parse HEAD` && + head=$(git rev-parse HEAD) && echo "more" >> file && git add file && GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head && - test "`git log -1 --pretty=format:%s`" = "$head" + test "$(git log -1 --pretty=format:%s)" = "$head" ' @@ -141,7 +141,7 @@ test_expect_success 'with hook (merge)' ' git commit -m other && git checkout - && git merge --no-ff other && - test "`git log -1 --pretty=format:%s`" = "merge (no editor)" + test "$(git log -1 --pretty=format:%s)" = "merge (no editor)" ' test_expect_success 'with hook and editor (merge)' ' @@ -153,7 +153,7 @@ test_expect_success 'with hook and editor (merge)' ' git commit -m other && git checkout - && env GIT_EDITOR="\"\$FAKE_EDITOR\"" git merge --no-ff -e other && - test "`git log -1 --pretty=format:%s`" = "merge" + test "$(git log -1 --pretty=format:%s)" = "merge" ' cat > "$HOOK" <<'EOF' @@ -164,7 +164,7 @@ EOF test_expect_success 'with failing hook' ' test_when_finished "git checkout -f master" && - head=`git rev-parse HEAD` && + head=$(git rev-parse HEAD) && echo "more" >> file && git add file && test_must_fail env GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head @@ -174,7 +174,7 @@ test_expect_success 'with failing hook' ' test_expect_success 'with failing hook (--no-verify)' ' test_when_finished "git checkout -f master" && - head=`git rev-parse HEAD` && + head=$(git rev-parse HEAD) && echo "more" >> file && git add file && test_must_fail env GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index 322c436a49..aee785cffa 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -326,6 +326,46 @@ test_expect_success 'with complex patch, args and --trim-empty' ' test_cmp expected actual ' +test_expect_success 'in-place editing with basic patch' ' + cat basic_message >message && + cat basic_patch >>message && + cat basic_message >expected && + echo >>expected && + cat basic_patch >>expected && + git interpret-trailers --in-place message && + test_cmp expected message +' + +test_expect_success 'in-place editing with additional trailer' ' + cat basic_message >message && + cat basic_patch >>message && + cat basic_message >expected && + echo >>expected && + cat >>expected <<-\EOF && + Reviewed-by: Alice + EOF + cat basic_patch >>expected && + git interpret-trailers --trailer "Reviewed-by: Alice" --in-place message && + test_cmp expected message +' + +test_expect_success 'in-place editing on stdin disallowed' ' + test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place < basic_message +' + +test_expect_success 'in-place editing on non-existing file' ' + test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place nonexisting && + test_path_is_missing nonexisting +' + +test_expect_success POSIXPERM,SANITY "in-place editing doesn't clobber original file on error" ' + cat basic_message >message && + chmod -r message && + test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place message && + chmod +r message && + test_cmp message basic_message +' + test_expect_success 'using "where = before"' ' git config trailer.bug.where "before" && cat complex_message_body >expected && diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh new file mode 100755 index 0000000000..337e6e30c3 --- /dev/null +++ b/t/t7517-per-repo-email.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# Copyright (c) 2016 Dan Aloni +# Copyright (c) 2016 Jeff King +# + +test_description='per-repo forced setting of email address' + +. ./test-lib.sh + +test_expect_success 'setup a likely user.useConfigOnly use case' ' + # we want to make sure a reflog is written, since that needs + # a non-strict ident. So be sure we have an actual commit. + test_commit foo && + + sane_unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL && + sane_unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL && + git config user.name "test" && + git config --global user.useConfigOnly true +' + +test_expect_success 'fails committing if clone email is not set' ' + test_must_fail git commit --allow-empty -m msg +' + +test_expect_success 'fails committing if clone email is not set, but EMAIL set' ' + test_must_fail env EMAIL=test@fail.com git commit --allow-empty -m msg +' + +test_expect_success 'succeeds committing if clone email is set' ' + test_config user.email "test@ok.com" && + git commit --allow-empty -m msg +' + +test_expect_success 'succeeds cloning if global email is not set' ' + git clone . clone +' + +test_done diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 955f09f8e8..6abe441ae3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -19,7 +19,7 @@ test_expect_success 'setup' ' git add c$i.c && git commit -m c$i && git tag c$i && - i=`expr $i + 1` || return 1 + i=$(expr $i + 1) || return 1 done ' @@ -30,7 +30,7 @@ test_expect_success 'merge c1 with c2, c3, c4, ... c29' ' while test $i -le 30 do refs="$refs c$i" - i=`expr $i + 1` + i=$(expr $i + 1) done && git merge $refs && test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" && @@ -38,14 +38,14 @@ test_expect_success 'merge c1 with c2, c3, c4, ... c29' ' while test $i -le 30 do test "$(git rev-parse c$i)" = "$(git rev-parse HEAD^$i)" && - i=`expr $i + 1` || return 1 + i=$(expr $i + 1) || return 1 done && git diff --exit-code && i=1 && while test $i -le 30 do test -f c$i.c && - i=`expr $i + 1` || return 1 + i=$(expr $i + 1) || return 1 done ' diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 021c5479bd..6061a04147 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -69,7 +69,7 @@ test_expect_success 'writing bitmaps via config can duplicate .keep objects' ' test_expect_success 'loose objects in alternate ODB are not repacked' ' mkdir alt_objects && - echo `pwd`/alt_objects > .git/objects/info/alternates && + echo $(pwd)/alt_objects > .git/objects/info/alternates && echo content3 > file3 && objsha1=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) && git add file3 && @@ -168,7 +168,7 @@ test_expect_success 'packed unreachable obs in alternate ODB are not loosened' ' ' test_expect_success 'local packed unreachable obs that exist in alternate ODB are not loosened' ' - echo `pwd`/alt_objects > .git/objects/info/alternates && + echo $(pwd)/alt_objects > .git/objects/info/alternates && echo "$csha1" | git pack-objects --non-empty --all --reflog pack && rm -f .git/objects/pack/* && mv pack-* .git/objects/pack/ && diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index ec8bc8c765..4e713f7aa5 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -430,11 +430,11 @@ EOF test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' ' cat >expect <<-EOF && file - $(pwd)/file + $PWD/file file2 - $(pwd)/file2 + $PWD/file2 sub/sub - $(pwd)/sub/sub + $PWD/sub/sub EOF git difftool --dir-diff --symlink \ --extcmd "./.git/CHECK_SYMLINKS" branch HEAD && @@ -448,14 +448,14 @@ EOF run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' ' test_when_finished git reset --hard && echo "orig content" >file && - git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch && + git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch && echo "new content" >expect && test_cmp expect file ' run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' ' test_when_finished git reset --hard && - git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch && + git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch && echo "new content" >expect && test_cmp expect file ' @@ -466,7 +466,7 @@ EOF test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' ' echo "orig content" >file && - git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-file" branch && + git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-file" branch && echo "new content" >expect && test_cmp expect file ' @@ -482,7 +482,7 @@ test_expect_success PERL 'difftool --no-symlinks detects conflict ' ' TMPDIR=$TRASH_DIRECTORY && export TMPDIR && echo "orig content" >file && - test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-both-files" branch && + test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-both-files" branch && echo "wt content" >expect && test_cmp expect file && echo "tmp content" >expect && diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 028ffe4a05..b540944408 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -791,12 +791,12 @@ test_expect_success 'outside of git repository' ' } >non/expect.full && echo file2:world >non/expect.sub && ( - GIT_CEILING_DIRECTORIES="$(pwd)/non/git" && + GIT_CEILING_DIRECTORIES="$(pwd)/non" && export GIT_CEILING_DIRECTORIES && cd non/git && test_must_fail git grep o && git grep --no-index o >../actual.full && - test_cmp ../expect.full ../actual.full + test_cmp ../expect.full ../actual.full && cd sub && test_must_fail git grep o && git grep --no-index o >../../actual.sub && @@ -805,7 +805,7 @@ test_expect_success 'outside of git repository' ' echo ".*o*" >non/git/.gitignore && ( - GIT_CEILING_DIRECTORIES="$(pwd)/non/git" && + GIT_CEILING_DIRECTORIES="$(pwd)/non" && export GIT_CEILING_DIRECTORIES && cd non/git && test_must_fail git grep o && @@ -813,7 +813,7 @@ test_expect_success 'outside of git repository' ' test_cmp ../expect.full ../actual.full && { - echo ".gitignore:.*o*" + echo ".gitignore:.*o*" && cat ../expect.full } >../expect.with.ignored && git grep --no-index --no-exclude o >../actual.full && @@ -821,6 +821,47 @@ test_expect_success 'outside of git repository' ' ) ' +test_expect_success 'outside of git repository with fallbackToNoIndex' ' + rm -fr non && + mkdir -p non/git/sub && + echo hello >non/git/file1 && + echo world >non/git/sub/file2 && + cat <<-\EOF >non/expect.full && + file1:hello + sub/file2:world + EOF + echo file2:world >non/expect.sub && + ( + GIT_CEILING_DIRECTORIES="$(pwd)/non" && + export GIT_CEILING_DIRECTORIES && + cd non/git && + test_must_fail git -c grep.fallbackToNoIndex=false grep o && + git -c grep.fallbackToNoIndex=true grep o >../actual.full && + test_cmp ../expect.full ../actual.full && + cd sub && + test_must_fail git -c grep.fallbackToNoIndex=false grep o && + git -c grep.fallbackToNoIndex=true grep o >../../actual.sub && + test_cmp ../../expect.sub ../../actual.sub + ) && + + echo ".*o*" >non/git/.gitignore && + ( + GIT_CEILING_DIRECTORIES="$(pwd)/non" && + export GIT_CEILING_DIRECTORIES && + cd non/git && + test_must_fail git -c grep.fallbackToNoIndex=false grep o && + git -c grep.fallbackToNoIndex=true grep --exclude-standard o >../actual.full && + test_cmp ../expect.full ../actual.full && + + { + echo ".gitignore:.*o*" && + cat ../expect.full + } >../expect.with.ignored && + git -c grep.fallbackToNoIndex grep --no-exclude o >../actual.full && + test_cmp ../expect.with.ignored ../actual.full + ) +' + test_expect_success 'inside git repository but with --no-index' ' rm -fr is && mkdir -p is/git/sub && diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index 16f1442c1e..6568429753 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -153,7 +153,7 @@ test_expect_success 'blame path that used to be a directory' ' ' test_expect_success 'blame to a commit with no author name' ' - TREE=`git rev-parse HEAD:` && + TREE=$(git rev-parse HEAD:) && cat >badcommit <<EOF && tree $TREE author <noname> 1234567890 +0000 @@ -161,7 +161,7 @@ committer David Reiss <dreiss@facebook.com> 1234567890 +0000 some message EOF - COMMIT=`git hash-object -t commit -w badcommit` && + COMMIT=$(git hash-object -t commit -w badcommit) && git --no-pager blame $COMMIT -- uno >/dev/null ' diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh index 847d098c09..75da219ed1 100755 --- a/t/t8005-blame-i18n.sh +++ b/t/t8005-blame-i18n.sh @@ -33,11 +33,15 @@ author $SJIS_NAME summary $SJIS_MSG EOF +filter_author_summary () { + sed -n -e '/^author /p' -e '/^summary /p' "$@" +} + test_expect_success !MINGW \ 'blame respects i18n.commitencoding' ' - git blame --incremental file | \ - egrep "^(author|summary) " > actual && - test_cmp actual expected + git blame --incremental file >output && + filter_author_summary output >actual && + test_cmp expected actual ' cat >expected <<EOF @@ -52,9 +56,9 @@ EOF test_expect_success !MINGW \ 'blame respects i18n.logoutputencoding' ' git config i18n.logoutputencoding eucJP && - git blame --incremental file | \ - egrep "^(author|summary) " > actual && - test_cmp actual expected + git blame --incremental file >output && + filter_author_summary output >actual && + test_cmp expected actual ' cat >expected <<EOF @@ -68,9 +72,9 @@ EOF test_expect_success !MINGW \ 'blame respects --encoding=UTF-8' ' - git blame --incremental --encoding=UTF-8 file | \ - egrep "^(author|summary) " > actual && - test_cmp actual expected + git blame --incremental --encoding=UTF-8 file >output && + filter_author_summary output >actual && + test_cmp expected actual ' cat >expected <<EOF @@ -84,9 +88,9 @@ EOF test_expect_success !MINGW \ 'blame respects --encoding=none' ' - git blame --incremental --encoding=none file | \ - egrep "^(author|summary) " > actual && - test_cmp actual expected + git blame --incremental --encoding=none file >output && + filter_author_summary output >actual && + test_cmp expected actual ' test_done diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 3c49536e0e..b3355d2c70 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -36,7 +36,7 @@ clean_fake_sendmail () { } test_expect_success $PREREQ 'Extract patches' ' - patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1` + patches=$(git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1) ' # Test no confirm early to ensure remaining tests will not hang @@ -1151,7 +1151,7 @@ test_expect_success $PREREQ '--no-bcc overrides sendemail.bcc' ' ' test_expect_success $PREREQ 'patches To headers are used by default' ' - patch=`git format-patch -1 --to="bodies@example.com"` && + patch=$(git format-patch -1 --to="bodies@example.com") && test_when_finished "rm $patch" && git send-email \ --dry-run \ @@ -1162,7 +1162,7 @@ test_expect_success $PREREQ 'patches To headers are used by default' ' ' test_expect_success $PREREQ 'patches To headers are appended to' ' - patch=`git format-patch -1 --to="bodies@example.com"` && + patch=$(git format-patch -1 --to="bodies@example.com") && test_when_finished "rm $patch" && git send-email \ --dry-run \ @@ -1175,8 +1175,8 @@ test_expect_success $PREREQ 'patches To headers are appended to' ' ' test_expect_success $PREREQ 'To headers from files reset each patch' ' - patch1=`git format-patch -1 --to="bodies@example.com"` && - patch2=`git format-patch -1 --to="other@example.com" HEAD~` && + patch1=$(git format-patch -1 --to="bodies@example.com") && + patch2=$(git format-patch -1 --to="other@example.com" HEAD~) && test_when_finished "rm $patch1 && rm $patch2" && git send-email \ --dry-run \ @@ -1488,7 +1488,7 @@ test_cover_addresses () { clean_fake_sendmail && rm -fr outdir && git format-patch --cover-letter -2 -o outdir && - cover=`echo outdir/0000-*.patch` && + cover=$(echo outdir/0000-*.patch) && mv $cover cover-to-edit.patch && perl -pe "s/^From:/$header: extra\@address.com\nFrom:/" cover-to-edit.patch >"$cover" && git send-email \ @@ -1527,6 +1527,21 @@ test_expect_success $PREREQ 'cccover adds Cc to all mail' ' test_cover_addresses "Cc" ' +test_expect_success $PREREQ 'escaped quotes in sendemail.aliasfiletype=mutt' ' + clean_fake_sendmail && + echo "alias sbd \\\"Dot U. Sir\\\" <somebody@example.org>" >.mutt && + git config --replace-all sendemail.aliasesfile "$(pwd)/.mutt" && + git config sendemail.aliasfiletype mutt && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=sbd \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && + grep "^!somebody@example\.org!$" commandline1 && + grep -F "To: \"Dot U. Sir\" <somebody@example.org>" out +' + test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' ' clean_fake_sendmail && echo "alias sbd somebody@example.org" >.mailrc && diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh new file mode 100755 index 0000000000..dfe95c923b --- /dev/null +++ b/t/t9003-help-autocorrect.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +test_description='help.autocorrect finding a match' +. ./test-lib.sh + +test_expect_success 'setup' ' + # An alias + git config alias.lgf "log --format=%s --first-parent" && + + # A random user-defined command + write_script git-distimdistim <<-EOF && + echo distimdistim was called + EOF + + PATH="$PATH:." && + export PATH && + + git commit --allow-empty -m "a single log entry" && + + # Sanity check + git lgf >actual && + echo "a single log entry" >expect && + test_cmp expect actual && + + git distimdistim >actual && + echo "distimdistim was called" >expect && + test_cmp expect actual +' + +test_expect_success 'autocorrect showing candidates' ' + git config help.autocorrect 0 && + + test_must_fail git lfg 2>actual && + sed -e "1,/^Did you mean this/d" actual | grep lgf && + + test_must_fail git distimdist 2>actual && + sed -e "1,/^Did you mean this/d" actual | grep distimdistim +' + +test_expect_success 'autocorrect running commands' ' + git config help.autocorrect -1 && + + git lfg >actual && + echo "a single log entry" >expect && + test_cmp expect actual && + + git distimdist >actual && + echo "distimdistim was called" >expect && + test_cmp expect actual +' + +test_done diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index 4fea8d901b..22d8367ff3 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -117,7 +117,7 @@ test_expect_success "$name" ' name='remove executable bit from a file' -test_expect_success "$name" ' +test_expect_success POSIXPERM "$name" ' rm -f "$GIT_DIR"/index && git checkout -f -b mybranch5 ${remotes_git_svn} && chmod -x exec.sh && @@ -130,7 +130,7 @@ test_expect_success "$name" ' name='add executable bit back file' -test_expect_success "$name" ' +test_expect_success POSIXPERM "$name" ' chmod +x exec.sh && git update-index exec.sh && git commit -m "$name" && @@ -141,7 +141,7 @@ test_expect_success "$name" ' name='executable file becomes a symlink to file' -test_expect_success "$name" ' +test_expect_success SYMLINKS "$name" ' rm exec.sh && ln -s file exec.sh && git update-index exec.sh && @@ -153,7 +153,7 @@ test_expect_success "$name" ' name='new symlink is added to a file that was also just made executable' -test_expect_success "$name" ' +test_expect_success POSIXPERM,SYMLINKS "$name" ' chmod +x file && ln -s file exec-2.sh && git update-index --add file exec-2.sh && @@ -165,7 +165,7 @@ test_expect_success "$name" ' test -h "$SVN_TREE"/exec-2.sh' name='modify a symlink to become a file' -test_expect_success "$name" ' +test_expect_success POSIXPERM,SYMLINKS "$name" ' echo git help >help && rm exec-2.sh && cp help exec-2.sh && @@ -181,7 +181,8 @@ test_expect_success "$name" ' name="commit with UTF-8 message: locale: $GIT_SVN_LC_ALL" LC_ALL="$GIT_SVN_LC_ALL" export LC_ALL -test_expect_success UTF8 "$name" " +# This test relies on the previous test, hence requires POSIXPERM,SYMLINKS +test_expect_success UTF8,POSIXPERM,SYMLINKS "$name" " echo '# hello' >> exec-2.sh && git update-index exec-2.sh && git commit -m 'éï∏' && @@ -214,7 +215,7 @@ tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4 EOF -test_expect_success "$name" "test_cmp a expected" +test_expect_success POSIXPERM,SYMLINKS "$name" "test_cmp a expected" test_expect_success 'exit if remote refs are ambigious' " git config --add svn-remote.svn.fetch \ @@ -265,18 +266,18 @@ test_expect_success 'able to dcommit to a subdirectory' " git update-index --add d && git commit -m '/bar/d should be in the log' && git svn dcommit -i bar && - test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" && + test -z \"\$(git diff refs/heads/my-bar refs/remotes/bar)\" && mkdir newdir && echo new > newdir/dir && git update-index --add newdir/dir && git commit -m 'add a new directory' && git svn dcommit -i bar && - test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" && + test -z \"\$(git diff refs/heads/my-bar refs/remotes/bar)\" && echo foo >> newdir/dir && git update-index newdir/dir && git commit -m 'modify a file in new directory' && git svn dcommit -i bar && - test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" + test -z \"\$(git diff refs/heads/my-bar refs/remotes/bar)\" " test_expect_success 'dcommit should not fail with a touched file' ' @@ -295,7 +296,7 @@ test_expect_success 'able to set-tree to a subdirectory' " git update-index d && git commit -m 'update /bar/d' && git svn set-tree -i bar HEAD && - test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" + test -z \"\$(git diff refs/heads/my-bar refs/remotes/bar)\" " test_expect_success 'git-svn works in a bare repository' ' diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh index 8869f5018e..e8173d5fef 100755 --- a/t/t9101-git-svn-props.sh +++ b/t/t9101-git-svn-props.sh @@ -26,27 +26,27 @@ cd import EOF printf "Hello\r\nWorld\r\n" > crlf - a_crlf=`git hash-object -w crlf` + a_crlf=$(git hash-object -w crlf) printf "Hello\rWorld\r" > cr - a_cr=`git hash-object -w cr` + a_cr=$(git hash-object -w cr) printf "Hello\nWorld\n" > lf - a_lf=`git hash-object -w lf` + a_lf=$(git hash-object -w lf) printf "Hello\r\nWorld" > ne_crlf - a_ne_crlf=`git hash-object -w ne_crlf` + a_ne_crlf=$(git hash-object -w ne_crlf) printf "Hello\nWorld" > ne_lf - a_ne_lf=`git hash-object -w ne_lf` + a_ne_lf=$(git hash-object -w ne_lf) printf "Hello\rWorld" > ne_cr - a_ne_cr=`git hash-object -w ne_cr` + a_ne_cr=$(git hash-object -w ne_cr) touch empty - a_empty=`git hash-object -w empty` + a_empty=$(git hash-object -w empty) printf "\n" > empty_lf - a_empty_lf=`git hash-object -w empty_lf` + a_empty_lf=$(git hash-object -w empty_lf) printf "\r" > empty_cr - a_empty_cr=`git hash-object -w empty_cr` + a_empty_cr=$(git hash-object -w empty_cr) printf "\r\n" > empty_crlf - a_empty_crlf=`git hash-object -w empty_crlf` + a_empty_crlf=$(git hash-object -w empty_crlf) svn_cmd import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null cd .. @@ -80,7 +80,7 @@ test_expect_success "$name" \ git pull . ${remotes_git_svn}' expect='/* $Id$ */' -got="`sed -ne 2p kw.c`" +got="$(sed -ne 2p kw.c)" test_expect_success 'raw $Id$ found in kw.c' "test '$expect' = '$got'" test_expect_success "propset CR on crlf files" ' @@ -107,8 +107,8 @@ done cd test_wc printf '$Id$\rHello\rWorld\r' > cr printf '$Id$\rHello\rWorld' > ne_cr - a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git hash-object --stdin` - a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git hash-object --stdin` + a_cr=$(printf '$Id$\r\nHello\r\nWorld\r\n' | git hash-object --stdin) + a_ne_cr=$(printf '$Id$\r\nHello\r\nWorld' | git hash-object --stdin) test_expect_success 'Set CRLF on cr files' \ 'svn_cmd propset svn:eol-style CRLF cr && svn_cmd propset svn:eol-style CRLF ne_cr && @@ -119,8 +119,8 @@ cd .. test_expect_success 'fetch and pull latest from svn' \ 'git svn fetch && git pull . ${remotes_git_svn}' -b_cr="`git hash-object cr`" -b_ne_cr="`git hash-object ne_cr`" +b_cr="$(git hash-object cr)" +b_ne_cr="$(git hash-object ne_cr)" test_expect_success 'CRLF + $Id$' "test '$a_cr' = '$b_cr'" test_expect_success 'CRLF + $Id$ (no newline)' "test '$a_ne_cr' = '$b_ne_cr'" diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh index 83f17e13e8..cd480edf16 100755 --- a/t/t9104-git-svn-follow-parent.sh +++ b/t/t9104-git-svn-follow-parent.sh @@ -31,12 +31,12 @@ test_expect_success 'initialize repo' ' test_expect_success 'init and fetch a moved directory' ' git svn init --minimize-url -i thunk "$svnrepo"/thunk && git svn fetch -i thunk && - test "`git rev-parse --verify refs/remotes/thunk@2`" \ - = "`git rev-parse --verify refs/remotes/thunk~1`" && - test "`git cat-file blob refs/remotes/thunk:readme |\ - sed -n -e "3p"`" = goodbye && - test -z "`git config --get svn-remote.svn.fetch \ - "^trunk:refs/remotes/thunk@2$"`" + test "$(git rev-parse --verify refs/remotes/thunk@2)" \ + = "$(git rev-parse --verify refs/remotes/thunk~1)" && + test "$(git cat-file blob refs/remotes/thunk:readme |\ + sed -n -e "3p")" = goodbye && + test -z "$(git config --get svn-remote.svn.fetch \ + "^trunk:refs/remotes/thunk@2$")" ' test_expect_success 'init and fetch from one svn-remote' ' @@ -46,10 +46,10 @@ test_expect_success 'init and fetch from one svn-remote' ' git config --add svn-remote.svn.fetch \ thunk:refs/remotes/svn/thunk && git svn fetch -i svn/thunk && - test "`git rev-parse --verify refs/remotes/svn/trunk`" \ - = "`git rev-parse --verify refs/remotes/svn/thunk~1`" && - test "`git cat-file blob refs/remotes/svn/thunk:readme |\ - sed -n -e "3p"`" = goodbye + test "$(git rev-parse --verify refs/remotes/svn/trunk)" \ + = "$(git rev-parse --verify refs/remotes/svn/thunk~1)" && + test "$(git cat-file blob refs/remotes/svn/thunk:readme |\ + sed -n -e "3p")" = goodbye ' test_expect_success 'follow deleted parent' ' @@ -61,9 +61,9 @@ test_expect_success 'follow deleted parent' ' junk:refs/remotes/svn/junk && git svn fetch -i svn/thunk && git svn fetch -i svn/junk && - test -z "`git diff svn/junk svn/trunk`" && - test "`git merge-base svn/junk svn/trunk`" \ - = "`git rev-parse svn/trunk`" + test -z "$(git diff svn/junk svn/trunk)" && + test "$(git merge-base svn/junk svn/trunk)" \ + = "$(git rev-parse svn/trunk)" ' test_expect_success 'follow larger parent' ' @@ -80,10 +80,10 @@ test_expect_success 'follow larger parent' ' git rev-parse --verify refs/remotes/larger && git rev-parse --verify \ refs/remotes/larger-parent && - test "`git merge-base \ + test "$(git merge-base \ refs/remotes/larger-parent \ - refs/remotes/larger`" = \ - "`git rev-parse refs/remotes/larger`" + refs/remotes/larger)" = \ + "$(git rev-parse refs/remotes/larger)" ' test_expect_success 'follow higher-level parent' ' @@ -106,8 +106,8 @@ test_expect_success 'follow deleted directory' ' svn_cmd rm -m "remove glob" "$svnrepo"/glob && git svn init --minimize-url -i glob "$svnrepo"/glob && git svn fetch -i glob && - test "`git cat-file blob refs/remotes/glob:blob/bye`" = hi && - test "`git ls-tree refs/remotes/glob | wc -l `" -eq 1 + test "$(git cat-file blob refs/remotes/glob:blob/bye)" = hi && + test "$(git ls-tree refs/remotes/glob | wc -l )" -eq 1 ' # ref: r9270 of the Subversion repository: (http://svn.collab.net/repos/svn) @@ -142,9 +142,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' ' git svn init --minimize-url -i r9270-t \ "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl/native/t && git svn fetch -i r9270-t && - test `git rev-list r9270-t | wc -l` -eq 2 && - test "`git ls-tree --name-only r9270-t~1`" = \ - "`git ls-tree --name-only r9270-t`" + test $(git rev-list r9270-t | wc -l) -eq 2 && + test "$(git ls-tree --name-only r9270-t~1)" = \ + "$(git ls-tree --name-only r9270-t)" ' test_expect_success "track initial change if it was only made to parent" ' @@ -152,11 +152,11 @@ test_expect_success "track initial change if it was only made to parent" ' git svn init --minimize-url -i r9270-d \ "$svnrepo"/r9270/drunk/subversion/bindings/swig/perl/native/t && git svn fetch -i r9270-d && - test `git rev-list r9270-d | wc -l` -eq 3 && - test "`git ls-tree --name-only r9270-t`" = \ - "`git ls-tree --name-only r9270-d`" && - test "`git rev-parse r9270-t`" = \ - "`git rev-parse r9270-d~1`" + test $(git rev-list r9270-d | wc -l) -eq 3 && + test "$(git ls-tree --name-only r9270-t)" = \ + "$(git ls-tree --name-only r9270-d)" && + test "$(git rev-parse r9270-t)" = \ + "$(git rev-parse r9270-d~1)" ' test_expect_success "follow-parent is atomic" ' @@ -193,19 +193,19 @@ test_expect_success "follow-parent is atomic" ' git svn fetch -i stunk && git svn init --minimize-url -i flunked "$svnrepo"/flunked && git svn fetch -i flunked && - test "`git rev-parse --verify refs/remotes/flunk@18`" \ - = "`git rev-parse --verify refs/remotes/stunk`" && - test "`git rev-parse --verify refs/remotes/flunk~1`" \ - = "`git rev-parse --verify refs/remotes/stunk`" && - test "`git rev-parse --verify refs/remotes/flunked~1`" \ - = "`git rev-parse --verify refs/remotes/stunk~1`" + test "$(git rev-parse --verify refs/remotes/flunk@18)" \ + = "$(git rev-parse --verify refs/remotes/stunk)" && + test "$(git rev-parse --verify refs/remotes/flunk~1)" \ + = "$(git rev-parse --verify refs/remotes/stunk)" && + test "$(git rev-parse --verify refs/remotes/flunked~1)" \ + = "$(git rev-parse --verify refs/remotes/stunk~1)" ' test_expect_success "track multi-parent paths" ' svn_cmd cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob && git svn multi-fetch && - test `git cat-file commit refs/remotes/glob | \ - grep "^parent " | wc -l` -eq 2 + test $(git cat-file commit refs/remotes/glob | \ + grep "^parent " | wc -l) -eq 2 ' test_expect_success "multi-fetch continues to work" " diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh index 5d0afeae6c..6ed5f74e25 100755 --- a/t/t9105-git-svn-commit-diff.sh +++ b/t/t9105-git-svn-commit-diff.sh @@ -18,8 +18,8 @@ test_expect_success 'initialize repo' ' git commit -a -m "another" ' -head=`git rev-parse --verify HEAD^0` -prev=`git rev-parse --verify HEAD^1` +head=$(git rev-parse --verify HEAD^0) +prev=$(git rev-parse --verify HEAD^1) # the internals of the commit-diff command are the same as the regular # commit, so only a basic test of functionality is needed since we've diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index 6e69fc4c65..9060198037 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -24,10 +24,10 @@ test_expect_success 'setup old-looking metadata' ' git update-ref -d refs/${remotes_git_svn} refs/${remotes_git_svn} ' -head=`git rev-parse --verify refs/heads/git-svn-HEAD^0` +head=$(git rev-parse --verify refs/heads/git-svn-HEAD^0) test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'" -svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'` +svnrepo_escaped=$(echo $svnrepo | sed 's/ /%20/') test_expect_success 'initialize old-style (v0) git svn layout' ' mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info && @@ -38,7 +38,7 @@ test_expect_success 'initialize old-style (v0) git svn layout' ' git rev-parse --verify refs/${remotes_git_svn}^0 && git rev-parse --verify refs/remotes/svn^0 && test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" && - test `git config --get svn-remote.svn.fetch` = \ + test $(git config --get svn-remote.svn.fetch) = \ ":refs/${remotes_git_svn}" ' @@ -46,10 +46,10 @@ test_expect_success 'initialize a multi-repository repo' ' git svn init "$svnrepo" -T trunk -t tags -b branches && git config --get-all svn-remote.svn.fetch > fetch.out && grep "^trunk:refs/remotes/origin/trunk$" fetch.out && - test -n "`git config --get svn-remote.svn.branches \ - "^branches/\*:refs/remotes/origin/\*$"`" && - test -n "`git config --get svn-remote.svn.tags \ - "^tags/\*:refs/remotes/origin/tags/\*$"`" && + test -n "$(git config --get svn-remote.svn.branches \ + "^branches/\*:refs/remotes/origin/\*$")" && + test -n "$(git config --get svn-remote.svn.tags \ + "^tags/\*:refs/remotes/origin/tags/\*$")" && git config --unset svn-remote.svn.branches \ "^branches/\*:refs/remotes/origin/\*$" && git config --unset svn-remote.svn.tags \ @@ -75,28 +75,28 @@ test_expect_success 'multi-fetch works on partial urls + paths' " for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do git rev-parse --verify refs/remotes/origin/\$i^0 >> refs.out || exit 1; done && - test -z \"\`sort < refs.out | uniq -d\`\" && + test -z \"\$(sort < refs.out | uniq -d)\" && for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do for j in trunk a b tags/0.1 tags/0.2 tags/0.3; do if test \$j != \$i; then continue; fi - test -z \"\`git diff refs/remotes/origin/\$i \ - refs/remotes/origin/\$j\`\" ||exit 1; done; done + test -z \"\$(git diff refs/remotes/origin/\$i \ + refs/remotes/origin/\$j)\" ||exit 1; done; done " test_expect_success 'migrate --minimize on old inited layout' ' git config --unset-all svn-remote.svn.fetch && git config --unset-all svn-remote.svn.url && rm -rf "$GIT_DIR"/svn && - for i in `cat fetch.out`; do - path=`expr $i : "\([^:]*\):.*$"` - ref=`expr $i : "[^:]*:\(refs/remotes/.*\)$"` + for i in $(cat fetch.out); do + path=$(expr $i : "\([^:]*\):.*$") + ref=$(expr $i : "[^:]*:\(refs/remotes/.*\)$") if test -z "$ref"; then continue; fi if test -n "$path"; then path="/$path"; fi ( mkdir -p "$GIT_DIR"/svn/$ref/info/ && echo "$svnrepo"$path > "$GIT_DIR"/svn/$ref/info/url ) || exit 1; done && git svn migrate --minimize && - test -z "`git config -l | grep "^svn-remote\.git-svn\."`" && + test -z "$(git config -l | grep "^svn-remote\.git-svn\.")" && git config --get-all svn-remote.svn.fetch > fetch.out && grep "^trunk:refs/remotes/origin/trunk$" fetch.out && grep "^branches/a:refs/remotes/origin/a$" fetch.out && diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh index d732d31302..a526d60379 100755 --- a/t/t9108-git-svn-glob.sh +++ b/t/t9108-git-svn-glob.sh @@ -50,10 +50,10 @@ test_expect_success 'test refspec globbing' ' git log --pretty=oneline refs/remotes/tags/end | \ sed -e "s/^.\{41\}//" > output.end && test_cmp expect.end output.end && - test "`git rev-parse refs/remotes/tags/end~1`" = \ - "`git rev-parse refs/remotes/branches/start`" && - test "`git rev-parse refs/remotes/branches/start~2`" = \ - "`git rev-parse refs/remotes/trunk`" && + test "$(git rev-parse refs/remotes/tags/end~1)" = \ + "$(git rev-parse refs/remotes/branches/start)" && + test "$(git rev-parse refs/remotes/branches/start~2)" = \ + "$(git rev-parse refs/remotes/trunk)" && test_must_fail git rev-parse refs/remotes/tags/end@3 ' @@ -75,12 +75,12 @@ test_expect_success 'test left-hand-side only globbing' ' svn_cmd commit -m "try to try" ) && git svn fetch two && - test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 && - test `git rev-list refs/remotes/two/branches/start | wc -l` -eq 3 && - test `git rev-parse refs/remotes/two/branches/start~2` = \ - `git rev-parse refs/remotes/two/trunk` && - test `git rev-parse refs/remotes/two/tags/end~3` = \ - `git rev-parse refs/remotes/two/branches/start` && + test $(git rev-list refs/remotes/two/tags/end | wc -l) -eq 6 && + test $(git rev-list refs/remotes/two/branches/start | wc -l) -eq 3 && + test $(git rev-parse refs/remotes/two/branches/start~2) = \ + $(git rev-parse refs/remotes/two/trunk) && + test $(git rev-parse refs/remotes/two/tags/end~3) = \ + $(git rev-parse refs/remotes/two/branches/start) && git log --pretty=oneline refs/remotes/two/tags/end | \ sed -e "s/^.\{41\}//" > output.two && test_cmp expect.two output.two diff --git a/t/t9109-git-svn-multi-glob.sh b/t/t9109-git-svn-multi-glob.sh index c318f9f946..f36b749242 100755 --- a/t/t9109-git-svn-multi-glob.sh +++ b/t/t9109-git-svn-multi-glob.sh @@ -50,10 +50,10 @@ test_expect_success 'test refspec globbing' ' git log --pretty=oneline refs/remotes/tags/end | \ sed -e "s/^.\{41\}//" > output.end && test_cmp expect.end output.end && - test "`git rev-parse refs/remotes/tags/end~1`" = \ - "`git rev-parse refs/remotes/branches/v1/start`" && - test "`git rev-parse refs/remotes/branches/v1/start~2`" = \ - "`git rev-parse refs/remotes/trunk`" && + test "$(git rev-parse refs/remotes/tags/end~1)" = \ + "$(git rev-parse refs/remotes/branches/v1/start)" && + test "$(git rev-parse refs/remotes/branches/v1/start~2)" = \ + "$(git rev-parse refs/remotes/trunk)" && test_must_fail git rev-parse refs/remotes/tags/end@3 ' @@ -75,12 +75,12 @@ test_expect_success 'test left-hand-side only globbing' ' svn_cmd commit -m "try to try" ) && git svn fetch two && - test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 && - test `git rev-list refs/remotes/two/branches/v1/start | wc -l` -eq 3 && - test `git rev-parse refs/remotes/two/branches/v1/start~2` = \ - `git rev-parse refs/remotes/two/trunk` && - test `git rev-parse refs/remotes/two/tags/end~3` = \ - `git rev-parse refs/remotes/two/branches/v1/start` && + test $(git rev-list refs/remotes/two/tags/end | wc -l) -eq 6 && + test $(git rev-list refs/remotes/two/branches/v1/start | wc -l) -eq 3 && + test $(git rev-parse refs/remotes/two/branches/v1/start~2) = \ + $(git rev-parse refs/remotes/two/trunk) && + test $(git rev-parse refs/remotes/two/tags/end~3) = \ + $(git rev-parse refs/remotes/two/branches/v1/start) && git log --pretty=oneline refs/remotes/two/tags/end | \ sed -e "s/^.\{41\}//" > output.two && test_cmp expect.two output.two @@ -124,12 +124,12 @@ test_expect_success 'test another branch' ' git config --add svn-remote.four.tags \ "tags/*:refs/remotes/four/tags/*" && git svn fetch four && - test `git rev-list refs/remotes/four/tags/next | wc -l` -eq 5 && - test `git rev-list refs/remotes/four/branches/v2/start | wc -l` -eq 3 && - test `git rev-parse refs/remotes/four/branches/v2/start~2` = \ - `git rev-parse refs/remotes/four/trunk` && - test `git rev-parse refs/remotes/four/tags/next~2` = \ - `git rev-parse refs/remotes/four/branches/v2/start` && + test $(git rev-list refs/remotes/four/tags/next | wc -l) -eq 5 && + test $(git rev-list refs/remotes/four/branches/v2/start | wc -l) -eq 3 && + test $(git rev-parse refs/remotes/four/branches/v2/start~2) = \ + $(git rev-parse refs/remotes/four/trunk) && + test $(git rev-parse refs/remotes/four/tags/next~2) = \ + $(git rev-parse refs/remotes/four/branches/v2/start) && git log --pretty=oneline refs/remotes/four/tags/next | \ sed -e "s/^.\{41\}//" > output.four && test_cmp expect.four output.four diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh index a06e4c5b8e..29fbdfdd3f 100755 --- a/t/t9110-git-svn-use-svm-props.sh +++ b/t/t9110-git-svn-use-svm-props.sh @@ -51,7 +51,7 @@ test_expect_success 'verify metadata for /dir' " test_expect_success 'find commit based on SVN revision number' " git svn find-rev r12 | - grep `git rev-parse HEAD` + grep $(git rev-parse HEAD) " test_expect_success 'empty rebase' " diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh index fb41876677..a3d388228a 100755 --- a/t/t9114-git-svn-dcommit-merge.sh +++ b/t/t9114-git-svn-dcommit-merge.sh @@ -68,8 +68,8 @@ test_expect_success 'setup git mirror and merge' ' test_debug 'gitk --all & sleep 1' test_expect_success 'verify pre-merge ancestry' " - test x\`git rev-parse --verify refs/heads/svn^2\` = \ - x\`git rev-parse --verify refs/heads/merge\` && + test x\$(git rev-parse --verify refs/heads/svn^2) = \ + x\$(git rev-parse --verify refs/heads/merge) && git cat-file commit refs/heads/svn^ | grep '^friend$' " @@ -80,10 +80,10 @@ test_expect_success 'git svn dcommit merges' " test_debug 'gitk --all & sleep 1' test_expect_success 'verify post-merge ancestry' " - test x\`git rev-parse --verify refs/heads/svn\` = \ - x\`git rev-parse --verify refs/remotes/origin/trunk \` && - test x\`git rev-parse --verify refs/heads/svn^2\` = \ - x\`git rev-parse --verify refs/heads/merge\` && + test x\$(git rev-parse --verify refs/heads/svn) = \ + x\$(git rev-parse --verify refs/remotes/origin/trunk) && + test x\$(git rev-parse --verify refs/heads/svn^2) = \ + x\$(git rev-parse --verify refs/heads/merge) && git cat-file commit refs/heads/svn^ | grep '^friend$' " diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh index 6a48e40429..0990f8d235 100755 --- a/t/t9115-git-svn-dcommit-funky-renames.sh +++ b/t/t9115-git-svn-dcommit-funky-renames.sh @@ -77,11 +77,47 @@ test_expect_success 'make a commit to test rebase' ' ' test_expect_success 'git svn rebase works inside a fresh-cloned repository' ' - cd test-rebase && + ( + cd test-rebase && git svn rebase && test -e test-rebase-main && test -e test-rebase - ' + )' + +# Without this, LC_ALL=C as set in test-lib.sh, and Cygwin converts +# non-ASCII characters in filenames unexpectedly, and causes errors. +# https://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-specialchars +# > Some characters are disallowed in filenames on Windows filesystems. ... +# ... +# > ... All of the above characters, except for the backslash, are converted +# > to special UNICODE characters in the range 0xf000 to 0xf0ff (the +# > "Private use area") when creating or accessing files. +prepare_a_utf8_locale +test_expect_success UTF8 'svn.pathnameencoding=cp932 new file on dcommit' ' + LC_ALL=$a_utf8_locale && + export LC_ALL && + neq=$(printf "\201\202") && + git config svn.pathnameencoding cp932 && + echo neq >"$neq" && + git add "$neq" && + git commit -m "neq" && + git svn dcommit +' + +# See the comment on the above test for setting of LC_ALL. +test_expect_success 'svn.pathnameencoding=cp932 rename on dcommit' ' + LC_ALL=$a_utf8_locale && + export LC_ALL && + inf=$(printf "\201\207") && + git config svn.pathnameencoding cp932 && + echo inf >"$inf" && + git add "$inf" && + git commit -m "inf" && + git svn dcommit && + git mv "$inf" inf && + git commit -m "inf rename" && + git svn dcommit +' stop_httpd diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index ed4d1369cc..ecb1fed147 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -23,8 +23,11 @@ test_expect_success 'setup svnrepo' ' "$svnrepo/pr ject/branches/$scary_uri" && svn_cmd cp -m "leading dot" "$svnrepo/pr ject/trunk" \ "$svnrepo/pr ject/branches/.leading_dot" && - svn_cmd cp -m "trailing dot" "$svnrepo/pr ject/trunk" \ - "$svnrepo/pr ject/branches/trailing_dot." && + if test_have_prereq !MINGW + then + svn_cmd cp -m "trailing dot" "$svnrepo/pr ject/trunk" \ + "$svnrepo/pr ject/branches/trailing_dot." + fi && svn_cmd cp -m "trailing .lock" "$svnrepo/pr ject/trunk" \ "$svnrepo/pr ject/branches/trailing_dotlock.lock" && svn_cmd cp -m "reflog" "$svnrepo/pr ject/trunk" \ @@ -35,7 +38,7 @@ test_expect_success 'setup svnrepo' ' # SVN 1.7 will truncate "not-a%40{0]" to just "not-a". # Look at what SVN wound up naming the branch and use that. # Be sure to escape the @ if it shows up. -non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'` +non_reflog=$(svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/') test_expect_success 'test clone with funky branch names' ' git svn clone -s "$svnrepo/pr ject" project && @@ -45,7 +48,10 @@ test_expect_success 'test clone with funky branch names' ' git rev-parse "refs/remotes/origin/more%20fun%20plugin!" && git rev-parse "refs/remotes/origin/$scary_ref" && git rev-parse "refs/remotes/origin/%2Eleading_dot" && - git rev-parse "refs/remotes/origin/trailing_dot%2E" && + if test_have_prereq !MINGW + then + git rev-parse "refs/remotes/origin/trailing_dot%2E" + fi && git rev-parse "refs/remotes/origin/trailing_dotlock%2Elock" && git rev-parse "refs/remotes/origin/$non_reflog" ) diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh index f16f3234a1..88241baee3 100755 --- a/t/t9119-git-svn-info.sh +++ b/t/t9119-git-svn-info.sh @@ -8,7 +8,7 @@ test_description='git svn info' # Tested with: svn, version 1.4.4 (r25188) # Tested with: svn, version 1.6.[12345689] -v=`svn_cmd --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'` +v=$(svn_cmd --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p') case $v in 1.[456].*) ;; diff --git a/t/t9124-git-svn-dcommit-auto-props.sh b/t/t9124-git-svn-dcommit-auto-props.sh index aa841e1299..9f7231d5b7 100755 --- a/t/t9124-git-svn-dcommit-auto-props.sh +++ b/t/t9124-git-svn-dcommit-auto-props.sh @@ -34,8 +34,7 @@ test_expect_success 'enable auto-props config' ' ' test_expect_success 'add files matching auto-props' ' - echo "#!$SHELL_PATH" >exec1.sh && - chmod +x exec1.sh && + write_script exec1.sh </dev/null && echo "hello" >hello.txt && echo bar >bar && git add exec1.sh hello.txt bar && @@ -48,8 +47,7 @@ test_expect_success 'disable auto-props config' ' ' test_expect_success 'add files matching disabled auto-props' ' - echo "#$SHELL_PATH" >exec2.sh && - chmod +x exec2.sh && + write_script exec2.sh </dev/null && echo "world" >world.txt && echo zot >zot && git add exec2.sh world.txt zot && @@ -65,7 +63,10 @@ test_expect_success 'check resulting svn repository' ' cd svnrepo && # Check properties from first commit. - test "x$(svn_cmd propget svn:executable exec1.sh)" = "x*" && + if test_have_prereq POSIXPERM + then + test "x$(svn_cmd propget svn:executable exec1.sh)" = "x*" + fi && test "x$(svn_cmd propget svn:mime-type exec1.sh)" = \ "xapplication/x-shellscript" && test "x$(svn_cmd propget svn:mime-type hello.txt)" = "xtext/plain" && @@ -73,7 +74,10 @@ test_expect_success 'check resulting svn repository' ' test "x$(svn_cmd propget svn:mime-type bar)" = "x" && # Check properties from second commit. - test "x$(svn_cmd propget svn:executable exec2.sh)" = "x*" && + if test_have_prereq POSIXPERM + then + test "x$(svn_cmd propget svn:executable exec2.sh)" = "x*" + fi && test "x$(svn_cmd propget svn:mime-type exec2.sh)" = "x" && test "x$(svn_cmd propget svn:mime-type world.txt)" = "x" && test "x$(svn_cmd propget svn:eol-style world.txt)" = "x" && diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh index 8cfdfe790f..8dbd6476fa 100755 --- a/t/t9129-git-svn-i18n-commitencoding.sh +++ b/t/t9129-git-svn-i18n-commitencoding.sh @@ -7,29 +7,19 @@ test_description='git svn honors i18n.commitEncoding in config' . ./lib-git-svn.sh compare_git_head_with () { - nr=`wc -l < "$1"` + nr=$(wc -l < "$1") a=7 b=$(($a + $nr - 1)) git cat-file commit HEAD | sed -ne "$a,${b}p" >current && test_cmp current "$1" } -a_utf8_locale=$(locale -a | sed -n '/\.[uU][tT][fF]-*8$/{ - p - q -}') - -if test -n "$a_utf8_locale" -then - test_set_prereq UTF8 -else - say "# UTF-8 locale not available, some tests are skipped" -fi +prepare_a_utf8_locale compare_svn_head_with () { # extract just the log message and strip out committer info. # don't use --limit here since svn 1.1.x doesn't have it, - LC_ALL="$a_utf8_locale" svn log `git svn info --url` | perl -w -e ' + LC_ALL="$a_utf8_locale" svn log $(git svn info --url) | perl -w -e ' use bytes; $/ = ("-"x72) . "\n"; my @x = <STDIN>; diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh index c44de267a1..41264818cc 100755 --- a/t/t9130-git-svn-authors-file.sh +++ b/t/t9130-git-svn-authors-file.sh @@ -26,7 +26,7 @@ test_expect_success 'start import with incomplete authors file' ' test_expect_success 'imported 2 revisions successfully' ' ( cd x - test "`git rev-list refs/remotes/git-svn | wc -l`" -eq 2 && + test "$(git rev-list refs/remotes/git-svn | wc -l)" -eq 2 && git rev-list -1 --pretty=raw refs/remotes/git-svn | \ grep "^author BBBBBBB BBBBBBB <bb@example\.com> " && git rev-list -1 --pretty=raw refs/remotes/git-svn~1 | \ @@ -43,7 +43,7 @@ test_expect_success 'continues to import once authors have been added' ' ( cd x git svn fetch --authors-file=../svn-authors && - test "`git rev-list refs/remotes/git-svn | wc -l`" -eq 4 && + test "$(git rev-list refs/remotes/git-svn | wc -l)" -eq 4 && git rev-list -1 --pretty=raw refs/remotes/git-svn | \ grep "^author DDDDDDD DDDDDDD <dd@example\.com> " && git rev-list -1 --pretty=raw refs/remotes/git-svn~1 | \ @@ -73,8 +73,8 @@ tmp_config_get () { test_expect_success 'failure happened without negative side effects' ' ( cd aa-work && - test 6 -eq "`tmp_config_get svn-remote.svn.branches-maxRev`" && - test 6 -eq "`tmp_config_get svn-remote.svn.tags-maxRev`" + test 6 -eq "$(tmp_config_get svn-remote.svn.branches-maxRev)" && + test 6 -eq "$(tmp_config_get svn-remote.svn.tags-maxRev)" ) ' @@ -86,12 +86,12 @@ test_expect_success 'fetch continues after authors-file is fixed' ' ( cd aa-work && git svn fetch --authors-file=../svn-authors && - test 8 -eq "`tmp_config_get svn-remote.svn.branches-maxRev`" && - test 8 -eq "`tmp_config_get svn-remote.svn.tags-maxRev`" + test 8 -eq "$(tmp_config_get svn-remote.svn.branches-maxRev)" && + test 8 -eq "$(tmp_config_get svn-remote.svn.tags-maxRev)" ) ' -test_expect_success 'fresh clone with svn.authors-file in config' ' +test_expect_success !MINGW 'fresh clone with svn.authors-file in config' ' ( rm -r "$GIT_DIR" && test x = x"$(git config svn.authorsfile)" && diff --git a/t/t9132-git-svn-broken-symlink.sh b/t/t9132-git-svn-broken-symlink.sh index 6c4c90b036..aeceffaf7b 100755 --- a/t/t9132-git-svn-broken-symlink.sh +++ b/t/t9132-git-svn-broken-symlink.sh @@ -87,7 +87,7 @@ test_expect_success 'clone using git svn' 'git svn clone -r1 "$svnrepo" x' test_expect_success SYMLINKS '"bar" is a symlink that points to "asdf"' ' test -L x/bar && - (cd x && test xasdf = x"`git cat-file blob HEAD:bar`") + (cd x && test xasdf = x"$(git cat-file blob HEAD:bar)") ' test_expect_success 'get "bar" => symlink fix from svn' ' @@ -96,7 +96,7 @@ test_expect_success 'get "bar" => symlink fix from svn' ' test_expect_success SYMLINKS '"bar" remains a proper symlink' ' test -L x/bar && - (cd x && test xdoink = x"`git cat-file blob HEAD:bar`") + (cd x && test xdoink = x"$(git cat-file blob HEAD:bar)") ' test_done diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh index d60da63f7a..5fa07a369f 100755 --- a/t/t9137-git-svn-dcommit-clobber-series.sh +++ b/t/t9137-git-svn-dcommit-clobber-series.sh @@ -16,15 +16,15 @@ test_expect_success 'initialize repo' ' ' test_expect_success '(supposedly) non-conflicting change from SVN' ' - test x"`sed -n -e 58p < file`" = x58 && - test x"`sed -n -e 61p < file`" = x61 && + test x"$(sed -n -e 58p < file)" = x58 && + test x"$(sed -n -e 61p < file)" = x61 && svn_cmd co "$svnrepo" tmp && (cd tmp && perl -i.bak -p -e "s/^58$/5588/" file && perl -i.bak -p -e "s/^61$/6611/" file && poke file && - test x"`sed -n -e 58p < file`" = x5588 && - test x"`sed -n -e 61p < file`" = x6611 && + test x"$(sed -n -e 58p < file)" = x5588 && + test x"$(sed -n -e 61p < file)" = x6611 && svn_cmd commit -m "58 => 5588, 61 => 6611" ) ' @@ -38,20 +38,20 @@ test_expect_success 'some unrelated changes to git' " " test_expect_success 'change file but in unrelated area' " - test x\"\`sed -n -e 4p < file\`\" = x4 && - test x\"\`sed -n -e 7p < file\`\" = x7 && + test x\"\$(sed -n -e 4p < file)\" = x4 && + test x\"\$(sed -n -e 7p < file)\" = x7 && perl -i.bak -p -e 's/^4\$/4444/' file && perl -i.bak -p -e 's/^7\$/7777/' file && - test x\"\`sed -n -e 4p < file\`\" = x4444 && - test x\"\`sed -n -e 7p < file\`\" = x7777 && + test x\"\$(sed -n -e 4p < file)\" = x4444 && + test x\"\$(sed -n -e 7p < file)\" = x7777 && git commit -m '4 => 4444, 7 => 7777' file && git svn dcommit && svn_cmd up tmp && cd tmp && - test x\"\`sed -n -e 4p < file\`\" = x4444 && - test x\"\`sed -n -e 7p < file\`\" = x7777 && - test x\"\`sed -n -e 58p < file\`\" = x5588 && - test x\"\`sed -n -e 61p < file\`\" = x6611 + test x\"\$(sed -n -e 4p < file)\" = x4444 && + test x\"\$(sed -n -e 7p < file)\" = x7777 && + test x\"\$(sed -n -e 58p < file)\" = x5588 && + test x\"\$(sed -n -e 61p < file)\" = x6611 " test_expect_success 'attempt to dcommit with a dirty index' ' diff --git a/t/t9138-git-svn-authors-prog.sh b/t/t9138-git-svn-authors-prog.sh index 2937f4c265..7d7e9d46bc 100755 --- a/t/t9138-git-svn-authors-prog.sh +++ b/t/t9138-git-svn-authors-prog.sh @@ -37,7 +37,7 @@ test_expect_success 'import authors with prog and file' ' test_expect_success 'imported 6 revisions successfully' ' ( cd x - test "`git rev-list refs/remotes/git-svn | wc -l`" -eq 6 + test "$(git rev-list refs/remotes/git-svn | wc -l)" -eq 6 ) ' diff --git a/t/t9145-git-svn-master-branch.sh b/t/t9145-git-svn-master-branch.sh index 6559137493..3bbf341f6a 100755 --- a/t/t9145-git-svn-master-branch.sh +++ b/t/t9145-git-svn-master-branch.sh @@ -17,8 +17,8 @@ test_expect_success 'git svn clone --stdlayout sets up trunk as master' ' git svn clone -s "$svnrepo" g && ( cd g && - test x`git rev-parse --verify refs/remotes/origin/trunk^0` = \ - x`git rev-parse --verify refs/heads/master^0` + test x$(git rev-parse --verify refs/remotes/origin/trunk^0) = \ + x$(git rev-parse --verify refs/heads/master^0) ) ' diff --git a/t/t9150-svk-mergetickets.sh b/t/t9150-svk-mergetickets.sh index 24c2421bfc..1bb676bede 100755 --- a/t/t9150-svk-mergetickets.sh +++ b/t/t9150-svk-mergetickets.sh @@ -19,7 +19,7 @@ test_expect_success 'load svk depot' " uuid=b48289b2-9c08-4d72-af37-0358a40b9c15 test_expect_success 'svk merges were represented coming in' " - [ `git cat-file commit HEAD | grep parent | wc -l` -eq 2 ] + [ $(git cat-file commit HEAD | grep parent | wc -l) -eq 2 ] " test_done diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 812c9cd462..bb879a527d 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -35,7 +35,7 @@ exit 1 check_entries () { # $1 == directory, $2 == expected - grep '^/' "$1/CVS/Entries" | sort | cut -d/ -f2,3,5 >actual + sed -ne '/^\//p' "$1/CVS/Entries" | sort | cut -d/ -f2,3,5 >actual if test -z "$2" then >expected @@ -197,7 +197,7 @@ if p="Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" && then # This test contains UTF-8 characters -test_expect_success \ +test_expect_success !MINGW \ 'File with non-ascii file name' \ 'mkdir -p Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö && echo Foo >Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt && diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 14a938402e..4c5f3c9d41 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -171,10 +171,10 @@ test_expect_success 'A: verify tag/series-A-blob' ' test_expect_success 'A: verify marks output' ' cat >expect <<-EOF && - :2 `git rev-parse --verify master:file2` - :3 `git rev-parse --verify master:file3` - :4 `git rev-parse --verify master:file4` - :5 `git rev-parse --verify master^0` + :2 $(git rev-parse --verify master:file2) + :3 $(git rev-parse --verify master:file3) + :4 $(git rev-parse --verify master:file4) + :5 $(git rev-parse --verify master^0) EOF test_cmp expect marks.out ' @@ -264,8 +264,8 @@ test_expect_success 'A: verify diff' ' EOF git diff-tree -M -r master verify--import-marks >actual && compare_diff_raw expect actual && - test `git rev-parse --verify master:file2` \ - = `git rev-parse --verify verify--import-marks:copy-of-file2` + test $(git rev-parse --verify master:file2) \ + = $(git rev-parse --verify verify--import-marks:copy-of-file2) ' test_expect_success 'A: export marks with large values' ' @@ -364,7 +364,7 @@ test_expect_success 'B: accept branch name "TEMP_TAG"' ' git prune" && git fast-import <input && test -f .git/TEMP_TAG && - test `git rev-parse master` = `git rev-parse TEMP_TAG^` + test $(git rev-parse master) = $(git rev-parse TEMP_TAG^) ' test_expect_success 'B: accept empty committer' ' @@ -473,8 +473,8 @@ test_expect_success 'B: fail on invalid committer (5)' ' ### test_expect_success 'C: incremental import create pack from stdin' ' - newf=`echo hi newf | git hash-object -w --stdin` && - oldf=`git rev-parse --verify master:file2` && + newf=$(echo hi newf | git hash-object -w --stdin) && + oldf=$(git rev-parse --verify master:file2) && test_tick && cat >input <<-INPUT_END && commit refs/heads/branch @@ -499,13 +499,13 @@ test_expect_success 'C: verify pack' ' ' test_expect_success 'C: validate reuse existing blob' ' - test $newf = `git rev-parse --verify branch:file2/newf` && - test $oldf = `git rev-parse --verify branch:file2/oldf` + test $newf = $(git rev-parse --verify branch:file2/newf) && + test $oldf = $(git rev-parse --verify branch:file2/oldf) ' test_expect_success 'C: verify commit' ' cat >expect <<-EOF && - parent `git rev-parse --verify master^0` + parent $(git rev-parse --verify master^0) author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE @@ -624,7 +624,7 @@ test_expect_success 'E: verify commit' ' ### test_expect_success 'F: non-fast-forward update skips' ' - old_branch=`git rev-parse --verify branch^0` && + old_branch=$(git rev-parse --verify branch^0) && test_tick && cat >input <<-INPUT_END && commit refs/heads/branch @@ -642,7 +642,7 @@ test_expect_success 'F: non-fast-forward update skips' ' test_must_fail git fast-import <input && # branch must remain unaffected - test $old_branch = `git rev-parse --verify branch^0` + test $old_branch = $(git rev-parse --verify branch^0) ' test_expect_success 'F: verify pack' ' @@ -651,8 +651,8 @@ test_expect_success 'F: verify pack' ' test_expect_success 'F: verify other commit' ' cat >expect <<-EOF && - tree `git rev-parse branch~1^{tree}` - parent `git rev-parse branch~1` + tree $(git rev-parse branch~1^{tree}) + parent $(git rev-parse branch~1) author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE @@ -667,7 +667,7 @@ test_expect_success 'F: verify other commit' ' ### test_expect_success 'G: non-fast-forward update forced' ' - old_branch=`git rev-parse --verify branch^0` && + old_branch=$(git rev-parse --verify branch^0) && test_tick && cat >input <<-INPUT_END && commit refs/heads/branch @@ -687,8 +687,8 @@ test_expect_success 'G: verify pack' ' ' test_expect_success 'G: branch changed, but logged' ' - test $old_branch != `git rev-parse --verify branch^0` && - test $old_branch = `git rev-parse --verify branch@{1}` + test $old_branch != $(git rev-parse --verify branch^0) && + test $old_branch = $(git rev-parse --verify branch@{1}) ' ### @@ -763,7 +763,7 @@ test_expect_success 'I: export-pack-edges' ' test_expect_success 'I: verify edge list' ' cat >expect <<-EOF && - .git/objects/pack/pack-.pack: `git rev-parse --verify export-boundary` + .git/objects/pack/pack-.pack: $(git rev-parse --verify export-boundary) EOF sed -e s/pack-.*pack/pack-.pack/ edges.list >actual && test_cmp expect actual @@ -795,8 +795,8 @@ test_expect_success 'J: reset existing branch creates empty commit' ' git fast-import <input ' test_expect_success 'J: branch has 1 commit, empty tree' ' - test 1 = `git rev-list J | wc -l` && - test 0 = `git ls-tree J | wc -l` + test 1 = $(git rev-list J | wc -l) && + test 0 = $(git ls-tree J | wc -l) ' test_expect_success 'J: tag must fail on empty branch' ' @@ -838,8 +838,8 @@ test_expect_success 'K: reinit branch with from' ' git fast-import <input ' test_expect_success 'K: verify K^1 = branch^1' ' - test `git rev-parse --verify branch^1` \ - = `git rev-parse --verify K^1` + test $(git rev-parse --verify branch^1) \ + = $(git rev-parse --verify K^1) ' ### @@ -929,7 +929,7 @@ test_expect_success 'L: nested tree copy does not corrupt deltas' ' git ls-tree L2 g/b/ >tmp && cat tmp | cut -f 2 >actual && test_cmp expect actual && - git fsck `git rev-parse L2` + git fsck $(git rev-parse L2) ' ### @@ -1106,7 +1106,7 @@ test_expect_success 'N: copy dirty subdirectory' ' INPUT_END git fast-import <input && - test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}` + test $(git rev-parse N2^{tree}) = $(git rev-parse N3^{tree}) ' test_expect_success 'N: copy directory by id' ' @@ -1503,7 +1503,7 @@ test_expect_success 'O: comments are all skipped' ' INPUT_END git fast-import <input && - test `git rev-parse N3` = `git rev-parse O1` + test $(git rev-parse N3) = $(git rev-parse O1) ' test_expect_success 'O: blank lines not necessary after data commands' ' @@ -1524,7 +1524,7 @@ test_expect_success 'O: blank lines not necessary after data commands' ' INPUT_END git fast-import <input && - test `git rev-parse N3` = `git rev-parse O2` + test $(git rev-parse N3) = $(git rev-parse O2) ' test_expect_success 'O: repack before next test' ' @@ -1570,8 +1570,8 @@ test_expect_success 'O: blank lines not necessary after other commands' ' INPUT_END git fast-import <input && - test 8 = `find .git/objects/pack -type f | wc -l` && - test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` && + test 8 = $(find .git/objects/pack -type f | wc -l) && + test $(git rev-parse refs/tags/O3-2nd) = $(git rev-parse O3^) && git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual && test_cmp expect actual ' @@ -1631,7 +1631,7 @@ test_expect_success 'P: superproject & submodule mix' ' data <<DATAEND [submodule "sub"] path = sub - url = "`pwd`/sub" + url = "$(pwd)/sub" DATAEND commit refs/heads/subuse1 @@ -1691,7 +1691,7 @@ test_expect_success 'P: verbatim SHA gitlinks' ' data <<DATAEND [submodule "sub"] path = sub - url = "`pwd`/sub" + url = "$(pwd)/sub" DATAEND commit refs/heads/subuse2 @@ -1978,7 +1978,7 @@ test_expect_success 'Q: verify first note for third commit' ' test_expect_success 'Q: verify second notes commit' ' cat >expect <<-EOF && - parent `git rev-parse --verify refs/notes/foobar~2` + parent $(git rev-parse --verify refs/notes/foobar~2) author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE @@ -2045,7 +2045,7 @@ test_expect_success 'Q: verify third note for first commit' ' test_expect_success 'Q: verify fourth notes commit' ' cat >expect <<-EOF && - parent `git rev-parse --verify refs/notes/foobar^` + parent $(git rev-parse --verify refs/notes/foobar^) author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 66c8b0a371..b5149fde6e 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -163,7 +163,7 @@ test_expect_success 'setup submodule' ' git add file && git commit -m sub_initial ) && - git submodule add "`pwd`/sub" sub && + git submodule add "$(pwd)/sub" sub && git commit -m initial && test_tick && ( @@ -377,7 +377,7 @@ test_expect_success 'full-tree re-shows unmodified files' ' test_expect_success 'set-up a few more tags for tag export tests' ' git checkout -f master && - HEAD_TREE=`git show -s --pretty=raw HEAD | grep tree | sed "s/tree //"` && + HEAD_TREE=$(git show -s --pretty=raw HEAD | grep tree | sed "s/tree //") && git tag tree_tag -m "tagging a tree" $HEAD_TREE && git tag -a tree_tag-obj -m "tagging a tree" $HEAD_TREE && git tag tag-obj_tag -m "tagging a tag" tree_tag-obj && @@ -422,7 +422,7 @@ test_expect_success 'directory becomes symlink' ' test_expect_success 'fast-export quotes pathnames' ' git init crazy-paths && (cd crazy-paths && - blob=`echo foo | git hash-object -w --stdin` && + blob=$(echo foo | git hash-object -w --stdin) && git update-index --add \ --cacheinfo 100644 $blob "$(printf "path with\\nnewline")" \ --cacheinfo 100644 $blob "path with \"quote\"" \ diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 6146c3fec2..d708cbf032 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -25,11 +25,11 @@ perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { test_done } -WORKDIR=$(pwd) -SERVERDIR=$(pwd)/gitcvs.git +WORKDIR=$PWD +SERVERDIR=$PWD/gitcvs.git git_config="$SERVERDIR/config" CVSROOT=":fork:$SERVERDIR" -CVSWORK="$(pwd)/cvswork" +CVSWORK="$PWD/cvswork" CVS_SERVER=git-cvsserver export CVSROOT CVS_SERVER diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index 5a4ed28e49..f324b9f010 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -74,11 +74,11 @@ perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { } unset GIT_DIR GIT_CONFIG -WORKDIR=$(pwd) -SERVERDIR=$(pwd)/gitcvs.git +WORKDIR=$PWD +SERVERDIR=$PWD/gitcvs.git git_config="$SERVERDIR/config" CVSROOT=":fork:$SERVERDIR" -CVSWORK="$(pwd)/cvswork" +CVSWORK="$PWD/cvswork" CVS_SERVER=git-cvsserver export CVSROOT CVS_SERVER diff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh index d00df08731..6d2d3c8739 100755 --- a/t/t9402-git-cvsserver-refs.sh +++ b/t/t9402-git-cvsserver-refs.sh @@ -82,11 +82,11 @@ perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { } unset GIT_DIR GIT_CONFIG -WORKDIR=$(pwd) -SERVERDIR=$(pwd)/gitcvs.git +WORKDIR=$PWD +SERVERDIR=$PWD/gitcvs.git git_config="$SERVERDIR/config" CVSROOT=":fork:$SERVERDIR" -CVSWORK="$(pwd)/cvswork" +CVSWORK="$PWD/cvswork" CVS_SERVER=git-cvsserver export CVSROOT CVS_SERVER diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh index d3a5bac754..2a0ffed870 100755 --- a/t/t9501-gitweb-standalone-http-status.sh +++ b/t/t9501-gitweb-standalone-http-status.sh @@ -100,14 +100,14 @@ test_expect_success 'snapshots: bad tree-ish id (tagged object)' ' echo object > tag-object && git add tag-object && test_tick && git commit -m "Object to be tagged" && - git tag tagged-object `git hash-object tag-object` && + git tag tagged-object $(git hash-object tag-object) && gitweb_run "p=.git;a=snapshot;h=tagged-object;sf=tgz" && grep "400 - Object is not a tree-ish" gitweb.output ' test_debug 'cat gitweb.output' test_expect_success 'snapshots: good object id' ' - ID=`git rev-parse --verify HEAD` && + ID=$(git rev-parse --verify HEAD) && gitweb_run "p=.git;a=snapshot;h=$ID;sf=tgz" && grep "Status: 200 OK" gitweb.output ' @@ -173,7 +173,7 @@ test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (unmod test_debug 'cat gitweb.headers' test_expect_success DATE_PARSER 'modification: tree snapshot' ' - ID=`git rev-parse --verify HEAD^{tree}` && + ID=$(git rev-parse --verify HEAD^{tree}) && HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 1140767b50..7e8c40b97b 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -33,7 +33,7 @@ is($r->config_int("test.int"), 2048, "config_int: integer"); is($r->config_int("test.nonexistent"), undef, "config_int: nonexistent"); ok($r->config_bool("test.booltrue"), "config_bool: true"); ok(!$r->config_bool("test.boolfalse"), "config_bool: false"); -is($r->config_path("test.path"), $r->config("test.pathexpanded"), +is($r->config_path("test.path") =~ s/\\/\//gr, $r->config("test.pathexpanded"), "config_path: ~/foo expansion"); is_deeply([$r->config_path("test.pathmulti")], ["foo", "bar"], "config_path: multiple values"); diff --git a/t/t9827-git-p4-change-filetype.sh b/t/t9827-git-p4-change-filetype.sh new file mode 100755 index 0000000000..7433998f47 --- /dev/null +++ b/t/t9827-git-p4-change-filetype.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +test_description='git p4 support for file type change' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'create files' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + cat >file1 <<-EOF && + text without any funny substitution business + EOF + cat >file2 <<-EOF && + second file whose type will change + EOF + p4 add file1 file2 && + p4 submit -d "add files" + ) +' + +test_expect_success SYMLINKS 'change file to symbolic link' ' + git p4 clone --dest="$git" //depot@all && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + + rm file2 && + ln -s file1 file2 && + git add file2 && + git commit -m "symlink file1 to file2" && + git p4 submit && + p4 filelog -m 1 //depot/file2 >filelog && + grep "(symlink)" filelog + ) +' + +test_expect_success SYMLINKS 'change symbolic link to file' ' + git p4 clone --dest="$git" //depot@all && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + + rm file2 && + cat >file2 <<-EOF && + This is another content for the second file. + EOF + git add file2 && + git commit -m "re-write file2" && + git p4 submit && + p4 filelog -m 1 //depot/file2 >filelog && + grep "(text)" filelog + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9901-git-web--browse.sh b/t/t9901-git-web--browse.sh index b0a6bad8dd..de7152f827 100755 --- a/t/t9901-git-web--browse.sh +++ b/t/t9901-git-web--browse.sh @@ -43,7 +43,7 @@ test_expect_success \ echo fake: "$@" EOF chmod +x "fake browser" && - git config browser.w3m.path "`pwd`/fake browser" && + git config browser.w3m.path "$(pwd)/fake browser" && test_web_browse w3m http://example.com/foo ' diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index af82049f82..ffbfa0efb8 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -67,7 +67,7 @@ repo_with_newline='repo with newline' -if mkdir "$repo_with_newline" 2>/dev/null +if test_have_prereq !MINGW && mkdir "$repo_with_newline" 2>/dev/null then test_set_prereq FUNNYNAMES else diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index c64e5a5025..8d99eb303f 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -617,7 +617,7 @@ test_must_fail () { return 0 elif test $exit_code -gt 129 && test $exit_code -le 192 then - echo >&2 "test_must_fail: died by signal: $*" + echo >&2 "test_must_fail: died by signal $(($exit_code - 128)): $*" return 1 elif test $exit_code -eq 127 then diff --git a/t/test-lib.sh b/t/test-lib.sh index 16c4d7b516..0b47eb6bb2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -907,9 +907,11 @@ yes () { y="$*" fi - while echo "$y" + i=0 + while test $i -lt 99 do - : + echo "$y" + i=$(($i+1)) done } @@ -998,7 +1000,7 @@ test_i18ngrep () { test_lazy_prereq PIPE ' # test whether the filesystem supports FIFOs case $(uname -s) in - CYGWIN*) + CYGWIN*|MINGW*) false ;; *) @@ -1054,20 +1056,28 @@ test_lazy_prereq NOT_ROOT ' test "$uid" != 0 ' -# On a filesystem that lacks SANITY, a file can be deleted even if -# the containing directory doesn't have write permissions, or a file -# can be accessed even if the containing directory doesn't have read -# or execute permissions, causing our tests that validate that Git -# works sensibly in such situations. +# SANITY is about "can you correctly predict what the filesystem would +# do by only looking at the permission bits of the files and +# directories?" A typical example of !SANITY is running the test +# suite as root, where a test may expect "chmod -r file && cat file" +# to fail because file is supposed to be unreadable after a successful +# chmod. In an environment (i.e. combination of what filesystem is +# being used and who is running the tests) that lacks SANITY, you may +# be able to delete or create a file when the containing directory +# doesn't have write permissions, or access a file even if the +# containing directory doesn't have read or execute permissions. + test_lazy_prereq SANITY ' mkdir SANETESTD.1 SANETESTD.2 && chmod +w SANETESTD.1 SANETESTD.2 && >SANETESTD.1/x 2>SANETESTD.2/x && chmod -w SANETESTD.1 && + chmod -r SANETESTD.1/x && chmod -rx SANETESTD.2 || error "bug in test sript: cannot prepare SANETESTD" + ! test -r SANETESTD.1/x && ! rm SANETESTD.1/x && ! test -f SANETESTD.2/x status=$? diff --git a/test-dump-untracked-cache.c b/test-dump-untracked-cache.c index 25d855d98b..0a1c285246 100644 --- a/test-dump-untracked-cache.c +++ b/test-dump-untracked-cache.c @@ -44,6 +44,10 @@ int main(int ac, char **av) { struct untracked_cache *uc; struct strbuf base = STRBUF_INIT; + + /* Hack to avoid modifying the untracked cache when we read it */ + ignore_untracked_cache_config = 1; + setup_git_directory(); if (read_cache() < 0) die("unable to read index file"); diff --git a/test-fake-ssh.c b/test-fake-ssh.c new file mode 100644 index 0000000000..980de216e1 --- /dev/null +++ b/test-fake-ssh.c @@ -0,0 +1,30 @@ +#include "git-compat-util.h" +#include "run-command.h" +#include "strbuf.h" + +int main(int argc, char **argv) +{ + const char *trash_directory = getenv("TRASH_DIRECTORY"); + struct strbuf buf = STRBUF_INIT; + FILE *f; + int i; + const char *child_argv[] = { NULL, NULL }; + + /* First, print all parameters into $TRASH_DIRECTORY/ssh-output */ + if (!trash_directory) + die("Need a TRASH_DIRECTORY!"); + strbuf_addf(&buf, "%s/ssh-output", trash_directory); + f = fopen(buf.buf, "w"); + if (!f) + die("Could not write to %s", buf.buf); + for (i = 0; i < argc; i++) + fprintf(f, "%s%s", i > 0 ? " " : "", i > 0 ? argv[i] : "ssh:"); + fprintf(f, "\n"); + fclose(f); + + /* Now, evaluate the *last* parameter */ + if (argc < 2) + return 0; + child_argv[0] = argv[argc - 1]; + return run_command_v_opt(child_argv, RUN_USING_SHELL); +} diff --git a/test-path-utils.c b/test-path-utils.c index c67bf65b34..ba805b374c 100644 --- a/test-path-utils.c +++ b/test-path-utils.c @@ -8,21 +8,14 @@ */ static int normalize_ceiling_entry(struct string_list_item *item, void *unused) { - const char *ceil = item->string; - int len = strlen(ceil); - char buf[PATH_MAX+1]; + char *ceil = item->string; - if (len == 0) + if (!*ceil) die("Empty path is not supported"); - if (len > PATH_MAX) - die("Path \"%s\" is too long", ceil); if (!is_absolute_path(ceil)) die("Path \"%s\" is not absolute", ceil); - if (normalize_path_copy(buf, ceil) < 0) + if (normalize_path_copy(ceil, ceil) < 0) die("Path \"%s\" could not be normalized", ceil); - len = strlen(buf); - free(item->string); - item->string = xstrdup(buf); return 1; } @@ -39,10 +32,134 @@ static void normalize_argv_string(const char **var, const char *input) die("Bad value: %s\n", input); } +struct test_data { + const char *from; /* input: transform from this ... */ + const char *to; /* output: ... to this. */ + const char *alternative; /* output: ... or this. */ +}; + +static int test_function(struct test_data *data, char *(*func)(char *input), + const char *funcname) +{ + int failed = 0, i; + char buffer[1024]; + char *to; + + for (i = 0; data[i].to; i++) { + if (!data[i].from) + to = func(NULL); + else { + xsnprintf(buffer, sizeof(buffer), "%s", data[i].from); + to = func(buffer); + } + if (!strcmp(to, data[i].to)) + continue; + if (!data[i].alternative) + error("FAIL: %s(%s) => '%s' != '%s'\n", + funcname, data[i].from, to, data[i].to); + else if (!strcmp(to, data[i].alternative)) + continue; + else + error("FAIL: %s(%s) => '%s' != '%s', '%s'\n", + funcname, data[i].from, to, data[i].to, + data[i].alternative); + failed = 1; + } + return failed; +} + +static struct test_data basename_data[] = { + /* --- POSIX type paths --- */ + { NULL, "." }, + { "", "." }, + { ".", "." }, + { "..", ".." }, + { "/", "/" }, + { "//", "/", "//" }, + { "///", "/", "//" }, + { "////", "/", "//" }, + { "usr", "usr" }, + { "/usr", "usr" }, + { "/usr/", "usr" }, + { "/usr//", "usr" }, + { "/usr/lib", "lib" }, + { "usr/lib", "lib" }, + { "usr/lib///", "lib" }, + +#if defined(__MINGW32__) || defined(_MSC_VER) + /* --- win32 type paths --- */ + { "\\usr", "usr" }, + { "\\usr\\", "usr" }, + { "\\usr\\\\", "usr" }, + { "\\usr\\lib", "lib" }, + { "usr\\lib", "lib" }, + { "usr\\lib\\\\\\", "lib" }, + { "C:/usr", "usr" }, + { "C:/usr", "usr" }, + { "C:/usr/", "usr" }, + { "C:/usr//", "usr" }, + { "C:/usr/lib", "lib" }, + { "C:usr/lib", "lib" }, + { "C:usr/lib///", "lib" }, + { "C:", "." }, + { "C:a", "a" }, + { "C:/", "/" }, + { "C:///", "/" }, + { "\\", "\\", "/" }, + { "\\\\", "\\", "/" }, + { "\\\\\\", "\\", "/" }, +#endif + { NULL, NULL } +}; + +static struct test_data dirname_data[] = { + /* --- POSIX type paths --- */ + { NULL, "." }, + { "", "." }, + { ".", "." }, + { "..", "." }, + { "/", "/" }, + { "//", "/", "//" }, + { "///", "/", "//" }, + { "////", "/", "//" }, + { "usr", "." }, + { "/usr", "/" }, + { "/usr/", "/" }, + { "/usr//", "/" }, + { "/usr/lib", "/usr" }, + { "usr/lib", "usr" }, + { "usr/lib///", "usr" }, + +#if defined(__MINGW32__) || defined(_MSC_VER) + /* --- win32 type paths --- */ + { "\\", "\\" }, + { "\\\\", "\\\\" }, + { "\\usr", "\\" }, + { "\\usr\\", "\\" }, + { "\\usr\\\\", "\\" }, + { "\\usr\\lib", "\\usr" }, + { "usr\\lib", "usr" }, + { "usr\\lib\\\\\\", "usr" }, + { "C:a", "C:." }, + { "C:/", "C:/" }, + { "C:///", "C:/" }, + { "C:/usr", "C:/" }, + { "C:/usr/", "C:/" }, + { "C:/usr//", "C:/" }, + { "C:/usr/lib", "C:/usr" }, + { "C:usr/lib", "C:usr" }, + { "C:usr/lib///", "C:usr" }, + { "\\\\\\", "\\" }, + { "\\\\\\\\", "\\" }, + { "C:", "C:.", "." }, +#endif + { NULL, NULL } +}; + int main(int argc, char **argv) { if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) { - char *buf = xmalloc(PATH_MAX + 1); + char *buf = xmallocz(strlen(argv[2])); int rv = normalize_path_copy(buf, argv[2]); if (rv) buf = "++failed++"; @@ -133,6 +250,12 @@ int main(int argc, char **argv) return 0; } + if (argc == 2 && !strcmp(argv[1], "basename")) + return test_function(basename_data, basename, argv[1]); + + if (argc == 2 && !strcmp(argv[1], "dirname")) + return test_function(dirname_data, dirname, argv[1]); + fprintf(stderr, "%s: unknown function name: %s\n", argv[0], argv[1] ? argv[1] : "(there was none)"); return 1; diff --git a/test-run-command.c b/test-run-command.c index 89c7de2c60..fbe0a27ef3 100644 --- a/test-run-command.c +++ b/test-run-command.c @@ -10,16 +10,54 @@ #include "git-compat-util.h" #include "run-command.h" +#include "argv-array.h" +#include "strbuf.h" #include <string.h> #include <errno.h> +static int number_callbacks; +static int parallel_next(struct child_process *cp, + struct strbuf *err, + void *cb, + void **task_cb) +{ + struct child_process *d = cb; + if (number_callbacks >= 4) + return 0; + + argv_array_pushv(&cp->args, d->argv); + strbuf_addf(err, "preloaded output of a child\n"); + number_callbacks++; + return 1; +} + +static int no_job(struct child_process *cp, + struct strbuf *err, + void *cb, + void **task_cb) +{ + strbuf_addf(err, "no further jobs available\n"); + return 0; +} + +static int task_finished(int result, + struct child_process *cp, + struct strbuf *err, + void *pp_cb, + void *pp_task_cb) +{ + strbuf_addf(err, "asking for a quick stop\n"); + return 1; +} + int main(int argc, char **argv) { struct child_process proc = CHILD_PROCESS_INIT; + int jobs; if (argc < 3) return 1; - proc.argv = (const char **)argv+2; + proc.argv = (const char **)argv + 2; if (!strcmp(argv[1], "start-command-ENOENT")) { if (start_command(&proc) < 0 && errno == ENOENT) @@ -30,6 +68,21 @@ int main(int argc, char **argv) if (!strcmp(argv[1], "run-command")) exit(run_command(&proc)); + jobs = atoi(argv[2]); + proc.argv = (const char **)argv + 3; + + if (!strcmp(argv[1], "run-command-parallel")) + exit(run_processes_parallel(jobs, parallel_next, + NULL, NULL, &proc)); + + if (!strcmp(argv[1], "run-command-abort")) + exit(run_processes_parallel(jobs, parallel_next, + NULL, task_finished, &proc)); + + if (!strcmp(argv[1], "run-command-no-jobs")) + exit(run_processes_parallel(jobs, no_job, + NULL, task_finished, &proc)); + fprintf(stderr, "check usage\n"); return 1; } diff --git a/test-sha1-array.c b/test-sha1-array.c index ddc491eff9..60ea1d5f14 100644 --- a/test-sha1-array.c +++ b/test-sha1-array.c @@ -11,7 +11,7 @@ int main(int argc, char **argv) struct sha1_array array = SHA1_ARRAY_INIT; struct strbuf line = STRBUF_INIT; - while (strbuf_getline(&line, stdin, '\n') != EOF) { + while (strbuf_getline(&line, stdin) != EOF) { const char *arg; unsigned char sha1[20]; diff --git a/test-sha1.sh b/test-sha1.sh index 0f0bc5d02f..cef4bcc866 100755 --- a/test-sha1.sh +++ b/test-sha1.sh @@ -6,13 +6,13 @@ dd if=/dev/zero bs=1048576 count=100 2>/dev/null | while read expect cnt pfx do case "$expect" in '#'*) continue ;; esac - actual=` + actual=$( { test -z "$pfx" || echo "$pfx" dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null | perl -pe 'y/\000/g/' } | ./test-sha1 $cnt - ` + ) if test "$expect" = "$actual" then echo "OK: $expect $cnt $pfx" @@ -51,14 +51,14 @@ exit while read cnt pfx do - actual=` + actual=$( { test -z "$pfx" || echo "$pfx" dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null | perl -pe 'y/\000/g/' } | sha1sum | sed -e 's/ .*//' - ` + ) echo "$actual $cnt $pfx" done <<EOF 0 @@ -2,6 +2,7 @@ #include "string-list.h" #include "run-command.h" #include "commit.h" +#include "tempfile.h" #include "trailer.h" /* * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org> @@ -108,23 +109,23 @@ static char last_non_space_char(const char *s) return '\0'; } -static void print_tok_val(const char *tok, const char *val) +static void print_tok_val(FILE *outfile, const char *tok, const char *val) { char c = last_non_space_char(tok); if (!c) return; if (strchr(separators, c)) - printf("%s%s\n", tok, val); + fprintf(outfile, "%s%s\n", tok, val); else - printf("%s%c %s\n", tok, separators[0], val); + fprintf(outfile, "%s%c %s\n", tok, separators[0], val); } -static void print_all(struct trailer_item *first, int trim_empty) +static void print_all(FILE *outfile, struct trailer_item *first, int trim_empty) { struct trailer_item *item; for (item = first; item; item = item->next) { if (!trim_empty || strlen(item->value) > 0) - print_tok_val(item->token, item->value); + print_tok_val(outfile, item->token, item->value); } } @@ -795,14 +796,15 @@ static int has_blank_line_before(struct strbuf **lines, int start) return 0; } -static void print_lines(struct strbuf **lines, int start, int end) +static void print_lines(FILE *outfile, struct strbuf **lines, int start, int end) { int i; for (i = start; lines[i] && i < end; i++) - printf("%s", lines[i]->buf); + fprintf(outfile, "%s", lines[i]->buf); } -static int process_input_file(struct strbuf **lines, +static int process_input_file(FILE *outfile, + struct strbuf **lines, struct trailer_item **in_tok_first, struct trailer_item **in_tok_last) { @@ -818,10 +820,10 @@ static int process_input_file(struct strbuf **lines, trailer_start = find_trailer_start(lines, trailer_end); /* Print lines before the trailers as is */ - print_lines(lines, 0, trailer_start); + print_lines(outfile, lines, 0, trailer_start); if (!has_blank_line_before(lines, trailer_start - 1)) - printf("\n"); + fprintf(outfile, "\n"); /* Parse trailer lines */ for (i = trailer_start; i < trailer_end; i++) { @@ -842,13 +844,45 @@ static void free_all(struct trailer_item **first) } } -void process_trailers(const char *file, int trim_empty, struct string_list *trailers) +static struct tempfile trailers_tempfile; + +static FILE *create_in_place_tempfile(const char *file) +{ + struct stat st; + struct strbuf template = STRBUF_INIT; + const char *tail; + FILE *outfile; + + if (stat(file, &st)) + die_errno(_("could not stat %s"), file); + if (!S_ISREG(st.st_mode)) + die(_("file %s is not a regular file"), file); + if (!(st.st_mode & S_IWUSR)) + die(_("file %s is not writable by user"), file); + + /* Create temporary file in the same directory as the original */ + tail = strrchr(file, '/'); + if (tail != NULL) + strbuf_add(&template, file, tail - file + 1); + strbuf_addstr(&template, "git-interpret-trailers-XXXXXX"); + + xmks_tempfile_m(&trailers_tempfile, template.buf, st.st_mode); + strbuf_release(&template); + outfile = fdopen_tempfile(&trailers_tempfile, "w"); + if (!outfile) + die_errno(_("could not open temporary file")); + + return outfile; +} + +void process_trailers(const char *file, int in_place, int trim_empty, struct string_list *trailers) { struct trailer_item *in_tok_first = NULL; struct trailer_item *in_tok_last = NULL; struct trailer_item *arg_tok_first; struct strbuf **lines; int trailer_end; + FILE *outfile = stdout; /* Default config must be setup first */ git_config(git_trailer_default_config, NULL); @@ -856,19 +890,26 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai lines = read_input_file(file); + if (in_place) + outfile = create_in_place_tempfile(file); + /* Print the lines before the trailers */ - trailer_end = process_input_file(lines, &in_tok_first, &in_tok_last); + trailer_end = process_input_file(outfile, lines, &in_tok_first, &in_tok_last); arg_tok_first = process_command_line_args(trailers); process_trailers_lists(&in_tok_first, &in_tok_last, &arg_tok_first); - print_all(in_tok_first, trim_empty); + print_all(outfile, in_tok_first, trim_empty); free_all(&in_tok_first); /* Print the lines after the trailers as is */ - print_lines(lines, trailer_end, INT_MAX); + print_lines(outfile, lines, trailer_end, INT_MAX); + + if (in_place) + if (rename_tempfile(&trailers_tempfile, file)) + die_errno(_("could not rename temporary file to %s"), file); strbuf_list_free(lines); } @@ -1,6 +1,7 @@ #ifndef TRAILER_H #define TRAILER_H -void process_trailers(const char *file, int trim_empty, struct string_list *trailers); +void process_trailers(const char *file, int in_place, int trim_empty, + struct string_list *trailers); #endif /* TRAILER_H */ diff --git a/transport-helper.c b/transport-helper.c index 0eb3cf01aa..b934183236 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -54,7 +54,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name) strbuf_reset(buffer); if (debug) fprintf(stderr, "Debug: Remote helper: Waiting...\n"); - if (strbuf_getline(buffer, helper, '\n') == EOF) { + if (strbuf_getline(buffer, helper) == EOF) { if (debug) fprintf(stderr, "Debug: Remote helper quit.\n"); return 1; @@ -137,7 +137,8 @@ static struct child_process *get_helper(struct transport *transport) data->no_disconnect_req = 0; /* - * Open the output as FILE* so strbuf_getline() can be used. + * Open the output as FILE* so strbuf_getline_*() family of + * functions can be used. * Do this with duped fd because fclose() will close the fd, * and stuff like taking over will require the fd to remain. */ @@ -320,6 +321,21 @@ static void standard_options(struct transport *t) if (n >= sizeof(buf)) die("impossibly large verbosity value"); set_helper_option(t, "verbosity", buf); + + switch (t->family) { + case TRANSPORT_FAMILY_ALL: + /* + * this is already the default, + * do not break old remote helpers by setting "all" here + */ + break; + case TRANSPORT_FAMILY_IPV4: + set_helper_option(t, "family", "ipv4"); + break; + case TRANSPORT_FAMILY_IPV6: + set_helper_option(t, "family", "ipv6"); + break; + } } static int release_helper(struct transport *transport) diff --git a/transport.c b/transport.c index 67f366687c..ca3cfa4b00 100644 --- a/transport.c +++ b/transport.c @@ -17,133 +17,6 @@ #include "sha1-array.h" #include "sigchain.h" -/* rsync support */ - -/* - * We copy packed-refs and refs/ into a temporary file, then read the - * loose refs recursively (sorting whenever possible), and then inserting - * those packed refs that are not yet in the list (not validating, but - * assuming that the file is sorted). - * - * Appears refactoring this from refs.c is too cumbersome. - */ - -static int str_cmp(const void *a, const void *b) -{ - const char *s1 = a; - const char *s2 = b; - - return strcmp(s1, s2); -} - -/* path->buf + name_offset is expected to point to "refs/" */ - -static int read_loose_refs(struct strbuf *path, int name_offset, - struct ref **tail) -{ - DIR *dir = opendir(path->buf); - struct dirent *de; - struct { - char **entries; - int nr, alloc; - } list; - int i, pathlen; - - if (!dir) - return -1; - - memset (&list, 0, sizeof(list)); - - while ((de = readdir(dir))) { - if (is_dot_or_dotdot(de->d_name)) - continue; - ALLOC_GROW(list.entries, list.nr + 1, list.alloc); - list.entries[list.nr++] = xstrdup(de->d_name); - } - closedir(dir); - - /* sort the list */ - - qsort(list.entries, list.nr, sizeof(char *), str_cmp); - - pathlen = path->len; - strbuf_addch(path, '/'); - - for (i = 0; i < list.nr; i++, strbuf_setlen(path, pathlen + 1)) { - strbuf_addstr(path, list.entries[i]); - if (read_loose_refs(path, name_offset, tail)) { - int fd = open(path->buf, O_RDONLY); - char buffer[40]; - struct ref *next; - - if (fd < 0) - continue; - next = alloc_ref(path->buf + name_offset); - if (read_in_full(fd, buffer, 40) != 40 || - get_oid_hex(buffer, &next->old_oid)) { - close(fd); - free(next); - continue; - } - close(fd); - (*tail)->next = next; - *tail = next; - } - } - strbuf_setlen(path, pathlen); - - for (i = 0; i < list.nr; i++) - free(list.entries[i]); - free(list.entries); - - return 0; -} - -/* insert the packed refs for which no loose refs were found */ - -static void insert_packed_refs(const char *packed_refs, struct ref **list) -{ - FILE *f = fopen(packed_refs, "r"); - static char buffer[PATH_MAX]; - - if (!f) - return; - - for (;;) { - int cmp = 0; /* assigned before used */ - int len; - - if (!fgets(buffer, sizeof(buffer), f)) { - fclose(f); - return; - } - - if (!isxdigit(buffer[0])) - continue; - len = strlen(buffer); - if (len && buffer[len - 1] == '\n') - buffer[--len] = '\0'; - if (len < 41) - continue; - while ((*list)->next && - (cmp = strcmp(buffer + 41, - (*list)->next->name)) > 0) - list = &(*list)->next; - if (!(*list)->next || cmp < 0) { - struct ref *next = alloc_ref(buffer + 41); - buffer[40] = '\0'; - if (get_oid_hex(buffer, &next->old_oid)) { - warning ("invalid SHA-1: %s", buffer); - free(next); - continue; - } - next->next = (*list)->next; - (*list)->next = next; - list = &(*list)->next; - } - } -} - static void set_upstreams(struct transport *transport, struct ref *refs, int pretend) { @@ -192,205 +65,6 @@ static void set_upstreams(struct transport *transport, struct ref *refs, } } -static const char *rsync_url(const char *url) -{ - if (!starts_with(url, "rsync://")) - skip_prefix(url, "rsync:", &url); - return url; -} - -static struct ref *get_refs_via_rsync(struct transport *transport, int for_push) -{ - struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT; - struct ref dummy = {NULL}, *tail = &dummy; - struct child_process rsync = CHILD_PROCESS_INIT; - const char *args[5]; - int temp_dir_len; - - if (for_push) - return NULL; - - /* copy the refs to the temporary directory */ - - strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX")); - if (!mkdtemp(temp_dir.buf)) - die_errno ("Could not make temporary directory"); - temp_dir_len = temp_dir.len; - - strbuf_addstr(&buf, rsync_url(transport->url)); - strbuf_addstr(&buf, "/refs"); - - rsync.argv = args; - rsync.stdout_to_stderr = 1; - args[0] = "rsync"; - args[1] = (transport->verbose > 1) ? "-rv" : "-r"; - args[2] = buf.buf; - args[3] = temp_dir.buf; - args[4] = NULL; - - if (run_command(&rsync)) - die ("Could not run rsync to get refs"); - - strbuf_reset(&buf); - strbuf_addstr(&buf, rsync_url(transport->url)); - strbuf_addstr(&buf, "/packed-refs"); - - args[2] = buf.buf; - - if (run_command(&rsync)) - die ("Could not run rsync to get refs"); - - /* read the copied refs */ - - strbuf_addstr(&temp_dir, "/refs"); - read_loose_refs(&temp_dir, temp_dir_len + 1, &tail); - strbuf_setlen(&temp_dir, temp_dir_len); - - tail = &dummy; - strbuf_addstr(&temp_dir, "/packed-refs"); - insert_packed_refs(temp_dir.buf, &tail); - strbuf_setlen(&temp_dir, temp_dir_len); - - if (remove_dir_recursively(&temp_dir, 0)) - warning ("Error removing temporary directory %s.", - temp_dir.buf); - - strbuf_release(&buf); - strbuf_release(&temp_dir); - - return dummy.next; -} - -static int fetch_objs_via_rsync(struct transport *transport, - int nr_objs, struct ref **to_fetch) -{ - struct child_process rsync = CHILD_PROCESS_INIT; - - rsync.stdout_to_stderr = 1; - argv_array_push(&rsync.args, "rsync"); - argv_array_push(&rsync.args, (transport->verbose > 1) ? "-rv" : "-r"); - argv_array_push(&rsync.args, "--ignore-existing"); - argv_array_push(&rsync.args, "--exclude"); - argv_array_push(&rsync.args, "info"); - argv_array_pushf(&rsync.args, "%s/objects/", rsync_url(transport->url)); - argv_array_push(&rsync.args, get_object_directory()); - - /* NEEDSWORK: handle one level of alternates */ - return run_command(&rsync); -} - -static int write_one_ref(const char *name, const struct object_id *oid, - int flags, void *data) -{ - struct strbuf *buf = data; - int len = buf->len; - - /* when called via for_each_ref(), flags is non-zero */ - if (flags && !starts_with(name, "refs/heads/") && - !starts_with(name, "refs/tags/")) - return 0; - - strbuf_addstr(buf, name); - if (safe_create_leading_directories(buf->buf) || - write_file_gently(buf->buf, "%s", oid_to_hex(oid))) - return error("problems writing temporary file %s: %s", - buf->buf, strerror(errno)); - strbuf_setlen(buf, len); - return 0; -} - -static int write_refs_to_temp_dir(struct strbuf *temp_dir, - int refspec_nr, const char **refspec) -{ - int i; - - for (i = 0; i < refspec_nr; i++) { - struct object_id oid; - char *ref; - - if (dwim_ref(refspec[i], strlen(refspec[i]), oid.hash, &ref) != 1) - return error("Could not get ref %s", refspec[i]); - - if (write_one_ref(ref, &oid, 0, temp_dir)) { - free(ref); - return -1; - } - free(ref); - } - return 0; -} - -static int rsync_transport_push(struct transport *transport, - int refspec_nr, const char **refspec, int flags) -{ - struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT; - int result = 0, i; - struct child_process rsync = CHILD_PROCESS_INIT; - const char *args[10]; - - if (flags & TRANSPORT_PUSH_MIRROR) - return error("rsync transport does not support mirror mode"); - - /* first push the objects */ - - strbuf_addstr(&buf, rsync_url(transport->url)); - strbuf_addch(&buf, '/'); - - rsync.argv = args; - rsync.stdout_to_stderr = 1; - i = 0; - args[i++] = "rsync"; - args[i++] = "-a"; - if (flags & TRANSPORT_PUSH_DRY_RUN) - args[i++] = "--dry-run"; - if (transport->verbose > 1) - args[i++] = "-v"; - args[i++] = "--ignore-existing"; - args[i++] = "--exclude"; - args[i++] = "info"; - args[i++] = get_object_directory(); - args[i++] = buf.buf; - args[i++] = NULL; - - if (run_command(&rsync)) - return error("Could not push objects to %s", - rsync_url(transport->url)); - - /* copy the refs to the temporary directory; they could be packed. */ - - strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX")); - if (!mkdtemp(temp_dir.buf)) - die_errno ("Could not make temporary directory"); - strbuf_addch(&temp_dir, '/'); - - if (flags & TRANSPORT_PUSH_ALL) { - if (for_each_ref(write_one_ref, &temp_dir)) - return -1; - } else if (write_refs_to_temp_dir(&temp_dir, refspec_nr, refspec)) - return -1; - - i = 2; - if (flags & TRANSPORT_PUSH_DRY_RUN) - args[i++] = "--dry-run"; - if (!(flags & TRANSPORT_PUSH_FORCE)) - args[i++] = "--ignore-existing"; - args[i++] = temp_dir.buf; - args[i++] = rsync_url(transport->url); - args[i++] = NULL; - if (run_command(&rsync)) - result = error("Could not push to %s", - rsync_url(transport->url)); - - if (remove_dir_recursively(&temp_dir, 0)) - warning ("Could not remove temporary directory %s.", - temp_dir.buf); - - strbuf_release(&buf); - strbuf_release(&temp_dir); - - return result; -} - struct bundle_transport_data { int fd; struct bundle_header header; @@ -481,17 +155,24 @@ static int set_git_option(struct git_transport_options *opts, return 1; } -static int connect_setup(struct transport *transport, int for_push, int verbose) +static int connect_setup(struct transport *transport, int for_push) { struct git_transport_data *data = transport->data; + int flags = transport->verbose > 0 ? CONNECT_VERBOSE : 0; if (data->conn) return 0; + switch (transport->family) { + case TRANSPORT_FAMILY_ALL: break; + case TRANSPORT_FAMILY_IPV4: flags |= CONNECT_IPV4; break; + case TRANSPORT_FAMILY_IPV6: flags |= CONNECT_IPV6; break; + } + data->conn = git_connect(data->fd, transport->url, for_push ? data->options.receivepack : data->options.uploadpack, - verbose ? CONNECT_VERBOSE : 0); + flags); return 0; } @@ -501,7 +182,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus struct git_transport_data *data = transport->data; struct ref *refs; - connect_setup(transport, for_push, 0); + connect_setup(transport, for_push); get_remote_heads(data->fd[0], NULL, 0, &refs, for_push ? REF_NORMAL : 0, &data->extra_have, @@ -536,7 +217,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.update_shallow = data->options.update_shallow; if (!data->got_remote_heads) { - connect_setup(transport, 0, 0); + connect_setup(transport, 0); get_remote_heads(data->fd[0], NULL, 0, &refs_tmp, 0, NULL, &data->shallow); data->got_remote_heads = 1; @@ -812,7 +493,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re if (!data->got_remote_heads) { struct ref *tmp_refs; - connect_setup(transport, 1, 0); + connect_setup(transport, 1); get_remote_heads(data->fd[0], NULL, 0, &tmp_refs, REF_NORMAL, NULL, &data->shallow); @@ -984,11 +665,7 @@ struct transport *transport_get(struct remote *remote, const char *url) if (helper) { transport_helper_init(ret, helper); } else if (starts_with(url, "rsync:")) { - transport_check_allowed("rsync"); - ret->get_refs_list = get_refs_via_rsync; - ret->fetch = fetch_objs_via_rsync; - ret->push = rsync_transport_push; - ret->smart_options = NULL; + die("git-over-rsync is no longer supported"); } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); transport_check_allowed("file"); @@ -1306,7 +983,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs) * This condition shouldn't be met in a non-deepening fetch * (see builtin/fetch.c:quickfetch()). */ - heads = xmalloc(nr_refs * sizeof(*heads)); + ALLOC_ARRAY(heads, nr_refs); for (rm = refs; rm; rm = rm->next) heads[nr_heads++] = rm; } @@ -1350,7 +1027,7 @@ int transport_disconnect(struct transport *transport) */ char *transport_anonymize_url(const char *url) { - char *anon_url, *scheme_prefix, *anon_part; + char *scheme_prefix, *anon_part; size_t anon_len, prefix_len = 0; anon_part = strchr(url, '@'); @@ -1384,10 +1061,8 @@ char *transport_anonymize_url(const char *url) goto literal_copy; prefix_len = scheme_prefix - url + 3; } - anon_url = xcalloc(1, 1 + prefix_len + anon_len); - memcpy(anon_url, url, prefix_len); - memcpy(anon_url + prefix_len, anon_part, anon_len); - return anon_url; + return xstrfmt("%.*s%.*s", (int)prefix_len, url, + (int)anon_len, anon_part); literal_copy: return xstrdup(url); } diff --git a/transport.h b/transport.h index 8ebaaf2cae..c68140892c 100644 --- a/transport.h +++ b/transport.h @@ -18,6 +18,12 @@ struct git_transport_options { struct push_cas_option *cas; }; +enum transport_family { + TRANSPORT_FAMILY_ALL = 0, + TRANSPORT_FAMILY_IPV4, + TRANSPORT_FAMILY_IPV6 +}; + struct transport { struct remote *remote; const char *url; @@ -110,6 +116,8 @@ struct transport { * actually turns out to be smart. */ struct git_transport_options *smart_options; + + enum transport_family family; }; #define TRANSPORT_PUSH_ALL 1 diff --git a/tree-diff.c b/tree-diff.c index 290a1da4ce..4dda9a14ab 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -124,8 +124,8 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last, unsigned mode, const unsigned char *sha1) { struct combine_diff_path *p; - int len = base->len + pathlen; - int alloclen = combine_diff_path_size(nparent, len); + size_t len = st_add(base->len, pathlen); + size_t alloclen = combine_diff_path_size(nparent, len); /* if last->next is !NULL - it is a pre-allocated memory, we can reuse */ p = last->next; diff --git a/tree-walk.c b/tree-walk.c index 6dccd2d5dd..cd4bb2c38b 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -320,6 +320,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info) struct tree_desc_x *tx = xcalloc(n, sizeof(*tx)); struct strbuf base = STRBUF_INIT; int interesting = 1; + char *traverse_path; for (i = 0; i < n; i++) tx[i].d = t[i]; @@ -329,7 +330,11 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info) make_traverse_path(base.buf, info->prev, &info->name); base.buf[info->pathlen-1] = '/'; strbuf_setlen(&base, info->pathlen); + traverse_path = xstrndup(base.buf, info->pathlen); + } else { + traverse_path = xstrndup(info->name.path, info->pathlen); } + info->traverse_path = traverse_path; for (;;) { int trees_used; unsigned long mask, dirmask; @@ -411,6 +416,8 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info) for (i = 0; i < n; i++) free_extended_entry(tx + i); free(tx); + free(traverse_path); + info->traverse_path = NULL; strbuf_release(&base); return error; } diff --git a/tree-walk.h b/tree-walk.h index 3b2f7bf17d..174eb617df 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -59,6 +59,7 @@ enum follow_symlinks_result { enum follow_symlinks_result get_tree_entry_follow_symlinks(unsigned char *tree_sha1, const char *name, unsigned char *result, struct strbuf *result_path, unsigned *mode); struct traverse_info { + const char *traverse_path; struct traverse_info *prev; struct name_entry name; int pathlen; diff --git a/unimplemented.sh b/unimplemented.sh index 5252de4b25..fee21d24e8 100644 --- a/unimplemented.sh +++ b/unimplemented.sh @@ -1,4 +1,4 @@ #!/bin/sh -echo >&2 "fatal: git was built without support for `basename $0` (@@REASON@@)." +echo >&2 "fatal: git was built without support for $(basename $0) (@@REASON@@)." exit 128 diff --git a/unpack-trees.c b/unpack-trees.c index 8e2032f4e5..9f55cc28b9 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -498,13 +498,14 @@ static int traverse_trees_recursive(int n, unsigned long dirmask, * itself - the caller needs to do the final check for the cache * entry having more data at the end! */ -static int do_compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n) +static int do_compare_entry_piecewise(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n) { int len, pathlen, ce_len; const char *ce_name; if (info->prev) { - int cmp = do_compare_entry(ce, info->prev, &info->name); + int cmp = do_compare_entry_piecewise(ce, info->prev, + &info->name); if (cmp) return cmp; } @@ -522,6 +523,39 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_ return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode); } +static int do_compare_entry(const struct cache_entry *ce, + const struct traverse_info *info, + const struct name_entry *n) +{ + int len, pathlen, ce_len; + const char *ce_name; + int cmp; + + /* + * If we have not precomputed the traverse path, it is quicker + * to avoid doing so. But if we have precomputed it, + * it is quicker to use the precomputed version. + */ + if (!info->traverse_path) + return do_compare_entry_piecewise(ce, info, n); + + cmp = strncmp(ce->name, info->traverse_path, info->pathlen); + if (cmp) + return cmp; + + pathlen = info->pathlen; + ce_len = ce_namelen(ce); + + if (ce_len < pathlen) + return -1; + + ce_len -= pathlen; + ce_name = ce->name + pathlen; + + len = tree_entry_len(n); + return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode); +} + static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n) { int cmp = do_compare_entry(ce, info, n); @@ -661,8 +695,19 @@ static int find_cache_pos(struct traverse_info *info, ++o->cache_bottom; continue; } - if (!ce_in_traverse_path(ce, info)) + if (!ce_in_traverse_path(ce, info)) { + /* + * Check if we can skip future cache checks + * (because we're already past all possible + * entries in the traverse path). + */ + if (info->traverse_path) { + if (strncmp(ce->name, info->traverse_path, + info->pathlen) > 0) + break; + } continue; + } ce_name = ce->name + pfxlen; ce_slash = strchr(ce_name, '/'); if (ce_slash) diff --git a/userdiff.h b/userdiff.h index 4a7e78ffbc..2ef0ce5452 100644 --- a/userdiff.h +++ b/userdiff.h @@ -23,6 +23,10 @@ int userdiff_config(const char *k, const char *v); struct userdiff_driver *userdiff_find_by_name(const char *name); struct userdiff_driver *userdiff_find_by_path(const char *path); +/* + * Initialize any textconv-related fields in the driver and return it, or NULL + * if it does not have textconv enabled at all. + */ struct userdiff_driver *userdiff_get_textconv(struct userdiff_driver *driver); #endif /* USERDIFF */ @@ -220,7 +220,7 @@ int walker_targets_stdin(char ***target, const char ***write_ref) char *rf_one = NULL; char *tg_one; - if (strbuf_getline(&buf, stdin, '\n') == EOF) + if (strbuf_getline_lf(&buf, stdin) == EOF) break; tg_one = buf.buf; rf_one = strchr(tg_one, '\t'); diff --git a/worktree.c b/worktree.c index 981f810e80..6181a66f1e 100644 --- a/worktree.c +++ b/worktree.c @@ -176,10 +176,10 @@ struct worktree **get_worktrees(void) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; - if ((linked = get_linked_worktree(d->d_name))) { - ALLOC_GROW(list, counter + 1, alloc); - list[counter++] = linked; - } + if ((linked = get_linked_worktree(d->d_name))) { + ALLOC_GROW(list, counter + 1, alloc); + list[counter++] = linked; + } } closedir(dir); } @@ -152,6 +152,9 @@ void *xcalloc(size_t nmemb, size_t size) { void *ret; + if (unsigned_mult_overflows(nmemb, size)) + die("data too large to fit into virtual memory space"); + memory_limit_check(size * nmemb, 0); ret = calloc(nmemb, size); if (!ret && (!nmemb || !size)) @@ -236,8 +239,24 @@ ssize_t xread(int fd, void *buf, size_t len) len = MAX_IO_SIZE; while (1) { nr = read(fd, buf, len); - if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) - continue; + if (nr < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + struct pollfd pfd; + pfd.events = POLLIN; + pfd.fd = fd; + /* + * it is OK if this poll() failed; we + * want to leave this infinite loop + * only when read() returns with + * success, or an expected failure, + * which would be checked by the next + * call to read(2). + */ + poll(&pfd, 1, -1); + } + } return nr; } } @@ -375,6 +394,19 @@ FILE *xfdopen(int fd, const char *mode) return stream; } +FILE *fopen_for_writing(const char *path) +{ + FILE *ret = fopen(path, "w"); + + if (!ret && errno == EPERM) { + if (!unlink(path)) + ret = fopen(path, "w"); + else + errno = EPERM; + } + return ret; +} + int xmkstemp(char *template) { int fd; diff --git a/write_or_die.c b/write_or_die.c index e7afe7a295..49e80aa222 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -1,8 +1,12 @@ #include "cache.h" +#include "run-command.h" static void check_pipe(int err) { if (err == EPIPE) { + if (in_async()) + async_exit(141); + signal(SIGPIPE, SIG_DFL); raise(SIGPIPE); /* Should never happen, but just in case... */ diff --git a/wt-status.c b/wt-status.c index bba25960b4..ab4f80d6d0 100644 --- a/wt-status.c +++ b/wt-status.c @@ -988,7 +988,7 @@ static char *read_line_from_git_path(const char *filename) strbuf_release(&buf); return NULL; } - strbuf_getline(&buf, fp, '\n'); + strbuf_getline_lf(&buf, fp); if (!fclose(fp)) { return strbuf_detach(&buf, NULL); } else { @@ -1076,7 +1076,7 @@ static void read_rebase_todolist(const char *fname, struct string_list *lines) if (!f) die_errno("Could not open file %s for reading", git_path("%s", fname)); - while (!strbuf_getline(&line, f, '\n')) { + while (!strbuf_getline_lf(&line, f)) { if (line.len && line.buf[0] == comment_line_char) continue; strbuf_trim(&line); diff --git a/xdiff-interface.c b/xdiff-interface.c index cb67c1c42b..54236f24b9 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -265,7 +265,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags) for (i = 0, regs->nr = 1; value[i]; i++) if (value[i] == '\n') regs->nr++; - regs->array = xmalloc(regs->nr * sizeof(struct ff_reg)); + ALLOC_ARRAY(regs->array, regs->nr); for (i = 0; i < regs->nr; i++) { struct ff_reg *reg = regs->array + i; const char *ep = strchr(value, '\n'), *expression; diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index c0339919cc..4fb7e79410 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -42,7 +42,6 @@ extern "C" { #define XDF_IGNORE_BLANK_LINES (1 << 7) #define XDL_EMIT_FUNCNAMES (1 << 0) -#define XDL_EMIT_COMMON (1 << 1) #define XDL_EMIT_FUNCCONTEXT (1 << 2) #define XDL_MMB_READONLY (1 << 0) diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 4266ada23f..993724b11c 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -120,21 +120,6 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) return -1; } -static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, - xdemitconf_t const *xecfg) { - xdfile_t *xdf = &xe->xdf2; - const char *rchg = xdf->rchg; - long ix; - - for (ix = 0; ix < xdf->nrec; ix++) { - if (rchg[ix]) - continue; - if (xdl_emit_record(xdf, ix, "", ecb)) - return -1; - } - return 0; -} - struct func_line { long len; char buf[80]; @@ -170,9 +155,6 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, long funclineprev = -1; struct func_line func_line = { 0 }; - if (xecfg->flags & XDL_EMIT_COMMON) - return xdl_emit_common(xe, xscr, ecb, xecfg); - for (xch = xscr; xch; xch = xche->next) { xche = xdl_get_hunk(&xch, xecfg); if (!xch) diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c index 625198e058..f338ad6c75 100644 --- a/xdiff/xmerge.c +++ b/xdiff/xmerge.c @@ -109,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2, return 0; } -static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) { xrecord_t **recs; int size = 0; @@ -125,6 +125,12 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add if (add_nl) { i = recs[count - 1]->size; if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') { + if (needs_cr) { + if (dest) + dest[size] = '\r'; + size++; + } + if (dest) dest[size] = '\n'; size++; @@ -133,14 +139,58 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add return size; } -static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) +{ + return xdl_recs_copy_0(0, xe, i, count, needs_cr, add_nl, dest); +} + +static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) +{ + return xdl_recs_copy_0(1, xe, i, count, needs_cr, add_nl, dest); +} + +/* + * Returns 1 if the i'th line ends in CR/LF (if it is the last line and + * has no eol, the preceding line, if any), 0 if it ends in LF-only, and + * -1 if the line ending cannot be determined. + */ +static int is_eol_crlf(xdfile_t *file, int i) { - return xdl_recs_copy_0(0, xe, i, count, add_nl, dest); + long size; + + if (i < file->nrec - 1) + /* All lines before the last *must* end in LF */ + return (size = file->recs[i]->size) > 1 && + file->recs[i]->ptr[size - 2] == '\r'; + if (!file->nrec) + /* Cannot determine eol style from empty file */ + return -1; + if ((size = file->recs[i]->size) && + file->recs[i]->ptr[size - 1] == '\n') + /* Last line; ends in LF; Is it CR/LF? */ + return size > 1 && + file->recs[i]->ptr[size - 2] == '\r'; + if (!i) + /* The only line has no eol */ + return -1; + /* Determine eol from second-to-last line */ + return (size = file->recs[i - 1]->size) > 1 && + file->recs[i - 1]->ptr[size - 2] == '\r'; } -static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m) { - return xdl_recs_copy_0(1, xe, i, count, add_nl, dest); + int needs_cr; + + /* Match post-images' preceding, or first, lines' end-of-line style */ + needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0); + if (needs_cr) + needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0); + /* Look at pre-image's first line, unless we already settled on LF */ + if (needs_cr) + needs_cr = is_eol_crlf(&xe1->xdf1, 0); + /* If still undecided, use LF-only */ + return needs_cr < 0 ? 0 : needs_cr; } static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, @@ -152,16 +202,17 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, int marker1_size = (name1 ? strlen(name1) + 1 : 0); int marker2_size = (name2 ? strlen(name2) + 1 : 0); int marker3_size = (name3 ? strlen(name3) + 1 : 0); + int needs_cr = is_cr_needed(xe1, xe2, m); if (marker_size <= 0) marker_size = DEFAULT_CONFLICT_MARKER_SIZE; /* Before conflicting part */ - size += xdl_recs_copy(xe1, i, m->i1 - i, 0, + size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0, dest ? dest + size : NULL); if (!dest) { - size += marker_size + 1 + marker1_size; + size += marker_size + 1 + needs_cr + marker1_size; } else { memset(dest + size, '<', marker_size); size += marker_size; @@ -170,17 +221,19 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, memcpy(dest + size + 1, name1, marker1_size - 1); size += marker1_size; } + if (needs_cr) + dest[size++] = '\r'; dest[size++] = '\n'; } /* Postimage from side #1 */ - size += xdl_recs_copy(xe1, m->i1, m->chg1, 1, + size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1, dest ? dest + size : NULL); if (style == XDL_MERGE_DIFF3) { /* Shared preimage */ if (!dest) { - size += marker_size + 1 + marker3_size; + size += marker_size + 1 + needs_cr + marker3_size; } else { memset(dest + size, '|', marker_size); size += marker_size; @@ -189,25 +242,29 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, memcpy(dest + size + 1, name3, marker3_size - 1); size += marker3_size; } + if (needs_cr) + dest[size++] = '\r'; dest[size++] = '\n'; } - size += xdl_orig_copy(xe1, m->i0, m->chg0, 1, + size += xdl_orig_copy(xe1, m->i0, m->chg0, needs_cr, 1, dest ? dest + size : NULL); } if (!dest) { - size += marker_size + 1; + size += marker_size + 1 + needs_cr; } else { memset(dest + size, '=', marker_size); size += marker_size; + if (needs_cr) + dest[size++] = '\r'; dest[size++] = '\n'; } /* Postimage from side #2 */ - size += xdl_recs_copy(xe2, m->i2, m->chg2, 1, + size += xdl_recs_copy(xe2, m->i2, m->chg2, needs_cr, 1, dest ? dest + size : NULL); if (!dest) { - size += marker_size + 1 + marker2_size; + size += marker_size + 1 + needs_cr + marker2_size; } else { memset(dest + size, '>', marker_size); size += marker_size; @@ -216,6 +273,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, memcpy(dest + size + 1, name2, marker2_size - 1); size += marker2_size; } + if (needs_cr) + dest[size++] = '\r'; dest[size++] = '\n'; } return size; @@ -241,21 +300,24 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, marker_size); else if (m->mode & 3) { /* Before conflicting part */ - size += xdl_recs_copy(xe1, i, m->i1 - i, 0, + size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0, dest ? dest + size : NULL); /* Postimage from side #1 */ - if (m->mode & 1) - size += xdl_recs_copy(xe1, m->i1, m->chg1, (m->mode & 2), + if (m->mode & 1) { + int needs_cr = is_cr_needed(xe1, xe2, m); + + size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, (m->mode & 2), dest ? dest + size : NULL); + } /* Postimage from side #2 */ if (m->mode & 2) - size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, + size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, 0, dest ? dest + size : NULL); } else continue; i = m->i1 + m->chg1; } - size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, + size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, 0, dest ? dest + size : NULL); return size; } @@ -579,8 +641,11 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, result->ptr = NULL; result->size = 0; - if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0 || - xdl_do_diff(orig, mf2, xpp, &xe2) < 0) { + if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) { + return -1; + } + if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) { + xdl_free_env(&xe1); return -1; } if (xdl_change_compact(&xe1.xdf1, &xe1.xdf2, xpp->flags) < 0 || @@ -592,6 +657,8 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, if (xdl_change_compact(&xe2.xdf1, &xe2.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe2.xdf2, &xe2.xdf1, xpp->flags) < 0 || xdl_build_script(&xe2, &xscr2) < 0) { + xdl_free_script(xscr1); + xdl_free_env(&xe1); xdl_free_env(&xe2); return -1; } |