diff options
138 files changed, 7614 insertions, 2640 deletions
diff --git a/Documentation/RelNotes/2.3.6.txt b/Documentation/RelNotes/2.3.6.txt new file mode 100644 index 0000000000..432f770ef3 --- /dev/null +++ b/Documentation/RelNotes/2.3.6.txt @@ -0,0 +1,13 @@ +Git v2.3.6 Release Notes +======================== + +Fixes since v2.3.5 +------------------ + + * "diff-highlight" (in contrib/) used to show byte-by-byte + differences, which meant that multi-byte characters can be chopped + in the middle. It learned to pay attention to character boundaries + (assuming the UTF-8 payload). + +Also contains typofixes, documentation updates and trivial code +clean-ups. diff --git a/Documentation/RelNotes/2.3.7.txt b/Documentation/RelNotes/2.3.7.txt new file mode 100644 index 0000000000..fc95812cb3 --- /dev/null +++ b/Documentation/RelNotes/2.3.7.txt @@ -0,0 +1,21 @@ +Git v2.3.7 Release Notes +======================== + +Fixes since v2.3.6 +------------------ + + * An earlier update to the parser that disects a URL broke an + address, followed by a colon, followed by an empty string (instead + of the port number), e.g. ssh://example.com:/path/to/repo. + + * The completion script (in contrib/) contaminated global namespace + and clobbered on a shell variable $x. + + * The "git push --signed" protocol extension did not limit what the + "nonce" that is a server-chosen string can contain or how long it + can be, which was unnecessarily lax. Limit both the length and the + alphabet to a reasonably small space that can still have enough + entropy. + +Also contains typofixes, documentation updates and trivial code +clean-ups. diff --git a/Documentation/RelNotes/2.4.0.txt b/Documentation/RelNotes/2.4.0.txt index 0e70681828..cde64be535 100644 --- a/Documentation/RelNotes/2.4.0.txt +++ b/Documentation/RelNotes/2.4.0.txt @@ -6,19 +6,19 @@ Backward compatibility warning(s) This release has a few changes in the user-visible output from Porcelain commands. These are not meant to be parsed by scripts, but -the users still may want to be aware of the changes: +users still may want to be aware of the changes: - * Output from "git log --decorate" (and "%d" format specifier used in - the userformat "--format=<string>" parameter "git log" family of - command takes) used to list "HEAD" just like other tips of branch - names, separated with a comma in between. E.g. + * The output from "git log --decorate" (and, more generally, the "%d" + format specifier used in the "--format=<string>" parameter to the + "git log" family of commands) has changed. It used to list "HEAD" + just like other branches; e.g., $ git log --decorate -1 master commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD, master) ... - This release updates the output slightly when HEAD refers to the tip - of a branch whose name is also shown in the output. The above is + This release changes the output slightly when HEAD refers to a + branch whose name is also shown in the output. The above is now shown as: $ git log --decorate -1 master @@ -26,15 +26,15 @@ the users still may want to be aware of the changes: ... * The phrasing "git branch" uses to describe a detached HEAD has been - updated to match that of "git status": + updated to agree with the phrasing used by "git status": - - When the HEAD is at the same commit as it was originally + - When HEAD is at the same commit as when it was originally detached, they now both show "detached at <commit object name>". - - When the HEAD has moved since it was originally detached, - they now both show "detached from <commit object name>". + - When HEAD has moved since it was originally detached, they now + both show "detached from <commit object name>". - Earlier "git branch" always used "from" + Previously, "git branch" always used "from". Updates since v2.3 @@ -46,8 +46,9 @@ Ports platforms with smaller SSIZE_MAX, leading to read(2)/write(2) failures. - * We did not check the curl library version before using - CURLOPT_PROXYAUTH feature that may not exist. + * We did not check the curl library version before using the + CURLOPT_PROXYAUTH feature, which did not exist in older versions of + the library. * We now detect number of CPUs on older BSD-derived systems. @@ -66,99 +67,105 @@ UI, Workflows & Features * "git log --invert-grep --grep=WIP" will show only commits that do not have the string "WIP" in their messages. - * "git push" has been taught a "--atomic" option that makes push to - update more than one ref an "all-or-none" affair. + * "git push" has been taught an "--atomic" option that makes a push + that updates more than one ref an "all-or-none" affair. - * Extending the "push to deploy" added in 2.3, the behaviour of "git - push" when updating the branch that is checked out can now be - tweaked by push-to-checkout hook. + * Extending the "push to deploy" feature that was added in 2.3, the + behaviour of "git push" when updating the branch that is checked + out can now be tweaked by a "push-to-checkout" hook. - * Using environment variable LANGUAGE and friends on the client side, - HTTP-based transports now send Accept-Language when making requests. + * HTTP-based transports now send Accept-Language when making + requests. The languages to accept are inferred from environment + variables on the client side (LANGUAGE, etc). * "git send-email" used to accept a mistaken "y" (or "yes") as an - answer to "What encoding do you want to use [UTF-8]? " without - questioning. Now it asks for confirmation when the answer looks - too short to be a valid encoding name. + answer to "What encoding do you want to use [UTF-8]?" without + questioning. Now it asks for confirmation when the answer looks too + short to be a valid encoding name. * When "git apply --whitespace=fix" fixed whitespace errors in the common context lines, the command reports that it did so. - * "git status" now allows the "-v" to be given twice to show the - differences that are left in the working tree not to be committed. + * "git status" now allows the "-v" option to be given twice, in which + case it also shows the differences in the working tree that are not + staged to be committed. - * "git cherry-pick" used to clean-up the log message even when it is - merely replaying an existing commit. It now replays the message - verbatim unless you are editing the message of resulting commits. + * "git cherry-pick" used to clean up the log message even when it is + merely replaying an existing commit. It now replays the message + verbatim unless you are editing the message of the resulting + commit. * "git archive" can now be told to set the 'text' attribute in the resulting zip archive. - * Output from "git log --decorate" mentions HEAD when it points at a - tip of an branch differently from a detached HEAD. + * Output from "git log --decorate" now distinguishes between a + detached HEAD vs. a HEAD that points at a branch. - This is a potentially backward-incompatible change. + This is a potentially backward-incompatible change; see above for + more information. - * "git branch" on a detached HEAD always said "(detached from xyz)", - even when "git status" would report "detached at xyz". The HEAD is - actually at xyz and haven't been moved since it was detached in - such a case, but the user cannot read what the current value of - HEAD is when "detached from" is used. + * When HEAD was detached when at commit xyz and hasn't been moved + since it was detached, "git status" would report "detached at xyz" + whereas "git branch" would report "detached from xyz". Now the + output of "git branch" agrees with that of "git status". - * "git -C '' subcmd" refused to work in the current directory, unlike - "cd ''" which silently behaves as a no-op. + This is a potentially backward-incompatible change; see above for + more information. + + * "git -C '' subcmd" now works in the current directory (analogously + to "cd ''") rather than dying with an error message. (merge 6a536e2 kn/git-cd-to-empty later to maint). - * The versionsort.prerelease configuration variable can be used to - specify that v1.0-pre1 comes before v1.0. + * The versionsort.prereleaseSuffix configuration variable can be used + to specify that, for example, v1.0-pre1 comes before v1.0. * A new "push.followTags" configuration turns the "--follow-tags" option on by default for the "git push" command. - * "git log --graph --no-walk A B..." is a conflicting request that - asks nonsense; no-walk tells us show discrete points in the - history, while graph asks to draw connections between these - discrete points. Forbid the combination. + * "git log --graph --no-walk A B..." is a nonsensical combination of + options: "--no-walk" requests discrete points in the history, while + "--graph" asks to draw connections between these discrete points. + Forbid the use of these options together. * "git rev-list --bisect --first-parent" does not work (yet) and can - even cause SEGV; forbid it. "git log --bisect --first-parent" - would not be useful until "git bisect --first-parent" materializes, - so it is also forbidden for now. + even cause SEGV; forbid it. "git log --bisect --first-parent" would + not be useful until "git bisect --first-parent" materializes, so + also forbid it for now. Performance, Internal Implementation, Development Support etc. - * Implementation of N_() macro has been updated slightly to help us + * Slightly change the implementation of the N_() macro to help us detect mistakes. - * Implementation of "reflog expire" has been restructured to fit the - reflogs better with the recently updated ref API. + * Restructure the implementation of "reflog expire" to fit better + with the recently updated reference API. - * The transport-helper did not give transport options such as + * The transport-helper did not pass transport options such as verbosity, progress, cloning, etc. to import and export based helpers, like it did for fetch and push based helpers, robbing them - the chance to honor the wish of the end-users better. - - * The tests that wanted to see that file becomes unreadable after - running "chmod a-r file", and the tests that wanted to make sure it - is not run as root, we used "can we write into the / directory?" as - a cheap substitute, but on some platforms that is not a good - heuristics. The tests and their prerequisites have been updated to - check what they really require. + of the chance to honor the wish of the end-users better. + + * The tests that wanted to see that a file becomes unreadable after + running "chmod a-r file", and the tests that wanted to make sure + that they are not run as root, used "can we write into the / + directory?" as a cheap substitute. But on some platforms that is + not a good heuristic. The tests and their prerequisites have been + updated to check what they really require. (merge f400e51 jk/sanity later to maint). * Various issues around "reflog expire", e.g. using --updateref when expiring a reflog for a symbolic reference, have been corrected and/or made saner. - * The strbuf API was explained between the API documentation and in - the header file. Move missing bits to strbuf.h so that programmers - can check only one place for all necessary information. + * The documentation for the strbuf API had been split between the API + documentation and the header file. Consolidate the documentation in + strbuf.h. * The error handling functions and conventions are now documented in - the API manual. + the API manual (in api-error-handling.txt). - * Optimize attribute look-up, mostly useful in "git grep" on a + * Optimize gitattribute look-up, mostly useful in "git grep" on a project that does not use many attributes, by avoiding it when we (should) know that the attributes are not defined in the first place. @@ -170,26 +177,25 @@ Performance, Internal Implementation, Development Support etc. (merge 0b868f0 sb/hex-object-name-is-at-most-41-bytes-long later to maint). (merge 5d30851 dp/remove-duplicated-header-inclusion later to maint). - * Simplify the ref transaction API around how "the ref should be - pointing at this object" is specified. + * Simplify the ref transaction API for verifying that "the ref should + be pointing at this object". - * Code in "git daemon" to parse out and hold hostnames used in - request interpolation has been simplified. + * Simplify the code in "git daemon" that parses out and holds + hostnames used in request interpolation. - * "git push" codepath has been restructured to make it easier to add - new configuration bits. + * Restructure the "git push" codepath to make it easier to add new + configuration bits. - * The run-command interface was easy to abuse and make a pipe for us - to read from the process, wait for the process to finish and then - attempt to read its output, which is a pattern that lead to a - deadlock. Fix such uses by introducing a helper to do this - correctly (i.e. we need to read first and then wait the process to - finish) and also add code to prevent such abuse in the run-command - helper. + * The run-command interface made it easy to make a pipe for us to + read from a process, wait for the process to finish, and then + attempt to read its output. But this pattern can lead to deadlock. + So introduce a helper to do this correctly (i.e., first read, and + then wait the process to finish) and also add code to prevent such + abuse in the run-command helper. * People often forget to chain the commands in their test together - with &&, leaving a failure from an earlier command in the test go - unnoticed. The new GIT_TEST_CHAIN_LINT mechanism allows you to + with &&, letting a failure from an earlier command in the test go + unnoticed. The new GIT_TEST_CHAIN_LINT mechanism allows you to catch such a mistake more easily. @@ -208,33 +214,34 @@ notes for details). (merge a46442f jk/blame-commit-label later to maint). * "git rerere" (invoked internally from many mergy operations) did - not correctly signal errors when told to update the working tree - files and failed to do so for whatever reason. + not correctly signal errors when it attempted to update the working + tree files but failed for whatever reason. (merge 89ea903 jn/rerere-fail-on-auto-update-failure later to maint). * Setting diff.submodule to 'log' made "git format-patch" produce broken patches. (merge 339de50 dk/format-patch-ignore-diff-submodule later to maint). - * After attempting and failing a password-less authentication - (e.g. Kerberos), libcURL refuses to fall back to password based - Basic authentication without a bit of help/encouragement. + * After attempting and failing a password-less authentication (e.g., + Kerberos), libcURL refuses to fall back to password-based Basic + authentication without a bit of help/encouragement. (merge 4dbe664 bc/http-fallback-to-password-after-krb-fails later to maint). - * The "git push" documentation made the "--repo=<there>" option + * The "git push" documentation for the "--repo=<there>" option was easily misunderstood. (merge 57b92a7 mg/push-repo-option-doc later to maint). - * Code to read branch name from various files in .git/ directory - would have misbehaved if the code to write them left an empty file. + * Code to read a branch name from various files in the .git/ + directory would have overrun array limits if asked to read an empty + file. (merge 66ec904 jk/status-read-branch-name-fix later to maint). - * A misspelled conditional that is always true has been fixed. + * Remove a superfluous conditional that is always true. (merge 94ee8e2 jk/remote-curl-an-array-in-struct-cannot-be-null later to maint). - * The documentation incorrectly said that C(opy) and R(ename) are the - only ones that can be followed by the score number in the output in - the --raw format. + * The "git diff --raw" documentation incorrectly implied that C(opy) + and R(ename) are the only statuses that can be followed by a score + number. (merge ac1c2d9 jc/diff-format-doc later to maint). * A broken pack .idx file in the receiving repository prevented the @@ -251,34 +258,44 @@ notes for details). to the "log" command. (merge 3cab02d jc/doc-log-rev-list-options later to maint). - * "git apply --whitespace=fix" used to under-allocate the memory when - the fix resulted in a longer text than the original patch. + * "git apply --whitespace=fix" used to under-allocate memory when the + fix resulted in a longer text than the original patch. (merge 407a792 jc/apply-ws-fix-expands later to maint). * The interactive "show a list and let the user choose from it" - interface "add -i" used showed and prompted to the user even when - the candidate list was empty, against which the only "choice" the - user could have made was to choose nothing. + interface used by "git add -i" unnecessarily prompted the user even + when the candidate list was empty, against which the only "choice" + the user could have made was to choose nothing. (merge a9c4641 ak/add-i-empty-candidates later to maint). - * The insn sheet "git rebase -i" creates did not fully honor + * The todo list created by "git rebase -i" did not fully honor core.abbrev settings. (merge edb72d5 ks/rebase-i-abbrev later to maint). - * "git fetch" over a remote-helper that cannot respond to "list" - command could not fetch from a symbolic reference e.g. HEAD. + * "git fetch" over a remote-helper that cannot respond to the "list" + command could not fetch from a symbolic reference (e.g., HEAD). (merge 33cae54 mh/deref-symref-over-helper-transport later to maint). * "git push --signed" gave an incorrectly worded error message when the other side did not support the capability. - (merge 45917f0 jc/push-cert later to maint). - * We didn't format an integer that wouldn't fit in "int" but in - "uintmax_t" correctly. + * The "git push --signed" protocol extension did not limit what the + "nonce" (a server-chosen string) could contain nor how long it + could be, which was unnecessarily lax. Limit both the length and + the alphabet to a reasonably small space that can still have enough + entropy. + (merge afcb6ee jc/push-cert later to maint). + + * The completion script (in contrib/) clobbered the shell variable $x + in the global shell namespace. + (merge 852ff1c ma/bash-completion-leaking-x later to maint). + + * We incorrectly formatted a "uintmax_t" integer that doesn't fit in + "int". (merge d306f3d jk/decimal-width-for-uintmax later to maint). - * Reading configuration from a blob object, when it ends with a lone - CR, use to confuse the configuration parser. + * The configuration parser used to be confused when reading + configuration from a blob object that ends with a lone CR. (merge 1d0655c jk/config-no-ungetc-eof later to maint). * The pack bitmap support did not build with older versions of GCC. @@ -294,25 +311,21 @@ notes for details). (merge 1f985d6 ch/new-gpg-drops-rfc-1991 later to maint). * The credential helper for Windows (in contrib/) used to mishandle - a user name with an at-sign in it. + user names that contain an at-sign. (merge 13d261e av/wincred-with-at-in-username-fix later to maint). * "diff-highlight" (in contrib/) used to show byte-by-byte - differences, which meant that multi-byte characters can be chopped - in the middle. It learned to pay attention to character boundaries - (assuming the UTF-8 payload). + differences, which could cause multi-byte characters to be chopped + in the middle. It learned to pay attention to character boundaries + (assuming UTF-8). (merge 8d00662 jk/colors later to maint). - * "git merge --quiet" did not squelch messages from the underlying - merge-recursive strategy. - (merge 2bf15a3 jk/merge-quiet later to maint). - - * Longstanding configuration variable naming rules has been added to - the documentation. + * Document longstanding configuration variable naming rules in + CodingGuidelines. (merge 35840a3 jc/conf-var-doc later to maint). * An earlier workaround to squelch unhelpful deprecation warnings - from the compiler on Mac OSX unnecessarily set minimum required + from the compiler on OS X unnecessarily set a minimum required version of the OS, which the user might want to raise (or lower) for other reasons. (merge 88c03eb es/squelch-openssl-warnings-on-macosx later to maint). @@ -329,33 +342,36 @@ notes for details). "path/to/submodule". (merge 8196e72 ps/submodule-sanitize-path-upon-add later to maint). - * "git merge-file" did not work correctly in a subdirectory. + * "git merge-file" did not work correctly when invoked in a + subdirectory. (merge 204a8ff ab/merge-file-prefix later to maint). - * "git blame" died, trying to free an uninitialized piece of memory. + * "git blame" could die trying to free an uninitialized piece of + memory. (merge e600592 es/blame-commit-info-fix later to maint). * "git fast-import" used to crash when it could not close and - conclude the resulting packfile cleanly. + finalize the resulting packfile cleanly. (merge 5e915f3 jk/fast-import-die-nicely-fix later to maint). - * "update-index --refresh" used to leak when an entry cannot be - refreshed for whatever reason. + * "update-index --refresh" used to leak memory when an entry could + not be refreshed for whatever reason. (merge bc1c2ca sb/plug-leak-in-make-cache-entry later to maint). * The "interpolated-path" option of "git daemon" inserted any string - client declared on the "host=" capability request without checking. - Sanitize and limit %H and %CH to a saner and a valid DNS name. + the client declared on the "host=" capability request without + checking. Sanitize and limit %H and %CH to a saner and a valid DNS + name. (merge b485373 jk/daemon-interpolate later to maint). - * "git daemon" looked up the hostname even when "%CH" and "%IP" - interpolations are not requested, which was unnecessary. + * "git daemon" unnecessarily looked up the hostname even when "%CH" + and "%IP" interpolations were not requested. (merge dc8edc8 rs/daemon-interpolate later to maint). - * Even though we officially haven't dropped Perl 5.8 support, the - Getopt::Long package that came with it does not support "--no-" - prefix to negate a boolean option; manually add support to help - people with older Getopt::Long package. + * We relied on "--no-" prefix handling in Perl's Getopt::Long + package, even though that support didn't exist in Perl 5.8 (which + we still support). Manually add support to help people with older + Getopt::Long packages. (merge f471494 km/send-email-getopt-long-workarounds later to maint). * "git apply" was not very careful about reading from, removing, @@ -364,13 +380,13 @@ notes for details). replacement for GNU patch). (merge e0d201b jc/apply-beyond-symlink later to maint). - * A breakage to git-svn around v2.2 era that triggers premature - closing of FileHandle has been corrected. + * Correct a breakage in git-svn, introduced around the v2.2 era, that + can cause FileHandles to be closed prematurely. (merge e426311 ew/svn-maint-fixes later to maint). - * We did not parse username followed by literal IPv6 address in SSH - transport URLs, e.g. ssh://user@[2001:db8::1]:22/repo.git - correctly. + * We did not parse usernames followed by literal IPv6 addresses + correctly in SSH transport URLs; e.g., + ssh://user@[2001:db8::1]:22/repo.git. (merge 6b6c5f7 tb/connect-ipv6-parse-fix later to maint). * The configuration variable 'mailinfo.scissors' was hard to @@ -381,28 +397,26 @@ notes for details). submodule.*.update configuration was not clearly documented. (merge 5c31acf ms/submodule-update-config-doc later to maint). - * "git diff --shortstat --dirstat=changes" showed a dirstat based on - lines that was never asked by the end user in addition to the - dirstat that the user asked for. + * "git diff --shortstat" used together with "--dirstat=changes" or + "--dirstat=files" incorrectly output dirstat information twice. (merge ab27389 mk/diff-shortstat-dirstat-fix later to maint). - * "git remote add" mentioned "--tags" and "--no-tags" and was not - clear that fetch from the remote in the future will use the default - behaviour when neither is given to override it. + * The manpage for "git remote add" mentioned "--tags" and "--no-tags" + but did not explain what happens if neither option is provided. (merge aaba0ab mg/doc-remote-tags-or-not later to maint). - * Description given by "grep -h" for its --exclude-standard option - was phrased poorly. + * The description of "--exclude-standard option" in the output of + "git grep -h" was phrased poorly. (merge 77fdb8a nd/grep-exclude-standard-help-fix later to maint). - * "git rebase -i" recently started to include the number of - commits in the insn sheet to be processed, but on a platform - that prepends leading whitespaces to "wc -l" output, the numbers - are shown with extra whitespaces that aren't necessary. + * "git rebase -i" recently started to include the number of commits + in the todo list, but that output included extraneous whitespace on + a platform that prepends leading whitespaces to its "wc -l" output. (merge 2185d3b es/rebase-i-count-todo later to maint). - * The borrowed code in kwset API did not follow our usual convention - to use "unsigned char" to store values that range from 0-255. + * The borrowed code in the kwset API did not follow our usual + convention to use "unsigned char" to store values that range from + 0-255. (merge 189c860 bw/kwset-use-unsigned later to maint). * A corrupt input to "git diff -M" used to cause it to segfault. @@ -412,9 +426,8 @@ notes for details). (merge 3f88c1b mg/verify-commit later to maint). * "git imap-send" learned to optionally talk with an IMAP server via - libcURL; because there is no other option when Git is built with - NO_OPENSSL option, use that codepath by default under such - configuration. + libcURL. Because there is no other option when Git is built with + the NO_OPENSSL option, use libcURL by default in that case. (merge dcd01ea km/imap-send-libcurl-options later to maint). * "git log --decorate" did not reset colors correctly around the @@ -430,41 +443,47 @@ notes for details). transport. (merge 8ddf3ca jk/smart-http-hide-refs later to maint). - * "git tag -h" used to show the "--column" and "--sort" options - that are about listing in a wrong section. + * In the "git tag -h" output, move the documentation for the + "--column" and "--sort" options to the "Tag listing options" + section. (merge dd059c6 jk/tag-h-column-is-a-listing-option later to maint). * "git prune" used to largely ignore broken refs when deciding which - objects are still being used, which could spread an existing small - damage and make it a larger one. + objects are still being used, which could cause reference + corruption to lead to object loss. (merge ea56c4e jk/prune-with-corrupt-refs later to maint). - * The split-index mode introduced at v2.3.0-rc0~41 was broken in the + * The split-index mode introduced in v2.3.0-rc0~41 was broken in the codepath to protect us against a broken reimplementation of Git that writes an invalid index with duplicated index entries, etc. (merge 03f15a7 tg/fix-check-order-with-split-index later to maint). - * "git fetch" that fetches a commit using the allow-tip-sha1-in-want - extension could have failed to fetch all the requested refs. + * "git fetch", when fetching a commit using the + allow-tip-sha1-in-want extension, could have failed to fetch all of + the requested refs. (merge 32d0462 jk/fetch-pack later to maint). * An failure early in the "git clone" that started creating the - working tree and repository could have resulted in some directories - and files left without getting cleaned up. + working tree and repository could have resulted in the failure to + clean up some directories and files. (merge 16eff6c jk/cleanup-failed-clone later to maint). * Recommend format-patch and send-email for those who want to submit patches to this project. (merge b25c469 jc/submitting-patches-mention-send-email later to maint). - * Even though "git grep --quiet" is run merely to ask for the exit - status, we spawned the pager regardless. Stop doing that. + * Do not spawn the pager when "git grep" is run with "--quiet". (merge c2048f0 ws/grep-quiet-no-pager later to maint). * The prompt script (in contrib/) did not show the untracked sign when working in a subdirectory without any untracked files. (merge 9bdc517 ct/prompt-untracked-fix later to maint). + * An earlier update to the URL parser broke an address that contains + a colon but an empty string for the port number, like + ssh://example.com:/path/to/repo. + (merge 6b6c5f7 tb/connect-ipv6-parse-fix later to maint). + * Code cleanups and documentation updates. (merge 2ce63e9 rs/simple-cleanups later to maint). (merge 33baa69 rj/no-xopen-source-for-cygwin later to maint). @@ -491,3 +510,5 @@ notes for details). (merge 6c3b2af jg/cguide-we-cannot-count later to maint). (merge 2b8bd44 jk/pack-corruption-post-mortem later to maint). (merge 9585cb8 jn/doc-fast-import-no-16-octopus-limit later to maint). + (merge 5dcd1b1 ps/grep-help-all-callback-arg later to maint). + (merge f1f4c84 va/fix-git-p4-tests later to maint). diff --git a/Documentation/RelNotes/2.5.0.txt b/Documentation/RelNotes/2.5.0.txt new file mode 100644 index 0000000000..24992b2879 --- /dev/null +++ b/Documentation/RelNotes/2.5.0.txt @@ -0,0 +1,86 @@ +Git 2.5 Release Notes +===================== + +Updates since v2.4 +------------------ + +Ports + + +UI, Workflows & Features + + * "git p4" now detects the filetype (e.g. binary) correctly even when + the files are opened exclusively. + + * "git show-branch --topics HEAD" (with no other arguments) did not + do anything interesting. Instead, contrast the given revision + against all the local branches by default. + + +Performance, Internal Implementation, Development Support etc. + + * "unsigned char [20]" used thoughout the code to represent object + names are being converted into a semi-opaque "struct object_id". + This effort is expected to interfere with other topics in flight, + but hopefully will give us one extra level of abstraction in the + end, when completed. + + +Also contains various documentation updates and code clean-ups. + + +Fixes since v2.4 +---------------- + +Unless otherwise noted, all the fixes since v2.4 in the maintenance +track are contained in this release (see the maintenance releases' +notes for details). + + * We avoid setting core.worktree when the repository location is the + ".git" directory directly at the top level of the working tree, but + the code misdetected the case in which the working tree is at the + root level of the filesystem (which arguably is a silly thing to + do, but still valid). + (merge 84ccad8 jk/init-core-worktree-at-root later to maint). + + * "git commit --date=now" or anything that relies on approxidate lost + the daylight-saving-time offset. + (merge f6e6362 jc/epochtime-wo-tz later to maint). + + * Access to objects in repositories that borrow from another one on a + slow NFS server unnecessarily got more expensive due to recent code + becoming more cautious in a naive way not to lose objects to pruning. + (merge ee1c6c3 jk/prune-mtime later to maint). + + * The codepaths that read .gitignore and .gitattributes files have been + taught that these files encoded in UTF-8 may have UTF-8 BOM marker at + the beginning; this makes it in line with what we do for configuration + files already. + (merge 27547e5 cn/bom-in-gitignore later to maint). + + * a few helper scripts in the test suite did not report errors + correcty. + (merge de248e9 ep/fix-test-lib-functions-report later to maint). + + * The default $HOME/.gitconfig file created upon "git config --global" + that edits it had incorrectly spelled user.name and user.email + entries in it. + (merge 7e11052 oh/fix-config-default-user-name-section later to maint). + + * "git cat-file bl $blob" failed to barf even though there is no + object type that is "bl". + (merge b7994af jk/type-from-string-gently later to maint). + + * The usual "git diff" when seeing a file turning into a directory + showed a patchset to remove the file and create all files in the + directory, but "git diff --no-index" simply refused to work. Also, + when asked to compare a file and a directory, imitate POSIX "diff" + and compare the file with the file with the same name in the + directory, instead of refusing to run. + (merge 0615173 jc/diff-no-index-d-f later to maint). + + * Code cleanups and documentation updates. + (merge 0269f96 mm/usage-log-l-can-take-regex later to maint). + (merge 64f2589 nd/t1509-chroot-test later to maint). + (merge f86a374 sb/test-bitmap-free-at-end later to maint). + (merge 05bfc7d sb/line-log-plug-pairdiff-leak later to maint). diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index b299b59023..a09969ba08 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -10,7 +10,7 @@ Include additional statistics at the end of blame output. -L <start>,<end>:: --L :<regex>:: +-L :<funcname>:: Annotate only the given line range. May be specified multiple times. Overlapping ranges are allowed. + diff --git a/Documentation/config.txt b/Documentation/config.txt index 2e5ceaf719..948b8b0e5c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -453,6 +453,8 @@ false), while all other repositories are assumed to be bare (bare core.worktree:: Set the path to the root of the working tree. + If GIT_COMMON_DIR environment variable is set, core.worktree + is ignored and not used for determining the root of working tree. This can be overridden by the GIT_WORK_TREE environment variable and the '--work-tree' command-line option. The value can be an absolute path or relative to the path to @@ -1274,6 +1276,13 @@ gc.pruneExpire:: "now" may be used to disable this grace period and always prune unreachable objects immediately. +gc.pruneWorktreesExpire:: + When 'git gc' is run, it will call + 'prune --worktrees --expire 3.months.ago'. + Override the grace period with this config variable. The value + "now" may be used to disable the grace period and prune + $GIT_DIR/worktrees immediately. + gc.reflogExpire:: gc.<pattern>.reflogExpire:: 'git reflog expire' removes reflog entries older than diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index d5041082e8..d263a5652f 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -225,6 +225,19 @@ This means that you can use `git checkout -p` to selectively discard edits from your current working tree. See the ``Interactive Mode'' section of linkgit:git-add[1] to learn how to operate the `--patch` mode. +--to=<path>:: + Check out a branch in a separate working directory at + `<path>`. A new working directory is linked to the current + repository, sharing everything except working directory + specific files such as HEAD, index... See "MULTIPLE WORKING + TREES" section for more information. + +--ignore-other-worktrees:: + `git checkout` refuses when the wanted ref is already checked + out by another worktree. This option makes it check the ref + out anyway. In other words, the ref can be held by more than one + worktree. + <branch>:: Branch to checkout; if it refers to a branch (i.e., a name that, when prepended with "refs/heads/", is a valid ref), then that @@ -388,6 +401,71 @@ $ git reflog -2 HEAD # or $ git log -g -2 HEAD ------------ +MULTIPLE WORKING TREES +---------------------- + +A git repository can support multiple working trees, allowing you to check +out more than one branch at a time. With `git checkout --to` a new working +tree is associated with the repository. This new working tree is called a +"linked working tree" as opposed to the "main working tree" prepared by "git +init" or "git clone". A repository has one main working tree (if it's not a +bare repository) and zero or more linked working trees. + +Each linked working tree has a private sub-directory in the repository's +$GIT_DIR/worktrees directory. The private sub-directory's name is usually +the base name of the linked working tree's path, possibly appended with a +number to make it unique. For example, when `$GIT_DIR=/path/main/.git` the +command `git checkout --to /path/other/test-next next` creates the linked +working tree in `/path/other/test-next` and also creates a +`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1` +if `test-next` is already taken). + +Within a linked working tree, $GIT_DIR is set to point to this private +directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and +$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR +(e.g. `/path/main/.git`). These settings are made in a `.git` file located at +the top directory of the linked working tree. + +Path resolution via `git rev-parse --git-path` uses either +$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the +linked working tree `git rev-parse --git-path HEAD` returns +`/path/main/.git/worktrees/test-next/HEAD` (not +`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git +rev-parse --git-path refs/heads/master` uses +$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`, +since refs are shared across all working trees. + +See linkgit:gitrepository-layout[5] for more information. The rule of +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. + +When you are done with a linked working tree you can simply delete it. +The working tree's entry in the repository's $GIT_DIR/worktrees +directory will eventually be removed automatically (see +`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run +`git prune --worktrees` in the main or any linked working tree to +clean up any stale entries in $GIT_DIR/worktrees. + +If you move a linked working directory 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 directory +(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees +so that it does not get automatically removed. + +To prevent a $GIT_DIR/worktrees entry from 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 +'locked' to the entry's directory. The file contains the reason in +plain text. For example, if a linked working tree's `.git` file points +to `/path/main/.git/worktrees/test-next` then a file named +`/path/main/.git/worktrees/test-next/locked` will prevent the +`test-next` entry from being pruned. See +linkgit:gitrepository-layout[5] for details. + +Multiple checkout support for submodules is incomplete. It is NOT +recommended to make multiple checkouts of a superproject. + EXAMPLES -------- diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.txt index bc97071e76..e3c8f276b1 100644 --- a/Documentation/git-credential-store.txt +++ b/Documentation/git-credential-store.txt @@ -31,10 +31,41 @@ OPTIONS --file=<path>:: - Use `<path>` to store credentials. The file will have its + Use `<path>` to lookup and store credentials. The file will have its filesystem permissions set to prevent other users on the system from reading it, but will not be encrypted or otherwise - protected. Defaults to `~/.git-credentials`. + protected. If not specified, credentials will be searched for from + `~/.git-credentials` and `$XDG_CONFIG_HOME/git/credentials`, and + credentials will be written to `~/.git-credentials` if it exists, or + `$XDG_CONFIG_HOME/git/credentials` if it exists and the former does + not. See also <<FILES>>. + +[[FILES]] +FILES +----- + +If not set explicitly with '--file', there are two files where +git-credential-store will search for credentials in order of precedence: + +~/.git-credentials:: + User-specific credentials file. + +$XDG_CONFIG_HOME/git/credentials:: + Second user-specific credentials file. If '$XDG_CONFIG_HOME' is not set + or empty, `$HOME/.config/git/credentials` will be used. Any credentials + stored in this file will not be used if `~/.git-credentials` has a + matching credential as well. It is a good idea not to create this file + if you sometimes use older versions of Git that do not support it. + +For credential lookups, the files are read in the order given above, with the +first matching credential found taking precedence over credentials found in +files further down the list. + +Credential storage will by default write to the first existing file in the +list. If none of these files exist, `~/.git-credentials` will be created and +written to. + +When erasing credentials, matching credentials will be erased from all files. EXAMPLES -------- diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index 18bc716a0c..5692945a0b 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -62,9 +62,9 @@ produced by `--stat`, etc. output by allowing them to allocate space in advance. -L <start>,<end>:<file>:: --L :<regex>:<file>:: +-L :<funcname>:<file>:: Trace the evolution of the line range given by "<start>,<end>" - (or the funcname regex <regex>) within the <file>. You may + (or the function name regex <funcname>) within the <file>. You may not give any pathspec limiters. This is currently limited to a walk starting from a single revision, i.e., you may only give zero or one positive revision arguments. diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt index a1664b9f68..82aa5d6073 100644 --- a/Documentation/git-p4.txt +++ b/Documentation/git-p4.txt @@ -225,9 +225,20 @@ Git repository: they can find the p4 branches in refs/heads. --max-changes <n>:: - Limit the number of imported changes to 'n'. Useful to - limit the amount of history when using the '@all' p4 revision - specifier. + Import at most 'n' changes, rather than the entire range of + changes included in the given revision specifier. A typical + usage would be use '@all' as the revision specifier, but then + to use '--max-changes 1000' to import only the last 1000 + revisions rather than the entire revision history. + +--changes-block-size <n>:: + The internal block size to use when converting a revision + specifier such as '@all' into a list of specific change + numbers. Instead of using a single call to 'p4 changes' to + find the full list of changes for the conversion, there are a + sequence of calls to 'p4 changes -m', each of which requests + one block of changes of the given size. The default block size + is 500, which should usually be suitable. --keep-path:: The mapping of file names from the p4 depot path to Git, by diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt index 7a493c80f7..1cf3bed4ab 100644 --- a/Documentation/git-prune.txt +++ b/Documentation/git-prune.txt @@ -48,6 +48,9 @@ OPTIONS --expire <time>:: Only expire loose objects older than <time>. +--worktrees:: + Prune dead working tree information in $GIT_DIR/worktrees. + <head>...:: In addition to objects reachable from any of our references, keep objects diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index d6de42f74e..97fc703f4c 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -216,6 +216,9 @@ If `$GIT_DIR` is not defined and the current directory is not detected to lie in a Git repository or work tree print a message to stderr and exit with nonzero status. +--git-common-dir:: + Show `$GIT_COMMON_DIR` if defined, else `$GIT_DIR`. + --is-inside-git-dir:: When the current working directory is below the repository directory print "true", otherwise "false". @@ -233,6 +236,13 @@ print a message to stderr and exit with nonzero status. repository. If <path> is a gitfile then the resolved path to the real repository is printed. +--git-path <path>:: + Resolve "$GIT_DIR/<path>" and takes other path relocation + variables such as $GIT_OBJECT_DIRECTORY, + $GIT_INDEX_FILE... into account. For example, if + $GIT_OBJECT_DIRECTORY is set to /foo/bar then "git rev-parse + --git-path objects/abc" returns /foo/bar/abc. + --show-cdup:: When the command is invoked from a subdirectory, show the path of the top-level directory relative to the current diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index b3319f7c2a..5221f950ce 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -41,6 +41,14 @@ OPTIONS --long:: Give the output in the long-format. This is the default. +-v:: +--verbose:: + In addition to the names of files that have been changed, also + show the textual changes that are staged to be committed + (i.e., like the output of `git diff --cached`). If `-v` is specified + twice, then also show the changes in the working tree that + have not yet been staged (i.e., like the output of `git diff`). + -u[<mode>]:: --untracked-files[=<mode>]:: Show untracked files. diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index bfba4ef078..f5b267e1e3 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -98,10 +98,13 @@ OPTIONS --sort=<type>:: Sort in a specific order. Supported type is "refname" (lexicographic order), "version:refname" or "v:refname" (tag - names are treated as versions). Prepend "-" to reverse sort - order. When this option is not given, the sort order defaults to the - value configured for the 'tag.sort' variable if it exists, or - lexicographic order otherwise. See linkgit:git-config[1]. + names are treated as versions). The "version:refname" sort + order can also be affected by the + "versionsort.prereleaseSuffix" configuration variable. Prepend + "-" to reverse sort order. When this option is not given, the + sort order defaults to the value configured for the 'tag.sort' + variable if it exists, or lexicographic order otherwise. See + linkgit:git-config[1]. --column[=<options>]:: --no-column:: diff --git a/Documentation/git.txt b/Documentation/git.txt index 59e8335055..2789da4f8f 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,16 @@ 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.3.5/git.html[documentation for release 2.3.5] +* link:v2.4.0/git.html[documentation for release 2.4] * release notes for + link:RelNotes/2.4.0.txt[2.4]. + +* link:v2.3.7/git.html[documentation for release 2.3.7] + +* release notes for + link:RelNotes/2.3.7.txt[2.3.7], + link:RelNotes/2.3.6.txt[2.3.6], link:RelNotes/2.3.5.txt[2.3.5], link:RelNotes/2.3.4.txt[2.3.4], link:RelNotes/2.3.3.txt[2.3.3], @@ -826,6 +833,15 @@ Git so take care if using Cogito etc. an explicit repository directory set via 'GIT_DIR' or on the command line. +'GIT_COMMON_DIR':: + If this variable is set to a path, non-worktree files that are + normally in $GIT_DIR will be taken from this path + instead. Worktree-specific files such as HEAD or index are + taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and + the section 'MULTIPLE CHECKOUT MODE' in linkgit:checkout[1] + details. This variable has lower precedence than other path + variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY... + Git Commits ~~~~~~~~~~~ 'GIT_AUTHOR_NAME':: diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt index 7ae50aa26a..6ade002176 100644 --- a/Documentation/gitk.txt +++ b/Documentation/gitk.txt @@ -99,10 +99,10 @@ linkgit:git-rev-list[1] for a complete list. detailed explanation.) -L<start>,<end>:<file>:: --L:<regex>:<file>:: +-L:<funcname>:<file>:: Trace the evolution of the line range given by "<start>,<end>" - (or the funcname regex <regex>) within the <file>. You may + (or the function name regex <funcname>) within the <file>. You may not give any pathspec limiters. This is currently limited to a walk starting from a single revision, i.e., you may only give zero or one positive revision arguments. diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt index 79653f3134..7173b38830 100644 --- a/Documentation/gitrepository-layout.txt +++ b/Documentation/gitrepository-layout.txt @@ -46,6 +46,9 @@ of incomplete object store is not suitable to be published for use with dumb transports but otherwise is OK as long as `objects/info/alternates` points at the object stores it borrows from. ++ +This directory is ignored if $GIT_COMMON_DIR is set and +"$GIT_COMMON_DIR/objects" will be used instead. objects/[0-9a-f][0-9a-f]:: A newly created object is stored in its own file. @@ -92,7 +95,8 @@ refs:: References are stored in subdirectories of this directory. The 'git prune' command knows to preserve objects reachable from refs found in this directory and - its subdirectories. + its subdirectories. This directory is ignored if $GIT_COMMON_DIR + is set and "$GIT_COMMON_DIR/refs" will be used instead. refs/heads/`name`:: records tip-of-the-tree commit objects of branch `name` @@ -114,7 +118,8 @@ refs/replace/`<obj-sha1>`:: packed-refs:: records the same information as refs/heads/, refs/tags/, and friends record in a more efficient way. See - linkgit:git-pack-refs[1]. + linkgit:git-pack-refs[1]. This file is ignored if $GIT_COMMON_DIR + is set and "$GIT_COMMON_DIR/packed-refs" will be used instead. HEAD:: A symref (see glossary) to the `refs/heads/` namespace @@ -133,6 +138,11 @@ being a symref to point at the current branch. Such a state is often called 'detached HEAD.' See linkgit:git-checkout[1] for details. +config:: + Repository specific configuration file. This file is ignored + if $GIT_COMMON_DIR is set and "$GIT_COMMON_DIR/config" will be + used instead. + branches:: A slightly deprecated way to store shorthands to be used to specify a URL to 'git fetch', 'git pull' and 'git push'. @@ -140,7 +150,10 @@ branches:: 'name' can be given to these commands in place of 'repository' argument. See the REMOTES section in linkgit:git-fetch[1] for details. This mechanism is legacy - and not likely to be found in modern repositories. + and not likely to be found in modern repositories. This + directory is ignored if $GIT_COMMON_DIR is set and + "$GIT_COMMON_DIR/branches" will be used instead. + hooks:: Hooks are customization scripts used by various Git @@ -149,7 +162,9 @@ hooks:: default. To enable, the `.sample` suffix has to be removed from the filename by renaming. Read linkgit:githooks[5] for more details about - each hook. + each hook. This directory is ignored if $GIT_COMMON_DIR is set + and "$GIT_COMMON_DIR/hooks" will be used instead. + index:: The current index file for the repository. It is @@ -161,7 +176,8 @@ sharedindex.<SHA-1>:: info:: Additional information about the repository is recorded - in this directory. + in this directory. This directory is ignored if $GIT_COMMON_DIR + is set and "$GIT_COMMON_DIR/index" will be used instead. info/refs:: This file helps dumb transports discover what refs are @@ -201,12 +217,15 @@ remotes:: when interacting with remote repositories via 'git fetch', 'git pull' and 'git push' commands. See the REMOTES section in linkgit:git-fetch[1] for details. This mechanism is legacy - and not likely to be found in modern repositories. + and not likely to be found in modern repositories. This + directory is ignored if $GIT_COMMON_DIR is set and + "$GIT_COMMON_DIR/remotes" will be used instead. logs:: - Records of changes made to refs are stored in this - directory. See linkgit:git-update-ref[1] - for more information. + Records of changes made to refs are stored in this directory. + See linkgit:git-update-ref[1] for more information. This + directory is ignored if $GIT_COMMON_DIR is set and + "$GIT_COMMON_DIR/logs" will be used instead. logs/refs/heads/`name`:: Records all changes made to the branch tip named `name`. @@ -217,11 +236,46 @@ logs/refs/tags/`name`:: shallow:: This is similar to `info/grafts` but is internally used and maintained by shallow clone mechanism. See `--depth` - option to linkgit:git-clone[1] and linkgit:git-fetch[1]. + option to linkgit:git-clone[1] and linkgit:git-fetch[1]. This + file is ignored if $GIT_COMMON_DIR is set and + "$GIT_COMMON_DIR/shallow" will be used instead. + +commondir:: + If this file exists, $GIT_COMMON_DIR (see linkgit:git[1]) will + be set to the path specified in this file if it is not + explicitly set. If the specified path is relative, it is + relative to $GIT_DIR. The repository with commondir is + incomplete without the repository pointed by "commondir". modules:: Contains the git-repositories of the submodules. +worktrees:: + Contains worktree specific information of linked + checkouts. Each subdirectory contains the worktree-related + part of a linked checkout. This directory is ignored if + $GIT_COMMON_DIR is set and "$GIT_COMMON_DIR/worktrees" will be + used instead. + +worktrees/<id>/gitdir:: + A text file containing the absolute path back to the .git file + that points to here. This is used to check if the linked + repository has been manually removed and there is no need to + keep this directory any more. mtime of this file should be + updated every time the linked repository is accessed. + +worktrees/<id>/locked:: + If this file exists, the linked repository may be on a + portable device and not available. It does not mean that the + linked repository is gone and `worktrees/<id>` could be + removed. The file's content contains a reason string on why + the repository is locked. + +worktrees/<id>/link:: + If this file exists, it is a hard link to the linked .git + file. It is used to detect if the linked repository is + manually removed. + SEE ALSO -------- linkgit:git-init[1], diff --git a/Documentation/line-range-format.txt b/Documentation/line-range-format.txt index d7f26039ca..829676ff98 100644 --- a/Documentation/line-range-format.txt +++ b/Documentation/line-range-format.txt @@ -22,8 +22,9 @@ This is only valid for <end> and will specify a number of lines before or after the line given by <start>. + -If ``:<regex>'' is given in place of <start> and <end>, it denotes the range -from the first funcname line that matches <regex>, up to the next -funcname line. ``:<regex>'' searches from the end of the previous `-L` range, -if any, otherwise from the start of file. -``^:<regex>'' searches from the start of file. +If ``:<funcname>'' is given in place of <start> and <end>, it is a +regular expression that denotes the range from the first funcname line +that matches <funcname>, up to the next funcname line. ``:<funcname>'' +searches from the end of the previous `-L` range, if any, otherwise +from the start of file. ``^:<funcname>'' searches from the start of +file. diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index f620ee4e1c..77ac439234 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -59,8 +59,8 @@ endif::git-rev-list[] matches any of the given patterns are chosen (but see `--all-match`). + -When `--show-notes` is in effect, the message from the notes as -if it is part of the log message. +When `--show-notes` is in effect, the message from the notes is +matched as if it were part of the log message. --all-match:: Limit the commits output to ones that match all given `--grep`, diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index aa8519ca28..bfb715d3c8 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.4.0-rc2 +DEF_VER=v2.4.0.GIT LF=' ' @@ -359,6 +359,8 @@ all:: # compiler is detected to support it. # # Define HAVE_BSD_SYSCTL if your platform has a BSD-compatible sysctl function. +# +# Define HAVE_GETDELIM if your system has the getdelim() function. GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -1437,6 +1439,10 @@ ifdef HAVE_BSD_SYSCTL BASIC_CFLAGS += -DHAVE_BSD_SYSCTL endif +ifdef HAVE_GETDELIM + BASIC_CFLAGS += -DHAVE_GETDELIM +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK = NoThanks endif @@ -1 +1 @@ -Documentation/RelNotes/2.4.0.txt
\ No newline at end of file +Documentation/RelNotes/2.5.0.txt
\ No newline at end of file diff --git a/archive-zip.c b/archive-zip.c index ffb3535e93..ae3d67f9d3 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -448,12 +448,12 @@ static void write_zip_trailer(const unsigned char *sha1) copy_le16(trailer.entries, zip_dir_entries); copy_le32(trailer.size, zip_dir_offset); copy_le32(trailer.offset, zip_offset); - copy_le16(trailer.comment_length, sha1 ? 40 : 0); + copy_le16(trailer.comment_length, sha1 ? GIT_SHA1_HEXSZ : 0); write_or_die(1, zip_dir, zip_dir_offset); write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); if (sha1) - write_or_die(1, sha1_to_hex(sha1), 40); + write_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ); } static void dos_time(time_t *time, int *dos_date, int *dos_time) @@ -101,7 +101,7 @@ static void setup_archive_check(struct git_attr_check *check) struct directory { struct directory *up; - unsigned char sha1[20]; + struct object_id oid; int baselen, len; unsigned mode; int stage; @@ -177,7 +177,7 @@ static void queue_directory(const unsigned char *sha1, d->stage = stage; c->bottom = d; d->len = sprintf(d->path, "%.*s%s/", (int)base->len, base->buf, filename); - hashcpy(d->sha1, sha1); + hashcpy(d->oid.hash, sha1); } static int write_directory(struct archiver_context *c) @@ -191,7 +191,7 @@ static int write_directory(struct archiver_context *c) d->path[d->len - 1] = '\0'; /* no trailing slash */ ret = write_directory(c) || - write_archive_entry(d->sha1, d->path, d->baselen, + write_archive_entry(d->oid.hash, d->path, d->baselen, d->path + d->baselen, d->mode, d->stage, c) != READ_TREE_RECURSIVE; free(d); @@ -354,7 +354,7 @@ static void parse_treeish_arg(const char **argv, time_t archive_time; struct tree *tree; const struct commit *commit; - unsigned char sha1[20]; + struct object_id oid; /* Remotes are only allowed to fetch actual refs */ if (remote && !remote_allow_unreachable) { @@ -362,15 +362,15 @@ static void parse_treeish_arg(const char **argv, const char *colon = strchrnul(name, ':'); int refnamelen = colon - name; - if (!dwim_ref(name, refnamelen, sha1, &ref)) + if (!dwim_ref(name, refnamelen, oid.hash, &ref)) die("no such ref: %.*s", refnamelen, name); free(ref); } - if (get_sha1(name, sha1)) + if (get_sha1(name, oid.hash)) die("Not a valid object name"); - commit = lookup_commit_reference_gently(sha1, 1); + commit = lookup_commit_reference_gently(oid.hash, 1); if (commit) { commit_sha1 = commit->object.sha1; archive_time = commit->date; @@ -379,21 +379,21 @@ static void parse_treeish_arg(const char **argv, archive_time = time(NULL); } - tree = parse_tree_indirect(sha1); + tree = parse_tree_indirect(oid.hash); if (tree == NULL) die("not a tree object"); if (prefix) { - unsigned char tree_sha1[20]; + struct object_id tree_oid; unsigned int mode; int err; err = get_tree_entry(tree->object.sha1, prefix, - tree_sha1, &mode); + tree_oid.hash, &mode); if (err || !S_ISDIR(mode)) die("current working directory is untracked"); - tree = parse_tree_indirect(tree_sha1); + tree = parse_tree_indirect(tree_oid.hash); } ar_args->tree = tree; ar_args->commit_sha1 = commit_sha1; @@ -12,6 +12,7 @@ #include "exec_cmd.h" #include "attr.h" #include "dir.h" +#include "utf8.h" const char git_attr__true[] = "(builtin)true"; const char git_attr__false[] = "\0(builtin)false"; @@ -379,8 +380,12 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok) return NULL; } res = xcalloc(1, sizeof(*res)); - while (fgets(buf, sizeof(buf), fp)) - handle_attr_line(res, buf, path, ++lineno, macro_ok); + while (fgets(buf, sizeof(buf), fp)) { + char *bufp = buf; + if (!lineno) + skip_utf8_bom(&bufp, strlen(bufp)); + handle_attr_line(res, bufp, path, ++lineno, macro_ok); + } fclose(fp); return res; } @@ -15,7 +15,7 @@ static struct sha1_array good_revs; static struct sha1_array skipped_revs; -static unsigned char *current_bad_sha1; +static struct object_id *current_bad_oid; static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL}; static const char *argv_show_branch[] = {"show-branch", NULL, NULL}; @@ -404,8 +404,8 @@ static int register_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { if (!strcmp(refname, "bad")) { - current_bad_sha1 = xmalloc(20); - hashcpy(current_bad_sha1, sha1); + current_bad_oid = xmalloc(sizeof(*current_bad_oid)); + hashcpy(current_bad_oid->hash, sha1); } else if (starts_with(refname, "good-")) { sha1_array_append(&good_revs, sha1); } else if (starts_with(refname, "skip-")) { @@ -564,7 +564,7 @@ static struct commit_list *skip_away(struct commit_list *list, int count) for (i = 0; cur; cur = cur->next, i++) { if (i == index) { - if (hashcmp(cur->item->object.sha1, current_bad_sha1)) + if (hashcmp(cur->item->object.sha1, current_bad_oid->hash)) return cur; if (previous) return previous; @@ -607,7 +607,7 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix, /* rev_argv.argv[0] will be ignored by setup_revisions */ argv_array_push(&rev_argv, "bisect_rev_setup"); - argv_array_pushf(&rev_argv, bad_format, sha1_to_hex(current_bad_sha1)); + argv_array_pushf(&rev_argv, bad_format, oid_to_hex(current_bad_oid)); for (i = 0; i < good_revs.nr; i++) argv_array_pushf(&rev_argv, good_format, sha1_to_hex(good_revs.sha1[i])); @@ -628,7 +628,7 @@ static void bisect_common(struct rev_info *revs) } static void exit_if_skipped_commits(struct commit_list *tried, - const unsigned char *bad) + const struct object_id *bad) { if (!tried) return; @@ -637,12 +637,12 @@ static void exit_if_skipped_commits(struct commit_list *tried, "The first bad commit could be any of:\n"); print_commit_list(tried, "%s\n", "%s\n"); if (bad) - printf("%s\n", sha1_to_hex(bad)); + printf("%s\n", oid_to_hex(bad)); printf("We cannot bisect more!\n"); exit(2); } -static int is_expected_rev(const unsigned char *sha1) +static int is_expected_rev(const struct object_id *oid) { const char *filename = git_path("BISECT_EXPECTED_REV"); struct stat st; @@ -658,7 +658,7 @@ static int is_expected_rev(const unsigned char *sha1) return 0; if (strbuf_getline(&str, fp, '\n') != EOF) - res = !strcmp(str.buf, sha1_to_hex(sha1)); + res = !strcmp(str.buf, oid_to_hex(oid)); strbuf_release(&str); fclose(fp); @@ -719,7 +719,7 @@ static struct commit **get_bad_and_good_commits(int *rev_nr) struct commit **rev = xmalloc(len * sizeof(*rev)); int i, n = 0; - rev[n++] = get_commit_reference(current_bad_sha1); + 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]); *rev_nr = n; @@ -729,8 +729,8 @@ static struct commit **get_bad_and_good_commits(int *rev_nr) static void handle_bad_merge_base(void) { - if (is_expected_rev(current_bad_sha1)) { - char *bad_hex = sha1_to_hex(current_bad_sha1); + if (is_expected_rev(current_bad_oid)) { + char *bad_hex = oid_to_hex(current_bad_oid); char *good_hex = join_sha1_array_hex(&good_revs, ' '); fprintf(stderr, "The merge base %s is bad.\n" @@ -750,7 +750,7 @@ static void handle_bad_merge_base(void) static void handle_skipped_merge_base(const unsigned char *mb) { char *mb_hex = sha1_to_hex(mb); - char *bad_hex = sha1_to_hex(current_bad_sha1); + char *bad_hex = sha1_to_hex(current_bad_oid->hash); char *good_hex = join_sha1_array_hex(&good_revs, ' '); warning("the merge base between %s and [%s] " @@ -781,7 +781,7 @@ static void check_merge_bases(int no_checkout) for (; result; result = result->next) { const unsigned char *mb = result->item->object.sha1; - if (!hashcmp(mb, current_bad_sha1)) { + if (!hashcmp(mb, current_bad_oid->hash)) { handle_bad_merge_base(); } else if (0 <= sha1_array_lookup(&good_revs, mb)) { continue; @@ -838,7 +838,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout) struct stat st; int fd; - if (!current_bad_sha1) + if (!current_bad_oid) die("a bad revision is needed"); /* Check if file BISECT_ANCESTORS_OK exists. */ @@ -903,7 +903,7 @@ int bisect_next_all(const char *prefix, int no_checkout) struct commit_list *tried; int reaches = 0, all = 0, nr, steps; const unsigned char *bisect_rev; - char bisect_rev_hex[41]; + char bisect_rev_hex[GIT_SHA1_HEXSZ + 1]; if (read_bisect_refs()) die("reading bisect refs failed"); @@ -927,7 +927,7 @@ int bisect_next_all(const char *prefix, int no_checkout) exit_if_skipped_commits(tried, NULL); printf("%s was both good and bad\n", - sha1_to_hex(current_bad_sha1)); + oid_to_hex(current_bad_oid)); exit(1); } @@ -938,10 +938,10 @@ int bisect_next_all(const char *prefix, int no_checkout) } bisect_rev = revs.commits->item->object.sha1; - memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), 41); + memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1); - if (!hashcmp(bisect_rev, current_bad_sha1)) { - exit_if_skipped_commits(tried, current_bad_sha1); + if (!hashcmp(bisect_rev, current_bad_oid->hash)) { + exit_if_skipped_commits(tried, current_bad_oid); printf("%s is the first bad commit\n", bisect_rev_hex); show_diff_tree(prefix, revs.commits->item); /* This means the bisection process succeeded. */ diff --git a/builtin/apply.c b/builtin/apply.c index 0769b09287..146be97a1a 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -208,7 +208,7 @@ struct patch { struct patch *next; /* three-way fallback result */ - unsigned char threeway_stage[3][20]; + struct object_id threeway_stage[3]; }; static void free_fragment_list(struct fragment *list) @@ -3426,11 +3426,11 @@ static int try_threeway(struct image *image, struct patch *patch, if (status) { patch->conflicted_threeway = 1; if (patch->is_new) - hashclr(patch->threeway_stage[0]); + oidclr(&patch->threeway_stage[0]); else - hashcpy(patch->threeway_stage[0], pre_sha1); - hashcpy(patch->threeway_stage[1], our_sha1); - hashcpy(patch->threeway_stage[2], post_sha1); + hashcpy(patch->threeway_stage[0].hash, pre_sha1); + hashcpy(patch->threeway_stage[1].hash, our_sha1); + hashcpy(patch->threeway_stage[2].hash, post_sha1); fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name); } else { fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name); @@ -4186,14 +4186,14 @@ static void add_conflicted_stages_file(struct patch *patch) remove_file_from_cache(patch->new_name); for (stage = 1; stage < 4; stage++) { - if (is_null_sha1(patch->threeway_stage[stage - 1])) + if (is_null_oid(&patch->threeway_stage[stage - 1])) continue; ce = xcalloc(1, ce_size); memcpy(ce->name, patch->new_name, namelen); ce->ce_mode = create_ce_mode(mode); ce->ce_flags = create_ce_flags(stage); ce->ce_namelen = namelen; - hashcpy(ce->sha1, patch->threeway_stage[stage - 1]); + hashcpy(ce->sha1, patch->threeway_stage[stage - 1].hash); if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) die(_("unable to add cache entry for %s"), patch->new_name); } diff --git a/builtin/branch.c b/builtin/branch.c index 1d150378e9..258fe2ff9b 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -771,7 +771,6 @@ static const char edit_description[] = "BRANCH_DESCRIPTION"; static int edit_branch_description(const char *branch_name) { - FILE *fp; int status; struct strbuf buf = STRBUF_INIT; struct strbuf name = STRBUF_INIT; @@ -784,8 +783,7 @@ static int edit_branch_description(const char *branch_name) " %s\n" "Lines starting with '%c' will be stripped.\n", branch_name, comment_line_char); - fp = fopen(git_path(edit_description), "w"); - if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) { + if (write_file(git_path(edit_description), 0, "%s", buf.buf)) { strbuf_release(&buf); return error(_("could not write branch description template: %s"), strerror(errno)); diff --git a/builtin/checkout.c b/builtin/checkout.c index 3e141fc149..2f92328db4 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -20,6 +20,7 @@ #include "resolve-undo.h" #include "submodule.h" #include "argv-array.h" +#include "sigchain.h" static const char * const checkout_usage[] = { N_("git checkout [<options>] <branch>"), @@ -36,6 +37,7 @@ struct checkout_opts { int writeout_stage; int overwrite_ignore; int ignore_skipworktree; + int ignore_other_worktrees; const char *new_branch; const char *new_branch_force; @@ -48,6 +50,10 @@ struct checkout_opts { const char *prefix; struct pathspec pathspec; struct tree *source_tree; + + const char *new_worktree; + const char **saved_argv; + int new_worktree_mode; }; static int post_checkout_hook(struct commit *old, struct commit *new, @@ -267,6 +273,9 @@ static int checkout_paths(const struct checkout_opts *opts, die(_("Cannot update paths and switch to branch '%s' at the same time."), opts->new_branch); + if (opts->new_worktree) + die(_("'%s' cannot be used with updating paths"), "--to"); + if (opts->patch_mode) return run_add_interactive(revision, "--patch=checkout", &opts->pathspec); @@ -441,6 +450,11 @@ struct branch_info { const char *name; /* The short name used */ const char *path; /* The full name of a real branch */ struct commit *commit; /* The named commit */ + /* + * if not null the branch is detached because it's already + * checked out in this checkout + */ + char *checkout; }; static void setup_branch_path(struct branch_info *branch) @@ -502,7 +516,7 @@ static int merge_working_tree(const struct checkout_opts *opts, topts.dir->flags |= DIR_SHOW_IGNORED; setup_standard_excludes(topts.dir); } - tree = parse_tree_indirect(old->commit ? + tree = parse_tree_indirect(old->commit && !opts->new_worktree_mode ? old->commit->object.sha1 : EMPTY_TREE_SHA1_BIN); init_tree_desc(&trees[0], tree->buffer, tree->size); @@ -606,18 +620,21 @@ static void update_refs_for_switch(const struct checkout_opts *opts, if (opts->new_orphan_branch) { if (opts->new_branch_log && !log_all_ref_updates) { int temp; - char log_file[PATH_MAX]; - char *ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch); + struct strbuf log_file = STRBUF_INIT; + int ret; + const char *ref_name; + ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch); temp = log_all_ref_updates; log_all_ref_updates = 1; - if (log_ref_setup(ref_name, log_file, sizeof(log_file))) { + ret = log_ref_setup(ref_name, &log_file); + log_all_ref_updates = temp; + strbuf_release(&log_file); + if (ret) { fprintf(stderr, _("Can not do reflog for '%s'\n"), opts->new_orphan_branch); - log_all_ref_updates = temp; return; } - log_all_ref_updates = temp; } } else @@ -743,10 +760,17 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs) if (advice_detached_head) fprintf(stderr, - _( + Q_( + /* The singular version */ + "If you want to keep it by creating a new branch, " + "this may be a good time\nto do so with:\n\n" + " git branch <new-branch-name> %s\n\n", + /* The plural version */ "If you want to keep them by creating a new branch, " "this may be a good time\nto do so with:\n\n" - " git branch <new-branch-name> %s\n\n"), + " git branch <new-branch-name> %s\n\n", + /* Give ngettext() the count */ + lost), find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV)); } @@ -815,7 +839,8 @@ static int switch_branches(const struct checkout_opts *opts, return ret; } - if (!opts->quiet && !old.path && old.commit && new->commit != old.commit) + if (!opts->quiet && !old.path && old.commit && + new->commit != old.commit && !opts->new_worktree_mode) orphaned_commit_warning(old.commit, new->commit); update_refs_for_switch(opts, &old, new); @@ -825,6 +850,138 @@ static int switch_branches(const struct checkout_opts *opts, return ret || writeout_error; } +static char *junk_work_tree; +static char *junk_git_dir; +static int is_junk; +static pid_t junk_pid; + +static void remove_junk(void) +{ + struct strbuf sb = STRBUF_INIT; + if (!is_junk || getpid() != junk_pid) + return; + if (junk_git_dir) { + strbuf_addstr(&sb, junk_git_dir); + remove_dir_recursively(&sb, 0); + strbuf_reset(&sb); + } + if (junk_work_tree) { + strbuf_addstr(&sb, junk_work_tree); + remove_dir_recursively(&sb, 0); + } + strbuf_release(&sb); +} + +static void remove_junk_on_signal(int signo) +{ + remove_junk(); + sigchain_pop(signo); + raise(signo); +} + +static int prepare_linked_checkout(const struct checkout_opts *opts, + struct branch_info *new) +{ + struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT; + struct strbuf sb = STRBUF_INIT; + const char *path = opts->new_worktree, *name; + struct stat st; + struct child_process cp; + int counter = 0, len, ret; + + if (!new->commit) + die(_("no branch specified")); + if (file_exists(path) && !is_empty_dir(path)) + die(_("'%s' already exists"), path); + + len = strlen(path); + while (len && is_dir_sep(path[len - 1])) + len--; + + for (name = path + len - 1; name > path; name--) + if (is_dir_sep(*name)) { + name++; + break; + } + strbuf_addstr(&sb_repo, + git_path("worktrees/%.*s", (int)(path + len - name), name)); + len = sb_repo.len; + if (safe_create_leading_directories_const(sb_repo.buf)) + die_errno(_("could not create leading directories of '%s'"), + sb_repo.buf); + while (!stat(sb_repo.buf, &st)) { + counter++; + strbuf_setlen(&sb_repo, len); + strbuf_addf(&sb_repo, "%d", counter); + } + name = strrchr(sb_repo.buf, '/') + 1; + + junk_pid = getpid(); + atexit(remove_junk); + sigchain_push_common(remove_junk_on_signal); + + if (mkdir(sb_repo.buf, 0777)) + die_errno(_("could not create directory of '%s'"), sb_repo.buf); + junk_git_dir = xstrdup(sb_repo.buf); + is_junk = 1; + + /* + * lock the incomplete repo so prune won't delete it, unlock + * after the preparation is over. + */ + strbuf_addf(&sb, "%s/locked", sb_repo.buf); + write_file(sb.buf, 1, "initializing\n"); + + strbuf_addf(&sb_git, "%s/.git", path); + if (safe_create_leading_directories_const(sb_git.buf)) + die_errno(_("could not create leading directories of '%s'"), + sb_git.buf); + junk_work_tree = xstrdup(path); + + strbuf_reset(&sb); + strbuf_addf(&sb, "%s/gitdir", sb_repo.buf); + write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf)); + write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n", + real_path(get_git_common_dir()), name); + /* + * This is to keep resolve_ref() happy. We need a valid HEAD + * or is_git_directory() will reject the directory. Any valid + * value would do because this value will be ignored and + * replaced at the next (real) checkout. + */ + strbuf_reset(&sb); + strbuf_addf(&sb, "%s/HEAD", sb_repo.buf); + write_file(sb.buf, 1, "%s\n", sha1_to_hex(new->commit->object.sha1)); + strbuf_reset(&sb); + strbuf_addf(&sb, "%s/commondir", sb_repo.buf); + write_file(sb.buf, 1, "../..\n"); + + if (!opts->quiet) + fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name); + + setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1); + setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1); + setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1); + memset(&cp, 0, sizeof(cp)); + cp.git_cmd = 1; + cp.argv = opts->saved_argv; + ret = run_command(&cp); + if (!ret) { + is_junk = 0; + free(junk_work_tree); + free(junk_git_dir); + junk_work_tree = NULL; + junk_git_dir = NULL; + } + strbuf_reset(&sb); + strbuf_addf(&sb, "%s/locked", sb_repo.buf); + unlink_or_warn(sb.buf); + strbuf_release(&sb); + strbuf_release(&sb_repo); + strbuf_release(&sb_git); + return ret; +} + static int git_checkout_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "diff.ignoresubmodules")) { @@ -880,13 +1037,80 @@ static const char *unique_tracking_name(const char *name, unsigned char *sha1) return NULL; } +static void check_linked_checkout(struct branch_info *new, const char *id) +{ + struct strbuf sb = STRBUF_INIT; + struct strbuf path = STRBUF_INIT; + struct strbuf gitdir = STRBUF_INIT; + const char *start, *end; + + if (id) + strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id); + else + strbuf_addf(&path, "%s/HEAD", get_git_common_dir()); + + if (strbuf_read_file(&sb, path.buf, 0) < 0 || + !skip_prefix(sb.buf, "ref:", &start)) + goto done; + while (isspace(*start)) + start++; + end = start; + while (*end && !isspace(*end)) + end++; + if (strncmp(start, new->path, end - start) || new->path[end - start] != '\0') + goto done; + if (id) { + strbuf_reset(&path); + strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id); + if (strbuf_read_file(&gitdir, path.buf, 0) <= 0) + goto done; + strbuf_rtrim(&gitdir); + } else + strbuf_addstr(&gitdir, get_git_common_dir()); + die(_("'%s' is already checked out at '%s'"), new->name, gitdir.buf); +done: + strbuf_release(&path); + strbuf_release(&sb); + strbuf_release(&gitdir); +} + +static void check_linked_checkouts(struct branch_info *new) +{ + struct strbuf path = STRBUF_INIT; + DIR *dir; + struct dirent *d; + + strbuf_addf(&path, "%s/worktrees", get_git_common_dir()); + if ((dir = opendir(path.buf)) == NULL) { + strbuf_release(&path); + return; + } + + /* + * $GIT_COMMON_DIR/HEAD is practically outside + * $GIT_DIR so resolve_ref_unsafe() won't work (it + * uses git_path). Parse the ref ourselves. + */ + check_linked_checkout(new, NULL); + + while ((d = readdir(dir)) != NULL) { + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + check_linked_checkout(new, d->d_name); + } + strbuf_release(&path); + closedir(dir); +} + static int parse_branchname_arg(int argc, const char **argv, int dwim_new_local_branch_ok, struct branch_info *new, - struct tree **source_tree, - unsigned char rev[20], - const char **new_branch) + struct checkout_opts *opts, + unsigned char rev[20]) { + struct tree **source_tree = &opts->source_tree; + const char **new_branch = &opts->new_branch; + int force_detach = opts->force_detach; int argcount = 0; unsigned char branch_rev[20]; const char *arg; @@ -1007,6 +1231,17 @@ static int parse_branchname_arg(int argc, const char **argv, else new->path = NULL; /* not an existing branch */ + if (new->path && !force_detach && !*new_branch) { + unsigned char sha1[20]; + int flag; + char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag); + if (head_ref && + (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) && + !opts->ignore_other_worktrees) + check_linked_checkouts(new); + free(head_ref); + } + new->commit = lookup_commit_reference_gently(rev, 1); if (!new->commit) { /* not a commit */ @@ -1086,6 +1321,9 @@ static int checkout_branch(struct checkout_opts *opts, die(_("Cannot switch branch to a non-commit '%s'"), new->name); + if (opts->new_worktree) + return prepare_linked_checkout(opts, new); + if (!new->commit && opts->new_branch) { unsigned char rev[20]; int flag; @@ -1128,6 +1366,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) N_("do not limit pathspecs to sparse entries only")), OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch, N_("second guess 'git checkout <no-such-branch>'")), + OPT_FILENAME(0, "to", &opts.new_worktree, + N_("check a branch out in a separate working directory")), + OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees, + N_("do not check if another worktree is holding the given ref")), OPT_END(), }; @@ -1136,6 +1378,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.overwrite_ignore = 1; opts.prefix = prefix; + opts.saved_argv = xmalloc(sizeof(const char *) * (argc + 2)); + memcpy(opts.saved_argv, argv, sizeof(const char *) * (argc + 1)); + gitmodules_config(); git_config(git_checkout_config, &opts); @@ -1144,6 +1389,14 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, checkout_usage, PARSE_OPT_KEEP_DASHDASH); + /* recursive execution from checkout_new_worktree() */ + opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL; + if (opts.new_worktree_mode) + opts.new_worktree = NULL; + + if (!opts.new_worktree) + setup_work_tree(); + if (conflict_style) { opts.merge = 1; /* implied */ git_xmerge_config("merge.conflictstyle", conflict_style, NULL); @@ -1197,8 +1450,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.track == BRANCH_TRACK_UNSPECIFIED && !opts.new_branch; int n = parse_branchname_arg(argc, argv, dwim_ok, - &new, &opts.source_tree, - rev, &opts.new_branch); + &new, &opts, rev); argv += n; argc -= n; } diff --git a/builtin/clone.c b/builtin/clone.c index 53a2e5af35..166a645e2d 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -293,16 +293,17 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst, struct strbuf line = STRBUF_INIT; while (strbuf_getline(&line, in, '\n') != EOF) { - char *abs_path, abs_buf[PATH_MAX]; + char *abs_path; if (!line.len || line.buf[0] == '#') continue; if (is_absolute_path(line.buf)) { add_to_alternates_file(line.buf); continue; } - abs_path = mkpath("%s/objects/%s", src_repo, line.buf); - normalize_path_copy(abs_buf, abs_path); - add_to_alternates_file(abs_buf); + abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf); + normalize_path_copy(abs_path, abs_path); + add_to_alternates_file(abs_path); + free(abs_path); } strbuf_release(&line); fclose(in); diff --git a/builtin/commit.c b/builtin/commit.c index da79ac4bc7..310674cfd0 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -170,7 +170,7 @@ static void determine_whence(struct wt_status *s) whence = FROM_MERGE; else if (file_exists(git_path("CHERRY_PICK_HEAD"))) { whence = FROM_CHERRY_PICK; - if (file_exists(git_path("sequencer"))) + if (file_exists(git_path(SEQ_DIR))) sequencer_in_use = 1; } else diff --git a/builtin/config.c b/builtin/config.c index d32c5327e5..bfd3016e83 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -455,9 +455,9 @@ static char *default_user_config(void) struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, _("# This is Git's per-user configuration file.\n" - "[core]\n" + "[user]\n" "# Please adapt and uncomment the following lines:\n" - "# user = %s\n" + "# name = %s\n" "# email = %s\n"), ident_default_name(), ident_default_email()); diff --git a/builtin/count-objects.c b/builtin/count-objects.c index e47ef0b1af..ad0c79954a 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -70,8 +70,10 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) /* we do not take arguments other than flags for now */ if (argc) usage_with_options(count_objects_usage, opts); - if (verbose) + if (verbose) { report_garbage = real_report_garbage; + report_linked_checkout_garbage(); + } for_each_loose_file_in_objdir(get_object_directory(), count_loose, count_cruft, NULL, NULL); diff --git a/builtin/fetch.c b/builtin/fetch.c index f9512652cf..7910419c93 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -588,7 +588,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, struct strbuf note = STRBUF_INIT; const char *what, *kind; struct ref *rm; - char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD"); + char *url; + const char *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD"); int want_status; fp = fopen(filename, "a"); @@ -822,7 +823,7 @@ static void check_not_current_branch(struct ref *ref_map) static int truncate_fetch_head(void) { - char *filename = git_path("FETCH_HEAD"); + const char *filename = git_path("FETCH_HEAD"); FILE *fp = fopen(filename, "w"); if (!fp) diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 1d962dc569..05f4c26311 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -223,16 +223,14 @@ static void add_branch_desc(struct strbuf *out, const char *name) #define util_as_integral(elem) ((intptr_t)((elem)->util)) -static void record_person(int which, struct string_list *people, - struct commit *commit) +static void record_person_from_buf(int which, struct string_list *people, + const char *buffer) { - const char *buffer; char *name_buf, *name, *name_end; struct string_list_item *elem; const char *field; field = (which == 'a') ? "\nauthor " : "\ncommitter "; - buffer = get_commit_buffer(commit, NULL); name = strstr(buffer, field); if (!name) return; @@ -245,7 +243,6 @@ static void record_person(int which, struct string_list *people, if (name_end < name) return; name_buf = xmemdupz(name, name_end - name + 1); - unuse_commit_buffer(commit, buffer); elem = string_list_lookup(people, name_buf); if (!elem) { @@ -256,6 +253,15 @@ static void record_person(int which, struct string_list *people, free(name_buf); } + +static void record_person(int which, struct string_list *people, + struct commit *commit) +{ + const char *buffer = get_commit_buffer(commit, NULL); + record_person_from_buf(which, people, buffer); + unuse_commit_buffer(commit, buffer); +} + static int cmp_string_list_util_as_integral(const void *a_, const void *b_) { const struct string_list_item *a = a_, *b = b_; diff --git a/builtin/fsck.c b/builtin/fsck.c index 0c757862e8..4783896fd6 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -225,12 +225,12 @@ static void check_unreachable_object(struct object *obj) printf("dangling %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1)); if (write_lost_and_found) { - char *filename = git_path("lost-found/%s/%s", + const char *filename = git_path("lost-found/%s/%s", obj->type == OBJ_COMMIT ? "commit" : "other", sha1_to_hex(obj->sha1)); FILE *f; - if (safe_create_leading_directories(filename)) { + if (safe_create_leading_directories_const(filename)) { error("Could not create lost-found"); return; } diff --git a/builtin/gc.c b/builtin/gc.c index 5c634afc00..36fe33300f 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -33,11 +33,13 @@ static int gc_auto_threshold = 6700; static int gc_auto_pack_limit = 50; static int detach_auto = 1; static const char *prune_expire = "2.weeks.ago"; +static const char *prune_worktrees_expire = "3.months.ago"; static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT; static struct argv_array reflog = ARGV_ARRAY_INIT; static struct argv_array repack = ARGV_ARRAY_INIT; static struct argv_array prune = ARGV_ARRAY_INIT; +static struct argv_array prune_worktrees = ARGV_ARRAY_INIT; static struct argv_array rerere = ARGV_ARRAY_INIT; static char *pidfile; @@ -55,6 +57,17 @@ static void remove_pidfile_on_signal(int signo) raise(signo); } +static void git_config_date_string(const char *key, const char **output) +{ + if (git_config_get_string_const(key, output)) + return; + if (strcmp(*output, "now")) { + unsigned long now = approxidate("now"); + if (approxidate(*output) >= now) + git_die_config(key, _("Invalid %s: '%s'"), key, *output); + } +} + static void gc_config(void) { const char *value; @@ -71,16 +84,8 @@ static void gc_config(void) git_config_get_int("gc.auto", &gc_auto_threshold); git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit); git_config_get_bool("gc.autodetach", &detach_auto); - - if (!git_config_get_string_const("gc.pruneexpire", &prune_expire)) { - if (strcmp(prune_expire, "now")) { - unsigned long now = approxidate("now"); - if (approxidate(prune_expire) >= now) { - git_die_config("gc.pruneexpire", _("Invalid gc.pruneexpire: '%s'"), - prune_expire); - } - } - } + git_config_date_string("gc.pruneexpire", &prune_expire); + git_config_date_string("gc.pruneworktreesexpire", &prune_worktrees_expire); git_config(git_default_config, NULL); } @@ -287,7 +292,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix) argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL); argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL); argv_array_pushl(&repack, "repack", "-d", "-l", NULL); - argv_array_pushl(&prune, "prune", "--expire", NULL ); + argv_array_pushl(&prune, "prune", "--expire", NULL); + argv_array_pushl(&prune_worktrees, "prune", "--worktrees", "--expire", NULL); argv_array_pushl(&rerere, "rerere", "gc", NULL); gc_config(); @@ -357,6 +363,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix) return error(FAILED_RUN, prune.argv[0]); } + if (prune_worktrees_expire) { + argv_array_push(&prune_worktrees, prune_worktrees_expire); + if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD)) + return error(FAILED_RUN, prune_worktrees.argv[0]); + } + if (run_command_v_opt(rerere.argv, RUN_GIT_CMD)) return error(FAILED_RUN, rerere.argv[0]); diff --git a/builtin/grep.c b/builtin/grep.c index abc440023f..d04f4400d9 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -738,7 +738,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored, N_("allow calling of grep(1) (ignored by this build)")), - { OPTION_CALLBACK, 0, "help-all", &options, NULL, N_("show usage"), + { OPTION_CALLBACK, 0, "help-all", NULL, NULL, N_("show usage"), PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback }, OPT_END() }; diff --git a/builtin/index-pack.c b/builtin/index-pack.c index cf654df09b..7ea2020d82 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -18,16 +18,14 @@ static const char index_pack_usage[] = struct object_entry { struct pack_idx_entry idx; unsigned long size; - unsigned int hdr_size; - enum object_type type; - enum object_type real_type; - unsigned delta_depth; - int base_object_no; + unsigned char hdr_size; + signed char type; + signed char real_type; }; -union delta_base { - unsigned char sha1[20]; - off_t offset; +struct object_stat { + unsigned delta_depth; + int base_object_no; }; struct base_data { @@ -49,25 +47,28 @@ struct thread_local { int pack_fd; }; -/* - * Even if sizeof(union delta_base) == 24 on 64-bit archs, we really want - * to memcmp() only the first 20 bytes. - */ -#define UNION_BASE_SZ 20 - #define FLAG_LINK (1u<<20) #define FLAG_CHECKED (1u<<21) -struct delta_entry { - union delta_base base; +struct ofs_delta_entry { + off_t offset; + int obj_no; +}; + +struct ref_delta_entry { + unsigned char sha1[20]; int obj_no; }; static struct object_entry *objects; -static struct delta_entry *deltas; +static struct object_stat *obj_stat; +static struct ofs_delta_entry *ofs_deltas; +static struct ref_delta_entry *ref_deltas; static struct thread_local nothread_data; static int nr_objects; -static int nr_deltas; +static int nr_ofs_deltas; +static int nr_ref_deltas; +static int ref_deltas_alloc; static int nr_resolved_deltas; static int nr_threads; @@ -476,7 +477,8 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size, } static void *unpack_raw_entry(struct object_entry *obj, - union delta_base *delta_base, + off_t *ofs_offset, + unsigned char *ref_sha1, unsigned char *sha1) { unsigned char *p; @@ -505,11 +507,10 @@ static void *unpack_raw_entry(struct object_entry *obj, switch (obj->type) { case OBJ_REF_DELTA: - hashcpy(delta_base->sha1, fill(20)); + hashcpy(ref_sha1, fill(20)); use(20); break; case OBJ_OFS_DELTA: - memset(delta_base, 0, sizeof(*delta_base)); p = fill(1); c = *p; use(1); @@ -523,8 +524,8 @@ static void *unpack_raw_entry(struct object_entry *obj, use(1); base_offset = (base_offset << 7) + (c & 127); } - delta_base->offset = obj->idx.offset - base_offset; - if (delta_base->offset <= 0 || delta_base->offset >= obj->idx.offset) + *ofs_offset = obj->idx.offset - base_offset; + if (*ofs_offset <= 0 || *ofs_offset >= obj->idx.offset) bad_object(obj->idx.offset, _("delta base offset is out of bound")); break; case OBJ_COMMIT: @@ -608,55 +609,108 @@ static void *get_data_from_pack(struct object_entry *obj) return unpack_data(obj, NULL, NULL); } -static int compare_delta_bases(const union delta_base *base1, - const union delta_base *base2, - enum object_type type1, - enum object_type type2) +static int compare_ofs_delta_bases(off_t offset1, off_t offset2, + enum object_type type1, + enum object_type type2) { int cmp = type1 - type2; if (cmp) return cmp; - return memcmp(base1, base2, UNION_BASE_SZ); + return offset1 - offset2; } -static int find_delta(const union delta_base *base, enum object_type type) +static int find_ofs_delta(const off_t offset, enum object_type type) { - int first = 0, last = nr_deltas; - - while (first < last) { - int next = (first + last) / 2; - struct delta_entry *delta = &deltas[next]; - int cmp; - - cmp = compare_delta_bases(base, &delta->base, - type, objects[delta->obj_no].type); - if (!cmp) - return next; - if (cmp < 0) { - last = next; - continue; - } - first = next+1; - } - return -first-1; + int first = 0, last = nr_ofs_deltas; + + while (first < last) { + int next = (first + last) / 2; + struct ofs_delta_entry *delta = &ofs_deltas[next]; + int cmp; + + cmp = compare_ofs_delta_bases(offset, delta->offset, + type, objects[delta->obj_no].type); + if (!cmp) + return next; + if (cmp < 0) { + last = next; + continue; + } + first = next+1; + } + return -first-1; } -static void find_delta_children(const union delta_base *base, - int *first_index, int *last_index, - enum object_type type) +static void find_ofs_delta_children(off_t offset, + int *first_index, int *last_index, + enum object_type type) { - int first = find_delta(base, type); + int first = find_ofs_delta(offset, type); int last = first; - int end = nr_deltas - 1; + int end = nr_ofs_deltas - 1; if (first < 0) { *first_index = 0; *last_index = -1; return; } - while (first > 0 && !memcmp(&deltas[first - 1].base, base, UNION_BASE_SZ)) + while (first > 0 && ofs_deltas[first - 1].offset == offset) --first; - while (last < end && !memcmp(&deltas[last + 1].base, base, UNION_BASE_SZ)) + while (last < end && ofs_deltas[last + 1].offset == offset) + ++last; + *first_index = first; + *last_index = last; +} + +static int compare_ref_delta_bases(const unsigned char *sha1, + const unsigned char *sha2, + enum object_type type1, + enum object_type type2) +{ + int cmp = type1 - type2; + if (cmp) + return cmp; + return hashcmp(sha1, sha2); +} + +static int find_ref_delta(const unsigned char *sha1, enum object_type type) +{ + int first = 0, last = nr_ref_deltas; + + while (first < last) { + int next = (first + last) / 2; + struct ref_delta_entry *delta = &ref_deltas[next]; + int cmp; + + cmp = compare_ref_delta_bases(sha1, delta->sha1, + type, objects[delta->obj_no].type); + if (!cmp) + return next; + if (cmp < 0) { + last = next; + continue; + } + first = next+1; + } + return -first-1; +} + +static void find_ref_delta_children(const unsigned char *sha1, + int *first_index, int *last_index, + enum object_type type) +{ + int first = find_ref_delta(sha1, type); + int last = first; + int end = nr_ref_deltas - 1; + + if (first < 0) { + *first_index = 0; + *last_index = -1; + return; + } + while (first > 0 && !hashcmp(ref_deltas[first - 1].sha1, sha1)) + --first; + while (last < end && !hashcmp(ref_deltas[last + 1].sha1, sha1)) ++last; *first_index = first; *last_index = last; @@ -873,13 +927,15 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data, *delta_data; if (show_stat) { - delta_obj->delta_depth = base->obj->delta_depth + 1; + int i = delta_obj - objects; + int j = base->obj - objects; + obj_stat[i].delta_depth = obj_stat[j].delta_depth + 1; deepest_delta_lock(); - if (deepest_delta < delta_obj->delta_depth) - deepest_delta = delta_obj->delta_depth; + if (deepest_delta < obj_stat[i].delta_depth) + deepest_delta = obj_stat[i].delta_depth; deepest_delta_unlock(); + obj_stat[i].base_object_no = j; } - delta_obj->base_object_no = base->obj - objects; delta_data = get_data_from_pack(delta_obj); base_data = get_base_data(base); result->obj = delta_obj; @@ -902,7 +958,7 @@ static void resolve_delta(struct object_entry *delta_obj, * "want"; if so, swap in "set" and return true. Otherwise, leave it untouched * and return false. */ -static int compare_and_swap_type(enum object_type *type, +static int compare_and_swap_type(signed char *type, enum object_type want, enum object_type set) { @@ -921,16 +977,13 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct base_data *prev_base) { if (base->ref_last == -1 && base->ofs_last == -1) { - union delta_base base_spec; + find_ref_delta_children(base->obj->idx.sha1, + &base->ref_first, &base->ref_last, + OBJ_REF_DELTA); - hashcpy(base_spec.sha1, base->obj->idx.sha1); - find_delta_children(&base_spec, - &base->ref_first, &base->ref_last, OBJ_REF_DELTA); - - memset(&base_spec, 0, sizeof(base_spec)); - base_spec.offset = base->obj->idx.offset; - find_delta_children(&base_spec, - &base->ofs_first, &base->ofs_last, OBJ_OFS_DELTA); + find_ofs_delta_children(base->obj->idx.offset, + &base->ofs_first, &base->ofs_last, + OBJ_OFS_DELTA); if (base->ref_last == -1 && base->ofs_last == -1) { free(base->data); @@ -941,7 +994,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, } if (base->ref_first <= base->ref_last) { - struct object_entry *child = objects + deltas[base->ref_first].obj_no; + struct object_entry *child = objects + ref_deltas[base->ref_first].obj_no; struct base_data *result = alloc_base_data(); if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA, @@ -957,7 +1010,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, } if (base->ofs_first <= base->ofs_last) { - struct object_entry *child = objects + deltas[base->ofs_first].obj_no; + struct object_entry *child = objects + ofs_deltas[base->ofs_first].obj_no; struct base_data *result = alloc_base_data(); assert(child->real_type == OBJ_OFS_DELTA); @@ -993,15 +1046,20 @@ static void find_unresolved_deltas(struct base_data *base) } } -static int compare_delta_entry(const void *a, const void *b) +static int compare_ofs_delta_entry(const void *a, const void *b) { - const struct delta_entry *delta_a = a; - const struct delta_entry *delta_b = b; + const struct ofs_delta_entry *delta_a = a; + const struct ofs_delta_entry *delta_b = b; - /* group by type (ref vs ofs) and then by value (sha-1 or offset) */ - return compare_delta_bases(&delta_a->base, &delta_b->base, - objects[delta_a->obj_no].type, - objects[delta_b->obj_no].type); + return delta_a->offset - delta_b->offset; +} + +static int compare_ref_delta_entry(const void *a, const void *b) +{ + const struct ref_delta_entry *delta_a = a; + const struct ref_delta_entry *delta_b = b; + + return hashcmp(delta_a->sha1, delta_b->sha1); } static void resolve_base(struct object_entry *obj) @@ -1047,7 +1105,8 @@ static void *threaded_second_pass(void *data) static void parse_pack_objects(unsigned char *sha1) { int i, nr_delays = 0; - struct delta_entry *delta = deltas; + struct ofs_delta_entry *ofs_delta = ofs_deltas; + unsigned char ref_delta_sha1[20]; struct stat st; if (verbose) @@ -1056,12 +1115,18 @@ static void parse_pack_objects(unsigned char *sha1) nr_objects); for (i = 0; i < nr_objects; i++) { struct object_entry *obj = &objects[i]; - void *data = unpack_raw_entry(obj, &delta->base, obj->idx.sha1); + void *data = unpack_raw_entry(obj, &ofs_delta->offset, + ref_delta_sha1, obj->idx.sha1); obj->real_type = obj->type; - if (is_delta_type(obj->type)) { - nr_deltas++; - delta->obj_no = i; - delta++; + if (obj->type == OBJ_OFS_DELTA) { + nr_ofs_deltas++; + ofs_delta->obj_no = i; + ofs_delta++; + } else if (obj->type == OBJ_REF_DELTA) { + ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc); + hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_sha1); + ref_deltas[nr_ref_deltas].obj_no = i; + nr_ref_deltas++; } else if (!data) { /* large blobs, check later */ obj->real_type = OBJ_BAD; @@ -1112,15 +1177,18 @@ static void resolve_deltas(void) { int i; - if (!nr_deltas) + if (!nr_ofs_deltas && !nr_ref_deltas) return; /* Sort deltas by base SHA1/offset for fast searching */ - qsort(deltas, nr_deltas, sizeof(struct delta_entry), - compare_delta_entry); + qsort(ofs_deltas, nr_ofs_deltas, sizeof(struct ofs_delta_entry), + compare_ofs_delta_entry); + qsort(ref_deltas, nr_ref_deltas, sizeof(struct ref_delta_entry), + compare_ref_delta_entry); if (verbose) - progress = start_progress(_("Resolving deltas"), nr_deltas); + progress = start_progress(_("Resolving deltas"), + nr_ref_deltas + nr_ofs_deltas); #ifndef NO_PTHREADS nr_dispatched = 0; @@ -1158,7 +1226,7 @@ static void resolve_deltas(void) static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved); static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1) { - if (nr_deltas == nr_resolved_deltas) { + if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) { stop_progress(&progress); /* Flush remaining pack final 20-byte SHA1. */ flush(); @@ -1169,7 +1237,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha struct sha1file *f; unsigned char read_sha1[20], tail_sha1[20]; struct strbuf msg = STRBUF_INIT; - int nr_unresolved = nr_deltas - nr_resolved_deltas; + int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas; int nr_objects_initial = nr_objects; if (nr_unresolved <= 0) die(_("confusion beyond insanity")); @@ -1191,11 +1259,11 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha die(_("Unexpected tail checksum for %s " "(disk corruption?)"), curr_pack); } - if (nr_deltas != nr_resolved_deltas) + if (nr_ofs_deltas + nr_ref_deltas != nr_resolved_deltas) die(Q_("pack has %d unresolved delta", "pack has %d unresolved deltas", - nr_deltas - nr_resolved_deltas), - nr_deltas - nr_resolved_deltas); + nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas), + nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas); } static int write_compressed(struct sha1file *f, void *in, unsigned int size) @@ -1254,14 +1322,14 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f, static int delta_pos_compare(const void *_a, const void *_b) { - struct delta_entry *a = *(struct delta_entry **)_a; - struct delta_entry *b = *(struct delta_entry **)_b; + struct ref_delta_entry *a = *(struct ref_delta_entry **)_a; + struct ref_delta_entry *b = *(struct ref_delta_entry **)_b; return a->obj_no - b->obj_no; } static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved) { - struct delta_entry **sorted_by_pos; + struct ref_delta_entry **sorted_by_pos; int i, n = 0; /* @@ -1275,28 +1343,25 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved) * resolving deltas in the same order as their position in the pack. */ sorted_by_pos = xmalloc(nr_unresolved * sizeof(*sorted_by_pos)); - for (i = 0; i < nr_deltas; i++) { - if (objects[deltas[i].obj_no].real_type != OBJ_REF_DELTA) - continue; - sorted_by_pos[n++] = &deltas[i]; - } + for (i = 0; i < nr_ref_deltas; i++) + sorted_by_pos[n++] = &ref_deltas[i]; qsort(sorted_by_pos, n, sizeof(*sorted_by_pos), delta_pos_compare); for (i = 0; i < n; i++) { - struct delta_entry *d = sorted_by_pos[i]; + struct ref_delta_entry *d = sorted_by_pos[i]; enum object_type type; struct base_data *base_obj = alloc_base_data(); if (objects[d->obj_no].real_type != OBJ_REF_DELTA) continue; - base_obj->data = read_sha1_file(d->base.sha1, &type, &base_obj->size); + base_obj->data = read_sha1_file(d->sha1, &type, &base_obj->size); if (!base_obj->data) continue; - if (check_sha1_signature(d->base.sha1, base_obj->data, + if (check_sha1_signature(d->sha1, base_obj->data, base_obj->size, typename(type))) - die(_("local object %s is corrupt"), sha1_to_hex(d->base.sha1)); - base_obj->obj = append_obj_to_pack(f, d->base.sha1, + die(_("local object %s is corrupt"), sha1_to_hex(d->sha1)); + base_obj->obj = append_obj_to_pack(f, d->sha1, base_obj->data, base_obj->size, type); find_unresolved_deltas(base_obj); display_progress(progress, nr_resolved_deltas); @@ -1488,7 +1553,7 @@ static void read_idx_option(struct pack_idx_option *opts, const char *pack_name) static void show_pack_info(int stat_only) { - int i, baseobjects = nr_objects - nr_deltas; + int i, baseobjects = nr_objects - nr_ref_deltas - nr_ofs_deltas; unsigned long *chain_histogram = NULL; if (deepest_delta) @@ -1498,7 +1563,7 @@ static void show_pack_info(int stat_only) struct object_entry *obj = &objects[i]; if (is_delta_type(obj->type)) - chain_histogram[obj->delta_depth - 1]++; + chain_histogram[obj_stat[i].delta_depth - 1]++; if (stat_only) continue; printf("%s %-6s %lu %lu %"PRIuMAX, @@ -1507,8 +1572,8 @@ static void show_pack_info(int stat_only) (unsigned long)(obj[1].idx.offset - obj->idx.offset), (uintmax_t)obj->idx.offset); if (is_delta_type(obj->type)) { - struct object_entry *bobj = &objects[obj->base_object_no]; - printf(" %u %s", obj->delta_depth, sha1_to_hex(bobj->idx.sha1)); + struct object_entry *bobj = &objects[obj_stat[i].base_object_no]; + printf(" %u %s", obj_stat[i].delta_depth, sha1_to_hex(bobj->idx.sha1)); } putchar('\n'); } @@ -1671,11 +1736,14 @@ 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)); - deltas = xcalloc(nr_objects, sizeof(struct delta_entry)); + if (show_stat) + obj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat)); + ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry)); parse_pack_objects(pack_sha1); resolve_deltas(); conclude_pack(fix_thin_pack, curr_pack, pack_sha1); - free(deltas); + free(ofs_deltas); + free(ref_deltas); if (strict) foreign_nr = check_objects(); diff --git a/builtin/init-db.c b/builtin/init-db.c index 6723d39c3b..4335738135 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -182,6 +182,20 @@ static int git_init_db_config(const char *k, const char *v, void *cb) return 0; } +/* + * If the git_dir is not directly inside the working tree, then git will not + * find it by default, and we need to set the worktree explicitly. + */ +static int needs_work_tree_config(const char *git_dir, const char *work_tree) +{ + if (!strcmp(work_tree, "/") && !strcmp(git_dir, "/.git")) + return 0; + if (skip_prefix(git_dir, work_tree, &git_dir) && + !strcmp(git_dir, "/.git")) + return 0; + return 1; +} + static int create_default_files(const char *template_path) { const char *git_dir = get_git_dir(); @@ -274,10 +288,8 @@ static int create_default_files(const char *template_path) /* allow template config file to override the default */ if (log_all_ref_updates == -1) git_config_set("core.logallrefupdates", "true"); - if (!starts_with(git_dir, work_tree) || - strcmp(git_dir + strlen(work_tree), "/.git")) { + if (needs_work_tree_config(git_dir, work_tree)) git_config_set("core.worktree", work_tree); - } } if (!reinit) { @@ -350,7 +362,6 @@ int set_git_dir_init(const char *git_dir, const char *real_git_dir, static void separate_git_dir(const char *git_dir) { struct stat st; - FILE *fp; if (!stat(git_link, &st)) { const char *src; @@ -366,11 +377,7 @@ static void separate_git_dir(const char *git_dir) die_errno(_("unable to move %s to %s"), src, git_dir); } - fp = fopen(git_link, "w"); - if (!fp) - die(_("Could not create git link %s"), git_link); - fprintf(fp, "gitdir: %s\n", git_dir); - fclose(fp); + write_file(git_link, 1, "gitdir: %s\n", git_dir); } int init_db(const char *template_dir, unsigned int flags) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index c3a75166bd..c067107a6a 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -961,10 +961,8 @@ static int want_object_in_pack(const unsigned char *sha1, off_t offset = find_pack_entry_one(sha1, p); if (offset) { if (!*found_pack) { - if (!is_pack_valid(p)) { - warning("packfile %s cannot be accessed", p->pack_name); + if (!is_pack_valid(p)) continue; - } *found_offset = offset; *found_pack = p; } diff --git a/builtin/patch-id.c b/builtin/patch-id.c index 77db8739b5..ba34dac4d2 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -1,14 +1,14 @@ #include "builtin.h" -static void flush_current_id(int patchlen, unsigned char *id, unsigned char *result) +static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result) { char name[50]; if (!patchlen) return; - memcpy(name, sha1_to_hex(id), 41); - printf("%s %s\n", sha1_to_hex(result), name); + memcpy(name, oid_to_hex(id), GIT_SHA1_HEXSZ + 1); + printf("%s %s\n", oid_to_hex(result), name); } static int remove_space(char *line) @@ -53,23 +53,23 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after) return 1; } -static void flush_one_hunk(unsigned char *result, git_SHA_CTX *ctx) +static void flush_one_hunk(struct object_id *result, git_SHA_CTX *ctx) { - unsigned char hash[20]; + unsigned char hash[GIT_SHA1_RAWSZ]; unsigned short carry = 0; int i; git_SHA1_Final(hash, ctx); git_SHA1_Init(ctx); /* 20-byte sum, with carry */ - for (i = 0; i < 20; ++i) { - carry += result[i] + hash[i]; - result[i] = carry; + for (i = 0; i < GIT_SHA1_RAWSZ; ++i) { + carry += result->hash[i] + hash[i]; + result->hash[i] = carry; carry >>= 8; } } -static int get_one_patchid(unsigned char *next_sha1, unsigned char *result, +static int get_one_patchid(struct object_id *next_oid, struct object_id *result, struct strbuf *line_buf, int stable) { int patchlen = 0, found_next = 0; @@ -77,7 +77,7 @@ static int get_one_patchid(unsigned char *next_sha1, unsigned char *result, git_SHA_CTX ctx; git_SHA1_Init(&ctx); - hashclr(result); + oidclr(result); while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) { char *line = line_buf->buf; @@ -93,7 +93,7 @@ static int get_one_patchid(unsigned char *next_sha1, unsigned char *result, else if (!memcmp(line, "\\ ", 2) && 12 < strlen(line)) continue; - if (!get_sha1_hex(p, next_sha1)) { + if (!get_oid_hex(p, next_oid)) { found_next = 1; break; } @@ -143,7 +143,7 @@ static int get_one_patchid(unsigned char *next_sha1, unsigned char *result, } if (!found_next) - hashclr(next_sha1); + oidclr(next_oid); flush_one_hunk(result, &ctx); @@ -152,15 +152,15 @@ static int get_one_patchid(unsigned char *next_sha1, unsigned char *result, static void generate_id_list(int stable) { - unsigned char sha1[20], n[20], result[20]; + struct object_id oid, n, result; int patchlen; struct strbuf line_buf = STRBUF_INIT; - hashclr(sha1); + oidclr(&oid); while (!feof(stdin)) { - patchlen = get_one_patchid(n, result, &line_buf, stable); - flush_current_id(patchlen, sha1, result); - hashcpy(sha1, n); + patchlen = get_one_patchid(&n, &result, &line_buf, stable); + flush_current_id(patchlen, &oid, &result); + oidcpy(&oid, &n); } strbuf_release(&line_buf); } diff --git a/builtin/prune.c b/builtin/prune.c index 17094ad954..0c73246c72 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -76,6 +76,95 @@ static int prune_subdir(int nr, const char *path, void *data) return 0; } +static int prune_worktree(const char *id, struct strbuf *reason) +{ + struct stat st; + char *path; + int fd, len; + + if (!is_directory(git_path("worktrees/%s", id))) { + strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), id); + return 1; + } + if (file_exists(git_path("worktrees/%s/locked", id))) + return 0; + if (stat(git_path("worktrees/%s/gitdir", id), &st)) { + strbuf_addf(reason, _("Removing worktrees/%s: gitdir file does not exist"), id); + return 1; + } + fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY); + if (fd < 0) { + strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"), + id, strerror(errno)); + return 1; + } + len = st.st_size; + path = xmalloc(len + 1); + read_in_full(fd, path, len); + close(fd); + while (len && (path[len - 1] == '\n' || path[len - 1] == '\r')) + len--; + if (!len) { + strbuf_addf(reason, _("Removing worktrees/%s: invalid gitdir file"), id); + free(path); + return 1; + } + path[len] = '\0'; + if (!file_exists(path)) { + struct stat st_link; + free(path); + /* + * the repo is moved manually and has not been + * accessed since? + */ + if (!stat(git_path("worktrees/%s/link", id), &st_link) && + st_link.st_nlink > 1) + return 0; + if (st.st_mtime <= expire) { + strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id); + return 1; + } else { + return 0; + } + } + free(path); + return 0; +} + +static void prune_worktrees(void) +{ + struct strbuf reason = STRBUF_INIT; + struct strbuf path = STRBUF_INIT; + DIR *dir = opendir(git_path("worktrees")); + struct dirent *d; + int ret; + if (!dir) + return; + while ((d = readdir(dir)) != NULL) { + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + strbuf_reset(&reason); + if (!prune_worktree(d->d_name, &reason)) + continue; + if (show_only || verbose) + printf("%s\n", reason.buf); + if (show_only) + continue; + strbuf_reset(&path); + strbuf_addstr(&path, git_path("worktrees/%s", d->d_name)); + ret = remove_dir_recursively(&path, 0); + if (ret < 0 && errno == ENOTDIR) + ret = unlink(path.buf); + if (ret) + error(_("failed to remove: %s"), strerror(errno)); + } + closedir(dir); + if (!show_only) + rmdir(git_path("worktrees")); + strbuf_release(&reason); + strbuf_release(&path); +} + /* * Write errors (particularly out of space) can result in * failed temporary packs (and more rarely indexes and other @@ -102,10 +191,12 @@ int cmd_prune(int argc, const char **argv, const char *prefix) { struct rev_info revs; struct progress *progress = NULL; + int do_prune_worktrees = 0; const struct option options[] = { OPT__DRY_RUN(&show_only, N_("do not remove, show only")), OPT__VERBOSE(&verbose, N_("report pruned objects")), OPT_BOOL(0, "progress", &show_progress, N_("show progress")), + OPT_BOOL(0, "worktrees", &do_prune_worktrees, N_("prune .git/worktrees")), OPT_EXPIRY_DATE(0, "expire", &expire, N_("expire objects older than <time>")), OPT_END() @@ -119,6 +210,14 @@ int cmd_prune(int argc, const char **argv, const char *prefix) init_revisions(&revs, prefix); argc = parse_options(argc, argv, prefix, options, prune_usage, 0); + + if (do_prune_worktrees) { + if (argc) + die(_("--worktrees does not take extra arguments")); + prune_worktrees(); + return 0; + } + while (argc--) { unsigned char sha1[20]; const char *name = *argv++; diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 5292bb5a50..d2ec52bca9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1008,7 +1008,7 @@ static void run_update_post_hook(struct command *commands) int argc; const char **argv; struct child_process proc = CHILD_PROCESS_INIT; - char *hook; + const char *hook; hook = find_hook("post-update"); for (argc = 0, cmd = commands; cmd; cmd = cmd->next) { diff --git a/builtin/remote.c b/builtin/remote.c index 5d3ab906bc..ad57fc984e 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -584,7 +584,7 @@ static int migrate_file(struct remote *remote) { struct strbuf buf = STRBUF_INIT; int i; - char *path = NULL; + const char *path = NULL; strbuf_addf(&buf, "remote.%s.url", remote->name); for (i = 0; i < remote->url_nr; i++) diff --git a/builtin/repack.c b/builtin/repack.c index f2edeb0f4c..af7340c7ba 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -285,7 +285,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix) failed = 0; for_each_string_list_item(item, &names) { for (ext = 0; ext < ARRAY_SIZE(exts); ext++) { - char *fname, *fname_old; + const char *fname_old; + char *fname; fname = mkpathdup("%s/pack-%s%s", packdir, item->string, exts[ext].name); if (!file_exists(fname)) { @@ -313,7 +314,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (failed) { struct string_list rollback_failure = STRING_LIST_INIT_DUP; for_each_string_list_item(item, &rollback) { - char *fname, *fname_old; + const char *fname_old; + char *fname; fname = mkpathdup("%s/%s", packdir, item->string); fname_old = mkpath("%s/old-%s", packdir, item->string); if (rename(fname_old, fname)) @@ -366,7 +368,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) /* Remove the "old-" files */ for_each_string_list_item(item, &names) { for (ext = 0; ext < ARRAY_SIZE(exts); ext++) { - char *fname; + const char *fname; fname = mkpath("%s/old-%s%s", packdir, item->string, diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 3626c61da6..4d10dd9545 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -533,6 +533,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) for (i = 1; i < argc; i++) { const char *arg = argv[i]; + if (!strcmp(arg, "--git-path")) { + if (!argv[i + 1]) + die("--git-path requires an argument"); + puts(git_path("%s", argv[i + 1])); + i++; + continue; + } if (as_is) { if (show_file(arg, output_prefix) && as_is < 2) verify_filename(prefix, arg, 0); @@ -755,6 +762,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) free(cwd); continue; } + if (!strcmp(arg, "--git-common-dir")) { + puts(get_git_common_dir()); + continue; + } if (!strcmp(arg, "--resolve-git-dir")) { const char *gitdir = argv[++i]; if (!gitdir) diff --git a/builtin/show-branch.c b/builtin/show-branch.c index f3fb5fb2bf..e69fb7c489 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -718,7 +718,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) } /* If nothing is specified, show all branches by default */ - if (ac + all_heads + all_remotes == 0) + if (ac <= topics && all_heads + all_remotes == 0) all_heads = 1; if (reflog) { @@ -785,13 +785,13 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) } free(ref); } - else if (all_heads + all_remotes) - snarf_refs(all_heads, all_remotes); else { while (0 < ac) { append_one_rev(*av); ac--; av++; } + if (all_heads + all_remotes) + snarf_refs(all_heads, all_remotes); } head_p = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, diff --git a/bulk-checkin.c b/bulk-checkin.c index 8d157eba45..7cffc3a579 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -24,7 +24,7 @@ static struct bulk_checkin_state { static void finish_bulk_checkin(struct bulk_checkin_state *state) { - unsigned char sha1[20]; + struct object_id oid; struct strbuf packname = STRBUF_INIT; int i; @@ -36,11 +36,11 @@ static void finish_bulk_checkin(struct bulk_checkin_state *state) unlink(state->pack_tmp_name); goto clear_exit; } else if (state->nr_written == 1) { - sha1close(state->f, sha1, CSUM_FSYNC); + sha1close(state->f, oid.hash, CSUM_FSYNC); } else { - int fd = sha1close(state->f, sha1, 0); - fixup_pack_header_footer(fd, sha1, state->pack_tmp_name, - state->nr_written, sha1, + int fd = sha1close(state->f, oid.hash, 0); + fixup_pack_header_footer(fd, oid.hash, state->pack_tmp_name, + state->nr_written, oid.hash, state->offset); close(fd); } @@ -48,7 +48,7 @@ static void finish_bulk_checkin(struct bulk_checkin_state *state) strbuf_addf(&packname, "%s/pack/pack-", get_object_directory()); finish_tmp_packfile(&packname, state->pack_tmp_name, state->written, state->nr_written, - &state->pack_idx_opts, sha1); + &state->pack_idx_opts, oid.hash); for (i = 0; i < state->nr_written; i++) free(state->written[i]); @@ -43,6 +43,14 @@ int git_deflate_end_gently(git_zstream *); int git_deflate(git_zstream *, int flush); unsigned long git_deflate_bound(git_zstream *, unsigned long); +/* The length in bytes and in hex digits of an object name (SHA-1 value). */ +#define GIT_SHA1_RAWSZ 20 +#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ) + +struct object_id { + unsigned char hash[GIT_SHA1_RAWSZ]; +}; + #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT) #define DTYPE(de) ((de)->d_type) #else @@ -370,6 +378,7 @@ static inline enum object_type object_type(unsigned int mode) /* Double-check local_repo_env below if you add to this list. */ #define GIT_DIR_ENVIRONMENT "GIT_DIR" +#define GIT_COMMON_DIR_ENVIRONMENT "GIT_COMMON_DIR" #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE" #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE" #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX" @@ -423,11 +432,13 @@ extern int is_inside_git_dir(void); 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); extern int set_git_dir(const char *path); +extern int get_common_dir(struct strbuf *sb, const char *gitdir); extern const char *get_git_namespace(void); extern const char *strip_namespace(const char *namespaced_ref); extern const char *get_git_work_tree(void); @@ -612,6 +623,7 @@ extern int core_apply_sparse_checkout; extern int precomposed_unicode; extern int protect_hfs; extern int protect_ntfs; +extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env; /* * Include broken refs in all ref iterations, which will @@ -682,18 +694,19 @@ extern int check_repository_format(void); extern char *mksnpath(char *buf, size_t n, const char *fmt, ...) __attribute__((format (printf, 3, 4))); -extern char *git_snpath(char *buf, size_t n, const char *fmt, ...) - __attribute__((format (printf, 3, 4))); +extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...) + __attribute__((format (printf, 2, 3))); extern char *git_pathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); extern char *mkpathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); /* Return a statically allocated filename matching the sha1 signature */ -extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); -extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); -extern char *git_path_submodule(const char *path, const char *fmt, ...) +extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +extern const char *git_path_submodule(const char *path, const char *fmt, ...) __attribute__((format (printf, 2, 3))); +extern void report_linked_checkout_garbage(void); /* * Return the name of the file in the local object database that would @@ -718,13 +731,13 @@ extern char *sha1_pack_name(const unsigned char *sha1); extern char *sha1_pack_index_name(const unsigned char *sha1); extern const char *find_unique_abbrev(const unsigned char *sha1, int); -extern const unsigned char null_sha1[20]; +extern const unsigned char null_sha1[GIT_SHA1_RAWSZ]; static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) { int i; - for (i = 0; i < 20; i++, sha1++, sha2++) { + for (i = 0; i < GIT_SHA1_RAWSZ; i++, sha1++, sha2++) { if (*sha1 != *sha2) return *sha1 - *sha2; } @@ -732,20 +745,42 @@ static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) return 0; } +static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2) +{ + return hashcmp(oid1->hash, oid2->hash); +} + static inline int is_null_sha1(const unsigned char *sha1) { return !hashcmp(sha1, null_sha1); } +static inline int is_null_oid(const struct object_id *oid) +{ + return !hashcmp(oid->hash, null_sha1); +} + static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src) { - memcpy(sha_dst, sha_src, 20); + memcpy(sha_dst, sha_src, GIT_SHA1_RAWSZ); } + +static inline void oidcpy(struct object_id *dst, const struct object_id *src) +{ + hashcpy(dst->hash, src->hash); +} + static inline void hashclr(unsigned char *hash) { - memset(hash, 0, 20); + memset(hash, 0, GIT_SHA1_RAWSZ); } +static inline void oidclr(struct object_id *oid) +{ + hashclr(oid->hash); +} + + #define EMPTY_TREE_SHA1_HEX \ "4b825dc642cb6eb9a060e54bf8d69288fbee4904" #define EMPTY_TREE_SHA1_BIN_LITERAL \ @@ -952,8 +987,10 @@ extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *); * null-terminated string. */ extern int get_sha1_hex(const char *hex, unsigned char *sha1); +extern int get_oid_hex(const char *hex, struct object_id *sha1); extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */ +extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */ extern int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags); extern int read_ref(const char *refname, unsigned char *sha1); @@ -1174,6 +1211,7 @@ extern struct packed_git { int pack_fd; unsigned pack_local:1, pack_keep:1, + freshened:1, do_not_close:1; unsigned char sha1[20]; /* something like ".git/objects/pack/xxxxx.pack" */ @@ -1289,14 +1327,16 @@ int for_each_loose_file_in_objdir_buf(struct strbuf *path, /* * Iterate over loose and packed objects in both the local - * repository and any alternates repositories. + * repository and any alternates repositories (unless the + * LOCAL_ONLY flag is set). */ +#define FOR_EACH_OBJECT_LOCAL_ONLY 0x1 typedef int each_packed_object_fn(const unsigned char *sha1, struct packed_git *pack, uint32_t pos, void *data); -extern int for_each_loose_object(each_loose_object_fn, void *); -extern int for_each_packed_object(each_packed_object_fn, void *); +extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags); +extern int for_each_packed_object(each_packed_object_fn, void *, unsigned flags); struct object_info { /* Request */ @@ -1508,6 +1548,8 @@ static inline ssize_t write_str_in_full(int fd, const char *str) { return write_in_full(fd, str, strlen(str)); } +__attribute__((format (printf, 3, 4))) +extern int write_file(const char *path, int fatal, const char *fmt, ...); /* pager.c */ extern void setup_pager(void); diff --git a/combine-diff.c b/combine-diff.c index 91edce58e1..8eb7278978 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -44,9 +44,9 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, memset(p->parent, 0, sizeof(p->parent[0]) * num_parent); - hashcpy(p->sha1, q->queue[i]->two->sha1); + hashcpy(p->oid.hash, q->queue[i]->two->sha1); p->mode = q->queue[i]->two->mode; - hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1); + hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1); p->parent[n].mode = q->queue[i]->one->mode; p->parent[n].status = q->queue[i]->status; *tail = p; @@ -77,7 +77,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, continue; } - hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1); + hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1); p->parent[n].mode = q->queue[i]->one->mode; p->parent[n].status = q->queue[i]->status; @@ -284,7 +284,7 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase, return base; } -static char *grab_blob(const unsigned char *sha1, unsigned int mode, +static char *grab_blob(const struct object_id *oid, unsigned int mode, unsigned long *size, struct userdiff_driver *textconv, const char *path) { @@ -294,20 +294,20 @@ static char *grab_blob(const unsigned char *sha1, unsigned int mode, if (S_ISGITLINK(mode)) { blob = xmalloc(100); *size = snprintf(blob, 100, - "Subproject commit %s\n", sha1_to_hex(sha1)); - } else if (is_null_sha1(sha1)) { + "Subproject commit %s\n", oid_to_hex(oid)); + } else if (is_null_oid(oid)) { /* deleted blob */ *size = 0; return xcalloc(1, 1); } else if (textconv) { struct diff_filespec *df = alloc_filespec(path); - fill_filespec(df, sha1, 1, mode); + fill_filespec(df, oid->hash, 1, mode); *size = fill_textconv(textconv, df, &blob); free_filespec(df); } else { - blob = read_sha1_file(sha1, &type, size); + blob = read_sha1_file(oid->hash, &type, size); if (type != OBJ_BLOB) - die("object '%s' is not a blob!", sha1_to_hex(sha1)); + die("object '%s' is not a blob!", oid_to_hex(oid)); } return blob; } @@ -389,7 +389,7 @@ static void consume_line(void *state_, char *line, unsigned long len) } } -static void combine_diff(const unsigned char *parent, unsigned int mode, +static void combine_diff(const struct object_id *parent, unsigned int mode, mmfile_t *result_file, struct sline *sline, unsigned int cnt, int n, int num_parent, int result_deleted, @@ -897,7 +897,7 @@ static void show_combined_header(struct combine_diff_path *elem, int show_file_header) { struct diff_options *opt = &rev->diffopt; - int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? 40 : DEFAULT_ABBREV; + int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV; const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/"; const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/"; const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO); @@ -914,11 +914,11 @@ static void show_combined_header(struct combine_diff_path *elem, "", elem->path, line_prefix, c_meta, c_reset); printf("%s%sindex ", line_prefix, c_meta); for (i = 0; i < num_parent; i++) { - abb = find_unique_abbrev(elem->parent[i].sha1, + abb = find_unique_abbrev(elem->parent[i].oid.hash, abbrev); printf("%s%s", i ? "," : "", abb); } - abb = find_unique_abbrev(elem->sha1, abbrev); + abb = find_unique_abbrev(elem->oid.hash, abbrev); printf("..%s%s\n", abb, c_reset); if (mode_differs) { @@ -991,7 +991,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, /* Read the result of merge first */ if (!working_tree_file) - result = grab_blob(elem->sha1, elem->mode, &result_size, + result = grab_blob(&elem->oid, elem->mode, &result_size, textconv, elem->path); else { /* Used by diff-tree to read from the working tree */ @@ -1013,12 +1013,12 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, result = strbuf_detach(&buf, NULL); elem->mode = canon_mode(st.st_mode); } else if (S_ISDIR(st.st_mode)) { - unsigned char sha1[20]; - if (resolve_gitlink_ref(elem->path, "HEAD", sha1) < 0) - result = grab_blob(elem->sha1, elem->mode, + struct object_id oid; + if (resolve_gitlink_ref(elem->path, "HEAD", oid.hash) < 0) + result = grab_blob(&elem->oid, elem->mode, &result_size, NULL, NULL); else - result = grab_blob(sha1, elem->mode, + result = grab_blob(&oid, elem->mode, &result_size, NULL, NULL); } else if (textconv) { struct diff_filespec *df = alloc_filespec(elem->path); @@ -1090,7 +1090,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, for (i = 0; !is_binary && i < num_parent; i++) { char *buf; unsigned long size; - buf = grab_blob(elem->parent[i].sha1, + buf = grab_blob(&elem->parent[i].oid, elem->parent[i].mode, &size, NULL, NULL); if (buffer_is_binary(buf, size)) @@ -1139,14 +1139,14 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, for (i = 0; i < num_parent; i++) { int j; for (j = 0; j < i; j++) { - if (!hashcmp(elem->parent[i].sha1, - elem->parent[j].sha1)) { + if (!oidcmp(&elem->parent[i].oid, + &elem->parent[j].oid)) { reuse_combine_diff(sline, cnt, i, j); break; } } if (i <= j) - combine_diff(elem->parent[i].sha1, + combine_diff(&elem->parent[i].oid, elem->parent[i].mode, &result_file, sline, cnt, i, num_parent, result_deleted, @@ -1206,9 +1206,9 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re /* Show sha1's */ for (i = 0; i < num_parent; i++) - printf(" %s", diff_unique_abbrev(p->parent[i].sha1, + printf(" %s", diff_unique_abbrev(p->parent[i].oid.hash, opt->abbrev)); - printf(" %s ", diff_unique_abbrev(p->sha1, opt->abbrev)); + printf(" %s ", diff_unique_abbrev(p->oid.hash, opt->abbrev)); } if (opt->output_format & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) { @@ -1271,16 +1271,16 @@ static struct diff_filepair *combined_pair(struct combine_diff_path *p, for (i = 0; i < num_parent; i++) { pair->one[i].path = p->path; pair->one[i].mode = p->parent[i].mode; - hashcpy(pair->one[i].sha1, p->parent[i].sha1); - pair->one[i].sha1_valid = !is_null_sha1(p->parent[i].sha1); + hashcpy(pair->one[i].sha1, p->parent[i].oid.hash); + pair->one[i].sha1_valid = !is_null_oid(&p->parent[i].oid); pair->one[i].has_more_entries = 1; } pair->one[num_parent - 1].has_more_entries = 0; pair->two->path = p->path; pair->two->mode = p->mode; - hashcpy(pair->two->sha1, p->sha1); - pair->two->sha1_valid = !is_null_sha1(p->sha1); + hashcpy(pair->two->sha1, p->oid.hash); + pair->two->sha1_valid = !is_null_oid(&p->oid); return pair; } @@ -55,12 +55,12 @@ struct commit *lookup_commit(const unsigned char *sha1) struct commit *lookup_commit_reference_by_name(const char *name) { - unsigned char sha1[20]; + struct object_id oid; struct commit *commit; - if (get_sha1_committish(name, sha1)) + if (get_sha1_committish(name, oid.hash)) return NULL; - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(oid.hash); if (parse_commit(commit)) return NULL; return commit; @@ -99,7 +99,7 @@ static int commit_graft_alloc, commit_graft_nr; static const unsigned char *commit_graft_sha1_access(size_t index, void *table) { struct commit_graft **commit_graft_table = table; - return commit_graft_table[index]->sha1; + return commit_graft_table[index]->oid.hash; } static int commit_graft_pos(const unsigned char *sha1) @@ -110,7 +110,7 @@ static int commit_graft_pos(const unsigned char *sha1) int register_commit_graft(struct commit_graft *graft, int ignore_dups) { - int pos = commit_graft_pos(graft->sha1); + int pos = commit_graft_pos(graft->oid.hash); if (0 <= pos) { if (ignore_dups) @@ -138,22 +138,23 @@ struct commit_graft *read_graft_line(char *buf, int len) /* The format is just "Commit Parent1 Parent2 ...\n" */ int i; struct commit_graft *graft = NULL; + const int entry_size = GIT_SHA1_HEXSZ + 1; while (len && isspace(buf[len-1])) buf[--len] = '\0'; if (buf[0] == '#' || buf[0] == '\0') return NULL; - if ((len + 1) % 41) + if ((len + 1) % entry_size) goto bad_graft_data; - i = (len + 1) / 41 - 1; - graft = xmalloc(sizeof(*graft) + 20 * i); + i = (len + 1) / entry_size - 1; + graft = xmalloc(sizeof(*graft) + GIT_SHA1_RAWSZ * i); graft->nr_parent = i; - if (get_sha1_hex(buf, graft->sha1)) + if (get_oid_hex(buf, &graft->oid)) goto bad_graft_data; - for (i = 40; i < len; i += 41) { + for (i = GIT_SHA1_HEXSZ; i < len; i += entry_size) { if (buf[i] != ' ') goto bad_graft_data; - if (get_sha1_hex(buf + i + 1, graft->parent[i/41])) + if (get_sha1_hex(buf + i + 1, graft->parent[i/entry_size].hash)) goto bad_graft_data; } return graft; @@ -302,39 +303,42 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s { const char *tail = buffer; const char *bufptr = buffer; - unsigned char parent[20]; + struct object_id parent; struct commit_list **pptr; struct commit_graft *graft; + const int tree_entry_len = GIT_SHA1_HEXSZ + 5; + const int parent_entry_len = GIT_SHA1_HEXSZ + 7; if (item->object.parsed) return 0; item->object.parsed = 1; tail += size; - if (tail <= bufptr + 46 || memcmp(bufptr, "tree ", 5) || bufptr[45] != '\n') + if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) || + bufptr[tree_entry_len] != '\n') return error("bogus commit object %s", sha1_to_hex(item->object.sha1)); - if (get_sha1_hex(bufptr + 5, parent) < 0) + if (get_sha1_hex(bufptr + 5, parent.hash) < 0) return error("bad tree pointer in commit %s", sha1_to_hex(item->object.sha1)); - item->tree = lookup_tree(parent); - bufptr += 46; /* "tree " + "hex sha1" + "\n" */ + item->tree = lookup_tree(parent.hash); + bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */ pptr = &item->parents; graft = lookup_commit_graft(item->object.sha1); - while (bufptr + 48 < tail && !memcmp(bufptr, "parent ", 7)) { + while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) { struct commit *new_parent; - if (tail <= bufptr + 48 || - get_sha1_hex(bufptr + 7, parent) || - bufptr[47] != '\n') + if (tail <= bufptr + parent_entry_len + 1 || + get_sha1_hex(bufptr + 7, parent.hash) || + bufptr[parent_entry_len] != '\n') return error("bad parents in commit %s", sha1_to_hex(item->object.sha1)); - bufptr += 48; + bufptr += parent_entry_len + 1; /* * The clone is shallow if nr_parent < 0, and we must * not traverse its real parents even when we unhide them. */ if (graft && (graft->nr_parent < 0 || grafts_replace_parents)) continue; - new_parent = lookup_commit(parent); + new_parent = lookup_commit(parent.hash); if (new_parent) pptr = &commit_list_insert(new_parent, pptr)->next; } @@ -342,7 +346,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s int i; struct commit *new_parent; for (i = 0; i < graft->nr_parent; i++) { - new_parent = lookup_commit(graft->parent[i]); + new_parent = lookup_commit(graft->parent[i].hash); if (!new_parent) continue; pptr = &commit_list_insert(new_parent, pptr)->next; @@ -1580,10 +1584,10 @@ struct commit *get_merge_parent(const char *name) { struct object *obj; struct commit *commit; - unsigned char sha1[20]; - if (get_sha1(name, sha1)) + struct object_id oid; + if (get_sha1(name, oid.hash)) return NULL; - obj = parse_object(sha1); + obj = parse_object(oid.hash); commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT); if (commit && !commit->util) { struct merge_remote_desc *desc; @@ -226,9 +226,9 @@ enum rev_sort_order { void sort_in_topological_order(struct commit_list **, enum rev_sort_order); struct commit_graft { - unsigned char sha1[20]; + struct object_id oid; int nr_parent; /* < 0 if shallow commit */ - unsigned char parent[FLEX_ARRAY][20]; /* more */ + struct object_id parent[FLEX_ARRAY]; /* more */ }; typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *); diff --git a/compat/mingw.h b/compat/mingw.h index 5e499cfb71..98c5e44294 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -98,8 +98,6 @@ static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline pid_t getppid(void) -{ return 1; } static inline void sync(void) {} static inline uid_t getuid(void) @@ -121,6 +119,12 @@ static inline int sigaddset(sigset_t *set, int signum) #define SIG_UNBLOCK 0 static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { return 0; } +static inline pid_t getppid(void) +{ return 1; } +static inline pid_t getpgid(pid_t pid) +{ return pid == 0 ? getpid() : pid; } +static inline pid_t tcgetpgrp(int fd) +{ return getpid(); } /* * simple adaptors @@ -12,6 +12,7 @@ #include "quote.h" #include "hashmap.h" #include "string-list.h" +#include "utf8.h" struct config_source { struct config_source *prev; @@ -49,7 +50,7 @@ static struct config_set the_config_set; static int config_file_fgetc(struct config_source *conf) { - return fgetc(conf->u.file); + return getc_unlocked(conf->u.file); } static int config_file_ungetc(int c, struct config_source *conf) @@ -417,8 +418,7 @@ static int git_parse_source(config_fn_t fn, void *data) struct strbuf *var = &cf->var; /* U+FEFF Byte Order Mark in UTF8 */ - static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; - const unsigned char *bomptr = utf8_bom; + const char *bomptr = utf8_bom; for (;;) { int c = get_next_char(); @@ -426,7 +426,7 @@ static int git_parse_source(config_fn_t fn, void *data) /* We are at the file beginning; skip UTF8-encoded BOM * if present. Sane editors won't put this in on their * own, but e.g. Windows Notepad will do it happily. */ - if ((unsigned char) c == *bomptr) { + if (c == (*bomptr & 0377)) { bomptr++; continue; } else { @@ -1088,7 +1088,9 @@ 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); + funlockfile(f); fclose(f); } return ret; diff --git a/config.mak.uname b/config.mak.uname index f4e77cb9e5..d26665fa54 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -36,6 +36,7 @@ ifeq ($(uname_S),Linux) HAVE_DEV_TTY = YesPlease HAVE_CLOCK_GETTIME = YesPlease HAVE_CLOCK_MONOTONIC = YesPlease + HAVE_GETDELIM = YesPlease endif ifeq ($(uname_S),GNU/kFreeBSD) HAVE_ALLOCA_H = YesPlease @@ -310,6 +310,8 @@ static void get_host_and_port(char **host, const char **port) if (end != colon + 1 && *end == '\0' && 0 <= portnr && portnr < 65536) { *colon = 0; *port = colon + 1; + } else if (!colon[1]) { + *colon = 0; } } } diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index fbe597232c..5944c824ab 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -186,7 +186,7 @@ fi __gitcompappend () { - local i=${#COMPREPLY[@]} + local x i=${#COMPREPLY[@]} for x in $1; do if [[ "$x" == "$3"* ]]; then COMPREPLY[i++]="$2$x$4" diff --git a/contrib/hooks/multimail/README b/contrib/hooks/multimail/README index 477d65fed3..6efa4ffe17 100644 --- a/contrib/hooks/multimail/README +++ b/contrib/hooks/multimail/README @@ -456,34 +456,35 @@ consider sharing them with the community! Getting involved ---------------- -git-multimail is an open-source project, built by volunteers. We -would welcome your help! +git-multimail is an open-source project, built by volunteers. We would +welcome your help! -The current maintainer is Michael Haggerty <mhagger@alum.mit.edu>. +The current maintainers are Michael Haggerty <mhagger@alum.mit.edu> +and Matthieu Moy <matthieu.moy@grenoble-inp.fr>. -General discussion of git-multimail takes place on the main Git -mailing list, +Please note that although a copy of git-multimail is distributed in +the "contrib" section of the main Git project, development takes place +in a separate git-multimail repository on GitHub: - git@vger.kernel.org + https://github.com/git-multimail/git-multimail -Please CC emails regarding git-multimail to me so that I don't -overlook them. +Whenever enough changes to git-multimail have accumulated, a new +code-drop of git-multimail will be submitted for inclusion in the Git +project. -The git-multimail project itself is currently hosted on GitHub: +We use the GitHub issue tracker to keep track of bugs and feature +requests, and we use GitHub pull requests to exchange patches (though, +if you prefer, you can send patches via the Git mailing list with CC +to the maintainers). Please sign off your patches as per the Git +project practice. - https://github.com/mhagger/git-multimail +General discussion of git-multimail can take place on the main Git +mailing list, -We use the GitHub issue tracker to keep track of bugs and feature -requests, and GitHub pull requests to exchange patches (though, if you -prefer, you can send patches via the Git mailing list with cc to me). -Please sign off your patches as per the Git project practice. - -Please note that although a copy of git-multimail will probably be -distributed in the "contrib" section of the main Git project, -development takes place in the separate git-multimail repository on -GitHub! (Whenever enough changes to git-multimail have accumulated, a -new code-drop of git-multimail will be submitted for inclusion in the -Git project.) + git@vger.kernel.org + +Please CC emails regarding git-multimail to the maintainers so that we +don't overlook them. Footnotes diff --git a/contrib/hooks/multimail/README.Git b/contrib/hooks/multimail/README.Git index 129b771410..ab3ece5221 100644 --- a/contrib/hooks/multimail/README.Git +++ b/contrib/hooks/multimail/README.Git @@ -3,13 +3,13 @@ section of the Git project as a convenience to Git users. git-multimail is developed as an independent project at the following website: - https://github.com/mhagger/git-multimail + https://github.com/git-multimail/git-multimail The version in this directory was obtained from the upstream project -on 2014-04-07 and consists of the "git-multimail" subdirectory from +on 2015-04-27 and consists of the "git-multimail" subdirectory from revision - 1b32653bafc4f902535b9fc1cd9cae911325b870 + 8c3aaafa873bf10de8dddf1d202c449b3eff3b42 refs/tags/1.0.2 Please see the README file in this directory for information about how to report bugs or contribute to git-multimail. diff --git a/credential-store.c b/credential-store.c index 925d3f4024..8b222513cb 100644 --- a/credential-store.c +++ b/credential-store.c @@ -6,7 +6,7 @@ static struct lock_file credential_lock; -static void parse_credential_file(const char *fn, +static int parse_credential_file(const char *fn, struct credential *c, void (*match_cb)(struct credential *), void (*other_cb)(struct strbuf *)) @@ -14,18 +14,20 @@ static void parse_credential_file(const char *fn, FILE *fh; struct strbuf line = STRBUF_INIT; struct credential entry = CREDENTIAL_INIT; + int found_credential = 0; fh = fopen(fn, "r"); if (!fh) { - if (errno != ENOENT) + if (errno != ENOENT && errno != EACCES) die_errno("unable to open %s", fn); - return; + return found_credential; } while (strbuf_getline(&line, fh, '\n') != EOF) { credential_from_url(&entry, line.buf); if (entry.username && entry.password && credential_match(c, &entry)) { + found_credential = 1; if (match_cb) { match_cb(&entry); break; @@ -38,6 +40,7 @@ static void parse_credential_file(const char *fn, credential_clear(&entry); strbuf_release(&line); fclose(fh); + return found_credential; } static void print_entry(struct credential *c) @@ -64,21 +67,10 @@ static void rewrite_credential_file(const char *fn, struct credential *c, die_errno("unable to commit credential store"); } -static void store_credential(const char *fn, struct credential *c) +static void store_credential_file(const char *fn, struct credential *c) { struct strbuf buf = STRBUF_INIT; - /* - * Sanity check that what we are storing is actually sensible. - * In particular, we can't make a URL without a protocol field. - * Without either a host or pathname (depending on the scheme), - * we have no primary key. And without a username and password, - * we are not actually storing a credential. - */ - if (!c->protocol || !(c->host || c->path) || - !c->username || !c->password) - return; - strbuf_addf(&buf, "%s://", c->protocol); strbuf_addstr_urlencode(&buf, c->username, 1); strbuf_addch(&buf, ':'); @@ -95,8 +87,37 @@ static void store_credential(const char *fn, struct credential *c) strbuf_release(&buf); } -static void remove_credential(const char *fn, struct credential *c) +static void store_credential(const struct string_list *fns, struct credential *c) +{ + struct string_list_item *fn; + + /* + * Sanity check that what we are storing is actually sensible. + * In particular, we can't make a URL without a protocol field. + * Without either a host or pathname (depending on the scheme), + * we have no primary key. And without a username and password, + * we are not actually storing a credential. + */ + if (!c->protocol || !(c->host || c->path) || !c->username || !c->password) + return; + + for_each_string_list_item(fn, fns) + if (!access(fn->string, F_OK)) { + store_credential_file(fn->string, c); + return; + } + /* + * Write credential to the filename specified by fns->items[0], thus + * creating it + */ + if (fns->nr) + store_credential_file(fns->items[0].string, c); +} + +static void remove_credential(const struct string_list *fns, struct credential *c) { + struct string_list_item *fn; + /* * Sanity check that we actually have something to match * against. The input we get is a restrictive pattern, @@ -105,14 +126,20 @@ static void remove_credential(const char *fn, struct credential *c) * to empty input. So explicitly disallow it, and require that the * pattern have some actual content to match. */ - if (c->protocol || c->host || c->path || c->username) - rewrite_credential_file(fn, c, NULL); + if (!c->protocol && !c->host && !c->path && !c->username) + return; + for_each_string_list_item(fn, fns) + if (!access(fn->string, F_OK)) + rewrite_credential_file(fn->string, c, NULL); } -static int lookup_credential(const char *fn, struct credential *c) +static void lookup_credential(const struct string_list *fns, struct credential *c) { - parse_credential_file(fn, c, print_entry, NULL); - return c->username && c->password; + struct string_list_item *fn; + + for_each_string_list_item(fn, fns) + if (parse_credential_file(fn->string, c, print_entry, NULL)) + return; /* Found credential */ } int main(int argc, char **argv) @@ -123,6 +150,7 @@ int main(int argc, char **argv) }; const char *op; struct credential c = CREDENTIAL_INIT; + struct string_list fns = STRING_LIST_INIT_DUP; char *file = NULL; struct option options[] = { OPT_STRING(0, "file", &file, "path", @@ -137,22 +165,30 @@ int main(int argc, char **argv) usage_with_options(usage, options); op = argv[0]; - if (!file) - file = expand_user_path("~/.git-credentials"); - if (!file) + if (file) { + string_list_append(&fns, file); + } else { + if ((file = expand_user_path("~/.git-credentials"))) + string_list_append_nodup(&fns, file); + home_config_paths(NULL, &file, "credentials"); + if (file) + string_list_append_nodup(&fns, file); + } + if (!fns.nr) die("unable to set up default path; use --file"); if (credential_read(&c, stdin) < 0) die("unable to read credential"); if (!strcmp(op, "get")) - lookup_credential(file, &c); + lookup_credential(&fns, &c); else if (!strcmp(op, "erase")) - remove_credential(file, &c); + remove_credential(&fns, &c); else if (!strcmp(op, "store")) - store_credential(file, &c); + store_credential(&fns, &c); else ; /* Ignore unknown operation. */ + string_list_clear(&fns, 0); return 0; } @@ -1166,15 +1166,6 @@ static struct credentials *prepare_credentials(const char *user_name, } #endif -static void store_pid(const char *path) -{ - FILE *f = fopen(path, "w"); - if (!f) - die_errno("cannot open pid file '%s'", path); - if (fprintf(f, "%"PRIuMAX"\n", (uintmax_t) getpid()) < 0 || fclose(f) != 0) - die_errno("failed to write pid file '%s'", path); -} - static int serve(struct string_list *listen_addr, int listen_port, struct credentials *cred) { @@ -1385,7 +1376,7 @@ int main(int argc, char **argv) sanitize_stdfds(); if (pid_file) - store_pid(pid_file); + write_file(pid_file, 1, "%"PRIuMAX"\n", (uintmax_t) getpid()); /* prepare argv for serving-processes */ cld_argv = xmalloc(sizeof (char *) * (argc + 2)); @@ -704,10 +704,17 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset) date += match; } - /* mktime uses local timezone */ + /* do not use mktime(), which uses local timezone, here */ *timestamp = tm_to_time_t(&tm); + if (*timestamp == -1) + return -1; + if (*offset == -1) { - time_t temp_time = mktime(&tm); + time_t temp_time; + + /* gmtime_r() in match_digit() may have clobbered it */ + tm.tm_isdst = -1; + temp_time = mktime(&tm); if ((time_t)*timestamp > temp_time) { *offset = ((time_t)*timestamp - temp_time) / 60; } else { @@ -715,9 +722,6 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset) } } - if (*timestamp == -1) - return -1; - if (!tm_gmt) *timestamp -= *offset * 60; return 0; /* success */ diff --git a/diff-lib.c b/diff-lib.c index a85c4971ac..241a8435eb 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -125,7 +125,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) dpath->next = NULL; memcpy(dpath->path, ce->name, path_len); dpath->path[path_len] = '\0'; - hashclr(dpath->sha1); + oidclr(&dpath->oid); memset(&(dpath->parent[0]), 0, sizeof(struct combine_diff_parent)*5); @@ -155,7 +155,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) if (2 <= stage) { int mode = nce->ce_mode; num_compare_stages++; - hashcpy(dpath->parent[stage-2].sha1, nce->sha1); + hashcpy(dpath->parent[stage-2].oid.hash, nce->sha1); dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode); dpath->parent[stage-2].status = DIFF_STATUS_MODIFIED; @@ -339,14 +339,14 @@ static int show_modified(struct rev_info *revs, memcpy(p->path, new->name, pathlen); p->path[pathlen] = 0; p->mode = mode; - hashclr(p->sha1); + oidclr(&p->oid); memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent)); p->parent[0].status = DIFF_STATUS_MODIFIED; p->parent[0].mode = new->ce_mode; - hashcpy(p->parent[0].sha1, new->sha1); + hashcpy(p->parent[0].oid.hash, new->sha1); p->parent[1].status = DIFF_STATUS_MODIFIED; p->parent[1].mode = old->ce_mode; - hashcpy(p->parent[1].sha1, old->sha1); + hashcpy(p->parent[1].oid.hash, old->sha1); show_combined_diff(p, 2, revs->dense_combined_merges, revs); free(p); return 0; diff --git a/diff-no-index.c b/diff-no-index.c index 265709ba8c..0320605a84 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -97,8 +97,27 @@ static int queue_diff(struct diff_options *o, if (get_mode(name1, &mode1) || get_mode(name2, &mode2)) return -1; - if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) - return error("file/directory conflict: %s, %s", name1, name2); + if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) { + struct diff_filespec *d1, *d2; + + if (S_ISDIR(mode1)) { + /* 2 is file that is created */ + d1 = noindex_filespec(NULL, 0); + d2 = noindex_filespec(name2, mode2); + name2 = NULL; + mode2 = 0; + } else { + /* 1 is file that is deleted */ + d1 = noindex_filespec(name1, mode1); + d2 = noindex_filespec(NULL, 0); + name1 = NULL; + mode1 = 0; + } + /* emit that file */ + diff_queue(&diff_queued_diff, d1, d2); + + /* and then let the entire directory be created or deleted */ + } if (S_ISDIR(mode1) || S_ISDIR(mode2)) { struct strbuf buffer1 = STRBUF_INIT; @@ -182,12 +201,50 @@ static int queue_diff(struct diff_options *o, } } +/* append basename of F to D */ +static void append_basename(struct strbuf *path, const char *dir, const char *file) +{ + const char *tail = strrchr(file, '/'); + + strbuf_addstr(path, dir); + while (path->len && path->buf[path->len - 1] == '/') + path->len--; + strbuf_addch(path, '/'); + strbuf_addstr(path, tail ? tail + 1 : file); +} + +/* + * DWIM "diff D F" into "diff D/F F" and "diff F D" into "diff F D/F" + * Note that we append the basename of F to D/, so "diff a/b/file D" + * becomes "diff a/b/file D/file", not "diff a/b/file D/a/b/file". + */ +static void fixup_paths(const char **path, struct strbuf *replacement) +{ + unsigned int isdir0, isdir1; + + if (path[0] == file_from_standard_input || + path[1] == file_from_standard_input) + return; + isdir0 = is_directory(path[0]); + isdir1 = is_directory(path[1]); + if (isdir0 == isdir1) + return; + if (isdir0) { + append_basename(replacement, path[0], path[1]); + path[0] = replacement->buf; + } else { + append_basename(replacement, path[1], path[0]); + path[1] = replacement->buf; + } +} + void diff_no_index(struct rev_info *revs, int argc, const char **argv, const char *prefix) { int i, prefixlen; const char *paths[2]; + struct strbuf replacement = STRBUF_INIT; diff_setup(&revs->diffopt); for (i = 1; i < argc - 2; ) { @@ -217,6 +274,9 @@ void diff_no_index(struct rev_info *revs, p = xstrdup(prefix_filename(prefix, prefixlen, p)); paths[i] = p; } + + fixup_paths(paths, &replacement); + revs->diffopt.skip_stat_unmatch = 1; if (!revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; @@ -235,6 +295,8 @@ void diff_no_index(struct rev_info *revs, diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); + strbuf_release(&replacement); + /* * The return code for --no-index imitates diff(1): * 0 = no changes, 1 = changes, else error @@ -6,6 +6,7 @@ #include "tree-walk.h" #include "pathspec.h" +#include "object.h" struct rev_info; struct diff_options; @@ -207,11 +208,11 @@ struct combine_diff_path { struct combine_diff_path *next; char *path; unsigned int mode; - unsigned char sha1[20]; + struct object_id oid; struct combine_diff_parent { char status; unsigned int mode; - unsigned char sha1[20]; + struct object_id oid; } parent[FLEX_ARRAY]; }; #define combine_diff_path_size(n, l) \ @@ -12,6 +12,7 @@ #include "refs.h" #include "wildmatch.h" #include "pathspec.h" +#include "utf8.h" struct path_simplify { int len; @@ -617,7 +618,12 @@ int add_excludes_from_file_to_list(const char *fname, } el->filebuf = buf; + + if (skip_utf8_bom(&buf, size)) + size -= buf - el->filebuf; + entry = buf; + for (i = 0; i < size; i++) { if (buf[i] == '\n') { if (entry != buf + i && entry[0] != '#') { diff --git a/environment.c b/environment.c index a40044c3bf..61c685b8d9 100644 --- a/environment.c +++ b/environment.c @@ -92,8 +92,9 @@ static char *work_tree; static const char *namespace; static size_t namespace_len; -static const char *git_dir; +static const char *git_dir, *git_common_dir; static char *git_object_dir, *git_index_file, *git_graft_file; +int git_db_env, git_index_env, git_graft_env, git_common_dir_env; /* * Repository-local GIT_* environment variables; see cache.h for details. @@ -111,6 +112,7 @@ const char * const local_repo_env[] = { NO_REPLACE_OBJECTS_ENVIRONMENT, GIT_PREFIX_ENVIRONMENT, GIT_SHALLOW_FILE_ENVIRONMENT, + GIT_COMMON_DIR_ENVIRONMENT, NULL }; @@ -135,14 +137,23 @@ static char *expand_namespace(const char *raw_namespace) return strbuf_detach(&buf, NULL); } -static char *git_path_from_env(const char *envvar, const char *path) +static char *git_path_from_env(const char *envvar, const char *git_dir, + const char *path, int *fromenv) { const char *value = getenv(envvar); - return value ? xstrdup(value) : git_pathdup("%s", path); + if (!value) { + char *buf = xmalloc(strlen(git_dir) + strlen(path) + 2); + sprintf(buf, "%s/%s", git_dir, path); + return buf; + } + if (fromenv) + *fromenv = 1; + return xstrdup(value); } static void setup_git_env(void) { + struct strbuf sb = STRBUF_INIT; const char *gitfile; const char *shallow_file; @@ -151,9 +162,15 @@ static void setup_git_env(void) git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; gitfile = read_gitfile(git_dir); git_dir = xstrdup(gitfile ? gitfile : git_dir); - git_object_dir = git_path_from_env(DB_ENVIRONMENT, "objects"); - git_index_file = git_path_from_env(INDEX_ENVIRONMENT, "index"); - git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, "info/grafts"); + if (get_common_dir(&sb, git_dir)) + git_common_dir_env = 1; + git_common_dir = strbuf_detach(&sb, NULL); + git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir, + "objects", &git_db_env); + git_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir, + "index", &git_index_env); + git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, git_common_dir, + "info/grafts", &git_graft_env); if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT)) check_replace_refs = 0; namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT)); @@ -176,6 +193,11 @@ const char *get_git_dir(void) return git_dir; } +const char *get_git_common_dir(void) +{ + return git_common_dir; +} + const char *get_git_namespace(void) { if (!namespace) diff --git a/fast-import.c b/fast-import.c index e78ca107b3..6378726993 100644 --- a/fast-import.c +++ b/fast-import.c @@ -405,7 +405,7 @@ static void dump_marks_helper(FILE *, uintmax_t, struct mark_set *); static void write_crash_report(const char *err) { - char *loc = git_path("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid()); + const char *loc = git_path("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid()); FILE *rpt = fopen(loc, "w"); struct branch *b; unsigned long lu; @@ -3113,12 +3113,9 @@ static void parse_progress(void) static char* make_fast_import_path(const char *path) { - struct strbuf abs_path = STRBUF_INIT; - if (!relative_marks_paths || is_absolute_path(path)) return xstrdup(path); - strbuf_addf(&abs_path, "%s/info/fast-import/%s", get_git_dir(), path); - return strbuf_detach(&abs_path, NULL); + return xstrdup(git_path("info/fast-import/%s", path)); } static void option_import_marks(const char *marks, @@ -827,10 +827,10 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"." continue fi - if test -x "$GIT_DIR"/hooks/applypatch-msg + hook="$(git rev-parse --git-path hooks/applypatch-msg)" + if test -x "$hook" then - "$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" || - stop_here $this + "$hook" "$dotest/final-commit" || stop_here $this fi if test -f "$dotest/final-commit" @@ -904,9 +904,10 @@ did you forget to use 'git add'?" stop_here_user_resolve $this fi - if test -x "$GIT_DIR"/hooks/pre-applypatch + hook="$(git rev-parse --git-path hooks/pre-applypatch)" + if test -x "$hook" then - "$GIT_DIR"/hooks/pre-applypatch || stop_here $this + "$hook" || stop_here $this fi tree=$(git write-tree) && @@ -933,18 +934,17 @@ did you forget to use 'git add'?" echo "$(cat "$dotest/original-commit") $commit" >> "$dotest/rewritten" fi - if test -x "$GIT_DIR"/hooks/post-applypatch - then - "$GIT_DIR"/hooks/post-applypatch - fi + hook="$(git rev-parse --git-path hooks/post-applypatch)" + test -x "$hook" && "$hook" go_next done if test -s "$dotest"/rewritten; then git notes copy --for-rewrite=rebase < "$dotest"/rewritten - if test -x "$GIT_DIR"/hooks/post-rewrite; then - "$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten + hook="$(git rev-parse --git-path hooks/post-rewrite)" + if test -x "$hook"; then + "$hook" rebase < "$dotest"/rewritten fi fi diff --git a/git-compat-util.h b/git-compat-util.h index bc8fc8cf85..685a0a4063 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -883,4 +883,10 @@ struct tm *git_gmtime_r(const time_t *, struct tm *); # define SHELL_PATH "/bin/sh" #endif +#ifndef _POSIX_THREAD_SAFE_FUNCTIONS +#define flockfile(fh) +#define funlockfile(fh) +#define getc_unlocked(fh) getc(fh) +#endif + #endif diff --git a/git-gui/GIT-VERSION-GEN b/git-gui/GIT-VERSION-GEN index a9ea21826a..a88b6824b9 100755 --- a/git-gui/GIT-VERSION-GEN +++ b/git-gui/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=0.19.GITGUI +DEF_VER=0.20.GITGUI LF=' ' diff --git a/git-gui/Makefile b/git-gui/Makefile index cde8b2ea31..4f00bdd3d6 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -177,7 +177,8 @@ git-gui: GIT-VERSION-FILE GIT-GUI-VARS echo then >>$@+ && \ echo ' 'echo \'git-gui version '$(GITGUI_VERSION)'\' >>$@+ && \ echo else >>$@+ && \ - echo ' 'exec \''$(libdir_SQ)/Git Gui.app/Contents/MacOS/$(subst \,,$(TKEXECUTABLE))'\' \ + echo ' libdir="$${GIT_GUI_LIB_DIR:-$(libdir_SQ)}"' >>$@+ && \ + echo ' 'exec \"'$$libdir/Git Gui.app/Contents/MacOS/$(subst \,,$(TKEXECUTABLE))'\" \ '"$$0" "$$@"' >>$@+ && \ echo fi >>$@+ && \ chmod +x $@+ && \ diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b186329d28..11048c7a0e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -49,7 +49,11 @@ catch {rename send {}} ; # What an evil concept... ## ## locate our library -set oguilib {@@GITGUI_LIBDIR@@} +if { [info exists ::env(GIT_GUI_LIB_DIR) ] } { + set oguilib $::env(GIT_GUI_LIB_DIR) +} else { + set oguilib {@@GITGUI_LIBDIR@@} +} set oguirel {@@GITGUI_RELATIVE@@} if {$oguirel eq {1}} { set oguilib [file dirname [file normalize $argv0]] @@ -79,9 +83,9 @@ if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} { return [uplevel 1 real__auto_load $name $args] } rename source real__source - proc source {name} { - puts stderr "source $name" - uplevel 1 real__source $name + proc source {args} { + puts stderr "source $args" + uplevel 1 [linsert $args 0 real__source] } if {[tk windowingsystem] eq "win32"} { console show } } @@ -666,9 +670,7 @@ proc kill_file_process {fd} { catch { if {[is_Windows]} { - # Use a Cygwin-specific flag to allow killing - # native Windows processes - exec kill -f $process + exec taskkill /pid $process } else { exec kill $process } @@ -908,6 +910,7 @@ set default_config(gui.fontdiff) [font configure font_diff] set default_config(gui.maxfilesdisplayed) 5000 set default_config(gui.usettk) 1 set default_config(gui.warndetachedcommit) 1 +set default_config(gui.tabsize) 8 set font_descs { {fontui font_ui {mc "Main Font"}} {fontdiff font_diff {mc "Diff/Console Font"}} @@ -1283,7 +1286,7 @@ load_config 0 apply_config # v1.7.0 introduced --show-toplevel to return the canonical work-tree -if {[package vsatisfies $_git_version 1.7.0-]} { +if {[package vcompare $_git_version 1.7.0] >= 0} { if { [is_Cygwin] } { catch {set _gitworktree [exec cygpath --windows [git rev-parse --show-toplevel]]} } else { @@ -1539,7 +1542,7 @@ proc rescan_stage2 {fd after} { close $fd } - if {[package vsatisfies $::_git_version 1.6.3-]} { + if {[package vcompare $::_git_version 1.6.3] >= 0} { set ls_others [list --exclude-standard] } else { set ls_others [list --exclude-per-directory=.gitignore] @@ -1962,20 +1965,22 @@ proc display_all_files {} { set to_display [lsort [array names file_states]] set display_limit [get_config gui.maxfilesdisplayed] - if {[llength $to_display] > $display_limit} { - if {!$files_warning} { - # do not repeatedly warn: - set files_warning 1 - info_popup [mc "Displaying only %s of %s files." \ - $display_limit [llength $to_display]] - } - set to_display [lrange $to_display 0 [expr {$display_limit-1}]] - } + set displayed 0 foreach path $to_display { set s $file_states($path) set m [lindex $s 0] set icon_name [lindex $s 1] + if {$displayed > $display_limit && [string index $m 1] eq {O} } { + if {!$files_warning} { + # do not repeatedly warn: + set files_warning 1 + info_popup [mc "Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files." \ + $display_limit [llength $to_display]] + } + continue + } + set s [string index $m 0] if {$s ne {U} && $s ne {_}} { display_all_files_helper $ui_index $path \ @@ -1990,6 +1995,7 @@ proc display_all_files {} { if {$s ne {_}} { display_all_files_helper $ui_workdir $path \ $icon_name $s + incr displayed } } diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 3c10bc656d..75d1da8d31 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -18,6 +18,7 @@ field local_path {} ; # Where this repository is locally field origin_url {} ; # Where we are cloning from field origin_name origin ; # What we shall call 'origin' field clone_type hardlink ; # Type of clone to construct +field recursive true ; # Recursive cloning flag field readtree_err ; # Error output from read-tree (if any) field sorted_recent ; # recent repositories (sorted) @@ -337,16 +338,31 @@ method _git_init {} { return 1 } -proc _is_git {path} { +proc _is_git {path {outdir_var ""}} { + if {$outdir_var ne ""} { + upvar 1 $outdir_var outdir + } + if {[file isfile $path]} { + set fp [open $path r] + gets $fp line + close $fp + if {[regexp "^gitdir: (.+)$" $line line link_target]} { + set path [file join [file dirname $path] $link_target] + set path [file normalize $path] + } + } + if {[file exists [file join $path HEAD]] && [file exists [file join $path objects]] && [file exists [file join $path config]]} { + set outdir $path return 1 } if {[is_Cygwin]} { if {[file exists [file join $path HEAD]] && [file exists [file join $path objects.lnk]] && [file exists [file join $path config.lnk]]} { + set outdir $path return 1 } } @@ -525,6 +541,11 @@ method _do_clone {} { foreach r $w_types { pack $r -anchor w } + ${NS}::checkbutton $args.type_f.recursive \ + -text [mc "Recursively clone submodules too"] \ + -variable @recursive \ + -onvalue true -offvalue false + pack $args.type_f.recursive -anchor w grid $args.type_l $args.type_f -sticky new grid columnconfigure $args 1 -weight 1 @@ -952,6 +973,30 @@ method _do_clone_checkout {HEAD} { fileevent $fd readable [cb _readtree_wait $fd] } +method _do_validate_submodule_cloning {ok} { + if {$ok} { + $o_cons done $ok + set done 1 + } else { + _clone_failed $this [mc "Cannot clone submodules."] + } +} + +method _do_clone_submodules {} { + if {$recursive eq {true}} { + destroy $w_body + set o_cons [console::embed \ + $w_body \ + [mc "Cloning submodules"]] + pack $w_body -fill both -expand 1 -padx 10 + $o_cons exec \ + [list git submodule update --init --recursive] \ + [cb _do_validate_submodule_cloning] + } else { + set done 1 + } +} + method _readtree_wait {fd} { set buf [read $fd] $o_cons update_meter $buf @@ -982,7 +1027,7 @@ method _readtree_wait {fd} { fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] } else { - set done 1 + _do_clone_submodules $this } } @@ -996,7 +1041,7 @@ method _postcheckout_wait {fd_ph} { hook_failed_popup post-checkout $pch_error 0 } unset pch_error - set done 1 + _do_clone_submodules $this return } fconfigure $fd_ph -blocking 0 @@ -1063,7 +1108,7 @@ method _open_local_path {} { } method _do_open2 {} { - if {![_is_git [file join $local_path .git]]} { + if {![_is_git [file join $local_path .git] actualgit]} { error_popup [mc "Not a Git repository: %s" [file tail $local_path]] return } @@ -1076,7 +1121,7 @@ method _do_open2 {} { } _append_recentrepos [pwd] - set ::_gitdir .git + set ::_gitdir $actualgit set ::_prefix {} set done 1 } diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index b0a5180af7..0d56986215 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -1,6 +1,19 @@ # git-gui diff viewer # Copyright (C) 2006, 2007 Shawn Pearce +proc apply_tab_size {{firsttab {}}} { + global have_tk85 repo_config ui_diff + + set w [font measure font_diff "0"] + if {$have_tk85 && $firsttab != 0} { + $ui_diff configure -tabs [list [expr {$firsttab * $w}] [expr {($firsttab + $repo_config(gui.tabsize)) * $w}]] + } elseif {$have_tk85 || $repo_config(gui.tabsize) != 8} { + $ui_diff configure -tabs [expr {$repo_config(gui.tabsize) * $w}] + } else { + $ui_diff configure -tabs {} + } +} + proc clear_diff {} { global ui_diff current_diff_path current_diff_header global ui_index ui_workdir @@ -105,6 +118,8 @@ proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} { set cont_info [list $scroll_pos $callback] + apply_tab_size 0 + if {[string first {U} $m] >= 0} { merge_load_stages $path [list show_unmerged_diff $cont_info] } elseif {$m eq {_O}} { @@ -401,7 +416,10 @@ proc read_diff {fd conflict_size cont_info} { # -- Automatically detect if this is a 3 way diff. # - if {[string match {@@@ *} $line]} {set is_3way_diff 1} + if {[string match {@@@ *} $line]} { + set is_3way_diff 1 + apply_tab_size 1 + } if {$::current_diff_inheader} { diff --git a/git-gui/lib/option.tcl b/git-gui/lib/option.tcl index 23c9ae72a4..b5b6b2fea6 100644 --- a/git-gui/lib/option.tcl +++ b/git-gui/lib/option.tcl @@ -161,6 +161,7 @@ proc do_options {} { {b gui.warndetachedcommit {mc "Warn before committing to a detached head"}} {s gui.stageuntracked {mc "Staging of untracked files"} {list "yes" "no" "ask"}} {b gui.displayuntracked {mc "Show untracked files"}} + {i-1..99 gui.tabsize {mc "Tab spacing"}} } { set type [lindex $option 0] set name [lindex $option 1] diff --git a/git-gui/macosx/AppMain.tcl b/git-gui/macosx/AppMain.tcl index 738bdd03ed..b6c6dc3500 100644 --- a/git-gui/macosx/AppMain.tcl +++ b/git-gui/macosx/AppMain.tcl @@ -1,5 +1,10 @@ set gitexecdir {@@gitexecdir@@} -set gitguilib {@@GITGUI_LIBDIR@@} +if { [info exists ::env(GIT_GUI_LIB_DIR) ] } { + set gitguilib $::env(GIT_GUI_LIB_DIR) +} else { + set gitguilib {@@GITGUI_LIBDIR@@} +} + set env(PATH) "$gitexecdir:$env(PATH)" if {[string first -psn [lindex $argv 0]] == 0} { diff --git a/git-gui/po/bg.po b/git-gui/po/bg.po index 89b3a4e53d..4d9b039dc2 100644 --- a/git-gui/po/bg.po +++ b/git-gui/po/bg.po @@ -1,15 +1,15 @@ # Bulgarian translation of git-gui po-file. -# Copyright (C) 2012, 2013, 2014 Alexander Shopov <ash@kambanaria.org>. +# Copyright (C) 2012, 2013, 2014, 2015 Alexander Shopov <ash@kambanaria.org>. # This file is distributed under the same license as the git package. -# Alexander Shopov <ash@kambanaria.org>, 2012, 2013, 2014. +# Alexander Shopov <ash@kambanaria.org>, 2012, 2013, 2014, 2015. # # msgid "" msgstr "" "Project-Id-Version: git-gui master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-01-13 20:45+0200\n" -"PO-Revision-Date: 2014-01-13 21:31+0200\n" +"POT-Creation-Date: 2015-04-07 07:37+0300\n" +"PO-Revision-Date: 2015-04-07 07:46+0300\n" "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n" "Language-Team: Bulgarian <dict@fsa-bg.org>\n" "Language: bg\n" @@ -18,33 +18,33 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: git-gui.sh:859 +#: git-gui.sh:861 #, tcl-format msgid "Invalid font specified in %s:" -msgstr "Указан е неправилен шрифт в %s:" +msgstr "Указан е неправилен шрифт в „%s“:" -#: git-gui.sh:912 +#: git-gui.sh:915 msgid "Main Font" msgstr "ОÑновен шрифт" -#: git-gui.sh:913 +#: git-gui.sh:916 msgid "Diff/Console Font" msgstr "Шрифт за разликите/конзолата" -#: git-gui.sh:928 git-gui.sh:942 git-gui.sh:955 git-gui.sh:1045 -#: git-gui.sh:1064 git-gui.sh:3115 +#: git-gui.sh:931 git-gui.sh:945 git-gui.sh:958 git-gui.sh:1048 +#: git-gui.sh:1067 git-gui.sh:3125 msgid "git-gui: fatal error" msgstr "git-gui: фатална грешка" -#: git-gui.sh:929 +#: git-gui.sh:932 msgid "Cannot find git in PATH." msgstr "Командата git липÑва в Ð¿ÑŠÑ‚Ñ (PATH)." -#: git-gui.sh:956 +#: git-gui.sh:959 msgid "Cannot parse Git version string:" msgstr "Ðизът Ñ Ð²ÐµÑ€ÑиÑта на Git не може да бъде интерпретиран:" -#: git-gui.sh:981 +#: git-gui.sh:984 #, tcl-format msgid "" "Git version cannot be determined.\n" @@ -57,504 +57,509 @@ msgid "" msgstr "" "ВерÑиÑта на Git не може да бъде определена.\n" "\n" -"ВерÑиÑта на %s изглежда, че е „%s“.\n" +"ВерÑиÑта на „%s“ изглежда, че е „%s“.\n" "\n" -"%s изиÑква Git, верÑÐ¸Ñ Ð¿Ð¾Ð½Ðµ 1.5.0.\n" +"„%s“ изиÑква Git, верÑÐ¸Ñ Ð¿Ð¾Ð½Ðµ 1.5.0.\n" "\n" -"Да Ñе приеме ли, че „%s“ е верÑÐ¸Ñ 1.5.0?\n" +"Да Ñе приеме ли, че „%s“ е верÑÐ¸Ñ â€ž1.5.0“?\n" -#: git-gui.sh:1278 +#: git-gui.sh:1281 msgid "Git directory not found:" msgstr "ДиректориÑта на Git не е открита:" -#: git-gui.sh:1312 +#: git-gui.sh:1315 msgid "Cannot move to top of working directory:" msgstr "Ðе може да Ñе премине към родителÑката директориÑ." -#: git-gui.sh:1320 +#: git-gui.sh:1323 msgid "Cannot use bare repository:" msgstr "Голо хранилище не може да Ñе използва:" -#: git-gui.sh:1328 +#: git-gui.sh:1331 msgid "No working directory" msgstr "Работната Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð»Ð¸Ð¿Ñва" -#: git-gui.sh:1500 lib/checkout_op.tcl:306 +#: git-gui.sh:1503 lib/checkout_op.tcl:306 msgid "Refreshing file status..." msgstr "ОбновÑване на ÑÑŠÑтоÑнието на файла…" -#: git-gui.sh:1560 +#: git-gui.sh:1563 msgid "Scanning for modified files ..." msgstr "Проверка за променени файлове…" -#: git-gui.sh:1632 +#: git-gui.sh:1639 msgid "Calling prepare-commit-msg hook..." -msgstr "Куката prepare-commit-msg Ñе изпълнÑва в момента…" +msgstr "Куката „prepare-commit-msg“ Ñе изпълнÑва в момента…" -#: git-gui.sh:1649 +#: git-gui.sh:1656 msgid "Commit declined by prepare-commit-msg hook." -msgstr "Подаването е отхвърлено от куката prepare-commit-msg." +msgstr "Подаването е отхвърлено от куката „prepare-commit-msg“." -#: git-gui.sh:1807 lib/browser.tcl:252 +#: git-gui.sh:1814 lib/browser.tcl:252 msgid "Ready." msgstr "Готово." -#: git-gui.sh:1965 +#: git-gui.sh:1978 #, tcl-format -msgid "Displaying only %s of %s files." -msgstr "Показване на Ñамо %s от %s файла." +msgid "" +"Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files." +msgstr "" +"ДоÑтигнат е макÑималниÑÑ‚ брой файлове за показване (gui.maxfilesdisplayed = " +"%s). Файловете Ñа общо %s." -#: git-gui.sh:2091 +#: git-gui.sh:2101 msgid "Unmodified" msgstr "Ðепроменен" -#: git-gui.sh:2093 +#: git-gui.sh:2103 msgid "Modified, not staged" msgstr "Променен, но не е в индекÑа" -#: git-gui.sh:2094 git-gui.sh:2106 +#: git-gui.sh:2104 git-gui.sh:2116 msgid "Staged for commit" msgstr "Ð’ индекÑа за подаване" -#: git-gui.sh:2095 git-gui.sh:2107 +#: git-gui.sh:2105 git-gui.sh:2117 msgid "Portions staged for commit" msgstr "ЧаÑти Ñа в индекÑа за подаване" -#: git-gui.sh:2096 git-gui.sh:2108 +#: git-gui.sh:2106 git-gui.sh:2118 msgid "Staged for commit, missing" msgstr "Ð’ индекÑа за подаване, но липÑва" -#: git-gui.sh:2098 +#: git-gui.sh:2108 msgid "File type changed, not staged" msgstr "Видът на файла е Ñменен, но не е в индекÑа" -#: git-gui.sh:2099 git-gui.sh:2100 +#: git-gui.sh:2109 git-gui.sh:2110 msgid "File type changed, old type staged for commit" -msgstr "Видът на файла е Ñменен, в индекÑа е ÑтариÑÑ‚" +msgstr "Видът на файла е Ñменен, но в индекÑа е вÑе още ÑтариÑÑ‚" -#: git-gui.sh:2101 +#: git-gui.sh:2111 msgid "File type changed, staged" msgstr "Видът на файла е Ñменен и е в индекÑа" -#: git-gui.sh:2102 +#: git-gui.sh:2112 msgid "File type change staged, modification not staged" -msgstr "Видът на файла е Ñменен, промÑната не е в индекÑа" +msgstr "Видът на файла е Ñменен, но промÑната не е в индекÑа" -#: git-gui.sh:2103 +#: git-gui.sh:2113 msgid "File type change staged, file missing" msgstr "Видът на файла е Ñменен, файлът липÑва" -#: git-gui.sh:2105 +#: git-gui.sh:2115 msgid "Untracked, not staged" msgstr "ÐеÑледен" -#: git-gui.sh:2110 +#: git-gui.sh:2120 msgid "Missing" msgstr "ЛипÑващ" -#: git-gui.sh:2111 +#: git-gui.sh:2121 msgid "Staged for removal" msgstr "Ð’ индекÑа за изтриване" -#: git-gui.sh:2112 +#: git-gui.sh:2122 msgid "Staged for removal, still present" msgstr "Ð’ индекÑа за изтриване, но още го има" -#: git-gui.sh:2114 git-gui.sh:2115 git-gui.sh:2116 git-gui.sh:2117 -#: git-gui.sh:2118 git-gui.sh:2119 +#: git-gui.sh:2124 git-gui.sh:2125 git-gui.sh:2126 git-gui.sh:2127 +#: git-gui.sh:2128 git-gui.sh:2129 msgid "Requires merge resolution" msgstr "ИзиÑква коригиране при Ñливане" -#: git-gui.sh:2154 +#: git-gui.sh:2164 msgid "Starting gitk... please wait..." -msgstr "Стартиране на gitk…, изчакайте…" +msgstr "Стартиране на „gitk“…, изчакайте…" -#: git-gui.sh:2166 +#: git-gui.sh:2176 msgid "Couldn't find gitk in PATH" -msgstr "Ð’ пътищата, определени от променливата PATH, липÑва изпълним gitk" +msgstr "Командата „gitk“ липÑва в пътищата, определени от променливата PATH." -#: git-gui.sh:2225 +#: git-gui.sh:2235 msgid "Couldn't find git gui in PATH" -msgstr "Ð’ пътищата, определени от променливата PATH, липÑва изпълним git gui" +msgstr "" +"Командата „git gui“ липÑва в пътищата, определени от променливата PATH." -#: git-gui.sh:2644 lib/choose_repository.tcl:40 +#: git-gui.sh:2654 lib/choose_repository.tcl:41 msgid "Repository" msgstr "Хранилище" -#: git-gui.sh:2645 +#: git-gui.sh:2655 msgid "Edit" msgstr "Редактиране" -#: git-gui.sh:2647 lib/choose_rev.tcl:567 +#: git-gui.sh:2657 lib/choose_rev.tcl:567 msgid "Branch" msgstr "Клон" -#: git-gui.sh:2650 lib/choose_rev.tcl:554 +#: git-gui.sh:2660 lib/choose_rev.tcl:554 msgid "Commit@@noun" msgstr "Подаване" -#: git-gui.sh:2653 lib/merge.tcl:123 lib/merge.tcl:152 lib/merge.tcl:170 +#: git-gui.sh:2663 lib/merge.tcl:123 lib/merge.tcl:152 lib/merge.tcl:170 msgid "Merge" msgstr "Сливане" -#: git-gui.sh:2654 lib/choose_rev.tcl:563 +#: git-gui.sh:2664 lib/choose_rev.tcl:563 msgid "Remote" msgstr "Отдалечено хранилище" -#: git-gui.sh:2657 +#: git-gui.sh:2667 msgid "Tools" msgstr "Команди" -#: git-gui.sh:2666 +#: git-gui.sh:2676 msgid "Explore Working Copy" msgstr "Разглеждане на работното копие" -#: git-gui.sh:2672 +#: git-gui.sh:2682 msgid "Git Bash" -msgstr "Bash на Git" +msgstr "Bash за Git" -#: git-gui.sh:2682 +#: git-gui.sh:2692 msgid "Browse Current Branch's Files" msgstr "Разглеждане на файловете в Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ ÐºÐ»Ð¾Ð½" -#: git-gui.sh:2686 +#: git-gui.sh:2696 msgid "Browse Branch Files..." -msgstr "Разглеждане на Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ ÐºÐ»Ð¾Ð½" +msgstr "Разглеждане на Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ ÐºÐ»Ð¾Ð½â€¦" -#: git-gui.sh:2691 +#: git-gui.sh:2701 msgid "Visualize Current Branch's History" msgstr "Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° иÑториÑта на Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ ÐºÐ»Ð¾Ð½" -#: git-gui.sh:2695 +#: git-gui.sh:2705 msgid "Visualize All Branch History" msgstr "Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° иÑториÑта на вÑички клонове" -#: git-gui.sh:2702 +#: git-gui.sh:2712 #, tcl-format msgid "Browse %s's Files" msgstr "Разглеждане на файловете в %s" -#: git-gui.sh:2704 +#: git-gui.sh:2714 #, tcl-format msgid "Visualize %s's History" msgstr "Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° иÑториÑта на %s" -#: git-gui.sh:2709 lib/database.tcl:40 lib/database.tcl:66 +#: git-gui.sh:2719 lib/database.tcl:40 lib/database.tcl:66 msgid "Database Statistics" msgstr "СтатиÑтика на базата от данни" -#: git-gui.sh:2712 lib/database.tcl:33 +#: git-gui.sh:2722 lib/database.tcl:33 msgid "Compress Database" msgstr "КомпреÑиране на базата от данни" -#: git-gui.sh:2715 +#: git-gui.sh:2725 msgid "Verify Database" msgstr "Проверка на базата от данни" -#: git-gui.sh:2722 git-gui.sh:2726 git-gui.sh:2730 lib/shortcut.tcl:8 +#: git-gui.sh:2732 git-gui.sh:2736 git-gui.sh:2740 lib/shortcut.tcl:8 #: lib/shortcut.tcl:40 lib/shortcut.tcl:72 msgid "Create Desktop Icon" msgstr "ДобавÑне на икона на Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ð»Ð¾Ñ‚" -#: git-gui.sh:2738 lib/choose_repository.tcl:192 lib/choose_repository.tcl:200 +#: git-gui.sh:2748 lib/choose_repository.tcl:193 lib/choose_repository.tcl:201 msgid "Quit" msgstr "Спиране на програмата" -#: git-gui.sh:2746 +#: git-gui.sh:2756 msgid "Undo" msgstr "ОтмÑна" -#: git-gui.sh:2749 +#: git-gui.sh:2759 msgid "Redo" msgstr "Повторение" -#: git-gui.sh:2753 git-gui.sh:3348 +#: git-gui.sh:2763 git-gui.sh:3368 msgid "Cut" msgstr "ОтрÑзване" -#: git-gui.sh:2756 git-gui.sh:3351 git-gui.sh:3425 git-gui.sh:3510 +#: git-gui.sh:2766 git-gui.sh:3371 git-gui.sh:3445 git-gui.sh:3530 #: lib/console.tcl:69 msgid "Copy" msgstr "Копиране" -#: git-gui.sh:2759 git-gui.sh:3354 +#: git-gui.sh:2769 git-gui.sh:3374 msgid "Paste" msgstr "ПоÑтавÑне" -#: git-gui.sh:2762 git-gui.sh:3357 lib/remote_branch_delete.tcl:39 +#: git-gui.sh:2772 git-gui.sh:3377 lib/remote_branch_delete.tcl:39 #: lib/branch_delete.tcl:28 msgid "Delete" msgstr "Изтриване" -#: git-gui.sh:2766 git-gui.sh:3361 git-gui.sh:3514 lib/console.tcl:71 +#: git-gui.sh:2776 git-gui.sh:3381 git-gui.sh:3534 lib/console.tcl:71 msgid "Select All" msgstr "Избиране на вÑичко" -#: git-gui.sh:2775 +#: git-gui.sh:2785 msgid "Create..." msgstr "Създаване…" -#: git-gui.sh:2781 +#: git-gui.sh:2791 msgid "Checkout..." msgstr "ИзтеглÑне…" -#: git-gui.sh:2787 +#: git-gui.sh:2797 msgid "Rename..." msgstr "Преименуване…" -#: git-gui.sh:2792 +#: git-gui.sh:2802 msgid "Delete..." msgstr "Изтриване…" -#: git-gui.sh:2797 +#: git-gui.sh:2807 msgid "Reset..." msgstr "ОтмÑна на промените…" -#: git-gui.sh:2807 +#: git-gui.sh:2817 msgid "Done" msgstr "Готово" -#: git-gui.sh:2809 +#: git-gui.sh:2819 msgid "Commit@@verb" msgstr "Подаване" -#: git-gui.sh:2818 git-gui.sh:3289 +#: git-gui.sh:2828 git-gui.sh:3309 msgid "New Commit" -msgstr "Подаване" +msgstr "Ðово подаване" -#: git-gui.sh:2826 git-gui.sh:3296 +#: git-gui.sh:2836 git-gui.sh:3316 msgid "Amend Last Commit" msgstr "ПоправÑне на поÑледното подаване" -#: git-gui.sh:2836 git-gui.sh:3250 lib/remote_branch_delete.tcl:101 +#: git-gui.sh:2846 git-gui.sh:3270 lib/remote_branch_delete.tcl:101 msgid "Rescan" msgstr "ОбновÑване" -#: git-gui.sh:2842 +#: git-gui.sh:2852 msgid "Stage To Commit" msgstr "Към индекÑа за подаване" -#: git-gui.sh:2848 +#: git-gui.sh:2858 msgid "Stage Changed Files To Commit" msgstr "Ð’Ñички променени файлове към индекÑа за подаване" -#: git-gui.sh:2854 +#: git-gui.sh:2864 msgid "Unstage From Commit" msgstr "Изваждане от индекÑа за подаване" -#: git-gui.sh:2860 lib/index.tcl:442 +#: git-gui.sh:2870 lib/index.tcl:442 msgid "Revert Changes" msgstr "Връщане на оригинала" -#: git-gui.sh:2868 git-gui.sh:3561 git-gui.sh:3592 +#: git-gui.sh:2878 git-gui.sh:3581 git-gui.sh:3612 msgid "Show Less Context" msgstr "По-малко контекÑÑ‚" -#: git-gui.sh:2872 git-gui.sh:3565 git-gui.sh:3596 +#: git-gui.sh:2882 git-gui.sh:3585 git-gui.sh:3616 msgid "Show More Context" msgstr "Повече контекÑÑ‚" -#: git-gui.sh:2879 git-gui.sh:3263 git-gui.sh:3372 +#: git-gui.sh:2889 git-gui.sh:3283 git-gui.sh:3392 msgid "Sign Off" msgstr "ПодпиÑване" -#: git-gui.sh:2895 +#: git-gui.sh:2905 msgid "Local Merge..." msgstr "Локално Ñливане…" -#: git-gui.sh:2900 +#: git-gui.sh:2910 msgid "Abort Merge..." msgstr "ПреуÑтановÑване на Ñливане…" -#: git-gui.sh:2912 git-gui.sh:2940 +#: git-gui.sh:2922 git-gui.sh:2950 msgid "Add..." msgstr "ДобавÑне…" -#: git-gui.sh:2916 +#: git-gui.sh:2926 msgid "Push..." msgstr "Избутване…" -#: git-gui.sh:2920 +#: git-gui.sh:2930 msgid "Delete Branch..." msgstr "Изтриване на клон…" -#: git-gui.sh:2930 git-gui.sh:3543 +#: git-gui.sh:2940 git-gui.sh:3563 msgid "Options..." msgstr "Опции…" -#: git-gui.sh:2941 +#: git-gui.sh:2951 msgid "Remove..." msgstr "Премахване…" -#: git-gui.sh:2950 lib/choose_repository.tcl:54 +#: git-gui.sh:2960 lib/choose_repository.tcl:55 msgid "Help" msgstr "Помощ" -#: git-gui.sh:2954 git-gui.sh:2958 lib/choose_repository.tcl:48 -#: lib/choose_repository.tcl:57 lib/about.tcl:14 +#: git-gui.sh:2964 git-gui.sh:2968 lib/choose_repository.tcl:49 +#: lib/choose_repository.tcl:58 lib/about.tcl:14 #, tcl-format msgid "About %s" msgstr "ОтноÑно %s" -#: git-gui.sh:2982 +#: git-gui.sh:2992 msgid "Online Documentation" msgstr "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð² Интернет" -#: git-gui.sh:2985 lib/choose_repository.tcl:51 lib/choose_repository.tcl:60 +#: git-gui.sh:2995 lib/choose_repository.tcl:52 lib/choose_repository.tcl:61 msgid "Show SSH Key" msgstr "Показване на ключа за SSH" -#: git-gui.sh:3004 git-gui.sh:3136 +#: git-gui.sh:3014 git-gui.sh:3146 msgid "Usage" msgstr "Употреба" -#: git-gui.sh:3085 lib/blame.tcl:573 +#: git-gui.sh:3095 lib/blame.tcl:573 msgid "Error" msgstr "Грешка" -#: git-gui.sh:3116 +#: git-gui.sh:3126 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" msgstr "" -"фатално: пътÑÑ‚ %s не може да бъде открит: такъв файл или Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ñма" +"ФÐТÐЛÐРГРЕШКÐ: пътÑÑ‚ %s не може да бъде открит: такъв файл или Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ " +"нÑма" -#: git-gui.sh:3149 +#: git-gui.sh:3159 msgid "Current Branch:" msgstr "Текущ клон:" -#: git-gui.sh:3175 +#: git-gui.sh:3185 msgid "Staged Changes (Will Commit)" msgstr "Промени в индекÑа (за подаване)" -#: git-gui.sh:3195 +#: git-gui.sh:3205 msgid "Unstaged Changes" msgstr "Промени извън индекÑа" -#: git-gui.sh:3256 +#: git-gui.sh:3276 msgid "Stage Changed" msgstr "ИндекÑÑŠÑ‚ е променен" -#: git-gui.sh:3275 lib/transport.tcl:137 lib/transport.tcl:229 +#: git-gui.sh:3295 lib/transport.tcl:137 lib/transport.tcl:229 msgid "Push" msgstr "ИзтлаÑкване" -#: git-gui.sh:3310 +#: git-gui.sh:3330 msgid "Initial Commit Message:" msgstr "Първоначално Ñъобщение при подаване:" -#: git-gui.sh:3311 +#: git-gui.sh:3331 msgid "Amended Commit Message:" msgstr "Поправено Ñъобщение при подаване:" -#: git-gui.sh:3312 +#: git-gui.sh:3332 msgid "Amended Initial Commit Message:" msgstr "Поправено първоначално Ñъобщение при подаване:" -#: git-gui.sh:3313 +#: git-gui.sh:3333 msgid "Amended Merge Commit Message:" msgstr "Поправено Ñъобщение при подаване ÑÑŠÑ Ñливане:" -#: git-gui.sh:3314 +#: git-gui.sh:3334 msgid "Merge Commit Message:" msgstr "Съобщение при подаване ÑÑŠÑ Ñливане:" -#: git-gui.sh:3315 +#: git-gui.sh:3335 msgid "Commit Message:" msgstr "Съобщение при подаване:" -#: git-gui.sh:3364 git-gui.sh:3518 lib/console.tcl:73 +#: git-gui.sh:3384 git-gui.sh:3538 lib/console.tcl:73 msgid "Copy All" msgstr "Копиране на вÑичко" -#: git-gui.sh:3388 lib/blame.tcl:105 +#: git-gui.sh:3408 lib/blame.tcl:105 msgid "File:" msgstr "Файл:" -#: git-gui.sh:3506 +#: git-gui.sh:3526 msgid "Refresh" msgstr "ОбновÑване" -#: git-gui.sh:3527 +#: git-gui.sh:3547 msgid "Decrease Font Size" msgstr "По-едър шрифт" -#: git-gui.sh:3531 +#: git-gui.sh:3551 msgid "Increase Font Size" msgstr "По-дребен шрифт" -#: git-gui.sh:3539 lib/blame.tcl:294 +#: git-gui.sh:3559 lib/blame.tcl:294 msgid "Encoding" msgstr "Кодиране" -#: git-gui.sh:3550 +#: git-gui.sh:3570 msgid "Apply/Reverse Hunk" msgstr "Прилагане/връщане на парче" -#: git-gui.sh:3555 +#: git-gui.sh:3575 msgid "Apply/Reverse Line" msgstr "Прилагане/връщане на ред" -#: git-gui.sh:3574 +#: git-gui.sh:3594 msgid "Run Merge Tool" msgstr "Изпълнение на програмата за Ñливане" -#: git-gui.sh:3579 +#: git-gui.sh:3599 msgid "Use Remote Version" msgstr "ВерÑÐ¸Ñ Ð¾Ñ‚ отдалеченото хранилище" -#: git-gui.sh:3583 +#: git-gui.sh:3603 msgid "Use Local Version" msgstr "Локална верÑиÑ" -#: git-gui.sh:3587 +#: git-gui.sh:3607 msgid "Revert To Base" msgstr "Връщане към родителÑката верÑиÑ" -#: git-gui.sh:3605 +#: git-gui.sh:3625 msgid "Visualize These Changes In The Submodule" msgstr "Визуализиране на промените в подмодула" -#: git-gui.sh:3609 +#: git-gui.sh:3629 msgid "Visualize Current Branch History In The Submodule" msgstr "Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° иÑториÑта на Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ ÐºÐ»Ð¾Ð½ в иÑториÑта за подмодула" -#: git-gui.sh:3613 +#: git-gui.sh:3633 msgid "Visualize All Branch History In The Submodule" msgstr "Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° иÑториÑта на вÑички клони в иÑториÑта за подмодула" -#: git-gui.sh:3618 +#: git-gui.sh:3638 msgid "Start git gui In The Submodule" msgstr "Стартиране на „git gui“ за подмодула" -#: git-gui.sh:3653 +#: git-gui.sh:3673 msgid "Unstage Hunk From Commit" msgstr "Изваждане на парчето от подаването" -#: git-gui.sh:3655 +#: git-gui.sh:3675 msgid "Unstage Lines From Commit" msgstr "Изваждане на редовете от подаването" -#: git-gui.sh:3657 +#: git-gui.sh:3677 msgid "Unstage Line From Commit" msgstr "Изваждане на реда от подаването" -#: git-gui.sh:3660 +#: git-gui.sh:3680 msgid "Stage Hunk For Commit" msgstr "ДобавÑне на парчето за подаване" -#: git-gui.sh:3662 +#: git-gui.sh:3682 msgid "Stage Lines For Commit" msgstr "ДобавÑне на редовете за подаване" -#: git-gui.sh:3664 +#: git-gui.sh:3684 msgid "Stage Line For Commit" msgstr "ДобавÑне на реда за подаване" -#: git-gui.sh:3689 +#: git-gui.sh:3709 msgid "Initializing..." msgstr "Инициализиране…" -#: git-gui.sh:3832 +#: git-gui.sh:3852 #, tcl-format msgid "" "Possible environment issues exist.\n" @@ -567,11 +572,11 @@ msgstr "" "Възможно е да има проблем ÑÑŠÑ Ñредата.\n" "\n" "Ðай-вероÑтно Ñледните променливи нÑма да бъдат\n" -"взети под внимание от подпроцеÑите Git изпълнени\n" +"взети под внимание от подпроцеÑите на Git\n" "от %s:\n" "\n" -#: git-gui.sh:3861 +#: git-gui.sh:3881 msgid "" "\n" "This is due to a known issue with the\n" @@ -581,7 +586,7 @@ msgstr "" "Това е познат проблем и Ñе дължи на\n" "верÑиÑта на Tcl включена в Cygwin." -#: git-gui.sh:3866 +#: git-gui.sh:3886 #, tcl-format msgid "" "\n" @@ -593,9 +598,9 @@ msgid "" msgstr "" "\n" "\n" -"Добър замеÑтител на %s\n" -"е да поÑтавите наÑтройките user.name и\n" -"user.email в Ð»Ð¸Ñ‡Ð½Ð¸Ñ Ñи файл ~/.gitconfig.\n" +"Добър замеÑтител на „%s“\n" +"е да поÑтавите наÑтройките „user.name“ и\n" +"„user.email“ в Ð»Ð¸Ñ‡Ð½Ð¸Ñ Ñи файл „~/.gitconfig“.\n" #: lib/spellcheck.tcl:57 msgid "Unsupported spell checker" @@ -744,9 +749,9 @@ msgstr "[Към родителÑ]" msgid "Browse Branch Files" msgstr "Разглеждане на файловете в клона" -#: lib/browser.tcl:288 lib/choose_repository.tcl:406 -#: lib/choose_repository.tcl:493 lib/choose_repository.tcl:502 -#: lib/choose_repository.tcl:1029 +#: lib/browser.tcl:288 lib/choose_repository.tcl:422 +#: lib/choose_repository.tcl:509 lib/choose_repository.tcl:518 +#: lib/choose_repository.tcl:1074 msgid "Browse" msgstr "Разглеждане" @@ -762,12 +767,12 @@ msgstr "За изпълнението на „%s“ Ñ‚Ñ€Ñбва да избер #: lib/tools.tcl:91 #, tcl-format msgid "Are you sure you want to run %1$s on file \"%2$s\"?" -msgstr "Сигурни ли Ñте, че иÑкате да Ñтартирате „%1$s“ върху „%2$s“?" +msgstr "Сигурни ли Ñте, че иÑкате да изпълните „%1$s“ върху файла „%2$s“?" #: lib/tools.tcl:95 #, tcl-format msgid "Are you sure you want to run %s?" -msgstr "Сигурни ли Ñте, че иÑкате да Ñтартирате „%s“?" +msgstr "Сигурни ли Ñте, че иÑкате да изпълните „%s“?" #: lib/tools.tcl:116 #, tcl-format @@ -797,7 +802,7 @@ msgstr "Клон за изтеглÑне" msgid "Checkout" msgstr "ИзтеглÑне" -#: lib/branch_checkout.tcl:39 lib/option.tcl:309 lib/branch_create.tcl:69 +#: lib/branch_checkout.tcl:39 lib/option.tcl:310 lib/branch_create.tcl:69 msgid "Options" msgstr "Опции" @@ -812,7 +817,7 @@ msgstr "Изтриване от Ð»Ð¾ÐºÐ°Ð»Ð½Ð¸Ñ ÐºÐ»Ð¾Ð½" #: lib/transport.tcl:7 #, tcl-format msgid "Fetching new changes from %s" -msgstr "ДоÑтавÑне на промените от %s" +msgstr "ДоÑтавÑне на промените от „%s“" #: lib/transport.tcl:18 #, tcl-format @@ -826,26 +831,25 @@ msgstr "ОкаÑÑ‚Ñ€Ñне на ÑледÑщите клони на изтритР#: lib/transport.tcl:25 msgid "fetch all remotes" -msgstr "доÑтавÑне на вÑички хранилища" +msgstr "доÑтавÑне на вÑички отдалечени хранилища" #: lib/transport.tcl:26 msgid "Fetching new changes from all remotes" -msgstr "ДоÑтавÑне на промените от вÑички отдалечени хранилища" +msgstr "ДоÑтавÑне на новите промени от вÑички отдалечени хранилища" #: lib/transport.tcl:40 msgid "remote prune all remotes" -msgstr "окаÑÑ‚Ñ€Ñне на вÑички клони ÑледÑщи изтрити клони" +msgstr "окаÑÑ‚Ñ€Ñне на вÑички ÑледÑщи клони" #: lib/transport.tcl:41 msgid "Pruning tracking branches deleted from all remotes" msgstr "" -"ОкаÑÑ‚Ñ€Ñне на ÑледÑщите клони на изтритите клони от вÑички отдалечени " -"хранилища" +"ОкаÑÑ‚Ñ€Ñне на вÑички клони, които ÑледÑÑ‚ изтрити клони от отдалечени хранилища" #: lib/transport.tcl:55 #, tcl-format msgid "Pushing changes to %s" -msgstr "ИзтлаÑкване на промените към %s" +msgstr "ИзтлаÑкване на промените към „%s“" #: lib/transport.tcl:93 #, tcl-format @@ -855,7 +859,7 @@ msgstr "ИзтлаÑкване на вÑичко към „%s“" #: lib/transport.tcl:111 #, tcl-format msgid "Pushing %s %s to %s" -msgstr "ИзтлаÑкване на %s %s към %s" +msgstr "ИзтлаÑкване на %s „%s“ към „%s“" #: lib/transport.tcl:132 msgid "Push Branches" @@ -1031,7 +1035,7 @@ msgid "" "If you like this text, it can be your font." msgstr "" "Това е примерен текÑÑ‚.\n" -"Ðко ви хареÑва как изглежда, изберете този шрифт." +"Ðко ви хареÑва как изглежда, изберете шрифта." #: lib/option.tcl:11 #, tcl-format @@ -1098,7 +1102,8 @@ msgstr "ÐапаÑване на ÑледÑщите клонове" #: lib/option.tcl:151 msgid "Use Textconv For Diffs and Blames" -msgstr "Използване на „textconv“ за разликите и анотациите" +msgstr "" +"Преобразуване на текÑта Ñ â€žtextconv“ при анотиране и извеждане на разлики" #: lib/option.tcl:152 msgid "Blame Copy Only On Changed Files" @@ -1106,7 +1111,7 @@ msgstr "Ðнотиране на копието Ñамо по Ð¿Ñ€Ð¾Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ #: lib/option.tcl:153 msgid "Maximum Length of Recent Repositories List" -msgstr "МакÑимален брой Ñкоро ползвани хранилища" +msgstr "МакÑимална дължина на ÑпиÑъка ÑÑŠÑ Ñкоро ползвани хранилища" #: lib/option.tcl:154 msgid "Minimum Letters To Blame Copy On" @@ -1122,7 +1127,7 @@ msgstr "Брой редове за контекÑта при извеждане #: lib/option.tcl:157 msgid "Additional Diff Parameters" -msgstr "Допълнителни параметри за разликите" +msgstr "Допълнителни аргументи към „git diff“" #: lib/option.tcl:158 msgid "Commit Message Text Width" @@ -1138,45 +1143,62 @@ msgstr "Стандартно кодиране на файловете" #: lib/option.tcl:161 msgid "Warn before committing to a detached head" -msgstr "Предупреждение при подаване към неÑвързан връх" +msgstr "Предупреждаване при подаването при неÑвързан връх" #: lib/option.tcl:162 msgid "Staging of untracked files" -msgstr "ДобавÑне на неÑледените файлове към индекÑа" +msgstr "Вкарване на неÑледени файлове в индекÑа" #: lib/option.tcl:163 msgid "Show untracked files" msgstr "Показване на неÑледените файлове" -#: lib/option.tcl:209 +#: lib/option.tcl:164 +msgid "Tab spacing" +msgstr "Размер на табулациÑта в интервали" + +#: lib/option.tcl:210 msgid "Change" msgstr "СмÑна" -#: lib/option.tcl:253 +#: lib/option.tcl:254 msgid "Spelling Dictionary:" msgstr "ПравопиÑен речник:" -#: lib/option.tcl:283 +#: lib/option.tcl:284 msgid "Change Font" msgstr "СмÑна на шрифта" -#: lib/option.tcl:287 +#: lib/option.tcl:288 #, tcl-format msgid "Choose %s" msgstr "Избор на „%s“" -#: lib/option.tcl:293 +#: lib/option.tcl:294 msgid "pt." msgstr "тчк." -#: lib/option.tcl:307 +#: lib/option.tcl:308 msgid "Preferences" msgstr "ÐаÑтройки" -#: lib/option.tcl:344 +#: lib/option.tcl:345 msgid "Failed to completely save options:" msgstr "ÐеуÑпешно запазване на наÑтройките:" +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "Стандартното" + +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "СиÑтемното (%s)" + +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Друго" + #: lib/mergetool.tcl:8 msgid "Force resolution to the base version?" msgstr "Да Ñе използва базовата верÑиÑ" @@ -1208,7 +1230,7 @@ msgstr "" #, tcl-format msgid "File %s seems to have unresolved conflicts, still stage?" msgstr "" -"Изглежда, че във файла „%s“ вÑе още има некоригирани конфликти. Да Ñе добави " +"Изглежда, че вÑе още има некоригирани конфликти във файла „%s“. Да Ñе добави " "ли файлът към индекÑа?" #: lib/mergetool.tcl:60 @@ -1286,7 +1308,7 @@ msgstr "ПодробноÑти за командата" #: lib/tools_dlg.tcl:49 msgid "Use '/' separators to create a submenu tree:" -msgstr "За Ñъздаване на подменюта използвайте за разделител знака „/“:" +msgstr "За Ñъздаване на подменюта използвайте знака „/“ за разделител:" #: lib/tools_dlg.tcl:60 msgid "Command:" @@ -1346,7 +1368,7 @@ msgstr "Премахване" #: lib/tools_dlg.tcl:231 msgid "(Blue denotes repository-local tools)" -msgstr "(команди към локалното хранилище Ñа обозначени в Ñиньо)" +msgstr "(командите към локалното хранилище Ñа обозначени в Ñиньо)" #: lib/tools_dlg.tcl:292 #, tcl-format @@ -1379,7 +1401,7 @@ msgstr "Предишна поÑва" #: lib/search.tcl:52 msgid "RegExp" -msgstr "Рег. изр." +msgstr "Рег. израз" #: lib/search.tcl:54 msgid "Case" @@ -1393,7 +1415,7 @@ msgstr "Клавишната ÐºÐ¾Ð¼Ð±Ð¸Ð½Ð°Ñ†Ð¸Ñ Ð½Ðµ може да бъде з msgid "Cannot write icon:" msgstr "Иконата не може да бъде запазена:" -#: lib/diff.tcl:64 +#: lib/diff.tcl:77 #, tcl-format msgid "" "No differences detected.\n" @@ -1416,12 +1438,12 @@ msgstr "" "Ðвтоматично ще започне нова проверка дали нÑма други файлове в това " "ÑÑŠÑтоÑние." -#: lib/diff.tcl:104 +#: lib/diff.tcl:117 #, tcl-format msgid "Loading diff of %s..." msgstr "Зареждане на разликите в „%s“…" -#: lib/diff.tcl:125 +#: lib/diff.tcl:140 msgid "" "LOCAL: deleted\n" "REMOTE:\n" @@ -1429,7 +1451,7 @@ msgstr "" "ЛОКÐЛÐО: изтрит\n" "ОТДÐЛЕЧЕÐО:\n" -#: lib/diff.tcl:130 +#: lib/diff.tcl:145 msgid "" "REMOTE: deleted\n" "LOCAL:\n" @@ -1437,41 +1459,41 @@ msgstr "" "ОТДÐЛЕЧЕÐО: изтрит\n" "ЛОКÐЛÐО:\n" -#: lib/diff.tcl:137 +#: lib/diff.tcl:152 msgid "LOCAL:\n" msgstr "ЛОКÐЛÐО:\n" -#: lib/diff.tcl:140 +#: lib/diff.tcl:155 msgid "REMOTE:\n" msgstr "ОТДÐЛЕЧЕÐО:\n" -#: lib/diff.tcl:202 lib/diff.tcl:337 +#: lib/diff.tcl:217 lib/diff.tcl:355 #, tcl-format msgid "Unable to display %s" -msgstr "Ðе може да бъде показан файлът „%s“" +msgstr "Файлът „%s“ не може да бъде показан" -#: lib/diff.tcl:203 +#: lib/diff.tcl:218 msgid "Error loading file:" msgstr "Грешка при зареждане на файл:" -#: lib/diff.tcl:210 +#: lib/diff.tcl:225 msgid "Git Repository (subproject)" -msgstr "Хранилище на Git (подпроект)" +msgstr "Хранилище на Git (подмодул)" -#: lib/diff.tcl:222 +#: lib/diff.tcl:237 msgid "* Binary file (not showing content)." -msgstr "⃠Двоичен файл (Ñъдържанието не Ñе показва)." +msgstr "◠Двоичен файл (Ñъдържанието не Ñе показва)." -#: lib/diff.tcl:227 +#: lib/diff.tcl:242 #, tcl-format msgid "" "* Untracked file is %d bytes.\n" "* Showing only first %d bytes.\n" msgstr "" -"⃠ÐеÑледениÑÑ‚ файл е %d байта.\n" -"⃠Показват Ñе Ñамо първите %d байта.\n" +"â— ÐеÑледениÑÑ‚ файл е %d байта.\n" +"◠Показват Ñе Ñамо първите %d байта.\n" -#: lib/diff.tcl:233 +#: lib/diff.tcl:248 #, tcl-format msgid "" "\n" @@ -1479,26 +1501,26 @@ msgid "" "* To see the entire file, use an external editor.\n" msgstr "" "\n" -"⃠ÐеÑледениÑÑ‚ файл е отрÑзан дотук %s.\n" -"⃠Използвайте външен редактор, за да видите Ñ†ÐµÐ»Ð¸Ñ Ñ„Ð°Ð¹Ð».\n" +"â— ÐеÑледениÑÑ‚ файл е отрÑзан дотук от програмата „%s“.\n" +"◠Използвайте външен редактор, за да видите Ñ†ÐµÐ»Ð¸Ñ Ñ„Ð°Ð¹Ð».\n" -#: lib/diff.tcl:338 lib/blame.tcl:1128 +#: lib/diff.tcl:356 lib/blame.tcl:1128 msgid "Error loading diff:" msgstr "Грешка при зареждане на разлика:" -#: lib/diff.tcl:557 +#: lib/diff.tcl:578 msgid "Failed to unstage selected hunk." msgstr "Избраното парче не може да бъде извадено от индекÑа." -#: lib/diff.tcl:564 +#: lib/diff.tcl:585 msgid "Failed to stage selected hunk." -msgstr "Избраното парче не може да бъде добавен към индекÑа." +msgstr "Избраното парче не може да бъде добавено към индекÑа." -#: lib/diff.tcl:643 +#: lib/diff.tcl:664 msgid "Failed to unstage selected line." msgstr "ИзбраниÑÑ‚ ред не може да бъде изваден от индекÑа." -#: lib/diff.tcl:651 +#: lib/diff.tcl:672 msgid "Failed to stage selected line." msgstr "ИзбраниÑÑ‚ ред не може да бъде добавен към индекÑа." @@ -1512,7 +1534,7 @@ msgstr "От хранилище" #: lib/remote_branch_delete.tcl:88 msgid "Branches" -msgstr "Клонове" +msgstr "Клони" #: lib/remote_branch_delete.tcl:110 msgid "Delete Only If" @@ -1539,7 +1561,7 @@ msgid "" msgstr "" "Следните клони не Ñа Ñлети напълно в „%s“:\n" "\n" -" ⃠%s" +" â— %s" #: lib/remote_branch_delete.tcl:190 #, tcl-format @@ -1578,239 +1600,251 @@ msgstr "Ðе е избрано хранилище." msgid "Scanning %s..." msgstr "ПретърÑване на „%s“…" -#: lib/choose_repository.tcl:32 +#: lib/choose_repository.tcl:33 msgid "Git Gui" msgstr "ГПИ на Git" -#: lib/choose_repository.tcl:91 lib/choose_repository.tcl:396 +#: lib/choose_repository.tcl:92 lib/choose_repository.tcl:412 msgid "Create New Repository" msgstr "Създаване на ново хранилище" -#: lib/choose_repository.tcl:97 +#: lib/choose_repository.tcl:98 msgid "New..." msgstr "Ðово…" -#: lib/choose_repository.tcl:104 lib/choose_repository.tcl:480 +#: lib/choose_repository.tcl:105 lib/choose_repository.tcl:496 msgid "Clone Existing Repository" msgstr "Клониране на ÑъщеÑтвуващо хранилище" -#: lib/choose_repository.tcl:115 +#: lib/choose_repository.tcl:116 msgid "Clone..." msgstr "Клониране…" -#: lib/choose_repository.tcl:122 lib/choose_repository.tcl:1019 +#: lib/choose_repository.tcl:123 lib/choose_repository.tcl:1064 msgid "Open Existing Repository" msgstr "ОтварÑне на ÑъщеÑтвуващо хранилище" -#: lib/choose_repository.tcl:128 +#: lib/choose_repository.tcl:129 msgid "Open..." msgstr "ОтварÑне…" -#: lib/choose_repository.tcl:141 +#: lib/choose_repository.tcl:142 msgid "Recent Repositories" msgstr "Скоро ползвани" -#: lib/choose_repository.tcl:147 +#: lib/choose_repository.tcl:148 msgid "Open Recent Repository:" msgstr "ОтварÑне на хранилище ползвано наÑкоро:" -#: lib/choose_repository.tcl:315 lib/choose_repository.tcl:322 -#: lib/choose_repository.tcl:329 +#: lib/choose_repository.tcl:316 lib/choose_repository.tcl:323 +#: lib/choose_repository.tcl:330 #, tcl-format msgid "Failed to create repository %s:" msgstr "ÐеуÑпешно Ñъздаване на хранилището „%s“:" -#: lib/choose_repository.tcl:391 lib/branch_create.tcl:33 +#: lib/choose_repository.tcl:407 lib/branch_create.tcl:33 msgid "Create" msgstr "Създаване" -#: lib/choose_repository.tcl:401 +#: lib/choose_repository.tcl:417 msgid "Directory:" msgstr "ДиректориÑ:" -#: lib/choose_repository.tcl:431 lib/choose_repository.tcl:552 -#: lib/choose_repository.tcl:1053 +#: lib/choose_repository.tcl:447 lib/choose_repository.tcl:573 +#: lib/choose_repository.tcl:1098 msgid "Git Repository" msgstr "Хранилище на Git" -#: lib/choose_repository.tcl:456 +#: lib/choose_repository.tcl:472 #, tcl-format msgid "Directory %s already exists." msgstr "Вече ÑъщеÑтвува Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ â€ž%s“." -#: lib/choose_repository.tcl:460 +#: lib/choose_repository.tcl:476 #, tcl-format msgid "File %s already exists." msgstr "Вече ÑъщеÑтвува файл „%s“." -#: lib/choose_repository.tcl:475 +#: lib/choose_repository.tcl:491 msgid "Clone" msgstr "Клониране" -#: lib/choose_repository.tcl:488 +#: lib/choose_repository.tcl:504 msgid "Source Location:" msgstr "ÐÐ´Ñ€ÐµÑ Ð½Ð° източника:" -#: lib/choose_repository.tcl:497 +#: lib/choose_repository.tcl:513 msgid "Target Directory:" msgstr "Целева директориÑ:" -#: lib/choose_repository.tcl:507 +#: lib/choose_repository.tcl:523 msgid "Clone Type:" msgstr "Вид клониране:" -#: lib/choose_repository.tcl:512 +#: lib/choose_repository.tcl:528 msgid "Standard (Fast, Semi-Redundant, Hardlinks)" msgstr "Стандартно (бързо, чаÑтично ÑподелÑне на файлове, твърди връзки)" -#: lib/choose_repository.tcl:517 +#: lib/choose_repository.tcl:533 msgid "Full Copy (Slower, Redundant Backup)" msgstr "Пълно (бавно, пълноценно резервно копие)" -#: lib/choose_repository.tcl:522 +#: lib/choose_repository.tcl:538 msgid "Shared (Fastest, Not Recommended, No Backup)" msgstr "Споделено (най-бързо, не Ñе препоръчва, не прави резервно копие)" -#: lib/choose_repository.tcl:558 lib/choose_repository.tcl:605 -#: lib/choose_repository.tcl:751 lib/choose_repository.tcl:821 -#: lib/choose_repository.tcl:1059 lib/choose_repository.tcl:1067 +#: lib/choose_repository.tcl:545 +msgid "Recursively clone submodules too" +msgstr "РекурÑивно клониране и на подмодулите" + +#: lib/choose_repository.tcl:579 lib/choose_repository.tcl:626 +#: lib/choose_repository.tcl:772 lib/choose_repository.tcl:842 +#: lib/choose_repository.tcl:1104 lib/choose_repository.tcl:1112 #, tcl-format msgid "Not a Git repository: %s" msgstr "Това не е хранилище на Git: %s" -#: lib/choose_repository.tcl:594 +#: lib/choose_repository.tcl:615 msgid "Standard only available for local repository." msgstr "Само локални хранилища могат да Ñе клонират Ñтандартно" -#: lib/choose_repository.tcl:598 +#: lib/choose_repository.tcl:619 msgid "Shared only available for local repository." msgstr "Само локални хранилища могат да Ñе клонират Ñподелено" -#: lib/choose_repository.tcl:619 +#: lib/choose_repository.tcl:640 #, tcl-format msgid "Location %s already exists." -msgstr "Вече ÑъщеÑтвува меÑтоположението „%s“." +msgstr "МеÑтоположението „%s“ вече ÑъщеÑтвува." -#: lib/choose_repository.tcl:630 +#: lib/choose_repository.tcl:651 msgid "Failed to configure origin" msgstr "ÐеуÑпешно наÑтройване на хранилището-източник" -#: lib/choose_repository.tcl:642 +#: lib/choose_repository.tcl:663 msgid "Counting objects" msgstr "ПреброÑване на обекти" -#: lib/choose_repository.tcl:643 +#: lib/choose_repository.tcl:664 msgid "buckets" msgstr "клетки" -#: lib/choose_repository.tcl:667 +#: lib/choose_repository.tcl:688 #, tcl-format msgid "Unable to copy objects/info/alternates: %s" msgstr "Обектите/информациÑта/Ñинонимите не могат да бъдат копирани: %s" -#: lib/choose_repository.tcl:703 +#: lib/choose_repository.tcl:724 #, tcl-format msgid "Nothing to clone from %s." msgstr "ÐÑма какво да Ñе клонира от „%s“." -#: lib/choose_repository.tcl:705 lib/choose_repository.tcl:919 -#: lib/choose_repository.tcl:931 +#: lib/choose_repository.tcl:726 lib/choose_repository.tcl:940 +#: lib/choose_repository.tcl:952 msgid "The 'master' branch has not been initialized." msgstr "ОÑновниÑÑ‚ клон — „master“ не е инициализиран." -#: lib/choose_repository.tcl:718 +#: lib/choose_repository.tcl:739 msgid "Hardlinks are unavailable. Falling back to copying." msgstr "Ðе Ñе поддържат твърди връзки. Преминава Ñе към копиране." -#: lib/choose_repository.tcl:730 +#: lib/choose_repository.tcl:751 #, tcl-format msgid "Cloning from %s" msgstr "Клониране на „%s“" -#: lib/choose_repository.tcl:761 +#: lib/choose_repository.tcl:782 msgid "Copying objects" msgstr "Копиране на обекти" -#: lib/choose_repository.tcl:762 +#: lib/choose_repository.tcl:783 msgid "KiB" msgstr "KiB" -#: lib/choose_repository.tcl:786 +#: lib/choose_repository.tcl:807 #, tcl-format msgid "Unable to copy object: %s" msgstr "ÐеуÑпешно копиране на обект: %s" -#: lib/choose_repository.tcl:796 +#: lib/choose_repository.tcl:817 msgid "Linking objects" msgstr "Създаване на връзки към обектите" -#: lib/choose_repository.tcl:797 +#: lib/choose_repository.tcl:818 msgid "objects" msgstr "обекти" -#: lib/choose_repository.tcl:805 +#: lib/choose_repository.tcl:826 #, tcl-format msgid "Unable to hardlink object: %s" msgstr "ÐеуÑпешно Ñъздаване на твърда връзка към обект: %s" -#: lib/choose_repository.tcl:860 +#: lib/choose_repository.tcl:881 msgid "Cannot fetch branches and objects. See console output for details." msgstr "" "Клоните и обектите не могат да бъдат изтеглени. За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ " "погледнете изхода на конзолата." -#: lib/choose_repository.tcl:871 +#: lib/choose_repository.tcl:892 msgid "Cannot fetch tags. See console output for details." msgstr "" "Етикетите не могат да бъдат изтеглени. За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð³Ð»ÐµÐ´Ð½ÐµÑ‚Ðµ " "изхода на конзолата." -#: lib/choose_repository.tcl:895 +#: lib/choose_repository.tcl:916 msgid "Cannot determine HEAD. See console output for details." msgstr "" -"Върхът HEAD не може да бъде определен. За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð³Ð»ÐµÐ´Ð½ÐµÑ‚Ðµ " +"Върхът „HEAD“ не може да бъде определен. За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð³Ð»ÐµÐ´Ð½ÐµÑ‚Ðµ " "изхода на конзолата." -#: lib/choose_repository.tcl:904 +#: lib/choose_repository.tcl:925 #, tcl-format msgid "Unable to cleanup %s" -msgstr "Ðе може да Ñе зачиÑти „%s“" +msgstr "„%s“ не може да Ñе зачиÑти" -#: lib/choose_repository.tcl:910 +#: lib/choose_repository.tcl:931 msgid "Clone failed." msgstr "ÐеуÑпешно клониране." -#: lib/choose_repository.tcl:917 +#: lib/choose_repository.tcl:938 msgid "No default branch obtained." msgstr "Ðе е получен клон по подразбиране." -#: lib/choose_repository.tcl:928 +#: lib/choose_repository.tcl:949 #, tcl-format msgid "Cannot resolve %s as a commit." msgstr "ÐÑма подаване отговарÑщо на „%s“." -#: lib/choose_repository.tcl:940 +#: lib/choose_repository.tcl:961 msgid "Creating working directory" msgstr "Създаване на работната директориÑ" -#: lib/choose_repository.tcl:941 lib/index.tcl:70 lib/index.tcl:136 +#: lib/choose_repository.tcl:962 lib/index.tcl:70 lib/index.tcl:136 #: lib/index.tcl:207 msgid "files" msgstr "файлове" -#: lib/choose_repository.tcl:970 +#: lib/choose_repository.tcl:981 +msgid "Cannot clone submodules." +msgstr "Подмодулите не могат да Ñе клонират." + +#: lib/choose_repository.tcl:990 +msgid "Cloning submodules" +msgstr "Клониране на подмодулите" + +#: lib/choose_repository.tcl:1015 msgid "Initial file checkout failed." msgstr "ÐеуÑпешно първоначално изтеглÑне." -#: lib/choose_repository.tcl:1014 +#: lib/choose_repository.tcl:1059 msgid "Open" msgstr "ОтварÑне" -#: lib/choose_repository.tcl:1024 +#: lib/choose_repository.tcl:1069 msgid "Repository:" msgstr "Хранилище:" -#: lib/choose_repository.tcl:1073 +#: lib/choose_repository.tcl:1118 #, tcl-format msgid "Failed to open repository %s:" msgstr "ÐеуÑпешно отварÑне на хранилището „%s“:" @@ -1849,7 +1883,7 @@ msgid "" msgstr "" "Клонът „%s“ ÑъщеÑтвува.\n" "\n" -"Той не може да бъде тривиално превъртÑн до %s.\n" +"Той не може да бъде тривиално ÑлÑÑ‚ до „%s“.\n" "Ðеобходимо е Ñливане." #: lib/checkout_op.tcl:243 @@ -2003,7 +2037,7 @@ msgstr "Изберете клон за Ñледени." #: lib/branch_create.tcl:141 #, tcl-format msgid "Tracking branch %s is not a branch in the remote repository." -msgstr "Клонът, който Ñе Ñледи „%s“ не ÑъщеÑтвува в отдалеченото хранилище." +msgstr "СледÑщиÑÑ‚ клон — „%s“, не ÑъщеÑтвува в отдалеченото хранилище." #: lib/console.tcl:59 msgid "Working... please wait..." @@ -2023,7 +2057,7 @@ msgstr "Това неÑвързано изтеглÑне" #: lib/choose_rev.tcl:60 msgid "Revision Expression:" -msgstr "Израз за верÑиÑ" +msgstr "Израз за верÑиÑ:" #: lib/choose_rev.tcl:72 msgid "Local Branch" @@ -2101,7 +2135,7 @@ msgstr "ИдентификациÑта ви не може да бъде опре #: lib/commit.tcl:80 msgid "Invalid GIT_COMMITTER_IDENT:" -msgstr "Ðеправилно поле GIT_COMMITTER_IDENT:" +msgstr "Ðеправилно поле „GIT_COMMITTER_IDENT“:" #: lib/commit.tcl:129 #, tcl-format @@ -2157,7 +2191,7 @@ msgid "" msgstr "" "ÐÑма промени за подаване.\n" "\n" -"ТрÑбва да добавите поне 1 файл към индекÑа, преди да подадете.\n" +"ТрÑбва да добавите поне един файл към индекÑа, за да подадете.\n" #: lib/commit.tcl:204 msgid "" @@ -2173,9 +2207,9 @@ msgstr "" "\n" "Използвайте ÑÐ»ÐµÐ´Ð½Ð¸Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚:\n" "\n" -"⃠Първи ред: опиÑание в едно изречение на промÑната.\n" -"⃠Втори ред: празен.\n" -"⃠ОÑтаналите редове: опишете защо Ñе налага тази промÑна.\n" +"◠Първи ред: опиÑание в едно изречение на промÑната.\n" +"◠Втори ред: празен.\n" +"◠ОÑтаналите редове: опишете защо Ñе налага тази промÑна.\n" #: lib/commit.tcl:235 msgid "Calling pre-commit hook..." @@ -2194,13 +2228,12 @@ msgid "" " \n" " Do you really want to proceed with your Commit?" msgstr "" -"Ще подадете към неÑвързан връх. Това дейÑтвие е опаÑно, защото при " -"преминаването към който и да е клон ще загубите промените Ñи и не е Ñигурно, " -"че ще можете по-къÑно да ги възÑтановите чрез журнала на указателите. Ðай-" -"вероÑтно Ñ‚Ñ€Ñбва първо да Ñъздадете клон базиран на текущото ÑÑŠÑтоÑние и да " -"подадете към него.\n" +"Ще подавате към неÑвързан връх. Това е опаÑно — при изтеглÑнето на друг клон " +"ще изгубите промените Ñи. След това може да е невъзможно да ги възÑтановите " +"от журнала на указателите „reflog“. Ðай-вероÑтно Ñ‚Ñ€Ñбва да отмените това " +"подаване и да Ñъздадете клон, в който да подадете.\n" " \n" -"Сигурни ли Ñте, че иÑкате да подадете точно Ñега?" +"Сигурни ли Ñте, че иÑкате да подадете към неÑвързан връх?" #: lib/commit.tcl:290 msgid "Calling commit-msg hook..." @@ -2212,7 +2245,7 @@ msgstr "Подаването е отхвърлено от куката за ÑÑŠ #: lib/commit.tcl:318 msgid "Committing changes..." -msgstr "Подаване на промените." +msgstr "Подаване на промените…" #: lib/commit.tcl:334 msgid "write-tree failed:" @@ -2278,7 +2311,7 @@ msgstr "Изтриване, Ñамо ако промените Ñа Ñлети Ð #: lib/branch_delete.tcl:103 #, tcl-format msgid "The following branches are not completely merged into %s:" -msgstr "Ðе вÑички промени в клоните Ñа Ñлети в %s:" +msgstr "Ðе вÑички промени в клоните Ñа Ñлети в „%s“:" #: lib/branch_delete.tcl:141 #, tcl-format @@ -2324,7 +2357,7 @@ msgstr "Ðнотиране на родителÑкото подаване" #: lib/blame.tcl:466 #, tcl-format msgid "Reading %s..." -msgstr "%s Ñе чете…" +msgstr "Чете Ñе „%s“…" #: lib/blame.tcl:594 msgid "Loading copy/move tracking annotations..." @@ -2372,7 +2405,7 @@ msgstr "Първоначален файл:" #: lib/blame.tcl:1057 msgid "Cannot find HEAD commit:" -msgstr "Подаването за връх HEAD не може да Ñе открие:" +msgstr "Подаването за връх „HEAD“ не може да Ñе открие:" #: lib/blame.tcl:1112 msgid "Cannot find parent commit:" @@ -2421,7 +2454,7 @@ msgstr "Отключване на индекÑа" #: lib/index.tcl:298 #, tcl-format msgid "Unstaging %s from commit" -msgstr "Изваждане на %s от подаването" +msgstr "Изваждане на „%s“ от подаването" #: lib/index.tcl:337 msgid "Ready to commit." @@ -2435,7 +2468,7 @@ msgstr "ДобавÑне на „%s“" #: lib/index.tcl:380 #, tcl-format msgid "Stage %d untracked files?" -msgstr "Да Ñе добавÑÑ‚ ли %d на брой неÑледени файла към индекÑа?" +msgstr "Да Ñе вкарат ли %d неÑледени файла в индекÑа?" #: lib/index.tcl:428 #, tcl-format @@ -2466,19 +2499,6 @@ msgstr "Махане на промените в избраните файловРmsgid "Reverting %s" msgstr "Махане на промените в „%s“" -#: lib/encoding.tcl:443 -msgid "Default" -msgstr "Стандартното" - -#: lib/encoding.tcl:448 -#, tcl-format -msgid "System (%s)" -msgstr "СиÑтемното (%s)" - -#: lib/encoding.tcl:459 lib/encoding.tcl:465 -msgid "Other" -msgstr "Друго" - #: lib/date.tcl:25 #, tcl-format msgid "Invalid date from Git: %s" @@ -2518,7 +2538,7 @@ msgstr "КомпреÑиране на базата Ñ Ð´Ð°Ð½Ð½Ð¸ за обект #: lib/database.tcl:83 msgid "Verifying the object database with fsck-objects" -msgstr "Проверка на базата Ñ Ð´Ð°Ð½Ð½Ð¸ за обектите Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð°Ñ‚Ð° fsck-objects" +msgstr "Проверка на базата Ñ Ð´Ð°Ð½Ð½Ð¸ за обектите Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð°Ñ‚Ð° „fsck-objects“" #: lib/database.tcl:107 #, tcl-format @@ -2532,7 +2552,7 @@ msgid "" msgstr "" "Ð’ това хранилище в момента има към %i непакетирани обекти.\n" "\n" -"Зd добра производителноÑÑ‚ Ñе препоръчва да компреÑирате базата Ñ Ð´Ð°Ð½Ð½Ð¸ за " +"За добра производителноÑÑ‚ Ñе препоръчва да компреÑирате базата Ñ Ð´Ð°Ð½Ð½Ð¸ за " "обектите.\n" "\n" "Да Ñе започне ли компреÑирането?" @@ -2547,7 +2567,7 @@ msgstr "предупреждение" #: lib/error.tcl:96 msgid "You must correct the above errors before committing." -msgstr "Преди да можете да подадете, оправете горните грешки." +msgstr "Преди да можете да подадете, коригирайте горните грешки." #: lib/merge.tcl:13 msgid "" @@ -2659,7 +2679,7 @@ msgid "" msgstr "" "Да Ñе преуÑтанови ли Ñливането?\n" "\n" -"Ð’ такъв Ñлучай *ВСИЧКИ* неподадени промени ще бъдат безвъзвратно загубени.\n" +"Ð’ такъв Ñлучай â—ВСИЧКИ◠неподадени промени ще бъдат безвъзвратно загубени.\n" "\n" "ÐаиÑтина ли да Ñе преуÑтанови Ñливането?" @@ -2673,7 +2693,7 @@ msgid "" msgstr "" "Да Ñе занулÑÑ‚ ли промените?\n" "\n" -"Ð’ такъв Ñлучай *ВСИЧКИ* неподадени промени ще бъдат безвъзвратно загубени.\n" +"Ð’ такъв Ñлучай â—ВСИЧКИ◠неподадени промени ще бъдат безвъзвратно загубени.\n" "\n" "ÐаиÑтина ли да Ñе занулÑÑ‚ промените?" diff --git a/git-gui/po/sv.po b/git-gui/po/sv.po index fcb063ffa6..1b4ad8368e 100644 --- a/git-gui/po/sv.po +++ b/git-gui/po/sv.po @@ -2,47 +2,51 @@ # Copyright (C) 2007-2008 Shawn Pearce, et al. # This file is distributed under the same license as the git-gui package. # -# Peter Krefting <peter@softwolves.pp.se>, 2007-2008. # Mikael Magnusson <mikachu@gmail.com>, 2008. +# Peter Krefting <peter@softwolves.pp.se>, 2007-2008, 2015. +# msgid "" msgstr "" "Project-Id-Version: sv\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-09-12 21:11+0100\n" -"PO-Revision-Date: 2010-09-12 21:12+0100\n" +"POT-Creation-Date: 2015-03-27 10:15+0100\n" +"PO-Revision-Date: 2015-03-27 10:24+0100\n" "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" +"Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Gtranslator 2.91.6\n" -#: git-gui.sh:781 +#: git-gui.sh:861 #, tcl-format msgid "Invalid font specified in %s:" msgstr "Ogiltigt teckensnitt angivet i %s:" -#: git-gui.sh:831 +#: git-gui.sh:915 msgid "Main Font" msgstr "Huvudteckensnitt" -#: git-gui.sh:832 +#: git-gui.sh:916 msgid "Diff/Console Font" msgstr "Diff/konsolteckensnitt" -#: git-gui.sh:845 git-gui.sh:859 git-gui.sh:872 git-gui.sh:955 git-gui.sh:974 -#: git-gui.sh:2964 +#: git-gui.sh:931 git-gui.sh:945 git-gui.sh:958 git-gui.sh:1048 +#: git-gui.sh:1067 git-gui.sh:3125 msgid "git-gui: fatal error" msgstr "git-gui: ödesdigert fel" -#: git-gui.sh:846 +#: git-gui.sh:932 msgid "Cannot find git in PATH." msgstr "Hittar inte git i PATH." -#: git-gui.sh:873 +#: git-gui.sh:959 msgid "Cannot parse Git version string:" msgstr "Kan inte tolka versionssträng frÃ¥n Git:" -#: git-gui.sh:891 +#: git-gui.sh:984 #, tcl-format msgid "" "Git version cannot be determined.\n" @@ -61,478 +65,505 @@ msgstr "" "\n" "Anta att \"%s\" är version 1.5.0?\n" -#: git-gui.sh:1180 +#: git-gui.sh:1281 msgid "Git directory not found:" msgstr "Git-katalogen hittades inte:" -#: git-gui.sh:1201 +#: git-gui.sh:1315 msgid "Cannot move to top of working directory:" msgstr "Kan inte gÃ¥ till början pÃ¥ arbetskatalogen:" -#: git-gui.sh:1209 +#: git-gui.sh:1323 msgid "Cannot use bare repository:" msgstr "Kan inte använda naket arkiv:" -#: git-gui.sh:1217 +#: git-gui.sh:1331 msgid "No working directory" msgstr "Ingen arbetskatalog" -#: git-gui.sh:1389 lib/checkout_op.tcl:306 +#: git-gui.sh:1503 lib/checkout_op.tcl:306 msgid "Refreshing file status..." msgstr "Uppdaterar filstatus..." -#: git-gui.sh:1445 +#: git-gui.sh:1563 msgid "Scanning for modified files ..." msgstr "Söker efter ändrade filer..." -#: git-gui.sh:1509 +#: git-gui.sh:1639 msgid "Calling prepare-commit-msg hook..." msgstr "" "Anropar kroken för förberedelse av incheckningsmeddelande (prepare-commit-" "msg)..." -#: git-gui.sh:1526 +#: git-gui.sh:1656 msgid "Commit declined by prepare-commit-msg hook." msgstr "" "Incheckningen avvisades av kroken för förberedelse av incheckningsmeddelande " "(prepare-commit-msg)." -#: git-gui.sh:1684 lib/browser.tcl:246 +#: git-gui.sh:1814 lib/browser.tcl:252 msgid "Ready." msgstr "Klar." -#: git-gui.sh:1842 +#: git-gui.sh:1978 #, tcl-format -msgid "Displaying only %s of %s files." -msgstr "Visar endast %s av %s filer." +msgid "" +"Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files." +msgstr "" +"Visningsgräns (gui.maxfilesdisplayed = %s) nÃ¥dd, visare inte samtliga %s " +"filer." -#: git-gui.sh:1968 +#: git-gui.sh:2101 msgid "Unmodified" msgstr "Oförändrade" -#: git-gui.sh:1970 +#: git-gui.sh:2103 msgid "Modified, not staged" msgstr "Förändrade, ej köade" -#: git-gui.sh:1971 git-gui.sh:1979 +#: git-gui.sh:2104 git-gui.sh:2116 msgid "Staged for commit" msgstr "Köade för incheckning" -#: git-gui.sh:1972 git-gui.sh:1980 +#: git-gui.sh:2105 git-gui.sh:2117 msgid "Portions staged for commit" msgstr "Delar köade för incheckning" -#: git-gui.sh:1973 git-gui.sh:1981 +#: git-gui.sh:2106 git-gui.sh:2118 msgid "Staged for commit, missing" msgstr "Köade för incheckning, saknade" -#: git-gui.sh:1975 +#: git-gui.sh:2108 msgid "File type changed, not staged" msgstr "Filtyp ändrad, ej köade" -#: git-gui.sh:1976 +#: git-gui.sh:2109 git-gui.sh:2110 +msgid "File type changed, old type staged for commit" +msgstr "Filtyp ändrad, gammal typ köade för incheckning" + +#: git-gui.sh:2111 msgid "File type changed, staged" msgstr "Filtyp ändrad, köade" -#: git-gui.sh:1978 +#: git-gui.sh:2112 +msgid "File type change staged, modification not staged" +msgstr "Filtypsändringar köade, innehÃ¥llsändringar ej köade" + +#: git-gui.sh:2113 +msgid "File type change staged, file missing" +msgstr "Filtypsändringar köade, fil saknas" + +#: git-gui.sh:2115 msgid "Untracked, not staged" msgstr "Ej spÃ¥rade, ej köade" -#: git-gui.sh:1983 +#: git-gui.sh:2120 msgid "Missing" msgstr "Saknade" -#: git-gui.sh:1984 +#: git-gui.sh:2121 msgid "Staged for removal" msgstr "Köade för borttagning" -#: git-gui.sh:1985 +#: git-gui.sh:2122 msgid "Staged for removal, still present" msgstr "Köade för borttagning, fortfarande närvarande" -#: git-gui.sh:1987 git-gui.sh:1988 git-gui.sh:1989 git-gui.sh:1990 -#: git-gui.sh:1991 git-gui.sh:1992 +#: git-gui.sh:2124 git-gui.sh:2125 git-gui.sh:2126 git-gui.sh:2127 +#: git-gui.sh:2128 git-gui.sh:2129 msgid "Requires merge resolution" msgstr "Kräver konflikthantering efter sammanslagning" -#: git-gui.sh:2027 +#: git-gui.sh:2164 msgid "Starting gitk... please wait..." msgstr "Startar gitk... vänta..." -#: git-gui.sh:2039 +#: git-gui.sh:2176 msgid "Couldn't find gitk in PATH" msgstr "Hittade inte gitk i PATH." -#: git-gui.sh:2098 +#: git-gui.sh:2235 msgid "Couldn't find git gui in PATH" msgstr "Hittade inte git gui i PATH." -#: git-gui.sh:2515 lib/choose_repository.tcl:36 +#: git-gui.sh:2654 lib/choose_repository.tcl:41 msgid "Repository" msgstr "Arkiv" -#: git-gui.sh:2516 +#: git-gui.sh:2655 msgid "Edit" msgstr "Redigera" -#: git-gui.sh:2518 lib/choose_rev.tcl:566 +#: git-gui.sh:2657 lib/choose_rev.tcl:567 msgid "Branch" msgstr "Gren" -#: git-gui.sh:2521 lib/choose_rev.tcl:553 +#: git-gui.sh:2660 lib/choose_rev.tcl:554 msgid "Commit@@noun" msgstr "Incheckning" -#: git-gui.sh:2524 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 +#: git-gui.sh:2663 lib/merge.tcl:123 lib/merge.tcl:152 lib/merge.tcl:170 msgid "Merge" msgstr "SlÃ¥ ihop" -#: git-gui.sh:2525 lib/choose_rev.tcl:562 +#: git-gui.sh:2664 lib/choose_rev.tcl:563 msgid "Remote" msgstr "Fjärrarkiv" -#: git-gui.sh:2528 +#: git-gui.sh:2667 msgid "Tools" msgstr "Verktyg" -#: git-gui.sh:2537 +#: git-gui.sh:2676 msgid "Explore Working Copy" msgstr "Utforska arbetskopia" -#: git-gui.sh:2543 +#: git-gui.sh:2682 +msgid "Git Bash" +msgstr "Git Bash" + +#: git-gui.sh:2692 msgid "Browse Current Branch's Files" msgstr "Bläddra i grenens filer" -#: git-gui.sh:2547 +#: git-gui.sh:2696 msgid "Browse Branch Files..." msgstr "Bläddra filer pÃ¥ gren..." -#: git-gui.sh:2552 +#: git-gui.sh:2701 msgid "Visualize Current Branch's History" msgstr "Visualisera grenens historik" -#: git-gui.sh:2556 +#: git-gui.sh:2705 msgid "Visualize All Branch History" msgstr "Visualisera alla grenars historik" -#: git-gui.sh:2563 +#: git-gui.sh:2712 #, tcl-format msgid "Browse %s's Files" msgstr "Bläddra i filer för %s" -#: git-gui.sh:2565 +#: git-gui.sh:2714 #, tcl-format msgid "Visualize %s's History" msgstr "Visualisera historik för %s" -#: git-gui.sh:2570 lib/database.tcl:40 lib/database.tcl:66 +#: git-gui.sh:2719 lib/database.tcl:40 lib/database.tcl:66 msgid "Database Statistics" msgstr "Databasstatistik" -#: git-gui.sh:2573 lib/database.tcl:33 +#: git-gui.sh:2722 lib/database.tcl:33 msgid "Compress Database" msgstr "Komprimera databas" -#: git-gui.sh:2576 +#: git-gui.sh:2725 msgid "Verify Database" msgstr "Verifiera databas" -#: git-gui.sh:2583 git-gui.sh:2587 git-gui.sh:2591 lib/shortcut.tcl:8 +#: git-gui.sh:2732 git-gui.sh:2736 git-gui.sh:2740 lib/shortcut.tcl:8 #: lib/shortcut.tcl:40 lib/shortcut.tcl:72 msgid "Create Desktop Icon" msgstr "Skapa skrivbordsikon" -#: git-gui.sh:2599 lib/choose_repository.tcl:188 lib/choose_repository.tcl:196 +#: git-gui.sh:2748 lib/choose_repository.tcl:193 lib/choose_repository.tcl:201 msgid "Quit" msgstr "Avsluta" -#: git-gui.sh:2607 +#: git-gui.sh:2756 msgid "Undo" msgstr "Ã…ngra" -#: git-gui.sh:2610 +#: git-gui.sh:2759 msgid "Redo" msgstr "Gör om" -#: git-gui.sh:2614 git-gui.sh:3190 +#: git-gui.sh:2763 git-gui.sh:3368 msgid "Cut" msgstr "Klipp ut" -#: git-gui.sh:2617 git-gui.sh:3193 git-gui.sh:3267 git-gui.sh:3340 +#: git-gui.sh:2766 git-gui.sh:3371 git-gui.sh:3445 git-gui.sh:3530 #: lib/console.tcl:69 msgid "Copy" msgstr "Kopiera" -#: git-gui.sh:2620 git-gui.sh:3196 +#: git-gui.sh:2769 git-gui.sh:3374 msgid "Paste" msgstr "Klistra in" -#: git-gui.sh:2623 git-gui.sh:3199 lib/branch_delete.tcl:28 -#: lib/remote_branch_delete.tcl:39 +#: git-gui.sh:2772 git-gui.sh:3377 lib/remote_branch_delete.tcl:39 +#: lib/branch_delete.tcl:28 msgid "Delete" msgstr "Ta bort" -#: git-gui.sh:2627 git-gui.sh:3203 git-gui.sh:3344 lib/console.tcl:71 +#: git-gui.sh:2776 git-gui.sh:3381 git-gui.sh:3534 lib/console.tcl:71 msgid "Select All" msgstr "Markera alla" -#: git-gui.sh:2636 +#: git-gui.sh:2785 msgid "Create..." msgstr "Skapa..." -#: git-gui.sh:2642 +#: git-gui.sh:2791 msgid "Checkout..." msgstr "Checka ut..." -#: git-gui.sh:2648 +#: git-gui.sh:2797 msgid "Rename..." msgstr "Byt namn..." -#: git-gui.sh:2653 +#: git-gui.sh:2802 msgid "Delete..." msgstr "Ta bort..." -#: git-gui.sh:2658 +#: git-gui.sh:2807 msgid "Reset..." msgstr "Ã…terställ..." -#: git-gui.sh:2668 +#: git-gui.sh:2817 msgid "Done" msgstr "Färdig" -#: git-gui.sh:2670 +#: git-gui.sh:2819 msgid "Commit@@verb" msgstr "Checka in" -#: git-gui.sh:2679 git-gui.sh:3131 +#: git-gui.sh:2828 git-gui.sh:3309 msgid "New Commit" msgstr "Ny incheckning" -#: git-gui.sh:2687 git-gui.sh:3138 +#: git-gui.sh:2836 git-gui.sh:3316 msgid "Amend Last Commit" msgstr "Lägg till föregÃ¥ende incheckning" -#: git-gui.sh:2697 git-gui.sh:3092 lib/remote_branch_delete.tcl:101 +#: git-gui.sh:2846 git-gui.sh:3270 lib/remote_branch_delete.tcl:101 msgid "Rescan" msgstr "Sök pÃ¥ nytt" -#: git-gui.sh:2703 +#: git-gui.sh:2852 msgid "Stage To Commit" msgstr "Köa för incheckning" -#: git-gui.sh:2709 +#: git-gui.sh:2858 msgid "Stage Changed Files To Commit" msgstr "Köa ändrade filer för incheckning" -#: git-gui.sh:2715 +#: git-gui.sh:2864 msgid "Unstage From Commit" msgstr "Ta bort frÃ¥n incheckningskö" -#: git-gui.sh:2721 lib/index.tcl:415 +#: git-gui.sh:2870 lib/index.tcl:442 msgid "Revert Changes" msgstr "Ã…terställ ändringar" -#: git-gui.sh:2729 git-gui.sh:3391 git-gui.sh:3422 +#: git-gui.sh:2878 git-gui.sh:3581 git-gui.sh:3612 msgid "Show Less Context" msgstr "Visa mindre sammanhang" -#: git-gui.sh:2733 git-gui.sh:3395 git-gui.sh:3426 +#: git-gui.sh:2882 git-gui.sh:3585 git-gui.sh:3616 msgid "Show More Context" msgstr "Visa mer sammanhang" -#: git-gui.sh:2740 git-gui.sh:3105 git-gui.sh:3214 +#: git-gui.sh:2889 git-gui.sh:3283 git-gui.sh:3392 msgid "Sign Off" msgstr "Skriv under" -#: git-gui.sh:2756 +#: git-gui.sh:2905 msgid "Local Merge..." msgstr "Lokal sammanslagning..." -#: git-gui.sh:2761 +#: git-gui.sh:2910 msgid "Abort Merge..." msgstr "Avbryt sammanslagning..." -#: git-gui.sh:2773 git-gui.sh:2801 +#: git-gui.sh:2922 git-gui.sh:2950 msgid "Add..." msgstr "Lägg till..." -#: git-gui.sh:2777 +#: git-gui.sh:2926 msgid "Push..." msgstr "Sänd..." -#: git-gui.sh:2781 +#: git-gui.sh:2930 msgid "Delete Branch..." msgstr "Ta bort gren..." -#: git-gui.sh:2791 git-gui.sh:3373 +#: git-gui.sh:2940 git-gui.sh:3563 msgid "Options..." msgstr "Alternativ..." -#: git-gui.sh:2802 +#: git-gui.sh:2951 msgid "Remove..." msgstr "Ta bort..." -#: git-gui.sh:2811 lib/choose_repository.tcl:50 +#: git-gui.sh:2960 lib/choose_repository.tcl:55 msgid "Help" msgstr "Hjälp" -#: git-gui.sh:2815 git-gui.sh:2819 lib/about.tcl:14 -#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 +#: git-gui.sh:2964 git-gui.sh:2968 lib/choose_repository.tcl:49 +#: lib/choose_repository.tcl:58 lib/about.tcl:14 #, tcl-format msgid "About %s" msgstr "Om %s" -#: git-gui.sh:2843 +#: git-gui.sh:2992 msgid "Online Documentation" msgstr "Webbdokumentation" -#: git-gui.sh:2846 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 +#: git-gui.sh:2995 lib/choose_repository.tcl:52 lib/choose_repository.tcl:61 msgid "Show SSH Key" msgstr "Visa SSH-nyckel" -#: git-gui.sh:2965 +#: git-gui.sh:3014 git-gui.sh:3146 +msgid "Usage" +msgstr "Användning" + +#: git-gui.sh:3095 lib/blame.tcl:573 +msgid "Error" +msgstr "Fel" + +#: git-gui.sh:3126 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" msgstr "" "ödesdigert: kunde inte ta status pÃ¥ sökvägen %s: Fil eller katalog saknas" -#: git-gui.sh:2997 +#: git-gui.sh:3159 msgid "Current Branch:" msgstr "Aktuell gren:" -#: git-gui.sh:3023 +#: git-gui.sh:3185 msgid "Staged Changes (Will Commit)" msgstr "Köade ändringar (kommer att checkas in)" -#: git-gui.sh:3043 +#: git-gui.sh:3205 msgid "Unstaged Changes" msgstr "Oköade ändringar" -#: git-gui.sh:3098 +#: git-gui.sh:3276 msgid "Stage Changed" msgstr "Köa ändrade" -#: git-gui.sh:3117 lib/transport.tcl:107 lib/transport.tcl:196 +#: git-gui.sh:3295 lib/transport.tcl:137 lib/transport.tcl:229 msgid "Push" msgstr "Sänd" -#: git-gui.sh:3152 +#: git-gui.sh:3330 msgid "Initial Commit Message:" msgstr "Inledande incheckningsmeddelande:" -#: git-gui.sh:3153 +#: git-gui.sh:3331 msgid "Amended Commit Message:" msgstr "Utökat incheckningsmeddelande:" -#: git-gui.sh:3154 +#: git-gui.sh:3332 msgid "Amended Initial Commit Message:" msgstr "Utökat inledande incheckningsmeddelande:" -#: git-gui.sh:3155 +#: git-gui.sh:3333 msgid "Amended Merge Commit Message:" msgstr "Utökat incheckningsmeddelande för sammanslagning:" -#: git-gui.sh:3156 +#: git-gui.sh:3334 msgid "Merge Commit Message:" msgstr "Incheckningsmeddelande för sammanslagning:" -#: git-gui.sh:3157 +#: git-gui.sh:3335 msgid "Commit Message:" msgstr "Incheckningsmeddelande:" -#: git-gui.sh:3206 git-gui.sh:3348 lib/console.tcl:73 +#: git-gui.sh:3384 git-gui.sh:3538 lib/console.tcl:73 msgid "Copy All" msgstr "Kopiera alla" -#: git-gui.sh:3230 lib/blame.tcl:104 +#: git-gui.sh:3408 lib/blame.tcl:105 msgid "File:" msgstr "Fil:" -#: git-gui.sh:3336 +#: git-gui.sh:3526 msgid "Refresh" msgstr "Uppdatera" -#: git-gui.sh:3357 +#: git-gui.sh:3547 msgid "Decrease Font Size" msgstr "Minska teckensnittsstorlek" -#: git-gui.sh:3361 +#: git-gui.sh:3551 msgid "Increase Font Size" msgstr "Öka teckensnittsstorlek" -#: git-gui.sh:3369 lib/blame.tcl:281 +#: git-gui.sh:3559 lib/blame.tcl:294 msgid "Encoding" msgstr "Teckenkodning" -#: git-gui.sh:3380 +#: git-gui.sh:3570 msgid "Apply/Reverse Hunk" msgstr "Använd/Ã¥terställ del" -#: git-gui.sh:3385 +#: git-gui.sh:3575 msgid "Apply/Reverse Line" msgstr "Använd/Ã¥terställ rad" -#: git-gui.sh:3404 +#: git-gui.sh:3594 msgid "Run Merge Tool" msgstr "Starta verktyg för sammanslagning" -#: git-gui.sh:3409 +#: git-gui.sh:3599 msgid "Use Remote Version" msgstr "Använd versionen frÃ¥n fjärrarkivet" -#: git-gui.sh:3413 +#: git-gui.sh:3603 msgid "Use Local Version" msgstr "Använd lokala versionen" -#: git-gui.sh:3417 +#: git-gui.sh:3607 msgid "Revert To Base" msgstr "Ã…terställ till basversionen" -#: git-gui.sh:3435 +#: git-gui.sh:3625 msgid "Visualize These Changes In The Submodule" msgstr "Visualisera ändringarna i undermodulen" -#: git-gui.sh:3439 +#: git-gui.sh:3629 msgid "Visualize Current Branch History In The Submodule" msgstr "Visualisera grenens historik i undermodulen" -#: git-gui.sh:3443 +#: git-gui.sh:3633 msgid "Visualize All Branch History In The Submodule" msgstr "Visualisera alla grenars historik i undermodulen" -#: git-gui.sh:3448 +#: git-gui.sh:3638 msgid "Start git gui In The Submodule" msgstr "Starta git gui i undermodulen" -#: git-gui.sh:3483 +#: git-gui.sh:3673 msgid "Unstage Hunk From Commit" msgstr "Ta bort del ur incheckningskö" -#: git-gui.sh:3485 +#: git-gui.sh:3675 msgid "Unstage Lines From Commit" msgstr "Ta bort rader ur incheckningskö" -#: git-gui.sh:3487 +#: git-gui.sh:3677 msgid "Unstage Line From Commit" msgstr "Ta bort rad ur incheckningskö" -#: git-gui.sh:3490 +#: git-gui.sh:3680 msgid "Stage Hunk For Commit" msgstr "Ställ del i incheckningskö" -#: git-gui.sh:3492 +#: git-gui.sh:3682 msgid "Stage Lines For Commit" msgstr "Ställ rader i incheckningskö" -#: git-gui.sh:3494 +#: git-gui.sh:3684 msgid "Stage Line For Commit" msgstr "Ställ rad i incheckningskö" -#: git-gui.sh:3519 +#: git-gui.sh:3709 msgid "Initializing..." msgstr "Initierar..." -#: git-gui.sh:3658 +#: git-gui.sh:3852 #, tcl-format msgid "" "Possible environment issues exist.\n" @@ -549,7 +580,7 @@ msgstr "" "av %s:\n" "\n" -#: git-gui.sh:3687 +#: git-gui.sh:3881 msgid "" "\n" "This is due to a known issue with the\n" @@ -559,7 +590,7 @@ msgstr "" "Detta beror pÃ¥ ett känt problem med\n" "Tcl-binären som följer med Cygwin." -#: git-gui.sh:3692 +#: git-gui.sh:3886 #, tcl-format msgid "" "\n" @@ -576,314 +607,30 @@ msgstr "" "user.name och user.email i din personliga\n" "~/.gitconfig-fil.\n" -#: lib/about.tcl:26 -msgid "git-gui - a graphical user interface for Git." -msgstr "git-gui - ett grafiskt användargränssnitt för Git." - -#: lib/blame.tcl:72 -msgid "File Viewer" -msgstr "Filvisare" - -#: lib/blame.tcl:78 -msgid "Commit:" -msgstr "Incheckning:" - -#: lib/blame.tcl:271 -msgid "Copy Commit" -msgstr "Kopiera incheckning" - -#: lib/blame.tcl:275 -msgid "Find Text..." -msgstr "Sök text..." - -#: lib/blame.tcl:284 -msgid "Do Full Copy Detection" -msgstr "Gör full kopieringsigenkänning" - -#: lib/blame.tcl:288 -msgid "Show History Context" -msgstr "Visa historiksammanhang" - -#: lib/blame.tcl:291 -msgid "Blame Parent Commit" -msgstr "Klandra föräldraincheckning" - -#: lib/blame.tcl:450 -#, tcl-format -msgid "Reading %s..." -msgstr "Läser %s..." - -#: lib/blame.tcl:581 -msgid "Loading copy/move tracking annotations..." -msgstr "Läser annoteringar för kopiering/flyttning..." - -#: lib/blame.tcl:601 -msgid "lines annotated" -msgstr "rader annoterade" - -#: lib/blame.tcl:793 -msgid "Loading original location annotations..." -msgstr "Läser in annotering av originalplacering..." - -#: lib/blame.tcl:796 -msgid "Annotation complete." -msgstr "Annotering fullbordad." - -#: lib/blame.tcl:826 -msgid "Busy" -msgstr "Upptagen" - -#: lib/blame.tcl:827 -msgid "Annotation process is already running." -msgstr "Annoteringsprocess körs redan." - -#: lib/blame.tcl:866 -msgid "Running thorough copy detection..." -msgstr "Kör grundlig kopieringsigenkänning..." - -#: lib/blame.tcl:934 -msgid "Loading annotation..." -msgstr "Läser in annotering..." - -#: lib/blame.tcl:987 -msgid "Author:" -msgstr "Författare:" - -#: lib/blame.tcl:991 -msgid "Committer:" -msgstr "Incheckare:" - -#: lib/blame.tcl:996 -msgid "Original File:" -msgstr "Ursprunglig fil:" - -#: lib/blame.tcl:1044 -msgid "Cannot find HEAD commit:" -msgstr "Hittar inte incheckning för HEAD:" - -#: lib/blame.tcl:1099 -msgid "Cannot find parent commit:" -msgstr "Hittar inte föräldraincheckning:" - -#: lib/blame.tcl:1114 -msgid "Unable to display parent" -msgstr "Kan inte visa förälder" - -#: lib/blame.tcl:1115 lib/diff.tcl:323 -msgid "Error loading diff:" -msgstr "Fel vid inläsning av differens:" - -#: lib/blame.tcl:1255 -msgid "Originally By:" -msgstr "Ursprungligen av:" - -#: lib/blame.tcl:1261 -msgid "In File:" -msgstr "I filen:" - -#: lib/blame.tcl:1266 -msgid "Copied Or Moved Here By:" -msgstr "Kopierad eller flyttad hit av:" - -#: lib/branch_checkout.tcl:16 lib/branch_checkout.tcl:21 -msgid "Checkout Branch" -msgstr "Checka ut gren" - -#: lib/branch_checkout.tcl:26 -msgid "Checkout" -msgstr "Checka ut" - -#: lib/branch_checkout.tcl:30 lib/branch_create.tcl:37 -#: lib/branch_delete.tcl:34 lib/branch_rename.tcl:32 lib/browser.tcl:286 -#: lib/checkout_op.tcl:579 lib/choose_font.tcl:45 lib/merge.tcl:172 -#: lib/option.tcl:127 lib/remote_add.tcl:34 lib/remote_branch_delete.tcl:43 -#: lib/tools_dlg.tcl:41 lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 -#: lib/transport.tcl:111 -msgid "Cancel" -msgstr "Avbryt" - -#: lib/branch_checkout.tcl:35 lib/browser.tcl:291 lib/tools_dlg.tcl:321 -msgid "Revision" -msgstr "Revision" +#: lib/line.tcl:17 +msgid "Goto Line:" +msgstr "GÃ¥ till rad:" -#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:69 lib/option.tcl:287 -msgid "Options" -msgstr "Alternativ" +#: lib/line.tcl:23 +msgid "Go" +msgstr "GÃ¥" -#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 -msgid "Fetch Tracking Branch" -msgstr "Hämta spÃ¥rande gren" - -#: lib/branch_checkout.tcl:47 -msgid "Detach From Local Branch" -msgstr "Koppla bort frÃ¥n lokal gren" - -#: lib/branch_create.tcl:23 -msgid "Create Branch" -msgstr "Skapa gren" - -#: lib/branch_create.tcl:28 -msgid "Create New Branch" -msgstr "Skapa ny gren" - -#: lib/branch_create.tcl:33 lib/choose_repository.tcl:389 -msgid "Create" -msgstr "Skapa" - -#: lib/branch_create.tcl:42 -msgid "Branch Name" -msgstr "Namn pÃ¥ gren" - -#: lib/branch_create.tcl:44 lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 -msgid "Name:" -msgstr "Namn:" - -#: lib/branch_create.tcl:57 -msgid "Match Tracking Branch Name" -msgstr "Använd namn pÃ¥ spÃ¥rad gren" - -#: lib/branch_create.tcl:66 -msgid "Starting Revision" -msgstr "Inledande revision" - -#: lib/branch_create.tcl:72 -msgid "Update Existing Branch:" -msgstr "Uppdatera befintlig gren:" - -#: lib/branch_create.tcl:75 -msgid "No" -msgstr "Nej" - -#: lib/branch_create.tcl:80 -msgid "Fast Forward Only" -msgstr "Endast snabbspolning" - -#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571 -msgid "Reset" -msgstr "Ã…terställ" - -#: lib/branch_create.tcl:97 -msgid "Checkout After Creation" -msgstr "Checka ut när skapad" - -#: lib/branch_create.tcl:132 -msgid "Please select a tracking branch." -msgstr "Välj en gren att spÃ¥ra." - -#: lib/branch_create.tcl:141 -#, tcl-format -msgid "Tracking branch %s is not a branch in the remote repository." -msgstr "Den spÃ¥rade grenen %s är inte en gren i fjärrarkivet." - -#: lib/branch_create.tcl:154 lib/branch_rename.tcl:92 -msgid "Please supply a branch name." -msgstr "Ange ett namn för grenen." - -#: lib/branch_create.tcl:165 lib/branch_rename.tcl:112 -#, tcl-format -msgid "'%s' is not an acceptable branch name." -msgstr "\"%s\" kan inte användas som namn pÃ¥ grenen." - -#: lib/branch_delete.tcl:16 -msgid "Delete Branch" -msgstr "Ta bort gren" - -#: lib/branch_delete.tcl:21 -msgid "Delete Local Branch" -msgstr "Ta bort lokal gren" - -#: lib/branch_delete.tcl:39 -msgid "Local Branches" -msgstr "Lokala grenar" - -#: lib/branch_delete.tcl:51 -msgid "Delete Only If Merged Into" -msgstr "Ta bara bort om sammanslagen med" - -#: lib/branch_delete.tcl:53 lib/remote_branch_delete.tcl:120 -msgid "Always (Do not perform merge checks)" -msgstr "Alltid (utför inte sammanslagningstest)" - -#: lib/branch_delete.tcl:103 -#, tcl-format -msgid "The following branches are not completely merged into %s:" -msgstr "Följande grenar är inte till fullo sammanslagna med %s:" - -#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:218 -msgid "" -"Recovering deleted branches is difficult.\n" -"\n" -"Delete the selected branches?" -msgstr "" -"Det kan vara svÃ¥rt att Ã¥terställa borttagna grenar.\n" -"\n" -"Ta bort de valda grenarna?" - -#: lib/branch_delete.tcl:141 -#, tcl-format -msgid "" -"Failed to delete branches:\n" -"%s" -msgstr "" -"Kunde inte ta bort grenar:\n" -"%s" - -#: lib/branch_rename.tcl:15 lib/branch_rename.tcl:23 -msgid "Rename Branch" -msgstr "Byt namn pÃ¥ gren" - -#: lib/branch_rename.tcl:28 -msgid "Rename" -msgstr "Byt namn" - -#: lib/branch_rename.tcl:38 -msgid "Branch:" -msgstr "Gren:" - -#: lib/branch_rename.tcl:46 -msgid "New Name:" -msgstr "Nytt namn:" - -#: lib/branch_rename.tcl:81 -msgid "Please select a branch to rename." -msgstr "Välj en gren att byta namn pÃ¥." - -#: lib/branch_rename.tcl:102 lib/checkout_op.tcl:202 -#, tcl-format -msgid "Branch '%s' already exists." -msgstr "Grenen \"%s\" finns redan." - -#: lib/branch_rename.tcl:123 -#, tcl-format -msgid "Failed to rename '%s'." -msgstr "Kunde inte byta namn pÃ¥ \"%s\"." - -#: lib/browser.tcl:17 -msgid "Starting..." -msgstr "Startar..." - -#: lib/browser.tcl:27 -msgid "File Browser" -msgstr "Filbläddrare" - -#: lib/browser.tcl:126 lib/browser.tcl:143 -#, tcl-format -msgid "Loading %s..." -msgstr "Läser %s..." +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "Arbetar... vänta..." -#: lib/browser.tcl:187 -msgid "[Up To Parent]" -msgstr "[Upp till förälder]" +#: lib/console.tcl:81 lib/checkout_op.tcl:146 lib/sshkey.tcl:55 +#: lib/database.tcl:30 +msgid "Close" +msgstr "Stäng" -#: lib/browser.tcl:269 lib/browser.tcl:276 -msgid "Browse Branch Files" -msgstr "Bläddra filer pÃ¥ grenen" +#: lib/console.tcl:186 +msgid "Success" +msgstr "Lyckades" -#: lib/browser.tcl:282 lib/choose_repository.tcl:404 -#: lib/choose_repository.tcl:491 lib/choose_repository.tcl:500 -#: lib/choose_repository.tcl:1027 -msgid "Browse" -msgstr "Bläddra" +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "Fel: Kommando misslyckades" #: lib/checkout_op.tcl:85 #, tcl-format @@ -895,11 +642,6 @@ msgstr "Hämtar %s frÃ¥n %s" msgid "fatal: Cannot resolve %s" msgstr "ödesdigert: Kunde inte slÃ¥ upp %s" -#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:30 -#: lib/sshkey.tcl:55 -msgid "Close" -msgstr "Stäng" - #: lib/checkout_op.tcl:175 #, tcl-format msgid "Branch '%s' does not exist." @@ -910,6 +652,11 @@ msgstr "Grenen \"%s\" finns inte." msgid "Failed to configure simplified git-pull for '%s'." msgstr "Kunde inte konfigurera förenklad git-pull för '%s'." +#: lib/checkout_op.tcl:202 lib/branch_rename.tcl:102 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "Grenen \"%s\" finns redan." + #: lib/checkout_op.tcl:229 #, tcl-format msgid "" @@ -1008,10 +755,23 @@ msgstr "Det kanske inte är sÃ¥ enkelt att Ã¥terskapa förlorade incheckningar." msgid "Reset '%s'?" msgstr "Ã…terställa \"%s\"?" -#: lib/checkout_op.tcl:567 lib/merge.tcl:164 lib/tools_dlg.tcl:336 +#: lib/checkout_op.tcl:567 lib/merge.tcl:166 lib/tools_dlg.tcl:336 msgid "Visualize" msgstr "Visualisera" +#: lib/checkout_op.tcl:571 lib/branch_create.tcl:85 +msgid "Reset" +msgstr "Ã…terställ" + +#: lib/checkout_op.tcl:579 lib/transport.tcl:141 lib/remote_add.tcl:34 +#: lib/browser.tcl:292 lib/merge.tcl:174 lib/branch_checkout.tcl:30 +#: lib/choose_font.tcl:45 lib/option.tcl:127 lib/tools_dlg.tcl:41 +#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/branch_rename.tcl:32 +#: lib/remote_branch_delete.tcl:43 lib/branch_create.tcl:37 +#: lib/branch_delete.tcl:34 +msgid "Cancel" +msgstr "Avbryt" + #: lib/checkout_op.tcl:635 #, tcl-format msgid "" @@ -1029,544 +789,442 @@ msgstr "" "\n" "Detta skulle inte ha hänt. %s kommer nu stängas och ge upp." -#: lib/choose_font.tcl:41 -msgid "Select" -msgstr "Välj" - -#: lib/choose_font.tcl:55 -msgid "Font Family" -msgstr "Teckensnittsfamilj" - -#: lib/choose_font.tcl:76 -msgid "Font Size" -msgstr "Storlek" - -#: lib/choose_font.tcl:93 -msgid "Font Example" -msgstr "Exempel" - -#: lib/choose_font.tcl:105 -msgid "" -"This is example text.\n" -"If you like this text, it can be your font." -msgstr "" -"Detta är en exempeltext.\n" -"Om du tycker om den här texten kan den vara ditt teckensnitt." - -#: lib/choose_repository.tcl:28 -msgid "Git Gui" -msgstr "Git Gui" - -#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:394 -msgid "Create New Repository" -msgstr "Skapa nytt arkiv" - -#: lib/choose_repository.tcl:93 -msgid "New..." -msgstr "Nytt..." - -#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:478 -msgid "Clone Existing Repository" -msgstr "Klona befintligt arkiv" - -#: lib/choose_repository.tcl:111 -msgid "Clone..." -msgstr "Klona..." - -#: lib/choose_repository.tcl:118 lib/choose_repository.tcl:1017 -msgid "Open Existing Repository" -msgstr "Öppna befintligt arkiv" - -#: lib/choose_repository.tcl:124 -msgid "Open..." -msgstr "Öppna..." - -#: lib/choose_repository.tcl:137 -msgid "Recent Repositories" -msgstr "Senaste arkiven" - -#: lib/choose_repository.tcl:143 -msgid "Open Recent Repository:" -msgstr "Öppna tidigare arkiv:" - -#: lib/choose_repository.tcl:313 lib/choose_repository.tcl:320 -#: lib/choose_repository.tcl:327 +#: lib/transport.tcl:6 lib/remote_add.tcl:132 #, tcl-format -msgid "Failed to create repository %s:" -msgstr "Kunde inte skapa arkivet %s:" - -#: lib/choose_repository.tcl:399 -msgid "Directory:" -msgstr "Katalog:" - -#: lib/choose_repository.tcl:429 lib/choose_repository.tcl:550 -#: lib/choose_repository.tcl:1051 -msgid "Git Repository" -msgstr "Gitarkiv" +msgid "fetch %s" +msgstr "hämta %s" -#: lib/choose_repository.tcl:454 +#: lib/transport.tcl:7 #, tcl-format -msgid "Directory %s already exists." -msgstr "Katalogen %s finns redan." +msgid "Fetching new changes from %s" +msgstr "Hämtar nya ändringar frÃ¥n %s" -#: lib/choose_repository.tcl:458 +#: lib/transport.tcl:18 #, tcl-format -msgid "File %s already exists." -msgstr "Filen %s finns redan." - -#: lib/choose_repository.tcl:473 -msgid "Clone" -msgstr "Klona" - -#: lib/choose_repository.tcl:486 -msgid "Source Location:" -msgstr "Plats för källkod:" +msgid "remote prune %s" +msgstr "fjärrborttagning %s" -#: lib/choose_repository.tcl:495 -msgid "Target Directory:" -msgstr "MÃ¥lkatalog:" +#: lib/transport.tcl:19 +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "Tar bort spÃ¥rande grenar som tagits bort frÃ¥n %s" -#: lib/choose_repository.tcl:505 -msgid "Clone Type:" -msgstr "Typ av klon:" +#: lib/transport.tcl:25 +msgid "fetch all remotes" +msgstr "hämta alla fjärrarkiv" -#: lib/choose_repository.tcl:510 -msgid "Standard (Fast, Semi-Redundant, Hardlinks)" -msgstr "Standard (snabb, semiredundant, hÃ¥rda länkar)" +#: lib/transport.tcl:26 +msgid "Fetching new changes from all remotes" +msgstr "Hämtar nya ändringar frÃ¥n alla fjärrarkiv" -#: lib/choose_repository.tcl:515 -msgid "Full Copy (Slower, Redundant Backup)" -msgstr "Full kopia (lÃ¥ngsammare, redundant säkerhetskopia)" +#: lib/transport.tcl:40 +msgid "remote prune all remotes" +msgstr "rensa alla fjärrarkiv" -#: lib/choose_repository.tcl:520 -msgid "Shared (Fastest, Not Recommended, No Backup)" -msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)" +#: lib/transport.tcl:41 +msgid "Pruning tracking branches deleted from all remotes" +msgstr "Rensar spÃ¥rande grenar som tagits bort, frÃ¥n alla fjärrarkiv" -#: lib/choose_repository.tcl:556 lib/choose_repository.tcl:603 -#: lib/choose_repository.tcl:749 lib/choose_repository.tcl:819 -#: lib/choose_repository.tcl:1057 lib/choose_repository.tcl:1065 +#: lib/transport.tcl:54 lib/transport.tcl:92 lib/transport.tcl:110 +#: lib/remote_add.tcl:162 #, tcl-format -msgid "Not a Git repository: %s" -msgstr "Inte ett Gitarkiv: %s" - -#: lib/choose_repository.tcl:592 -msgid "Standard only available for local repository." -msgstr "Standard är endast tillgängligt för lokala arkiv." - -#: lib/choose_repository.tcl:596 -msgid "Shared only available for local repository." -msgstr "Delat är endast tillgängligt för lokala arkiv." +msgid "push %s" +msgstr "sänd %s" -#: lib/choose_repository.tcl:617 +#: lib/transport.tcl:55 #, tcl-format -msgid "Location %s already exists." -msgstr "Platsen %s finns redan." - -#: lib/choose_repository.tcl:628 -msgid "Failed to configure origin" -msgstr "Kunde inte konfigurera ursprung" - -#: lib/choose_repository.tcl:640 -msgid "Counting objects" -msgstr "Räknar objekt" - -#: lib/choose_repository.tcl:641 -msgid "buckets" -msgstr "hinkar" +msgid "Pushing changes to %s" +msgstr "Sänder ändringar till %s" -#: lib/choose_repository.tcl:665 +#: lib/transport.tcl:93 #, tcl-format -msgid "Unable to copy objects/info/alternates: %s" -msgstr "Kunde inte kopiera objekt/info/alternativ: %s" +msgid "Mirroring to %s" +msgstr "Speglar till %s" -#: lib/choose_repository.tcl:701 +#: lib/transport.tcl:111 #, tcl-format -msgid "Nothing to clone from %s." -msgstr "Ingenting att klona frÃ¥n %s." +msgid "Pushing %s %s to %s" +msgstr "Sänder %s %s till %s" -#: lib/choose_repository.tcl:703 lib/choose_repository.tcl:917 -#: lib/choose_repository.tcl:929 -msgid "The 'master' branch has not been initialized." -msgstr "Grenen \"master\" har inte initierats." +#: lib/transport.tcl:132 +msgid "Push Branches" +msgstr "Sänd grenar" -#: lib/choose_repository.tcl:716 -msgid "Hardlinks are unavailable. Falling back to copying." -msgstr "HÃ¥rda länkar är inte tillgängliga. Faller tillbaka pÃ¥ kopiering." +#: lib/transport.tcl:147 +msgid "Source Branches" +msgstr "Källgrenar" -#: lib/choose_repository.tcl:728 -#, tcl-format -msgid "Cloning from %s" -msgstr "Klonar frÃ¥n %s" +#: lib/transport.tcl:162 +msgid "Destination Repository" +msgstr "Destinationsarkiv" -#: lib/choose_repository.tcl:759 -msgid "Copying objects" -msgstr "Kopierar objekt" +#: lib/transport.tcl:165 lib/remote_branch_delete.tcl:51 +msgid "Remote:" +msgstr "Fjärrarkiv:" -#: lib/choose_repository.tcl:760 -msgid "KiB" -msgstr "KiB" +#: lib/transport.tcl:187 lib/remote_branch_delete.tcl:72 +msgid "Arbitrary Location:" +msgstr "Godtycklig plats:" -#: lib/choose_repository.tcl:784 -#, tcl-format -msgid "Unable to copy object: %s" -msgstr "Kunde inte kopiera objekt: %s" +#: lib/transport.tcl:205 +msgid "Transfer Options" +msgstr "Överföringsalternativ" -#: lib/choose_repository.tcl:794 -msgid "Linking objects" -msgstr "Länkar objekt" +#: lib/transport.tcl:207 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "Tvinga överskrivning av befintlig gren (kan kasta bort ändringar)" -#: lib/choose_repository.tcl:795 -msgid "objects" -msgstr "objekt" +#: lib/transport.tcl:211 +msgid "Use thin pack (for slow network connections)" +msgstr "Använd tunt paket (för lÃ¥ngsamma nätverksanslutningar)" -#: lib/choose_repository.tcl:803 -#, tcl-format -msgid "Unable to hardlink object: %s" -msgstr "Kunde inte hÃ¥rdlänka objekt: %s" +#: lib/transport.tcl:215 +msgid "Include tags" +msgstr "Ta med taggar" -#: lib/choose_repository.tcl:858 -msgid "Cannot fetch branches and objects. See console output for details." -msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer." +#: lib/remote_add.tcl:20 +msgid "Add Remote" +msgstr "Lägg till fjärrarkiv" -#: lib/choose_repository.tcl:869 -msgid "Cannot fetch tags. See console output for details." -msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer." +#: lib/remote_add.tcl:25 +msgid "Add New Remote" +msgstr "Lägg till nytt fjärrarkiv" -#: lib/choose_repository.tcl:893 -msgid "Cannot determine HEAD. See console output for details." -msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer." +#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 +msgid "Add" +msgstr "Lägg till" -#: lib/choose_repository.tcl:902 -#, tcl-format -msgid "Unable to cleanup %s" -msgstr "Kunde inte städa upp %s" +#: lib/remote_add.tcl:39 +msgid "Remote Details" +msgstr "Detaljer för fjärrarkiv" -#: lib/choose_repository.tcl:908 -msgid "Clone failed." -msgstr "Kloning misslyckades." +#: lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 lib/branch_create.tcl:44 +msgid "Name:" +msgstr "Namn:" -#: lib/choose_repository.tcl:915 -msgid "No default branch obtained." -msgstr "Hämtade ingen standardgren." +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Plats:" -#: lib/choose_repository.tcl:926 -#, tcl-format -msgid "Cannot resolve %s as a commit." -msgstr "Kunde inte slÃ¥ upp %s till nÃ¥gon incheckning." +#: lib/remote_add.tcl:60 +msgid "Further Action" +msgstr "Ytterligare Ã¥tgärd" -#: lib/choose_repository.tcl:938 -msgid "Creating working directory" -msgstr "Skapar arbetskatalog" +#: lib/remote_add.tcl:63 +msgid "Fetch Immediately" +msgstr "Hämta omedelbart" -#: lib/choose_repository.tcl:939 lib/index.tcl:70 lib/index.tcl:133 -#: lib/index.tcl:201 -msgid "files" -msgstr "filer" +#: lib/remote_add.tcl:69 +msgid "Initialize Remote Repository and Push" +msgstr "Initiera fjärrarkiv och sänd till" -#: lib/choose_repository.tcl:968 -msgid "Initial file checkout failed." -msgstr "Inledande filutcheckning misslyckades." +#: lib/remote_add.tcl:75 +msgid "Do Nothing Else Now" +msgstr "Gör ingent mer nu" -#: lib/choose_repository.tcl:1012 -msgid "Open" -msgstr "Öppna" +#: lib/remote_add.tcl:100 +msgid "Please supply a remote name." +msgstr "Ange ett namn för fjärrarkivet." -#: lib/choose_repository.tcl:1022 -msgid "Repository:" -msgstr "Arkiv:" +#: lib/remote_add.tcl:113 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "\"%s\" kan inte användas som namn pÃ¥ fjärrarkivet." -#: lib/choose_repository.tcl:1071 +#: lib/remote_add.tcl:124 #, tcl-format -msgid "Failed to open repository %s:" -msgstr "Kunde inte öppna arkivet %s:" +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Kunde inte lägga till fjärrarkivet \"%s\" pÃ¥ platsen \"%s\"." -#: lib/choose_rev.tcl:52 -msgid "This Detached Checkout" -msgstr "Denna frÃ¥nkopplade utcheckning" +#: lib/remote_add.tcl:133 +#, tcl-format +msgid "Fetching the %s" +msgstr "Hämtar %s" -#: lib/choose_rev.tcl:60 -msgid "Revision Expression:" -msgstr "Revisionsuttryck:" +#: lib/remote_add.tcl:156 +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Vet inte hur arkivet pÃ¥ platsen \"%s\" skall initieras." -#: lib/choose_rev.tcl:72 -msgid "Local Branch" -msgstr "Lokal gren" +#: lib/remote_add.tcl:163 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Konfigurerar %s (pÃ¥ %s)" -#: lib/choose_rev.tcl:77 -msgid "Tracking Branch" -msgstr "SpÃ¥rande gren" +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "Startar..." -#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:543 -msgid "Tag" -msgstr "Tagg" +#: lib/browser.tcl:27 +msgid "File Browser" +msgstr "Filbläddrare" -#: lib/choose_rev.tcl:321 +#: lib/browser.tcl:132 lib/browser.tcl:149 #, tcl-format -msgid "Invalid revision: %s" -msgstr "Ogiltig revision: %s" - -#: lib/choose_rev.tcl:342 -msgid "No revision selected." -msgstr "Ingen revision vald." +msgid "Loading %s..." +msgstr "Läser %s..." -#: lib/choose_rev.tcl:350 -msgid "Revision expression is empty." -msgstr "Revisionsuttrycket är tomt." +#: lib/browser.tcl:193 +msgid "[Up To Parent]" +msgstr "[Upp till förälder]" -#: lib/choose_rev.tcl:536 -msgid "Updated" -msgstr "Uppdaterad" +#: lib/browser.tcl:275 lib/browser.tcl:282 +msgid "Browse Branch Files" +msgstr "Bläddra filer pÃ¥ grenen" -#: lib/choose_rev.tcl:564 -msgid "URL" -msgstr "Webbadress" +#: lib/browser.tcl:288 lib/choose_repository.tcl:422 +#: lib/choose_repository.tcl:509 lib/choose_repository.tcl:518 +#: lib/choose_repository.tcl:1074 +msgid "Browse" +msgstr "Bläddra" -#: lib/commit.tcl:9 -msgid "" -"There is nothing to amend.\n" -"\n" -"You are about to create the initial commit. There is no commit before this " -"to amend.\n" -msgstr "" -"Det finns ingenting att utöka.\n" -"\n" -"Du hÃ¥ller pÃ¥ att skapa den inledande incheckningen. Det finns ingen tidigare " -"incheckning att utöka.\n" +#: lib/browser.tcl:297 lib/branch_checkout.tcl:35 lib/tools_dlg.tcl:321 +msgid "Revision" +msgstr "Revision" -#: lib/commit.tcl:18 +#: lib/merge.tcl:13 msgid "" -"Cannot amend while merging.\n" +"Cannot merge while amending.\n" "\n" -"You are currently in the middle of a merge that has not been fully " -"completed. You cannot amend the prior commit unless you first abort the " -"current merge activity.\n" +"You must finish amending this commit before starting any type of merge.\n" msgstr "" -"Kan inte utöka vid sammanslagning.\n" +"Kan inte slÃ¥ ihop vid utökning.\n" "\n" -"Du är i mitten av en sammanslagning som inte är fullbordad. Du kan inte " -"utöka tidigare incheckningar om du inte först avbryter den pÃ¥gÃ¥ende " -"sammanslagningen.\n" - -#: lib/commit.tcl:48 -msgid "Error loading commit data for amend:" -msgstr "Fel vid inläsning av incheckningsdata för utökning:" - -#: lib/commit.tcl:75 -msgid "Unable to obtain your identity:" -msgstr "Kunde inte hämta din identitet:" - -#: lib/commit.tcl:80 -msgid "Invalid GIT_COMMITTER_IDENT:" -msgstr "Felaktig GIT_COMMITTER_IDENT:" - -#: lib/commit.tcl:129 -#, tcl-format -msgid "warning: Tcl does not support encoding '%s'." -msgstr "varning: Tcl stöder inte teckenkodningen \"%s\"." +"Du mÃ¥ste göra färdig utökningen av incheckningen innan du pÃ¥börjar nÃ¥gon " +"slags sammanslagning.\n" -#: lib/commit.tcl:149 +#: lib/merge.tcl:27 msgid "" "Last scanned state does not match repository state.\n" "\n" "Another Git program has modified this repository since the last scan. A " -"rescan must be performed before another commit can be created.\n" +"rescan must be performed before a merge can be performed.\n" "\n" "The rescan will be automatically started now.\n" msgstr "" "Det senaste inlästa tillstÃ¥ndet motsvarar inte tillstÃ¥ndet i arkivet.\n" "\n" "Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du mÃ¥ste " -"utföra en ny sökning innan du kan göra en ny incheckning.\n" +"utföra en ny sökning innan du kan utföra en sammanslagning.\n" "\n" "Sökningen kommer att startas automatiskt nu.\n" -#: lib/commit.tcl:172 +#: lib/merge.tcl:45 #, tcl-format msgid "" -"Unmerged files cannot be committed.\n" +"You are in the middle of a conflicted merge.\n" "\n" -"File %s has merge conflicts. You must resolve them and stage the file " -"before committing.\n" +"File %s has merge conflicts.\n" +"\n" +"You must resolve them, stage the file, and commit to complete the current " +"merge. Only then can you begin another merge.\n" msgstr "" -"Osammanslagna filer kan inte checkas in.\n" +"Du är mitt i en sammanslagning med konflikter.\n" "\n" -"Filen %s har sammanslagningskonflikter. Du mÃ¥ste lösa dem och köa filen " -"innan du checkar in den.\n" +"Filen %s har sammanslagningskonflikter.\n" +"\n" +"Du mÃ¥ste lösa dem, köa filen och checka in för att fullborda den aktuella " +"sammanslagningen. När du gjort det kan du pÃ¥börja en ny sammanslagning.\n" -#: lib/commit.tcl:180 +#: lib/merge.tcl:55 #, tcl-format msgid "" -"Unknown file state %s detected.\n" +"You are in the middle of a change.\n" "\n" -"File %s cannot be committed by this program.\n" +"File %s is modified.\n" +"\n" +"You should complete the current commit before starting a merge. Doing so " +"will help you abort a failed merge, should the need arise.\n" msgstr "" -"Okänd filstatus %s upptäckt.\n" +"Du är mitt i en ändring.\n" "\n" -"Filen %s kan inte checkas in av programmet.\n" +"Filen %s har ändringar.\n" +"\n" +"Du bör fullborda den aktuella incheckningen innan du pÃ¥börjar en " +"sammanslagning. Om du gör det blir det enklare att avbryta en misslyckad " +"sammanslagning, om det skulle vara nödvändigt.\n" + +#: lib/merge.tcl:108 +#, tcl-format +msgid "%s of %s" +msgstr "%s av %s" + +#: lib/merge.tcl:122 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "SlÃ¥r ihop %s och %s..." + +#: lib/merge.tcl:133 +msgid "Merge completed successfully." +msgstr "Sammanslagningen avslutades framgÃ¥ngsrikt." -#: lib/commit.tcl:188 +#: lib/merge.tcl:135 +msgid "Merge failed. Conflict resolution is required." +msgstr "Sammanslagningen misslyckades. Du mÃ¥ste lösa konflikterna." + +#: lib/merge.tcl:160 +#, tcl-format +msgid "Merge Into %s" +msgstr "SlÃ¥ ihop i %s" + +#: lib/merge.tcl:179 +msgid "Revision To Merge" +msgstr "Revisioner att slÃ¥ ihop" + +#: lib/merge.tcl:214 msgid "" -"No changes to commit.\n" +"Cannot abort while amending.\n" "\n" -"You must stage at least 1 file before you can commit.\n" +"You must finish amending this commit.\n" msgstr "" -"Inga ändringar att checka in.\n" +"Kan inte avbryta vid utökning.\n" "\n" -"Du mÃ¥ste köa Ã¥tminstone en fil innan du kan checka in.\n" +"Du mÃ¥ste göra dig färdig med att utöka incheckningen.\n" -#: lib/commit.tcl:203 +#: lib/merge.tcl:224 msgid "" -"Please supply a commit message.\n" +"Abort merge?\n" "\n" -"A good commit message has the following format:\n" +"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "\n" -"- First line: Describe in one sentence what you did.\n" -"- Second line: Blank\n" -"- Remaining lines: Describe why this change is good.\n" +"Continue with aborting the current merge?" msgstr "" -"Ange ett incheckningsmeddelande.\n" +"Avbryt sammanslagning?\n" "\n" -"Ett bra incheckningsmeddelande har följande format:\n" +"Om du avbryter sammanslagningen kommer *ALLA* ej incheckade ändringar att gÃ¥ " +"förlorade.\n" "\n" -"- Första raden: Beskriv i en mening vad du gjorde.\n" -"- Andra raden: Tom\n" -"- Följande rader: Beskriv varför det här är en bra ändring.\n" - -#: lib/commit.tcl:234 -msgid "Calling pre-commit hook..." -msgstr "Anropar kroken före incheckning (pre-commit)..." +"GÃ¥ vidare med att avbryta den aktuella sammanslagningen?" -#: lib/commit.tcl:249 -msgid "Commit declined by pre-commit hook." -msgstr "Incheckningen avvisades av kroken före incheckning (pre-commit)." +#: lib/merge.tcl:230 +msgid "" +"Reset changes?\n" +"\n" +"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with resetting the current changes?" +msgstr "" +"Ã…terställ ändringar?\n" +"\n" +"Om du Ã¥terställer ändringarna kommer *ALLA* ej incheckade ändringar att gÃ¥ " +"förlorade.\n" +"\n" +"GÃ¥ vidare med att Ã¥terställa de aktuella ändringarna?" -#: lib/commit.tcl:272 -msgid "Calling commit-msg hook..." -msgstr "Anropar kroken för incheckningsmeddelande (commit-msg)..." +#: lib/merge.tcl:241 +msgid "Aborting" +msgstr "Avbryter" -#: lib/commit.tcl:287 -msgid "Commit declined by commit-msg hook." -msgstr "Incheckning avvisad av kroken för incheckningsmeddelande (commit-msg)." +#: lib/merge.tcl:241 +msgid "files reset" +msgstr "filer Ã¥terställda" -#: lib/commit.tcl:300 -msgid "Committing changes..." -msgstr "Checkar in ändringar..." +#: lib/merge.tcl:269 +msgid "Abort failed." +msgstr "Misslyckades avbryta." -#: lib/commit.tcl:316 -msgid "write-tree failed:" -msgstr "write-tree misslyckades:" +#: lib/merge.tcl:271 +msgid "Abort completed. Ready." +msgstr "Avbrytning fullbordad. Redo." -#: lib/commit.tcl:317 lib/commit.tcl:361 lib/commit.tcl:382 -msgid "Commit failed." -msgstr "Incheckningen misslyckades." +#: lib/tools.tcl:75 +#, tcl-format +msgid "Running %s requires a selected file." +msgstr "För att starta %s mÃ¥ste du välja en fil." -#: lib/commit.tcl:334 +#: lib/tools.tcl:91 #, tcl-format -msgid "Commit %s appears to be corrupt" -msgstr "Incheckningen %s verkar vara trasig" +msgid "Are you sure you want to run %1$s on file \"%2$s\"?" +msgstr "Är du säker pÃ¥ att du vill starta %1$s med filen \"%2$s\"?" -#: lib/commit.tcl:339 -msgid "" -"No changes to commit.\n" -"\n" -"No files were modified by this commit and it was not a merge commit.\n" -"\n" -"A rescan will be automatically started now.\n" -msgstr "" -"Inga ändringar att checka in.\n" -"\n" -"Inga filer ändrades av incheckningen och det var inte en sammanslagning.\n" -"\n" -"En sökning kommer att startas automatiskt nu.\n" +#: lib/tools.tcl:95 +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Är du säker pÃ¥ att du vill starta %s?" -#: lib/commit.tcl:346 -msgid "No changes to commit." -msgstr "Inga ändringar att checka in." +#: lib/tools.tcl:116 +#, tcl-format +msgid "Tool: %s" +msgstr "Verktyg: %s" -#: lib/commit.tcl:360 -msgid "commit-tree failed:" -msgstr "commit-tree misslyckades:" +#: lib/tools.tcl:117 +#, tcl-format +msgid "Running: %s" +msgstr "Exekverar: %s" -#: lib/commit.tcl:381 -msgid "update-ref failed:" -msgstr "update-ref misslyckades:" +#: lib/tools.tcl:155 +#, tcl-format +msgid "Tool completed successfully: %s" +msgstr "Verktyget avslutades framgÃ¥ngsrikt: %s" -#: lib/commit.tcl:469 +#: lib/tools.tcl:157 #, tcl-format -msgid "Created commit %s: %s" -msgstr "Skapade incheckningen %s: %s" +msgid "Tool failed: %s" +msgstr "Verktyget misslyckades: %s" -#: lib/console.tcl:59 -msgid "Working... please wait..." -msgstr "Arbetar... vänta..." +#: lib/branch_checkout.tcl:16 lib/branch_checkout.tcl:21 +msgid "Checkout Branch" +msgstr "Checka ut gren" -#: lib/console.tcl:186 -msgid "Success" -msgstr "Lyckades" +#: lib/branch_checkout.tcl:26 +msgid "Checkout" +msgstr "Checka ut" -#: lib/console.tcl:200 -msgid "Error: Command Failed" -msgstr "Fel: Kommando misslyckades" +#: lib/branch_checkout.tcl:39 lib/option.tcl:310 lib/branch_create.tcl:69 +msgid "Options" +msgstr "Alternativ" -#: lib/database.tcl:42 -msgid "Number of loose objects" -msgstr "Antal lösa objekt" +#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "Hämta spÃ¥rande gren" -#: lib/database.tcl:43 -msgid "Disk space used by loose objects" -msgstr "Diskutrymme använt av lösa objekt" +#: lib/branch_checkout.tcl:47 +msgid "Detach From Local Branch" +msgstr "Koppla bort frÃ¥n lokal gren" -#: lib/database.tcl:44 -msgid "Number of packed objects" -msgstr "Antal packade objekt" +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "Stavningskontrollprogrammet stöds inte" -#: lib/database.tcl:45 -msgid "Number of packs" -msgstr "Antal paket" +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "Stavningskontroll är ej tillgänglig" -#: lib/database.tcl:46 -msgid "Disk space used by packed objects" -msgstr "Diskutrymme använt av packade objekt" +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "Ogiltig inställning för stavningskontroll" -#: lib/database.tcl:47 -msgid "Packed objects waiting for pruning" -msgstr "Packade objekt som väntar pÃ¥ städning" +#: lib/spellcheck.tcl:70 +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "Ã…terställer ordlistan till %s." -#: lib/database.tcl:48 -msgid "Garbage files" -msgstr "Skräpfiler" +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" +msgstr "Stavningskontroll misslyckades tyst vid start" -#: lib/database.tcl:72 -msgid "Compressing the object database" -msgstr "Komprimerar objektdatabasen" +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" +msgstr "Stavningskontrollprogrammet känns inte igen" -#: lib/database.tcl:83 -msgid "Verifying the object database with fsck-objects" -msgstr "Verifierar objektdatabasen med fsck-objects" +#: lib/spellcheck.tcl:186 +msgid "No Suggestions" +msgstr "Inga förslag" -#: lib/database.tcl:107 -#, tcl-format -msgid "" -"This repository currently has approximately %i loose objects.\n" -"\n" -"To maintain optimal performance it is strongly recommended that you compress " -"the database.\n" -"\n" -"Compress the database now?" -msgstr "" -"Arkivet har för närvarande omkring %i lösa objekt.\n" -"\n" -"För att bibehÃ¥lla optimal prestanda rekommenderas det Ã¥ det bestämdaste att " -"du komprimerar databasen.\n" -"\n" -"Komprimera databasen nu?" +#: lib/spellcheck.tcl:388 +msgid "Unexpected EOF from spell checker" +msgstr "Oväntat filslut frÃ¥n stavningskontroll" -#: lib/date.tcl:25 +#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "Stavningskontroll misslyckades" + +#: lib/status_bar.tcl:87 #, tcl-format -msgid "Invalid date from Git: %s" -msgstr "Ogiltigt datum frÃ¥n Git: %s" +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s... %*i av %*i %s (%3i%%)" -#: lib/diff.tcl:64 +#: lib/diff.tcl:77 #, tcl-format msgid "" "No differences detected.\n" @@ -1589,12 +1247,12 @@ msgstr "" "En sökning kommer automatiskt att startas för att hitta andra filer som kan " "vara i samma tillstÃ¥nd." -#: lib/diff.tcl:104 +#: lib/diff.tcl:117 #, tcl-format msgid "Loading diff of %s..." msgstr "Läser differens för %s..." -#: lib/diff.tcl:125 +#: lib/diff.tcl:140 msgid "" "LOCAL: deleted\n" "REMOTE:\n" @@ -1602,7 +1260,7 @@ msgstr "" "LOKAL: borttagen\n" "FJÄRR:\n" -#: lib/diff.tcl:130 +#: lib/diff.tcl:145 msgid "" "REMOTE: deleted\n" "LOCAL:\n" @@ -1610,32 +1268,32 @@ msgstr "" "FJÄRR: borttagen\n" "LOKAL:\n" -#: lib/diff.tcl:137 +#: lib/diff.tcl:152 msgid "LOCAL:\n" msgstr "LOKAL:\n" -#: lib/diff.tcl:140 +#: lib/diff.tcl:155 msgid "REMOTE:\n" msgstr "FJÄRR:\n" -#: lib/diff.tcl:202 lib/diff.tcl:322 +#: lib/diff.tcl:217 lib/diff.tcl:355 #, tcl-format msgid "Unable to display %s" msgstr "Kan inte visa %s" -#: lib/diff.tcl:203 +#: lib/diff.tcl:218 msgid "Error loading file:" msgstr "Fel vid läsning av fil:" -#: lib/diff.tcl:210 +#: lib/diff.tcl:225 msgid "Git Repository (subproject)" msgstr "Gitarkiv (underprojekt)" -#: lib/diff.tcl:222 +#: lib/diff.tcl:237 msgid "* Binary file (not showing content)." msgstr "* Binärfil (visar inte innehÃ¥llet)." -#: lib/diff.tcl:227 +#: lib/diff.tcl:242 #, tcl-format msgid "" "* Untracked file is %d bytes.\n" @@ -1644,7 +1302,7 @@ msgstr "" "* Den ospÃ¥rade filen är %d byte.\n" "* Visar endast inledande %d byte.\n" -#: lib/diff.tcl:233 +#: lib/diff.tcl:248 #, tcl-format msgid "" "\n" @@ -1655,257 +1313,213 @@ msgstr "" "* Den ospÃ¥rade filen klipptes här av %s.\n" "* För att se hela filen, använd ett externt redigeringsprogram.\n" -#: lib/diff.tcl:485 +#: lib/diff.tcl:356 lib/blame.tcl:1128 +msgid "Error loading diff:" +msgstr "Fel vid inläsning av differens:" + +#: lib/diff.tcl:578 msgid "Failed to unstage selected hunk." msgstr "Kunde inte ta bort den valda delen frÃ¥n kön." -#: lib/diff.tcl:492 +#: lib/diff.tcl:585 msgid "Failed to stage selected hunk." msgstr "Kunde inte lägga till den valda delen till kön." -#: lib/diff.tcl:571 +#: lib/diff.tcl:664 msgid "Failed to unstage selected line." msgstr "Kunde inte ta bort den valda raden frÃ¥n kön." -#: lib/diff.tcl:579 +#: lib/diff.tcl:672 msgid "Failed to stage selected line." msgstr "Kunde inte lägga till den valda raden till kön." -#: lib/encoding.tcl:443 -msgid "Default" -msgstr "Standard" +#: lib/remote.tcl:200 +msgid "Push to" +msgstr "Sänd till" -#: lib/encoding.tcl:448 -#, tcl-format -msgid "System (%s)" -msgstr "Systemets (%s)" +#: lib/remote.tcl:218 +msgid "Remove Remote" +msgstr "Ta bort fjärrarkiv" -#: lib/encoding.tcl:459 lib/encoding.tcl:465 -msgid "Other" -msgstr "Annan" +#: lib/remote.tcl:223 +msgid "Prune from" +msgstr "Ta bort frÃ¥n" -#: lib/error.tcl:20 lib/error.tcl:116 -msgid "error" -msgstr "fel" +#: lib/remote.tcl:228 +msgid "Fetch from" +msgstr "Hämta frÃ¥n" -#: lib/error.tcl:36 -msgid "warning" -msgstr "varning" +#: lib/choose_font.tcl:41 +msgid "Select" +msgstr "Välj" -#: lib/error.tcl:96 -msgid "You must correct the above errors before committing." -msgstr "Du mÃ¥ste rätta till felen ovan innan du checkar in." +#: lib/choose_font.tcl:55 +msgid "Font Family" +msgstr "Teckensnittsfamilj" -#: lib/index.tcl:6 -msgid "Unable to unlock the index." -msgstr "Kunde inte lÃ¥sa upp indexet." +#: lib/choose_font.tcl:76 +msgid "Font Size" +msgstr "Storlek" -#: lib/index.tcl:17 -msgid "Index Error" -msgstr "Indexfel" +#: lib/choose_font.tcl:93 +msgid "Font Example" +msgstr "Exempel" -#: lib/index.tcl:19 +#: lib/choose_font.tcl:105 msgid "" -"Updating the Git index failed. A rescan will be automatically started to " -"resynchronize git-gui." +"This is example text.\n" +"If you like this text, it can be your font." msgstr "" -"Misslyckades med att uppdatera Gitindexet. En omsökning kommer att startas " -"automatiskt för att synkronisera om git-gui." - -#: lib/index.tcl:30 -msgid "Continue" -msgstr "Fortsätt" +"Detta är en exempeltext.\n" +"Om du tycker om den här texten kan den vara ditt teckensnitt." -#: lib/index.tcl:33 -msgid "Unlock Index" -msgstr "LÃ¥s upp index" +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Den globala teckenkodningen \"%s\" är ogiltig" -#: lib/index.tcl:292 +#: lib/option.tcl:19 #, tcl-format -msgid "Unstaging %s from commit" -msgstr "Tar bort %s för incheckningskön" +msgid "Invalid repo encoding '%s'" +msgstr "Arkivets teckenkodning \"%s\" är ogiltig" -#: lib/index.tcl:331 -msgid "Ready to commit." -msgstr "Redo att checka in." +#: lib/option.tcl:119 +msgid "Restore Defaults" +msgstr "Ã…terställ standardvärden" -#: lib/index.tcl:344 -#, tcl-format -msgid "Adding %s" -msgstr "Lägger till %s" +#: lib/option.tcl:123 +msgid "Save" +msgstr "Spara" -#: lib/index.tcl:401 +#: lib/option.tcl:133 #, tcl-format -msgid "Revert changes in file %s?" -msgstr "Ã…terställ ändringarna i filen %s?" +msgid "%s Repository" +msgstr "Arkivet %s" -#: lib/index.tcl:403 -#, tcl-format -msgid "Revert changes in these %i files?" -msgstr "Ã…terställ ändringarna i dessa %i filer?" +#: lib/option.tcl:134 +msgid "Global (All Repositories)" +msgstr "Globalt (alla arkiv)" -#: lib/index.tcl:411 -msgid "Any unstaged changes will be permanently lost by the revert." -msgstr "" -"Alla oköade ändringar kommer permanent gÃ¥ förlorade vid Ã¥terställningen." +#: lib/option.tcl:140 +msgid "User Name" +msgstr "Användarnamn" -#: lib/index.tcl:414 -msgid "Do Nothing" -msgstr "Gör ingenting" +#: lib/option.tcl:141 +msgid "Email Address" +msgstr "E-postadress" -#: lib/index.tcl:432 -msgid "Reverting selected files" -msgstr "Ã…terställer valda filer" +#: lib/option.tcl:143 +msgid "Summarize Merge Commits" +msgstr "Summera sammanslagningsincheckningar" -#: lib/index.tcl:436 -#, tcl-format -msgid "Reverting %s" -msgstr "Ã…terställer %s" +#: lib/option.tcl:144 +msgid "Merge Verbosity" +msgstr "Pratsamhet för sammanslagningar" -#: lib/merge.tcl:13 -msgid "" -"Cannot merge while amending.\n" -"\n" -"You must finish amending this commit before starting any type of merge.\n" -msgstr "" -"Kan inte slÃ¥ ihop vid utökning.\n" -"\n" -"Du mÃ¥ste göra färdig utökningen av incheckningen innan du pÃ¥börjar nÃ¥gon " -"slags sammanslagning.\n" +#: lib/option.tcl:145 +msgid "Show Diffstat After Merge" +msgstr "Visa diffstatistik efter sammanslagning" -#: lib/merge.tcl:27 -msgid "" -"Last scanned state does not match repository state.\n" -"\n" -"Another Git program has modified this repository since the last scan. A " -"rescan must be performed before a merge can be performed.\n" -"\n" -"The rescan will be automatically started now.\n" -msgstr "" -"Det senaste inlästa tillstÃ¥ndet motsvarar inte tillstÃ¥ndet i arkivet.\n" -"\n" -"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du mÃ¥ste " -"utföra en ny sökning innan du kan utföra en sammanslagning.\n" -"\n" -"Sökningen kommer att startas automatiskt nu.\n" +#: lib/option.tcl:146 +msgid "Use Merge Tool" +msgstr "Använd verktyg för sammanslagning" -#: lib/merge.tcl:45 -#, tcl-format -msgid "" -"You are in the middle of a conflicted merge.\n" -"\n" -"File %s has merge conflicts.\n" -"\n" -"You must resolve them, stage the file, and commit to complete the current " -"merge. Only then can you begin another merge.\n" -msgstr "" -"Du är mitt i en sammanslagning med konflikter.\n" -"\n" -"Filen %s har sammanslagningskonflikter.\n" -"\n" -"Du mÃ¥ste lösa dem, köa filen och checka in för att fullborda den aktuella " -"sammanslagningen. När du gjort det kan du pÃ¥börja en ny sammanslagning.\n" +#: lib/option.tcl:148 +msgid "Trust File Modification Timestamps" +msgstr "Lita pÃ¥ filändringstidsstämplar" -#: lib/merge.tcl:55 -#, tcl-format -msgid "" -"You are in the middle of a change.\n" -"\n" -"File %s is modified.\n" -"\n" -"You should complete the current commit before starting a merge. Doing so " -"will help you abort a failed merge, should the need arise.\n" -msgstr "" -"Du är mitt i en ändring.\n" -"\n" -"Filen %s har ändringar.\n" -"\n" -"Du bör fullborda den aktuella incheckningen innan du pÃ¥börjar en " -"sammanslagning. Om du gör det blir det enklare att avbryta en misslyckad " -"sammanslagning, om det skulle vara nödvändigt.\n" +#: lib/option.tcl:149 +msgid "Prune Tracking Branches During Fetch" +msgstr "Städa spÃ¥rade grenar vid hämtning" -#: lib/merge.tcl:107 -#, tcl-format -msgid "%s of %s" -msgstr "%s av %s" +#: lib/option.tcl:150 +msgid "Match Tracking Branches" +msgstr "Matcha spÃ¥rade grenar" -#: lib/merge.tcl:120 -#, tcl-format -msgid "Merging %s and %s..." -msgstr "SlÃ¥r ihop %s och %s..." +#: lib/option.tcl:151 +msgid "Use Textconv For Diffs and Blames" +msgstr "Använd Textconv för diff och klandring" -#: lib/merge.tcl:131 -msgid "Merge completed successfully." -msgstr "Sammanslagningen avslutades framgÃ¥ngsrikt." +#: lib/option.tcl:152 +msgid "Blame Copy Only On Changed Files" +msgstr "Klandra kopiering bara i ändrade filer" -#: lib/merge.tcl:133 -msgid "Merge failed. Conflict resolution is required." -msgstr "Sammanslagningen misslyckades. Du mÃ¥ste lösa konflikterna." +#: lib/option.tcl:153 +msgid "Maximum Length of Recent Repositories List" +msgstr "Max längd för lista över tidigare arkiv" -#: lib/merge.tcl:158 -#, tcl-format -msgid "Merge Into %s" -msgstr "SlÃ¥ ihop i %s" +#: lib/option.tcl:154 +msgid "Minimum Letters To Blame Copy On" +msgstr "Minsta antal tecken att klandra kopiering för" -#: lib/merge.tcl:177 -msgid "Revision To Merge" -msgstr "Revisioner att slÃ¥ ihop" +#: lib/option.tcl:155 +msgid "Blame History Context Radius (days)" +msgstr "Historikradie för klandring (dagar)" -#: lib/merge.tcl:212 -msgid "" -"Cannot abort while amending.\n" -"\n" -"You must finish amending this commit.\n" -msgstr "" -"Kan inte avbryta vid utökning.\n" -"\n" -"Du mÃ¥ste göra dig färdig med att utöka incheckningen.\n" +#: lib/option.tcl:156 +msgid "Number of Diff Context Lines" +msgstr "Antal rader sammanhang i differenser" -#: lib/merge.tcl:222 -msgid "" -"Abort merge?\n" -"\n" -"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" -"\n" -"Continue with aborting the current merge?" -msgstr "" -"Avbryt sammanslagning?\n" -"\n" -"Om du avbryter sammanslagningen kommer *ALLA* ej incheckade ändringar att gÃ¥ " -"förlorade.\n" -"\n" -"GÃ¥ vidare med att avbryta den aktuella sammanslagningen?" +#: lib/option.tcl:157 +msgid "Additional Diff Parameters" +msgstr "Ytterligare diff-parametrar" -#: lib/merge.tcl:228 -msgid "" -"Reset changes?\n" -"\n" -"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" -"\n" -"Continue with resetting the current changes?" -msgstr "" -"Ã…terställ ändringar?\n" -"\n" -"Om du Ã¥terställer ändringarna kommer *ALLA* ej incheckade ändringar att gÃ¥ " -"förlorade.\n" -"\n" -"GÃ¥ vidare med att Ã¥terställa de aktuella ändringarna?" +#: lib/option.tcl:158 +msgid "Commit Message Text Width" +msgstr "Textbredd för incheckningsmeddelande" -#: lib/merge.tcl:239 -msgid "Aborting" -msgstr "Avbryter" +#: lib/option.tcl:159 +msgid "New Branch Name Template" +msgstr "Mall för namn pÃ¥ nya grenar" -#: lib/merge.tcl:239 -msgid "files reset" -msgstr "filer Ã¥terställda" +#: lib/option.tcl:160 +msgid "Default File Contents Encoding" +msgstr "Standardteckenkodning för filinnehÃ¥ll" -#: lib/merge.tcl:267 -msgid "Abort failed." -msgstr "Misslyckades avbryta." +#: lib/option.tcl:161 +msgid "Warn before committing to a detached head" +msgstr "Varna för incheckning pÃ¥ frÃ¥nkopplat huvud" -#: lib/merge.tcl:269 -msgid "Abort completed. Ready." -msgstr "Avbrytning fullbordad. Redo." +#: lib/option.tcl:162 +msgid "Staging of untracked files" +msgstr "Köa ospÃ¥rade filer" + +#: lib/option.tcl:163 +msgid "Show untracked files" +msgstr "Visa ospÃ¥rade filer" + +#: lib/option.tcl:164 +msgid "Tab spacing" +msgstr "Blanksteg för tabulatortecken" + +#: lib/option.tcl:210 +msgid "Change" +msgstr "Ändra" + +#: lib/option.tcl:254 +msgid "Spelling Dictionary:" +msgstr "Stavningsordlista:" + +#: lib/option.tcl:284 +msgid "Change Font" +msgstr "Byt teckensnitt" + +#: lib/option.tcl:288 +#, tcl-format +msgid "Choose %s" +msgstr "Välj %s" + +#: lib/option.tcl:294 +msgid "pt." +msgstr "p." + +#: lib/option.tcl:308 +msgid "Preferences" +msgstr "Inställningar" + +#: lib/option.tcl:345 +msgid "Failed to completely save options:" +msgstr "Misslyckades med att helt spara alternativ:" #: lib/mergetool.tcl:8 msgid "Force resolution to the base version?" @@ -1952,21 +1566,21 @@ msgstr "Kan inte lösa borttagnings- eller länkkonflikter med ett verktyg" msgid "Conflict file does not exist" msgstr "Konfliktfil existerar inte" -#: lib/mergetool.tcl:264 +#: lib/mergetool.tcl:246 #, tcl-format msgid "Not a GUI merge tool: '%s'" msgstr "Inte ett grafiskt verktyg för sammanslagning: %s" -#: lib/mergetool.tcl:268 +#: lib/mergetool.tcl:275 #, tcl-format msgid "Unsupported merge tool '%s'" msgstr "Verktyget \"%s\" för sammanslagning stöds inte" -#: lib/mergetool.tcl:303 +#: lib/mergetool.tcl:310 msgid "Merge tool is already running, terminate it?" msgstr "Verktyget för sammanslagning körs redan. Vill du avsluta det?" -#: lib/mergetool.tcl:323 +#: lib/mergetool.tcl:330 #, tcl-format msgid "" "Error retrieving versions:\n" @@ -1975,7 +1589,7 @@ msgstr "" "Fel vid hämtning av versioner:\n" "%s" -#: lib/mergetool.tcl:343 +#: lib/mergetool.tcl:350 #, tcl-format msgid "" "Could not start the merge tool:\n" @@ -1986,213 +1600,158 @@ msgstr "" "\n" "%s" -#: lib/mergetool.tcl:347 +#: lib/mergetool.tcl:354 msgid "Running merge tool..." msgstr "Kör verktyg för sammanslagning..." -#: lib/mergetool.tcl:375 lib/mergetool.tcl:383 +#: lib/mergetool.tcl:382 lib/mergetool.tcl:390 msgid "Merge tool failed." msgstr "Verktyget för sammanslagning misslyckades." -#: lib/option.tcl:11 -#, tcl-format -msgid "Invalid global encoding '%s'" -msgstr "Den globala teckenkodningen \"%s\" är ogiltig" - -#: lib/option.tcl:19 -#, tcl-format -msgid "Invalid repo encoding '%s'" -msgstr "Arkivets teckenkodning \"%s\" är ogiltig" - -#: lib/option.tcl:119 -msgid "Restore Defaults" -msgstr "Ã…terställ standardvärden" - -#: lib/option.tcl:123 -msgid "Save" -msgstr "Spara" - -#: lib/option.tcl:133 -#, tcl-format -msgid "%s Repository" -msgstr "Arkivet %s" - -#: lib/option.tcl:134 -msgid "Global (All Repositories)" -msgstr "Globalt (alla arkiv)" - -#: lib/option.tcl:140 -msgid "User Name" -msgstr "Användarnamn" - -#: lib/option.tcl:141 -msgid "Email Address" -msgstr "E-postadress" - -#: lib/option.tcl:143 -msgid "Summarize Merge Commits" -msgstr "Summera sammanslagningsincheckningar" +#: lib/tools_dlg.tcl:22 +msgid "Add Tool" +msgstr "Lägg till verktyg" -#: lib/option.tcl:144 -msgid "Merge Verbosity" -msgstr "Pratsamhet för sammanslagningar" +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Lägg till nytt verktygskommando" -#: lib/option.tcl:145 -msgid "Show Diffstat After Merge" -msgstr "Visa diffstatistik efter sammanslagning" +#: lib/tools_dlg.tcl:34 +msgid "Add globally" +msgstr "Lägg till globalt" -#: lib/option.tcl:146 -msgid "Use Merge Tool" -msgstr "Använd verktyg för sammanslagning" +#: lib/tools_dlg.tcl:46 +msgid "Tool Details" +msgstr "Detaljer för verktyg" -#: lib/option.tcl:148 -msgid "Trust File Modification Timestamps" -msgstr "Lita pÃ¥ filändringstidsstämplar" +#: lib/tools_dlg.tcl:49 +msgid "Use '/' separators to create a submenu tree:" +msgstr "Använd \"/\"-avdelare för att skapa ett undermenyträd:" -#: lib/option.tcl:149 -msgid "Prune Tracking Branches During Fetch" -msgstr "Städa spÃ¥rade grenar vid hämtning" +#: lib/tools_dlg.tcl:60 +msgid "Command:" +msgstr "Kommando:" -#: lib/option.tcl:150 -msgid "Match Tracking Branches" -msgstr "Matcha spÃ¥rade grenar" +#: lib/tools_dlg.tcl:71 +msgid "Show a dialog before running" +msgstr "Visa dialog innan programmet startas" -#: lib/option.tcl:151 -msgid "Use Textconv For Diffs and Blames" -msgstr "Använd Textconv för diff och klandring" +#: lib/tools_dlg.tcl:77 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Be användaren välja en version (sätter $REVISION)" -#: lib/option.tcl:152 -msgid "Blame Copy Only On Changed Files" -msgstr "Klandra kopiering bara i ändrade filer" +#: lib/tools_dlg.tcl:82 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Be användaren om ytterligare parametrar (sätter $ARGS)" -#: lib/option.tcl:153 -msgid "Minimum Letters To Blame Copy On" -msgstr "Minsta antal tecken att klandra kopiering för" +#: lib/tools_dlg.tcl:89 +msgid "Don't show the command output window" +msgstr "Visa inte kommandots utdatafönster" -#: lib/option.tcl:154 -msgid "Blame History Context Radius (days)" -msgstr "Historikradie för klandring (dagar)" +#: lib/tools_dlg.tcl:94 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Kör endast om en diff har markerats ($FILENAME är inte tomt)" -#: lib/option.tcl:155 -msgid "Number of Diff Context Lines" -msgstr "Antal rader sammanhang i differenser" +#: lib/tools_dlg.tcl:118 +msgid "Please supply a name for the tool." +msgstr "Ange ett namn för verktyget." -#: lib/option.tcl:156 -msgid "Commit Message Text Width" -msgstr "Textbredd för incheckningsmeddelande" +#: lib/tools_dlg.tcl:126 +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "Verktyget \"%s\" finns redan." -#: lib/option.tcl:157 -msgid "New Branch Name Template" -msgstr "Mall för namn pÃ¥ nya grenar" +#: lib/tools_dlg.tcl:148 +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Kunde inte lägga till verktyget:\n" +"%s" -#: lib/option.tcl:158 -msgid "Default File Contents Encoding" -msgstr "Standardteckenkodning för filinnehÃ¥ll" +#: lib/tools_dlg.tcl:187 +msgid "Remove Tool" +msgstr "Ta bort verktyg" -#: lib/option.tcl:204 -msgid "Change" -msgstr "Ändra" +#: lib/tools_dlg.tcl:193 +msgid "Remove Tool Commands" +msgstr "Ta bort verktygskommandon" -#: lib/option.tcl:231 -msgid "Spelling Dictionary:" -msgstr "Stavningsordlista:" +#: lib/tools_dlg.tcl:198 +msgid "Remove" +msgstr "Ta bort" -#: lib/option.tcl:261 -msgid "Change Font" -msgstr "Byt teckensnitt" +#: lib/tools_dlg.tcl:231 +msgid "(Blue denotes repository-local tools)" +msgstr "(BlÃ¥tt anger verktyg lokala för arkivet)" -#: lib/option.tcl:265 +#: lib/tools_dlg.tcl:292 #, tcl-format -msgid "Choose %s" -msgstr "Välj %s" - -#: lib/option.tcl:271 -msgid "pt." -msgstr "p." - -#: lib/option.tcl:285 -msgid "Preferences" -msgstr "Inställningar" - -#: lib/option.tcl:322 -msgid "Failed to completely save options:" -msgstr "Misslyckades med att helt spara alternativ:" - -#: lib/remote_add.tcl:20 -msgid "Add Remote" -msgstr "Lägg till fjärrarkiv" +msgid "Run Command: %s" +msgstr "Kör kommandot: %s" -#: lib/remote_add.tcl:25 -msgid "Add New Remote" -msgstr "Lägg till nytt fjärrarkiv" +#: lib/tools_dlg.tcl:306 +msgid "Arguments" +msgstr "Argument" -#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 -msgid "Add" -msgstr "Lägg till" +#: lib/tools_dlg.tcl:341 +msgid "OK" +msgstr "OK" -#: lib/remote_add.tcl:39 -msgid "Remote Details" -msgstr "Detaljer för fjärrarkiv" +#: lib/search.tcl:48 +msgid "Find:" +msgstr "Sök:" -#: lib/remote_add.tcl:50 -msgid "Location:" -msgstr "Plats:" +#: lib/search.tcl:50 +msgid "Next" +msgstr "Nästa" -#: lib/remote_add.tcl:60 -msgid "Further Action" -msgstr "Ytterligare Ã¥tgärd" +#: lib/search.tcl:51 +msgid "Prev" +msgstr "Föreg" -#: lib/remote_add.tcl:63 -msgid "Fetch Immediately" -msgstr "Hämta omedelbart" +#: lib/search.tcl:52 +msgid "RegExp" +msgstr "Reg.uttr." -#: lib/remote_add.tcl:69 -msgid "Initialize Remote Repository and Push" -msgstr "Initiera fjärrarkiv och sänd till" +#: lib/search.tcl:54 +msgid "Case" +msgstr "Skiftläge" -#: lib/remote_add.tcl:75 -msgid "Do Nothing Else Now" -msgstr "Gör ingent mer nu" - -#: lib/remote_add.tcl:100 -msgid "Please supply a remote name." -msgstr "Ange ett namn för fjärrarkivet." +#: lib/branch_rename.tcl:15 lib/branch_rename.tcl:23 +msgid "Rename Branch" +msgstr "Byt namn pÃ¥ gren" -#: lib/remote_add.tcl:113 -#, tcl-format -msgid "'%s' is not an acceptable remote name." -msgstr "\"%s\" kan inte användas som namn pÃ¥ fjärrarkivet." +#: lib/branch_rename.tcl:28 +msgid "Rename" +msgstr "Byt namn" -#: lib/remote_add.tcl:124 -#, tcl-format -msgid "Failed to add remote '%s' of location '%s'." -msgstr "Kunde inte lägga till fjärrarkivet \"%s\" pÃ¥ platsen \"%s\"." +#: lib/branch_rename.tcl:38 +msgid "Branch:" +msgstr "Gren:" -#: lib/remote_add.tcl:132 lib/transport.tcl:6 -#, tcl-format -msgid "fetch %s" -msgstr "hämta %s" +#: lib/branch_rename.tcl:46 +msgid "New Name:" +msgstr "Nytt namn:" -#: lib/remote_add.tcl:133 -#, tcl-format -msgid "Fetching the %s" -msgstr "Hämtar %s" +#: lib/branch_rename.tcl:81 +msgid "Please select a branch to rename." +msgstr "Välj en gren att byta namn pÃ¥." -#: lib/remote_add.tcl:156 -#, tcl-format -msgid "Do not know how to initialize repository at location '%s'." -msgstr "Vet inte hur arkivet pÃ¥ platsen \"%s\" skall initieras." +#: lib/branch_rename.tcl:92 lib/branch_create.tcl:154 +msgid "Please supply a branch name." +msgstr "Ange ett namn för grenen." -#: lib/remote_add.tcl:162 lib/transport.tcl:25 lib/transport.tcl:63 -#: lib/transport.tcl:81 +#: lib/branch_rename.tcl:112 lib/branch_create.tcl:165 #, tcl-format -msgid "push %s" -msgstr "sänd %s" +msgid "'%s' is not an acceptable branch name." +msgstr "\"%s\" kan inte användas som namn pÃ¥ grenen." -#: lib/remote_add.tcl:163 +#: lib/branch_rename.tcl:123 #, tcl-format -msgid "Setting up the %s (at %s)" -msgstr "Konfigurerar %s (pÃ¥ %s)" +msgid "Failed to rename '%s'." +msgstr "Kunde inte byta namn pÃ¥ \"%s\"." #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 msgid "Delete Branch Remotely" @@ -2202,14 +1761,6 @@ msgstr "Ta bort gren frÃ¥n fjärrarkiv" msgid "From Repository" msgstr "FrÃ¥n arkiv" -#: lib/remote_branch_delete.tcl:51 lib/transport.tcl:134 -msgid "Remote:" -msgstr "Fjärrarkiv:" - -#: lib/remote_branch_delete.tcl:72 lib/transport.tcl:154 -msgid "Arbitrary Location:" -msgstr "Godtycklig plats:" - #: lib/remote_branch_delete.tcl:88 msgid "Branches" msgstr "Grenar" @@ -2222,6 +1773,10 @@ msgstr "Ta endast bort om" msgid "Merged Into:" msgstr "Sammanslagen i:" +#: lib/remote_branch_delete.tcl:120 lib/branch_delete.tcl:53 +msgid "Always (Do not perform merge checks)" +msgstr "Alltid (utför inte sammanslagningstest)" + #: lib/remote_branch_delete.tcl:153 msgid "A branch is required for 'Merged Into'." msgstr "En gren krävs för \"Sammanslagen i\"." @@ -2250,96 +1805,381 @@ msgstr "" msgid "Please select one or more branches to delete." msgstr "Välj en eller flera grenar att ta bort." +#: lib/remote_branch_delete.tcl:218 lib/branch_delete.tcl:115 +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" +"Det kan vara svÃ¥rt att Ã¥terställa borttagna grenar.\n" +"\n" +"Ta bort de valda grenarna?" + #: lib/remote_branch_delete.tcl:227 #, tcl-format msgid "Deleting branches from %s" msgstr "Tar bort grenar frÃ¥n %s" -#: lib/remote_branch_delete.tcl:293 +#: lib/remote_branch_delete.tcl:300 msgid "No repository selected." msgstr "Inget arkiv markerat." -#: lib/remote_branch_delete.tcl:298 +#: lib/remote_branch_delete.tcl:305 #, tcl-format msgid "Scanning %s..." msgstr "Söker %s..." -#: lib/remote.tcl:163 -msgid "Remove Remote" -msgstr "Ta bort fjärrarkiv" +#: lib/choose_repository.tcl:33 +msgid "Git Gui" +msgstr "Git Gui" -#: lib/remote.tcl:168 -msgid "Prune from" -msgstr "Ta bort frÃ¥n" +#: lib/choose_repository.tcl:92 lib/choose_repository.tcl:412 +msgid "Create New Repository" +msgstr "Skapa nytt arkiv" -#: lib/remote.tcl:173 -msgid "Fetch from" -msgstr "Hämta frÃ¥n" +#: lib/choose_repository.tcl:98 +msgid "New..." +msgstr "Nytt..." -#: lib/remote.tcl:215 -msgid "Push to" -msgstr "Sänd till" +#: lib/choose_repository.tcl:105 lib/choose_repository.tcl:496 +msgid "Clone Existing Repository" +msgstr "Klona befintligt arkiv" -#: lib/search.tcl:22 -msgid "Find:" -msgstr "Sök:" +#: lib/choose_repository.tcl:116 +msgid "Clone..." +msgstr "Klona..." -#: lib/search.tcl:24 -msgid "Next" -msgstr "Nästa" +#: lib/choose_repository.tcl:123 lib/choose_repository.tcl:1064 +msgid "Open Existing Repository" +msgstr "Öppna befintligt arkiv" -#: lib/search.tcl:25 -msgid "Prev" -msgstr "Föreg" +#: lib/choose_repository.tcl:129 +msgid "Open..." +msgstr "Öppna..." -#: lib/search.tcl:26 -msgid "Case-Sensitive" -msgstr "Skilj pÃ¥ VERSALER/gemener" +#: lib/choose_repository.tcl:142 +msgid "Recent Repositories" +msgstr "Senaste arkiven" -#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 -msgid "Cannot write shortcut:" -msgstr "Kan inte skriva genväg:" +#: lib/choose_repository.tcl:148 +msgid "Open Recent Repository:" +msgstr "Öppna tidigare arkiv:" -#: lib/shortcut.tcl:137 -msgid "Cannot write icon:" -msgstr "Kan inte skriva ikon:" +#: lib/choose_repository.tcl:316 lib/choose_repository.tcl:323 +#: lib/choose_repository.tcl:330 +#, tcl-format +msgid "Failed to create repository %s:" +msgstr "Kunde inte skapa arkivet %s:" -#: lib/spellcheck.tcl:57 -msgid "Unsupported spell checker" -msgstr "Stavningskontrollprogrammet stöds inte" +#: lib/choose_repository.tcl:407 lib/branch_create.tcl:33 +msgid "Create" +msgstr "Skapa" -#: lib/spellcheck.tcl:65 -msgid "Spell checking is unavailable" -msgstr "Stavningskontroll är ej tillgänglig" +#: lib/choose_repository.tcl:417 +msgid "Directory:" +msgstr "Katalog:" -#: lib/spellcheck.tcl:68 -msgid "Invalid spell checking configuration" -msgstr "Ogiltig inställning för stavningskontroll" +#: lib/choose_repository.tcl:447 lib/choose_repository.tcl:573 +#: lib/choose_repository.tcl:1098 +msgid "Git Repository" +msgstr "Gitarkiv" -#: lib/spellcheck.tcl:70 +#: lib/choose_repository.tcl:472 #, tcl-format -msgid "Reverting dictionary to %s." -msgstr "Ã…terställer ordlistan till %s." +msgid "Directory %s already exists." +msgstr "Katalogen %s finns redan." -#: lib/spellcheck.tcl:73 -msgid "Spell checker silently failed on startup" -msgstr "Stavningskontroll misslyckades tyst vid start" +#: lib/choose_repository.tcl:476 +#, tcl-format +msgid "File %s already exists." +msgstr "Filen %s finns redan." -#: lib/spellcheck.tcl:80 -msgid "Unrecognized spell checker" -msgstr "Stavningskontrollprogrammet känns inte igen" +#: lib/choose_repository.tcl:491 +msgid "Clone" +msgstr "Klona" -#: lib/spellcheck.tcl:186 -msgid "No Suggestions" -msgstr "Inga förslag" +#: lib/choose_repository.tcl:504 +msgid "Source Location:" +msgstr "Plats för källkod:" -#: lib/spellcheck.tcl:388 -msgid "Unexpected EOF from spell checker" -msgstr "Oväntat filslut frÃ¥n stavningskontroll" +#: lib/choose_repository.tcl:513 +msgid "Target Directory:" +msgstr "MÃ¥lkatalog:" -#: lib/spellcheck.tcl:392 -msgid "Spell Checker Failed" -msgstr "Stavningskontroll misslyckades" +#: lib/choose_repository.tcl:523 +msgid "Clone Type:" +msgstr "Typ av klon:" + +#: lib/choose_repository.tcl:528 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "Standard (snabb, semiredundant, hÃ¥rda länkar)" + +#: lib/choose_repository.tcl:533 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "Full kopia (lÃ¥ngsammare, redundant säkerhetskopia)" + +#: lib/choose_repository.tcl:538 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)" + +#: lib/choose_repository.tcl:545 +msgid "Recursively clone submodules too" +msgstr "Klona även rekursivt undermoduler" + +#: lib/choose_repository.tcl:579 lib/choose_repository.tcl:626 +#: lib/choose_repository.tcl:772 lib/choose_repository.tcl:842 +#: lib/choose_repository.tcl:1104 lib/choose_repository.tcl:1112 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "Inte ett Gitarkiv: %s" + +#: lib/choose_repository.tcl:615 +msgid "Standard only available for local repository." +msgstr "Standard är endast tillgängligt för lokala arkiv." + +#: lib/choose_repository.tcl:619 +msgid "Shared only available for local repository." +msgstr "Delat är endast tillgängligt för lokala arkiv." + +#: lib/choose_repository.tcl:640 +#, tcl-format +msgid "Location %s already exists." +msgstr "Platsen %s finns redan." + +#: lib/choose_repository.tcl:651 +msgid "Failed to configure origin" +msgstr "Kunde inte konfigurera ursprung" + +#: lib/choose_repository.tcl:663 +msgid "Counting objects" +msgstr "Räknar objekt" + +#: lib/choose_repository.tcl:664 +msgid "buckets" +msgstr "hinkar" + +#: lib/choose_repository.tcl:688 +#, tcl-format +msgid "Unable to copy objects/info/alternates: %s" +msgstr "Kunde inte kopiera objekt/info/alternativ: %s" + +#: lib/choose_repository.tcl:724 +#, tcl-format +msgid "Nothing to clone from %s." +msgstr "Ingenting att klona frÃ¥n %s." + +#: lib/choose_repository.tcl:726 lib/choose_repository.tcl:940 +#: lib/choose_repository.tcl:952 +msgid "The 'master' branch has not been initialized." +msgstr "Grenen \"master\" har inte initierats." + +#: lib/choose_repository.tcl:739 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "HÃ¥rda länkar är inte tillgängliga. Faller tillbaka pÃ¥ kopiering." + +#: lib/choose_repository.tcl:751 +#, tcl-format +msgid "Cloning from %s" +msgstr "Klonar frÃ¥n %s" + +#: lib/choose_repository.tcl:782 +msgid "Copying objects" +msgstr "Kopierar objekt" + +#: lib/choose_repository.tcl:783 +msgid "KiB" +msgstr "KiB" + +#: lib/choose_repository.tcl:807 +#, tcl-format +msgid "Unable to copy object: %s" +msgstr "Kunde inte kopiera objekt: %s" + +#: lib/choose_repository.tcl:817 +msgid "Linking objects" +msgstr "Länkar objekt" + +#: lib/choose_repository.tcl:818 +msgid "objects" +msgstr "objekt" + +#: lib/choose_repository.tcl:826 +#, tcl-format +msgid "Unable to hardlink object: %s" +msgstr "Kunde inte hÃ¥rdlänka objekt: %s" + +#: lib/choose_repository.tcl:881 +msgid "Cannot fetch branches and objects. See console output for details." +msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:892 +msgid "Cannot fetch tags. See console output for details." +msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:916 +msgid "Cannot determine HEAD. See console output for details." +msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:925 +#, tcl-format +msgid "Unable to cleanup %s" +msgstr "Kunde inte städa upp %s" + +#: lib/choose_repository.tcl:931 +msgid "Clone failed." +msgstr "Kloning misslyckades." + +#: lib/choose_repository.tcl:938 +msgid "No default branch obtained." +msgstr "Hämtade ingen standardgren." + +#: lib/choose_repository.tcl:949 +#, tcl-format +msgid "Cannot resolve %s as a commit." +msgstr "Kunde inte slÃ¥ upp %s till nÃ¥gon incheckning." + +#: lib/choose_repository.tcl:961 +msgid "Creating working directory" +msgstr "Skapar arbetskatalog" + +#: lib/choose_repository.tcl:962 lib/index.tcl:70 lib/index.tcl:136 +#: lib/index.tcl:207 +msgid "files" +msgstr "filer" + +#: lib/choose_repository.tcl:981 +msgid "Cannot clone submodules." +msgstr "Kan inte klona undermoduler." + +#: lib/choose_repository.tcl:990 +msgid "Cloning submodules" +msgstr "Klonar undermoduler" + +#: lib/choose_repository.tcl:1015 +msgid "Initial file checkout failed." +msgstr "Inledande filutcheckning misslyckades." + +#: lib/choose_repository.tcl:1059 +msgid "Open" +msgstr "Öppna" + +#: lib/choose_repository.tcl:1069 +msgid "Repository:" +msgstr "Arkiv:" + +#: lib/choose_repository.tcl:1118 +#, tcl-format +msgid "Failed to open repository %s:" +msgstr "Kunde inte öppna arkivet %s:" + +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui - ett grafiskt användargränssnitt för Git." + +#: lib/blame.tcl:73 +msgid "File Viewer" +msgstr "Filvisare" + +#: lib/blame.tcl:79 +msgid "Commit:" +msgstr "Incheckning:" + +#: lib/blame.tcl:280 +msgid "Copy Commit" +msgstr "Kopiera incheckning" + +#: lib/blame.tcl:284 +msgid "Find Text..." +msgstr "Sök text..." + +#: lib/blame.tcl:288 +msgid "Goto Line..." +msgstr "GÃ¥ till rad..." + +#: lib/blame.tcl:297 +msgid "Do Full Copy Detection" +msgstr "Gör full kopieringsigenkänning" + +#: lib/blame.tcl:301 +msgid "Show History Context" +msgstr "Visa historiksammanhang" + +#: lib/blame.tcl:304 +msgid "Blame Parent Commit" +msgstr "Klandra föräldraincheckning" + +#: lib/blame.tcl:466 +#, tcl-format +msgid "Reading %s..." +msgstr "Läser %s..." + +#: lib/blame.tcl:594 +msgid "Loading copy/move tracking annotations..." +msgstr "Läser annoteringar för kopiering/flyttning..." + +#: lib/blame.tcl:614 +msgid "lines annotated" +msgstr "rader annoterade" + +#: lib/blame.tcl:806 +msgid "Loading original location annotations..." +msgstr "Läser in annotering av originalplacering..." + +#: lib/blame.tcl:809 +msgid "Annotation complete." +msgstr "Annotering fullbordad." + +#: lib/blame.tcl:839 +msgid "Busy" +msgstr "Upptagen" + +#: lib/blame.tcl:840 +msgid "Annotation process is already running." +msgstr "Annoteringsprocess körs redan." + +#: lib/blame.tcl:879 +msgid "Running thorough copy detection..." +msgstr "Kör grundlig kopieringsigenkänning..." + +#: lib/blame.tcl:947 +msgid "Loading annotation..." +msgstr "Läser in annotering..." + +#: lib/blame.tcl:1000 +msgid "Author:" +msgstr "Författare:" + +#: lib/blame.tcl:1004 +msgid "Committer:" +msgstr "Incheckare:" + +#: lib/blame.tcl:1009 +msgid "Original File:" +msgstr "Ursprunglig fil:" + +#: lib/blame.tcl:1057 +msgid "Cannot find HEAD commit:" +msgstr "Hittar inte incheckning för HEAD:" + +#: lib/blame.tcl:1112 +msgid "Cannot find parent commit:" +msgstr "Hittar inte föräldraincheckning:" + +#: lib/blame.tcl:1127 +msgid "Unable to display parent" +msgstr "Kan inte visa förälder" + +#: lib/blame.tcl:1269 +msgid "Originally By:" +msgstr "Ursprungligen av:" + +#: lib/blame.tcl:1275 +msgid "In File:" +msgstr "I filen:" + +#: lib/blame.tcl:1280 +msgid "Copied Or Moved Here By:" +msgstr "Kopierad eller flyttad hit av:" #: lib/sshkey.tcl:31 msgid "No keys found." @@ -2390,189 +2230,480 @@ msgstr "Lyckades skapa nyckeln, men hittar inte nÃ¥gon nyckel." msgid "Your key is in: %s" msgstr "Din nyckel finns i: %s" -#: lib/status_bar.tcl:86 +#: lib/branch_create.tcl:23 +msgid "Create Branch" +msgstr "Skapa gren" + +#: lib/branch_create.tcl:28 +msgid "Create New Branch" +msgstr "Skapa ny gren" + +#: lib/branch_create.tcl:42 +msgid "Branch Name" +msgstr "Namn pÃ¥ gren" + +#: lib/branch_create.tcl:57 +msgid "Match Tracking Branch Name" +msgstr "Använd namn pÃ¥ spÃ¥rad gren" + +#: lib/branch_create.tcl:66 +msgid "Starting Revision" +msgstr "Inledande revision" + +#: lib/branch_create.tcl:72 +msgid "Update Existing Branch:" +msgstr "Uppdatera befintlig gren:" + +#: lib/branch_create.tcl:75 +msgid "No" +msgstr "Nej" + +#: lib/branch_create.tcl:80 +msgid "Fast Forward Only" +msgstr "Endast snabbspolning" + +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "Checka ut när skapad" + +#: lib/branch_create.tcl:132 +msgid "Please select a tracking branch." +msgstr "Välj en gren att spÃ¥ra." + +#: lib/branch_create.tcl:141 #, tcl-format -msgid "%s ... %*i of %*i %s (%3i%%)" -msgstr "%s... %*i av %*i %s (%3i%%)" +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "Den spÃ¥rade grenen %s är inte en gren i fjärrarkivet." -#: lib/tools_dlg.tcl:22 -msgid "Add Tool" -msgstr "Lägg till verktyg" +#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 +msgid "Cannot write shortcut:" +msgstr "Kan inte skriva genväg:" -#: lib/tools_dlg.tcl:28 -msgid "Add New Tool Command" -msgstr "Lägg till nytt verktygskommando" +#: lib/shortcut.tcl:137 +msgid "Cannot write icon:" +msgstr "Kan inte skriva ikon:" -#: lib/tools_dlg.tcl:34 -msgid "Add globally" -msgstr "Lägg till globalt" +#: lib/choose_rev.tcl:52 +msgid "This Detached Checkout" +msgstr "Denna frÃ¥nkopplade utcheckning" -#: lib/tools_dlg.tcl:46 -msgid "Tool Details" -msgstr "Detaljer för verktyg" +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "Revisionsuttryck:" -#: lib/tools_dlg.tcl:49 -msgid "Use '/' separators to create a submenu tree:" -msgstr "Använd \"/\"-avdelare för att skapa ett undermenyträd:" +#: lib/choose_rev.tcl:72 +msgid "Local Branch" +msgstr "Lokal gren" -#: lib/tools_dlg.tcl:60 -msgid "Command:" -msgstr "Kommando:" +#: lib/choose_rev.tcl:77 +msgid "Tracking Branch" +msgstr "SpÃ¥rande gren" -#: lib/tools_dlg.tcl:71 -msgid "Show a dialog before running" -msgstr "Visa dialog innan programmet startas" +#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544 +msgid "Tag" +msgstr "Tagg" -#: lib/tools_dlg.tcl:77 -msgid "Ask the user to select a revision (sets $REVISION)" -msgstr "Be användaren välja en version (sätter $REVISION)" +#: lib/choose_rev.tcl:321 +#, tcl-format +msgid "Invalid revision: %s" +msgstr "Ogiltig revision: %s" -#: lib/tools_dlg.tcl:82 -msgid "Ask the user for additional arguments (sets $ARGS)" -msgstr "Be användaren om ytterligare parametrar (sätter $ARGS)" +#: lib/choose_rev.tcl:342 +msgid "No revision selected." +msgstr "Ingen revision vald." -#: lib/tools_dlg.tcl:89 -msgid "Don't show the command output window" -msgstr "Visa inte kommandots utdatafönster" +#: lib/choose_rev.tcl:350 +msgid "Revision expression is empty." +msgstr "Revisionsuttrycket är tomt." -#: lib/tools_dlg.tcl:94 -msgid "Run only if a diff is selected ($FILENAME not empty)" -msgstr "Kör endast om en diff har markerats ($FILENAME är inte tomt)" +#: lib/choose_rev.tcl:537 +msgid "Updated" +msgstr "Uppdaterad" -#: lib/tools_dlg.tcl:118 -msgid "Please supply a name for the tool." -msgstr "Ange ett namn för verktyget." +#: lib/choose_rev.tcl:565 +msgid "URL" +msgstr "Webbadress" -#: lib/tools_dlg.tcl:126 +#: lib/commit.tcl:9 +msgid "" +"There is nothing to amend.\n" +"\n" +"You are about to create the initial commit. There is no commit before this " +"to amend.\n" +msgstr "" +"Det finns ingenting att utöka.\n" +"\n" +"Du hÃ¥ller pÃ¥ att skapa den inledande incheckningen. Det finns ingen tidigare " +"incheckning att utöka.\n" + +#: lib/commit.tcl:18 +msgid "" +"Cannot amend while merging.\n" +"\n" +"You are currently in the middle of a merge that has not been fully " +"completed. You cannot amend the prior commit unless you first abort the " +"current merge activity.\n" +msgstr "" +"Kan inte utöka vid sammanslagning.\n" +"\n" +"Du är i mitten av en sammanslagning som inte är fullbordad. Du kan inte " +"utöka tidigare incheckningar om du inte först avbryter den pÃ¥gÃ¥ende " +"sammanslagningen.\n" + +#: lib/commit.tcl:48 +msgid "Error loading commit data for amend:" +msgstr "Fel vid inläsning av incheckningsdata för utökning:" + +#: lib/commit.tcl:75 +msgid "Unable to obtain your identity:" +msgstr "Kunde inte hämta din identitet:" + +#: lib/commit.tcl:80 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "Felaktig GIT_COMMITTER_IDENT:" + +#: lib/commit.tcl:129 #, tcl-format -msgid "Tool '%s' already exists." -msgstr "Verktyget \"%s\" finns redan." +msgid "warning: Tcl does not support encoding '%s'." +msgstr "varning: Tcl stöder inte teckenkodningen \"%s\"." -#: lib/tools_dlg.tcl:148 +#: lib/commit.tcl:149 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before another commit can be created.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Det senaste inlästa tillstÃ¥ndet motsvarar inte tillstÃ¥ndet i arkivet.\n" +"\n" +"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du mÃ¥ste " +"utföra en ny sökning innan du kan göra en ny incheckning.\n" +"\n" +"Sökningen kommer att startas automatiskt nu.\n" + +#: lib/commit.tcl:173 #, tcl-format msgid "" -"Could not add tool:\n" -"%s" +"Unmerged files cannot be committed.\n" +"\n" +"File %s has merge conflicts. You must resolve them and stage the file " +"before committing.\n" msgstr "" -"Kunde inte lägga till verktyget:\n" -"%s" +"Osammanslagna filer kan inte checkas in.\n" +"\n" +"Filen %s har sammanslagningskonflikter. Du mÃ¥ste lösa dem och köa filen " +"innan du checkar in den.\n" -#: lib/tools_dlg.tcl:187 -msgid "Remove Tool" -msgstr "Ta bort verktyg" +#: lib/commit.tcl:181 +#, tcl-format +msgid "" +"Unknown file state %s detected.\n" +"\n" +"File %s cannot be committed by this program.\n" +msgstr "" +"Okänd filstatus %s upptäckt.\n" +"\n" +"Filen %s kan inte checkas in av programmet.\n" -#: lib/tools_dlg.tcl:193 -msgid "Remove Tool Commands" -msgstr "Ta bort verktygskommandon" +#: lib/commit.tcl:189 +msgid "" +"No changes to commit.\n" +"\n" +"You must stage at least 1 file before you can commit.\n" +msgstr "" +"Inga ändringar att checka in.\n" +"\n" +"Du mÃ¥ste köa Ã¥tminstone en fil innan du kan checka in.\n" -#: lib/tools_dlg.tcl:198 -msgid "Remove" -msgstr "Ta bort" +#: lib/commit.tcl:204 +msgid "" +"Please supply a commit message.\n" +"\n" +"A good commit message has the following format:\n" +"\n" +"- First line: Describe in one sentence what you did.\n" +"- Second line: Blank\n" +"- Remaining lines: Describe why this change is good.\n" +msgstr "" +"Ange ett incheckningsmeddelande.\n" +"\n" +"Ett bra incheckningsmeddelande har följande format:\n" +"\n" +"- Första raden: Beskriv i en mening vad du gjorde.\n" +"- Andra raden: Tom\n" +"- Följande rader: Beskriv varför det här är en bra ändring.\n" -#: lib/tools_dlg.tcl:231 -msgid "(Blue denotes repository-local tools)" -msgstr "(BlÃ¥tt anger verktyg lokala för arkivet)" +#: lib/commit.tcl:235 +msgid "Calling pre-commit hook..." +msgstr "Anropar kroken före incheckning (pre-commit)..." -#: lib/tools_dlg.tcl:292 -#, tcl-format -msgid "Run Command: %s" -msgstr "Kör kommandot: %s" +#: lib/commit.tcl:250 +msgid "Commit declined by pre-commit hook." +msgstr "Incheckningen avvisades av kroken före incheckning (pre-commit)." -#: lib/tools_dlg.tcl:306 -msgid "Arguments" -msgstr "Argument" +#: lib/commit.tcl:269 +msgid "" +"You are about to commit on a detached head. This is a potentially dangerous " +"thing to do because if you switch to another branch you will lose your " +"changes and it can be difficult to retrieve them later from the reflog. You " +"should probably cancel this commit and create a new branch to continue.\n" +" \n" +" Do you really want to proceed with your Commit?" +msgstr "" +"Du är pÃ¥ väg att checka in pÃ¥ ett frÃ¥nkopplat huvud. Det kan potentiellt " +"vara farligt, eftersom du kommer förlora dina ändringar om du växlar till en " +"annan gren och det kan vara svÃ¥rt att hämta dem senare frÃ¥n ref-loggen. Du " +"bör troligen avbryta incheckningen och skapa en ny gren för att fortsätta.\n" +" \n" +" Vill du verkligen fortsätta checka in?" + +#: lib/commit.tcl:290 +msgid "Calling commit-msg hook..." +msgstr "Anropar kroken för incheckningsmeddelande (commit-msg)..." -#: lib/tools_dlg.tcl:341 -msgid "OK" -msgstr "OK" +#: lib/commit.tcl:305 +msgid "Commit declined by commit-msg hook." +msgstr "Incheckning avvisad av kroken för incheckningsmeddelande (commit-msg)." -#: lib/tools.tcl:75 +#: lib/commit.tcl:318 +msgid "Committing changes..." +msgstr "Checkar in ändringar..." + +#: lib/commit.tcl:334 +msgid "write-tree failed:" +msgstr "write-tree misslyckades:" + +#: lib/commit.tcl:335 lib/commit.tcl:379 lib/commit.tcl:400 +msgid "Commit failed." +msgstr "Incheckningen misslyckades." + +#: lib/commit.tcl:352 #, tcl-format -msgid "Running %s requires a selected file." -msgstr "För att starta %s mÃ¥ste du välja en fil." +msgid "Commit %s appears to be corrupt" +msgstr "Incheckningen %s verkar vara trasig" -#: lib/tools.tcl:90 +#: lib/commit.tcl:357 +msgid "" +"No changes to commit.\n" +"\n" +"No files were modified by this commit and it was not a merge commit.\n" +"\n" +"A rescan will be automatically started now.\n" +msgstr "" +"Inga ändringar att checka in.\n" +"\n" +"Inga filer ändrades av incheckningen och det var inte en sammanslagning.\n" +"\n" +"En sökning kommer att startas automatiskt nu.\n" + +#: lib/commit.tcl:364 +msgid "No changes to commit." +msgstr "Inga ändringar att checka in." + +#: lib/commit.tcl:378 +msgid "commit-tree failed:" +msgstr "commit-tree misslyckades:" + +#: lib/commit.tcl:399 +msgid "update-ref failed:" +msgstr "update-ref misslyckades:" + +#: lib/commit.tcl:492 #, tcl-format -msgid "Are you sure you want to run %s?" -msgstr "Är du säker pÃ¥ att du vill starta %s?" +msgid "Created commit %s: %s" +msgstr "Skapade incheckningen %s: %s" + +#: lib/branch_delete.tcl:16 +msgid "Delete Branch" +msgstr "Ta bort gren" + +#: lib/branch_delete.tcl:21 +msgid "Delete Local Branch" +msgstr "Ta bort lokal gren" + +#: lib/branch_delete.tcl:39 +msgid "Local Branches" +msgstr "Lokala grenar" -#: lib/tools.tcl:110 +#: lib/branch_delete.tcl:51 +msgid "Delete Only If Merged Into" +msgstr "Ta bara bort om sammanslagen med" + +#: lib/branch_delete.tcl:103 #, tcl-format -msgid "Tool: %s" -msgstr "Verktyg: %s" +msgid "The following branches are not completely merged into %s:" +msgstr "Följande grenar är inte till fullo sammanslagna med %s:" -#: lib/tools.tcl:111 +#: lib/branch_delete.tcl:141 #, tcl-format -msgid "Running: %s" -msgstr "Exekverar: %s" +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" +"Kunde inte ta bort grenar:\n" +"%s" + +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "Kunde inte lÃ¥sa upp indexet." + +#: lib/index.tcl:17 +msgid "Index Error" +msgstr "Indexfel" + +#: lib/index.tcl:19 +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" +"Misslyckades med att uppdatera Gitindexet. En omsökning kommer att startas " +"automatiskt för att synkronisera om git-gui." -#: lib/tools.tcl:149 +#: lib/index.tcl:30 +msgid "Continue" +msgstr "Fortsätt" + +#: lib/index.tcl:33 +msgid "Unlock Index" +msgstr "LÃ¥s upp index" + +#: lib/index.tcl:298 #, tcl-format -msgid "Tool completed successfully: %s" -msgstr "Verktyget avslutades framgÃ¥ngsrikt: %s" +msgid "Unstaging %s from commit" +msgstr "Tar bort %s för incheckningskön" -#: lib/tools.tcl:151 +#: lib/index.tcl:337 +msgid "Ready to commit." +msgstr "Redo att checka in." + +#: lib/index.tcl:350 #, tcl-format -msgid "Tool failed: %s" -msgstr "Verktyget misslyckades: %s" +msgid "Adding %s" +msgstr "Lägger till %s" -#: lib/transport.tcl:7 +#: lib/index.tcl:380 #, tcl-format -msgid "Fetching new changes from %s" -msgstr "Hämtar nya ändringar frÃ¥n %s" +msgid "Stage %d untracked files?" +msgstr "Köa %d ospÃ¥rade filer?" -#: lib/transport.tcl:18 +#: lib/index.tcl:428 #, tcl-format -msgid "remote prune %s" -msgstr "fjärrborttagning %s" +msgid "Revert changes in file %s?" +msgstr "Ã…terställ ändringarna i filen %s?" -#: lib/transport.tcl:19 +#: lib/index.tcl:430 #, tcl-format -msgid "Pruning tracking branches deleted from %s" -msgstr "Tar bort spÃ¥rande grenar som tagits bort frÃ¥n %s" +msgid "Revert changes in these %i files?" +msgstr "Ã…terställ ändringarna i dessa %i filer?" -#: lib/transport.tcl:26 +#: lib/index.tcl:438 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Alla oköade ändringar kommer permanent gÃ¥ förlorade vid Ã¥terställningen." + +#: lib/index.tcl:441 +msgid "Do Nothing" +msgstr "Gör ingenting" + +#: lib/index.tcl:459 +msgid "Reverting selected files" +msgstr "Ã…terställer valda filer" + +#: lib/index.tcl:463 #, tcl-format -msgid "Pushing changes to %s" -msgstr "Sänder ändringar till %s" +msgid "Reverting %s" +msgstr "Ã…terställer %s" -#: lib/transport.tcl:64 +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "Standard" + +#: lib/encoding.tcl:448 #, tcl-format -msgid "Mirroring to %s" -msgstr "Speglar till %s" +msgid "System (%s)" +msgstr "Systemets (%s)" -#: lib/transport.tcl:82 +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Annan" + +#: lib/date.tcl:25 #, tcl-format -msgid "Pushing %s %s to %s" -msgstr "Sänder %s %s till %s" +msgid "Invalid date from Git: %s" +msgstr "Ogiltigt datum frÃ¥n Git: %s" -#: lib/transport.tcl:102 -msgid "Push Branches" -msgstr "Sänd grenar" +#: lib/database.tcl:42 +msgid "Number of loose objects" +msgstr "Antal lösa objekt" -#: lib/transport.tcl:117 -msgid "Source Branches" -msgstr "Källgrenar" +#: lib/database.tcl:43 +msgid "Disk space used by loose objects" +msgstr "Diskutrymme använt av lösa objekt" -#: lib/transport.tcl:131 -msgid "Destination Repository" -msgstr "Destinationsarkiv" +#: lib/database.tcl:44 +msgid "Number of packed objects" +msgstr "Antal packade objekt" -#: lib/transport.tcl:172 -msgid "Transfer Options" -msgstr "Överföringsalternativ" +#: lib/database.tcl:45 +msgid "Number of packs" +msgstr "Antal paket" -#: lib/transport.tcl:174 -msgid "Force overwrite existing branch (may discard changes)" -msgstr "Tvinga överskrivning av befintlig gren (kan kasta bort ändringar)" +#: lib/database.tcl:46 +msgid "Disk space used by packed objects" +msgstr "Diskutrymme använt av packade objekt" -#: lib/transport.tcl:178 -msgid "Use thin pack (for slow network connections)" -msgstr "Använd tunt paket (för lÃ¥ngsamma nätverksanslutningar)" +#: lib/database.tcl:47 +msgid "Packed objects waiting for pruning" +msgstr "Packade objekt som väntar pÃ¥ städning" -#: lib/transport.tcl:182 -msgid "Include tags" -msgstr "Ta med taggar" +#: lib/database.tcl:48 +msgid "Garbage files" +msgstr "Skräpfiler" + +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "Komprimerar objektdatabasen" + +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "Verifierar objektdatabasen med fsck-objects" + +#: lib/database.tcl:107 +#, tcl-format +msgid "" +"This repository currently has approximately %i loose objects.\n" +"\n" +"To maintain optimal performance it is strongly recommended that you compress " +"the database.\n" +"\n" +"Compress the database now?" +msgstr "" +"Arkivet har för närvarande omkring %i lösa objekt.\n" +"\n" +"För att bibehÃ¥lla optimal prestanda rekommenderas det Ã¥ det bestämdaste att " +"du komprimerar databasen.\n" +"\n" +"Komprimera databasen nu?" + +#: lib/error.tcl:20 lib/error.tcl:116 +msgid "error" +msgstr "fel" + +#: lib/error.tcl:36 +msgid "warning" +msgstr "varning" + +#: lib/error.tcl:96 +msgid "You must correct the above errors before committing." +msgstr "Du mÃ¥ste rätta till felen ovan innan du checkar in." + +#~ msgid "Displaying only %s of %s files." +#~ msgstr "Visar endast %s av %s filer." + +#~ msgid "Case-Sensitive" +#~ msgstr "Skilj pÃ¥ VERSALER/gemener" #~ msgid "Cannot use funny .git directory:" #~ msgstr "Kan inte använda underlig .git-katalog:" diff --git a/git-gui/po/vi.po b/git-gui/po/vi.po new file mode 100644 index 0000000000..d956b59a9e --- /dev/null +++ b/git-gui/po/vi.po @@ -0,0 +1,2690 @@ +# Vietnamese translation for GIT-GUI +# Bản dịch Tiếng Việt dà nh cho gói Git-gui. +# This file is distributed under the same license as the git-core package. +# First translated by Trần Ngá»c Quân <vnwildman@gmail.com>, 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: git-gui 0.19.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-06-26 13:42+0700\n" +"PO-Revision-Date: 2014-06-27 07:48+0700\n" +"Last-Translator: Trần Ngá»c Quân <vnwildman@gmail.com>\n" +"Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n" +"Language: vi\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" +"X-Poedit-Language: Vietnamese\n" +"X-Poedit-Country: VIET NAM\n" +"X-Poedit-SourceCharset: utf-8\n" +"X-Poedit-Basepath: ../\n" + +#: git-gui.sh:859 +#, tcl-format +msgid "Invalid font specified in %s:" +msgstr "Phông chữ không hợp lệ được đặc tả trong %s:" + +#: git-gui.sh:912 +msgid "Main Font" +msgstr "Phông chữ chÃnh" + +#: git-gui.sh:913 +msgid "Diff/Console Font" +msgstr "Phông chữ cho Bảng Ä‘iá»u khiển hay Diff" + +#: git-gui.sh:928 git-gui.sh:942 git-gui.sh:955 git-gui.sh:1045 +#: git-gui.sh:1064 git-gui.sh:3119 +msgid "git-gui: fatal error" +msgstr "git-gui: lá»—i nghiêm trá»ng" + +#: git-gui.sh:929 +msgid "Cannot find git in PATH." +msgstr "Không tìm thấy git trong biến PATH." + +#: git-gui.sh:956 +msgid "Cannot parse Git version string:" +msgstr "Không thể phân tÃch chuá»—i phiên bản Git:" + +#: git-gui.sh:981 +#, tcl-format +msgid "" +"Git version cannot be determined.\n" +"\n" +"%s claims it is version '%s'.\n" +"\n" +"%s requires at least Git 1.5.0 or later.\n" +"\n" +"Assume '%s' is version 1.5.0?\n" +msgstr "" +"Không thể nháºn ra phiên bản của Git.\n" +"\n" +"%s nói đây là phiên bản '%s'.\n" +"\n" +"%s yêu cầu Git phiên bản từ 1.5.0 hay má»›i hÆ¡n.\n" +"\n" +"Cá»i '%s' có phiên bản là 1.5.0?\n" + +#: git-gui.sh:1278 +msgid "Git directory not found:" +msgstr "Không tìm thấy thÆ° mục git:" + +#: git-gui.sh:1312 +msgid "Cannot move to top of working directory:" +msgstr "Không thể di chuyển đến đỉnh của thÆ° mục là m việc:" + +#: git-gui.sh:1320 +msgid "Cannot use bare repository:" +msgstr "Không thể dùng kho trần:" + +#: git-gui.sh:1328 +msgid "No working directory" +msgstr "Không có thÆ° mục là m việc" + +#: git-gui.sh:1500 lib/checkout_op.tcl:306 +msgid "Refreshing file status..." +msgstr "Cáºp nháºt lại trạng thái táºp tin..." + +#: git-gui.sh:1560 +msgid "Scanning for modified files ..." +msgstr "Äang quét Ä‘Ä©a tìm táºp tin thay đổi..." + +#: git-gui.sh:1636 +msgid "Calling prepare-commit-msg hook..." +msgstr "Äang gá»i móc prepare-commit-msg..." + +#: git-gui.sh:1653 +msgid "Commit declined by prepare-commit-msg hook." +msgstr "Lần chuyển giao bị chối từ do móc prepare-commit-msg." + +#: git-gui.sh:1811 lib/browser.tcl:252 +msgid "Ready." +msgstr "Sẵn sà ng." + +#: git-gui.sh:1969 +#, tcl-format +msgid "Displaying only %s of %s files." +msgstr "Chỉ hiển thị %s trong số %s táºp tin." + +#: git-gui.sh:2095 +msgid "Unmodified" +msgstr "Không thay đổi gì" + +#: git-gui.sh:2097 +msgid "Modified, not staged" +msgstr "Äã sá»a nhÆ°ng chÆ°a đánh dấu để chuyển giao" + +#: git-gui.sh:2098 git-gui.sh:2110 +msgid "Staged for commit" +msgstr "Äánh dấu để chuyển giao" + +#: git-gui.sh:2099 git-gui.sh:2111 +msgid "Portions staged for commit" +msgstr "Các phần được đánh dấu là cần chuyển giao" + +#: git-gui.sh:2100 git-gui.sh:2112 +msgid "Staged for commit, missing" +msgstr "Äã đánh dấu là cần chuyển giao, thiếu" + +#: git-gui.sh:2102 +msgid "File type changed, not staged" +msgstr "Äã đổi kiểu táºp tin nhÆ°ng chÆ°a được đánh dấu cần chuyển giao" + +#: git-gui.sh:2103 git-gui.sh:2104 +msgid "File type changed, old type staged for commit" +msgstr "Äã đổi kiểu táºp tin, kiểu cÅ© đã được đánh dấu cần chuyển giao" + +#: git-gui.sh:2105 +msgid "File type changed, staged" +msgstr "Äã đổi kiểu táºp tin, đã được đánh dấu cần chuyển giao" + +#: git-gui.sh:2106 +msgid "File type change staged, modification not staged" +msgstr "" +"Thay đổi kiểu táºp tin đã được đánh dấu cần chuyển giao, nhÆ°ng các thay đổi " +"thì chÆ°a" + +#: git-gui.sh:2107 +msgid "File type change staged, file missing" +msgstr "" +"Thay đổi kiểu táºp tin đã được đánh dấu cần chuyển giao, táºp tin bị thiếu" + +#: git-gui.sh:2109 +msgid "Untracked, not staged" +msgstr "ChÆ°a được theo dõi, chÆ°a đánh dấu là cần chuyển giao" + +#: git-gui.sh:2114 +msgid "Missing" +msgstr "Thiếu" + +#: git-gui.sh:2115 +msgid "Staged for removal" +msgstr "Äã đánh dấu là cần gỡ bá»" + +#: git-gui.sh:2116 +msgid "Staged for removal, still present" +msgstr "Äã đánh dấu là cần gỡ bá», nhÆ°ng vẫn hiện diện" + +#: git-gui.sh:2118 git-gui.sh:2119 git-gui.sh:2120 git-gui.sh:2121 +#: git-gui.sh:2122 git-gui.sh:2123 +msgid "Requires merge resolution" +msgstr "Các yêu cầu phân giải hòa trá»™n" + +#: git-gui.sh:2158 +msgid "Starting gitk... please wait..." +msgstr "Äang khởi Ä‘á»™ng gitk... vui lòng chá»..." + +#: git-gui.sh:2170 +msgid "Couldn't find gitk in PATH" +msgstr "Không thể tìm thấy gitk trong PATH" + +#: git-gui.sh:2229 +msgid "Couldn't find git gui in PATH" +msgstr "Không thể tìm thấy git gui trong PATH" + +#: git-gui.sh:2648 lib/choose_repository.tcl:40 +msgid "Repository" +msgstr "Kho" + +#: git-gui.sh:2649 +msgid "Edit" +msgstr "Chỉnh sá»a" + +#: git-gui.sh:2651 lib/choose_rev.tcl:567 +msgid "Branch" +msgstr "Nhánh" + +#: git-gui.sh:2654 lib/choose_rev.tcl:554 +msgid "Commit@@noun" +msgstr "Chuyển giao@@noun" + +#: git-gui.sh:2657 lib/merge.tcl:123 lib/merge.tcl:152 lib/merge.tcl:170 +msgid "Merge" +msgstr "Trá»™n" + +#: git-gui.sh:2658 lib/choose_rev.tcl:563 +msgid "Remote" +msgstr "Máy chủ" + +#: git-gui.sh:2661 +msgid "Tools" +msgstr "Công cụ" + +#: git-gui.sh:2670 +msgid "Explore Working Copy" +msgstr "Quét dò thÆ° mục là m việc" + +#: git-gui.sh:2676 +msgid "Git Bash" +msgstr "Git Bash" + +#: git-gui.sh:2686 +msgid "Browse Current Branch's Files" +msgstr "Duyệt các Táºp tin ở nhánh hiện nay" + +#: git-gui.sh:2690 +msgid "Browse Branch Files..." +msgstr "Duyệt các táºp tin nhánh..." + +#: git-gui.sh:2695 +msgid "Visualize Current Branch's History" +msgstr "Hiển thị trá»±c quan lịch sá» nhánh hiện nay" + +#: git-gui.sh:2699 +msgid "Visualize All Branch History" +msgstr "Hiển thị trá»±c quan lịch sá» má»i nhánh" + +#: git-gui.sh:2706 +#, tcl-format +msgid "Browse %s's Files" +msgstr "Duyệt táºp tin của %s..." + +#: git-gui.sh:2708 +#, tcl-format +msgid "Visualize %s's History" +msgstr "Duyệt lịch sá» của %s trá»±c quan" + +#: git-gui.sh:2713 lib/database.tcl:40 lib/database.tcl:66 +msgid "Database Statistics" +msgstr "Thống kê cÆ¡ sở dữ liệu" + +#: git-gui.sh:2716 lib/database.tcl:33 +msgid "Compress Database" +msgstr "Nén cÆ¡ sở dữ liệu" + +#: git-gui.sh:2719 +msgid "Verify Database" +msgstr "Thẩm tra cÆ¡ sở dữ liệu" + +#: git-gui.sh:2726 git-gui.sh:2730 git-gui.sh:2734 lib/shortcut.tcl:8 +#: lib/shortcut.tcl:40 lib/shortcut.tcl:72 +msgid "Create Desktop Icon" +msgstr "Tạo lối tắt ở mà n hình ná»n" + +#: git-gui.sh:2742 lib/choose_repository.tcl:192 lib/choose_repository.tcl:200 +msgid "Quit" +msgstr "Thoát" + +#: git-gui.sh:2750 +msgid "Undo" +msgstr "Hủy lệnh vừa rồi" + +#: git-gui.sh:2753 +msgid "Redo" +msgstr "Là m lại" + +#: git-gui.sh:2757 git-gui.sh:3362 +msgid "Cut" +msgstr "Cắt" + +#: git-gui.sh:2760 git-gui.sh:3365 git-gui.sh:3439 git-gui.sh:3524 +#: lib/console.tcl:69 +msgid "Copy" +msgstr "Chép" + +#: git-gui.sh:2763 git-gui.sh:3368 +msgid "Paste" +msgstr "Dán" + +#: git-gui.sh:2766 git-gui.sh:3371 lib/branch_delete.tcl:28 +#: lib/remote_branch_delete.tcl:39 +msgid "Delete" +msgstr "Xóa bá»" + +#: git-gui.sh:2770 git-gui.sh:3375 git-gui.sh:3528 lib/console.tcl:71 +msgid "Select All" +msgstr "Chá»n tất cả" + +#: git-gui.sh:2779 +msgid "Create..." +msgstr "Tạo..." + +#: git-gui.sh:2785 +msgid "Checkout..." +msgstr "Lấy ra..." + +#: git-gui.sh:2791 +msgid "Rename..." +msgstr "Äổi tên..." + +#: git-gui.sh:2796 +msgid "Delete..." +msgstr "Xóa..." + +#: git-gui.sh:2801 +msgid "Reset..." +msgstr "Äặt lại.." + +#: git-gui.sh:2811 +msgid "Done" +msgstr "Xong" + +#: git-gui.sh:2813 +msgid "Commit@@verb" +msgstr "Chuyển giao@@verb" + +#: git-gui.sh:2822 git-gui.sh:3303 +msgid "New Commit" +msgstr "Lần chuyển giao má»›i" + +#: git-gui.sh:2830 git-gui.sh:3310 +msgid "Amend Last Commit" +msgstr "Tu bổ lần chuyển giao cuối" + +#: git-gui.sh:2840 git-gui.sh:3264 lib/remote_branch_delete.tcl:101 +msgid "Rescan" +msgstr "Quét lại" + +#: git-gui.sh:2846 +msgid "Stage To Commit" +msgstr "ÄÆ°a lên bệ phóng để chuyển giao" + +#: git-gui.sh:2852 +msgid "Stage Changed Files To Commit" +msgstr "Äánh dấu các táºp tin đã thay đổi cần chuyển giao" + +#: git-gui.sh:2858 +msgid "Unstage From Commit" +msgstr "ÄÆ°a ra khá»i bệ phóng để không chuyển giao" + +#: git-gui.sh:2864 lib/index.tcl:442 +msgid "Revert Changes" +msgstr "Hoà n nguyên các thay đổi" + +#: git-gui.sh:2872 git-gui.sh:3575 git-gui.sh:3606 +msgid "Show Less Context" +msgstr "Hiện Ãt ná»™i dung hÆ¡n" + +#: git-gui.sh:2876 git-gui.sh:3579 git-gui.sh:3610 +msgid "Show More Context" +msgstr "Hiện chi tiết hÆ¡n" + +#: git-gui.sh:2883 git-gui.sh:3277 git-gui.sh:3386 +msgid "Sign Off" +msgstr "Ký tên" + +#: git-gui.sh:2899 +msgid "Local Merge..." +msgstr "Trá»™n ná»™i bá»™..." + +#: git-gui.sh:2904 +msgid "Abort Merge..." +msgstr "Hủy bá» hòa trá»™n..." + +#: git-gui.sh:2916 git-gui.sh:2944 +msgid "Add..." +msgstr "Thêm..." + +#: git-gui.sh:2920 +msgid "Push..." +msgstr "Äẩy lên..." + +#: git-gui.sh:2924 +msgid "Delete Branch..." +msgstr "Xoá nhánh..." + +#: git-gui.sh:2934 git-gui.sh:3557 +msgid "Options..." +msgstr "Tùy chá»n..." + +#: git-gui.sh:2945 +msgid "Remove..." +msgstr "Gỡ bá»..." + +#: git-gui.sh:2954 lib/choose_repository.tcl:54 +msgid "Help" +msgstr "Trợ giúp" + +#: git-gui.sh:2958 git-gui.sh:2962 lib/about.tcl:14 +#: lib/choose_repository.tcl:48 lib/choose_repository.tcl:57 +#, tcl-format +msgid "About %s" +msgstr "Giá»›i thiệu vá» %s" + +#: git-gui.sh:2986 +msgid "Online Documentation" +msgstr "Äá»c tà i liệu trá»±c tuyến" + +#: git-gui.sh:2989 lib/choose_repository.tcl:51 lib/choose_repository.tcl:60 +msgid "Show SSH Key" +msgstr "Hiện khoá SSH" + +#: git-gui.sh:3008 git-gui.sh:3140 +msgid "Usage" +msgstr "Cách dùng" + +#: git-gui.sh:3089 lib/blame.tcl:573 +msgid "Error" +msgstr "Lá»—i" + +#: git-gui.sh:3120 +#, tcl-format +msgid "fatal: cannot stat path %s: No such file or directory" +msgstr "" +"lá»—i nghiêm trá»ng: không thể lấy thông tin vá» Ä‘Æ°á»ng dẫn %s: Không có táºp tin " +"hoặc thÆ° mục nhÆ° váºy" + +#: git-gui.sh:3153 +msgid "Current Branch:" +msgstr "Nhánh hiện hà nh:" + +#: git-gui.sh:3179 +msgid "Staged Changes (Will Commit)" +msgstr "Äánh dấu các thay đổi (Sẽ chuyển giao)" + +#: git-gui.sh:3199 +msgid "Unstaged Changes" +msgstr "Bá» ra khá»i bệ phóng các thay đổi" + +#: git-gui.sh:3270 +msgid "Stage Changed" +msgstr "Äặt lên bệ phóng các thay đổi" + +#: git-gui.sh:3289 lib/transport.tcl:137 lib/transport.tcl:229 +msgid "Push" +msgstr "Äẩy lên" + +#: git-gui.sh:3324 +msgid "Initial Commit Message:" +msgstr "Phần chú thÃch cho lần chuyển giao khởi tạo:" + +#: git-gui.sh:3325 +msgid "Amended Commit Message:" +msgstr "Phần chú giải cho lần chuyển giao tu bổ:" + +#: git-gui.sh:3326 +msgid "Amended Initial Commit Message:" +msgstr "Phần chú giải cho lần chuyển giao tu bổ lần khởi tạo:" + +#: git-gui.sh:3327 +msgid "Amended Merge Commit Message:" +msgstr "Phần chú giải cho lần chuyển giao tu bổ lần hòa trá»™n" + +#: git-gui.sh:3328 +msgid "Merge Commit Message:" +msgstr "Ghi chú của lần chuyển giao hòa trá»™n:" + +#: git-gui.sh:3329 +msgid "Commit Message:" +msgstr "Chú thÃch của lần chuyển giao:" + +#: git-gui.sh:3378 git-gui.sh:3532 lib/console.tcl:73 +msgid "Copy All" +msgstr "Chép tất cả" + +#: git-gui.sh:3402 lib/blame.tcl:105 +msgid "File:" +msgstr "Táºp tin:" + +#: git-gui.sh:3520 +msgid "Refresh" +msgstr "Là m tÆ°Æ¡i lại" + +#: git-gui.sh:3541 +msgid "Decrease Font Size" +msgstr "Giảm kÃch cỡ phông" + +#: git-gui.sh:3545 +msgid "Increase Font Size" +msgstr "Tăng kÃch cỡ phông" + +#: git-gui.sh:3553 lib/blame.tcl:294 +msgid "Encoding" +msgstr "Bảng mã" + +#: git-gui.sh:3564 +msgid "Apply/Reverse Hunk" +msgstr "Ãp dụng hay đảo ngược cả khối" + +#: git-gui.sh:3569 +msgid "Apply/Reverse Line" +msgstr "Ãp dụng hay đảo ngược dòng" + +#: git-gui.sh:3588 +msgid "Run Merge Tool" +msgstr "Chạy công cụ hòa trá»™n" + +#: git-gui.sh:3593 +msgid "Use Remote Version" +msgstr "Dùng phiên bản ở máy chủ" + +#: git-gui.sh:3597 +msgid "Use Local Version" +msgstr "Dùng phiên bản ở máy ná»™i bá»™" + +#: git-gui.sh:3601 +msgid "Revert To Base" +msgstr "Trở lại cÆ¡ bản" + +#: git-gui.sh:3619 +msgid "Visualize These Changes In The Submodule" +msgstr "Hiển thị trá»±c quan các thay đổi trong mô-Ä‘un con" + +#: git-gui.sh:3623 +msgid "Visualize Current Branch History In The Submodule" +msgstr "Hiển thị trá»±c quan lịch sá» nhánh hiện tại trong mô-Ä‘un con" + +#: git-gui.sh:3627 +msgid "Visualize All Branch History In The Submodule" +msgstr "Hiển thị trá»±c quan lịch sá» má»i nhánh trong mô-Ä‘un con" + +#: git-gui.sh:3632 +msgid "Start git gui In The Submodule" +msgstr "Khởi chạy git gui trong mô-Ä‘un-con" + +#: git-gui.sh:3667 +msgid "Unstage Hunk From Commit" +msgstr "BỠđánh dấu Ä‘oạn cần chuyển giao" + +#: git-gui.sh:3669 +msgid "Unstage Lines From Commit" +msgstr "BỠđánh dấu các dòng cần chuyển giao" + +#: git-gui.sh:3671 +msgid "Unstage Line From Commit" +msgstr "BỠđánh dấu dòng cần chuyển giao" + +#: git-gui.sh:3674 +msgid "Stage Hunk For Commit" +msgstr "Äánh dấu Ä‘oạn cần chuyển giao" + +#: git-gui.sh:3676 +msgid "Stage Lines For Commit" +msgstr "Äánh dấu các dòng cần chuyển giao" + +#: git-gui.sh:3678 +msgid "Stage Line For Commit" +msgstr "Äánh dấu dòng cần chuyển giao" + +#: git-gui.sh:3703 +msgid "Initializing..." +msgstr "Äang khởi tạo..." + +#: git-gui.sh:3846 +#, tcl-format +msgid "" +"Possible environment issues exist.\n" +"\n" +"The following environment variables are probably\n" +"going to be ignored by any Git subprocess run\n" +"by %s:\n" +"\n" +msgstr "" +"Gần nhÆ° chắc chắn là môi trÆ°á»ng tồn tại.\n" +"\n" +"Các biến môi trÆ°á»ng sau đây có lẽ sẽ bị bá» qua bởi các tiến trình con git\n" +"chạy bởi %s:\n" +"\n" + +#: git-gui.sh:3875 +msgid "" +"\n" +"This is due to a known issue with the\n" +"Tcl binary distributed by Cygwin." +msgstr "" +"\n" +"Cái nà y có nguyên nhân bởi má»™t lá»—i phát ra từ\n" +"Tcl phân phối bởi Cygwin." + +#: git-gui.sh:3880 +#, tcl-format +msgid "" +"\n" +"\n" +"A good replacement for %s\n" +"is placing values for the user.name and\n" +"user.email settings into your personal\n" +"~/.gitconfig file.\n" +msgstr "" +"\n" +"\n" +"Thay thế tốt cho %s\n" +"là thay thế các giá trị cà i đặt cho user.name và \n" +"user.email thà nh táºp tin cá nhân của bạn\n" +"~/.gitconfig.\n" + +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui - công cụ đồ há»a dà nh cho Git." + +#: lib/blame.tcl:73 +msgid "File Viewer" +msgstr "Bá»™ Xem Táºp Tin" + +#: lib/blame.tcl:79 +msgid "Commit:" +msgstr "Lần chuyển giao:" + +#: lib/blame.tcl:280 +msgid "Copy Commit" +msgstr "Chép lần chuyển giao" + +#: lib/blame.tcl:284 +msgid "Find Text..." +msgstr "Tìm chữ..." + +#: lib/blame.tcl:288 +msgid "Goto Line..." +msgstr "Nhảy đến dòng..." + +#: lib/blame.tcl:297 +msgid "Do Full Copy Detection" +msgstr "Thá»±c hiện dò tìm chép toà n bá»™" + +#: lib/blame.tcl:301 +msgid "Show History Context" +msgstr "Hiển thị ná»™i dung của lịch sá»" + +#: lib/blame.tcl:304 +msgid "Blame Parent Commit" +msgstr "Xem công trạng của lần chuyển giao cha mẹ" + +#: lib/blame.tcl:466 +#, tcl-format +msgid "Reading %s..." +msgstr "Äang Ä‘á»c %s..." + +#: lib/blame.tcl:594 +msgid "Loading copy/move tracking annotations..." +msgstr "Äang tải phần chú giải theo dõi chép/chuyển..." + +#: lib/blame.tcl:614 +msgid "lines annotated" +msgstr "dòng chú giải" + +#: lib/blame.tcl:806 +msgid "Loading original location annotations..." +msgstr "Äang tải các chú giải vị trà nguyên gốc..." + +#: lib/blame.tcl:809 +msgid "Annotation complete." +msgstr "Chú giải hoà n tất." + +#: lib/blame.tcl:839 +msgid "Busy" +msgstr "Báºn" + +#: lib/blame.tcl:840 +msgid "Annotation process is already running." +msgstr "Tiến trình chú giải Ä‘ang diá»…n ra." + +#: lib/blame.tcl:879 +msgid "Running thorough copy detection..." +msgstr "Äang chạy dò tìm sao chép toà n diện..." + +#: lib/blame.tcl:947 +msgid "Loading annotation..." +msgstr "Äang tải phần chú giải..." + +#: lib/blame.tcl:1000 +msgid "Author:" +msgstr "Tác giả:" + +#: lib/blame.tcl:1004 +msgid "Committer:" +msgstr "NgÆ°á»i chuyển giao:" + +#: lib/blame.tcl:1009 +msgid "Original File:" +msgstr "Táºp tin gốc:" + +#: lib/blame.tcl:1057 +msgid "Cannot find HEAD commit:" +msgstr "Không thể tìm thấy HEAD của lần chuyển giao:" + +#: lib/blame.tcl:1112 +msgid "Cannot find parent commit:" +msgstr "Không thể tìm thấy lần chuyển giao mẹ:" + +#: lib/blame.tcl:1127 +msgid "Unable to display parent" +msgstr "Không thể hiển thị cha mẹ" + +#: lib/blame.tcl:1128 lib/diff.tcl:341 +msgid "Error loading diff:" +msgstr "Gặp lá»—i khi tải diff:" + +#: lib/blame.tcl:1269 +msgid "Originally By:" +msgstr "Nguyên gốc bởi:" + +#: lib/blame.tcl:1275 +msgid "In File:" +msgstr "Trong táºp tin:" + +#: lib/blame.tcl:1280 +msgid "Copied Or Moved Here By:" +msgstr "Äã chép hoặc Di chuyển đến đây bởi:" + +#: lib/branch_checkout.tcl:16 lib/branch_checkout.tcl:21 +msgid "Checkout Branch" +msgstr "Lấy ra nhánh" + +#: lib/branch_checkout.tcl:26 +msgid "Checkout" +msgstr "Lấy ra" + +#: lib/branch_checkout.tcl:30 lib/branch_create.tcl:37 +#: lib/branch_delete.tcl:34 lib/branch_rename.tcl:32 lib/browser.tcl:292 +#: lib/checkout_op.tcl:579 lib/choose_font.tcl:45 lib/merge.tcl:174 +#: lib/option.tcl:127 lib/remote_add.tcl:34 lib/remote_branch_delete.tcl:43 +#: lib/tools_dlg.tcl:41 lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 +#: lib/transport.tcl:141 +msgid "Cancel" +msgstr "Thôi" + +#: lib/branch_checkout.tcl:35 lib/browser.tcl:297 lib/tools_dlg.tcl:321 +msgid "Revision" +msgstr "Äiểm sá»a đổi" + +#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:69 lib/option.tcl:309 +msgid "Options" +msgstr "Tùy chá»n" + +#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "Lấy vá» nhánh được theo dõi" + +#: lib/branch_checkout.tcl:47 +msgid "Detach From Local Branch" +msgstr "Tách rá»i từ Nhánh ná»™i bá»™" + +#: lib/branch_create.tcl:23 +msgid "Create Branch" +msgstr "Tạo nhánh" + +#: lib/branch_create.tcl:28 +msgid "Create New Branch" +msgstr "Tạo nhánh má»›i" + +#: lib/branch_create.tcl:33 lib/choose_repository.tcl:391 +msgid "Create" +msgstr "Tạo" + +#: lib/branch_create.tcl:42 +msgid "Branch Name" +msgstr "Tên nhánh" + +#: lib/branch_create.tcl:44 lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 +msgid "Name:" +msgstr "Tên:" + +#: lib/branch_create.tcl:57 +msgid "Match Tracking Branch Name" +msgstr "Khá»›p vá»›i tên nhánh được theo dõi" + +#: lib/branch_create.tcl:66 +msgid "Starting Revision" +msgstr "Äiểm đầu" + +#: lib/branch_create.tcl:72 +msgid "Update Existing Branch:" +msgstr "Cáºp nháºt nhánh sẵn có:" + +#: lib/branch_create.tcl:75 +msgid "No" +msgstr "Không" + +#: lib/branch_create.tcl:80 +msgid "Fast Forward Only" +msgstr "Chỉ fast-forward" + +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571 +msgid "Reset" +msgstr "Äặt lại" + +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "Lấy ra sau khi tạo" + +#: lib/branch_create.tcl:132 +msgid "Please select a tracking branch." +msgstr "Vui lòng chá»n nhánh theo dõi." + +#: lib/branch_create.tcl:141 +#, tcl-format +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "Nhánh theo dõi %s không phải là má»™t nhánh trên kho chứa máy chủ." + +#: lib/branch_create.tcl:154 lib/branch_rename.tcl:92 +msgid "Please supply a branch name." +msgstr "Hãy cung cấp tên nhánh." + +#: lib/branch_create.tcl:165 lib/branch_rename.tcl:112 +#, tcl-format +msgid "'%s' is not an acceptable branch name." +msgstr "'%s' không phải là má»™t tên nhánh được chấp nháºn." + +#: lib/branch_delete.tcl:16 +msgid "Delete Branch" +msgstr "Xoá nhánh" + +#: lib/branch_delete.tcl:21 +msgid "Delete Local Branch" +msgstr "Xóa nhánh ná»™i bá»™" + +#: lib/branch_delete.tcl:39 +msgid "Local Branches" +msgstr "Nhánh ná»™i bá»™" + +#: lib/branch_delete.tcl:51 +msgid "Delete Only If Merged Into" +msgstr "Chỉ xóa nếu đã hòa trá»™n và o" + +#: lib/branch_delete.tcl:53 lib/remote_branch_delete.tcl:120 +msgid "Always (Do not perform merge checks)" +msgstr "Luôn (Không thá»±c hiện kiểm tra hòa trá»™n)" + +#: lib/branch_delete.tcl:103 +#, tcl-format +msgid "The following branches are not completely merged into %s:" +msgstr "Các nhánh sau đây không được hòa trá»™n hoà n toà n và o %s:" + +#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:218 +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" +"Khôi phục các nhánh đã bị xóa là việc khó khăn.\n" +"\n" +"Xóa nhánh đã chá»n chứ?" + +#: lib/branch_delete.tcl:141 +#, tcl-format +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" +"Gặp lá»—i khi xóa các nhánh:\n" +"%s" + +#: lib/branch_rename.tcl:15 lib/branch_rename.tcl:23 +msgid "Rename Branch" +msgstr "Äổi tên nhánh" + +#: lib/branch_rename.tcl:28 +msgid "Rename" +msgstr "Äổi tên" + +#: lib/branch_rename.tcl:38 +msgid "Branch:" +msgstr "Nhánh:" + +#: lib/branch_rename.tcl:46 +msgid "New Name:" +msgstr "Tên má»›i:" + +#: lib/branch_rename.tcl:81 +msgid "Please select a branch to rename." +msgstr "Hãy chá»n nhánh cần đổi tên." + +#: lib/branch_rename.tcl:102 lib/checkout_op.tcl:202 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "Nhánh '%s' đã có rồi." + +#: lib/branch_rename.tcl:123 +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "Gặp lá»—i khi đổi tên '%s'." + +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "Äang khởi Ä‘á»™ng..." + +#: lib/browser.tcl:27 +msgid "File Browser" +msgstr "Bá»™ duyệt táºp tin" + +#: lib/browser.tcl:132 lib/browser.tcl:149 +#, tcl-format +msgid "Loading %s..." +msgstr "Äang tải %s..." + +#: lib/browser.tcl:193 +msgid "[Up To Parent]" +msgstr "[Tá»›i cha mẹ]" + +#: lib/browser.tcl:275 lib/browser.tcl:282 +msgid "Browse Branch Files" +msgstr "Duyệt các táºp tin nhánh" + +#: lib/browser.tcl:288 lib/choose_repository.tcl:406 +#: lib/choose_repository.tcl:493 lib/choose_repository.tcl:502 +#: lib/choose_repository.tcl:1029 +msgid "Browse" +msgstr "Tìm duyệt" + +#: lib/checkout_op.tcl:85 +#, tcl-format +msgid "Fetching %s from %s" +msgstr "Äang lấy vá» %s từ %s" + +#: lib/checkout_op.tcl:133 +#, tcl-format +msgid "fatal: Cannot resolve %s" +msgstr "gặp lá»—i nghiêm trá»ng: Không thể phân giải %s" + +#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:30 +#: lib/sshkey.tcl:55 +msgid "Close" +msgstr "Äóng" + +#: lib/checkout_op.tcl:175 +#, tcl-format +msgid "Branch '%s' does not exist." +msgstr "ChÆ°a có nhánh '%s'" + +#: lib/checkout_op.tcl:194 +#, tcl-format +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "Gặp lá»—i khi cấu hình git-pull Ä‘Æ¡n giản dà nh cho '%s'." + +#: lib/checkout_op.tcl:229 +#, tcl-format +msgid "" +"Branch '%s' already exists.\n" +"\n" +"It cannot fast-forward to %s.\n" +"A merge is required." +msgstr "" +"Nhánh '%s' đã sẵn có.\n" +"\n" +"Không thể fast-forward thà nh %s.\n" +"Bạn cần phải hòa trá»™n." + +#: lib/checkout_op.tcl:243 +#, tcl-format +msgid "Merge strategy '%s' not supported." +msgstr "Không há»— trợ chiến lược hòa trá»™n '%s'." + +#: lib/checkout_op.tcl:262 +#, tcl-format +msgid "Failed to update '%s'." +msgstr "Gặp lá»—i khi cáºp nháºt '%s'." + +#: lib/checkout_op.tcl:274 +msgid "Staging area (index) is already locked." +msgstr "Vùng bệ phóng (chỉ mục) đã bị khóa rồi." + +#: lib/checkout_op.tcl:289 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before the current branch can be changed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Trạng thái quét không khá»›p vá»›i trạng thái kho.\n" +"\n" +"Có Git khác đã sá»a kho nà y kể từ lần quét cuối. Cần quét lại trÆ°á»›c khi thá»±c " +"hiện việc chuyển nhánh.\n" +"\n" +"Sẽ thá»±c hiện việc quét lại ngay bây giá»i.\n" + +#: lib/checkout_op.tcl:345 +#, tcl-format +msgid "Updating working directory to '%s'..." +msgstr "Cáºp nháºt thÆ° mục là m việc thà nh '%s'..." + +#: lib/checkout_op.tcl:346 +msgid "files checked out" +msgstr "các táºp tin cần lấy ra" + +#: lib/checkout_op.tcl:376 +#, tcl-format +msgid "Aborted checkout of '%s' (file level merging is required)." +msgstr "Hủy bá» lấy ra '%s' (cần hòa trá»™n mức táºp tin)." + +#: lib/checkout_op.tcl:377 +msgid "File level merge required." +msgstr "Cần mức hòa trá»™n táºp tin." + +#: lib/checkout_op.tcl:381 +#, tcl-format +msgid "Staying on branch '%s'." +msgstr "Äang ở trên nhánh '%s'." + +#: lib/checkout_op.tcl:452 +msgid "" +"You are no longer on a local branch.\n" +"\n" +"If you wanted to be on a branch, create one now starting from 'This Detached " +"Checkout'." +msgstr "" +"Bạn hiện không còn ở nhánh ná»™i bá»™.\n" +"\n" +"Nếu bạn muốn trên má»™t nhánh, hãy tạo má»™t cái từ 'Äây là lấy ra tách rá»i'." + +#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 +#, tcl-format +msgid "Checked out '%s'." +msgstr "Äã lấy ra '%s'." + +#: lib/checkout_op.tcl:535 +#, tcl-format +msgid "Resetting '%s' to '%s' will lose the following commits:" +msgstr "Äặt lại '%s' thà nh '%s' sẽ là m mất những lần chuyển giao sau đây:" + +#: lib/checkout_op.tcl:557 +msgid "Recovering lost commits may not be easy." +msgstr "Lấy lại những lần chuyển giao đã mất là không dá»…." + +#: lib/checkout_op.tcl:562 +#, tcl-format +msgid "Reset '%s'?" +msgstr "Äặt lại '%s'?" + +#: lib/checkout_op.tcl:567 lib/merge.tcl:166 lib/tools_dlg.tcl:336 +msgid "Visualize" +msgstr "Trá»±c quan" + +#: lib/checkout_op.tcl:635 +#, tcl-format +msgid "" +"Failed to set current branch.\n" +"\n" +"This working directory is only partially switched. We successfully updated " +"your files, but failed to update an internal Git file.\n" +"\n" +"This should not have occurred. %s will now close and give up." +msgstr "" +"Gặp lá»—i khi đặt nhánh hiện hà nh.\n" +"\n" +"ThÆ° mục là m việc chỉ chuyển không hoà n toà n. Chúng tôi cáºp nháºt thà nh công " +"các táºp tin của bạn, nhÆ°ng lại gặp lá»—i khi cáºp nháºt má»™t táºp tin của Git.\n" +"\n" +"Äiá»u nà y đáng lẽ không thể xảy ra. %s giá» sẽ đóng lại và đầu hà ng." + +#: lib/choose_font.tcl:41 +msgid "Select" +msgstr "Chá»n" + +#: lib/choose_font.tcl:55 +msgid "Font Family" +msgstr "Há» phông chữ" + +#: lib/choose_font.tcl:76 +msgid "Font Size" +msgstr "Cỡ phông chữ" + +#: lib/choose_font.tcl:93 +msgid "Font Example" +msgstr "Phông chữ và dụ" + +#: lib/choose_font.tcl:105 +msgid "" +"This is example text.\n" +"If you like this text, it can be your font." +msgstr "" +"Äây là chữ mẫu.\n" +"Nếu bạn thÃch chữ nhÆ° thế nà y thì chá»n phông chữ nà y." + +#: lib/choose_repository.tcl:32 +msgid "Git Gui" +msgstr "Git Gui" + +#: lib/choose_repository.tcl:91 lib/choose_repository.tcl:396 +msgid "Create New Repository" +msgstr "Tạo kho má»›i" + +#: lib/choose_repository.tcl:97 +msgid "New..." +msgstr "Má»›i..." + +#: lib/choose_repository.tcl:104 lib/choose_repository.tcl:480 +msgid "Clone Existing Repository" +msgstr "Nhân bản má»™t kho sẵn có" + +#: lib/choose_repository.tcl:115 +msgid "Clone..." +msgstr "Nhân bản..." + +#: lib/choose_repository.tcl:122 lib/choose_repository.tcl:1019 +msgid "Open Existing Repository" +msgstr "Mở má»™t kho đã có." + +#: lib/choose_repository.tcl:128 +msgid "Open..." +msgstr "Mở..." + +#: lib/choose_repository.tcl:141 +msgid "Recent Repositories" +msgstr "Các kho má»›i dùng" + +#: lib/choose_repository.tcl:147 +msgid "Open Recent Repository:" +msgstr "Mở kho má»›i dùng:" + +#: lib/choose_repository.tcl:315 lib/choose_repository.tcl:322 +#: lib/choose_repository.tcl:329 +#, tcl-format +msgid "Failed to create repository %s:" +msgstr "Gặp lá»—i khi tạo kho %s:" + +#: lib/choose_repository.tcl:401 +msgid "Directory:" +msgstr "ThÆ° mục:" + +#: lib/choose_repository.tcl:431 lib/choose_repository.tcl:552 +#: lib/choose_repository.tcl:1053 +msgid "Git Repository" +msgstr "Kho Git" + +#: lib/choose_repository.tcl:456 +#, tcl-format +msgid "Directory %s already exists." +msgstr "ThÆ° mục %s đã sẵn có." + +#: lib/choose_repository.tcl:460 +#, tcl-format +msgid "File %s already exists." +msgstr "Táºp tin %s đã có sẵn." + +#: lib/choose_repository.tcl:475 +msgid "Clone" +msgstr "Nhân bản" + +#: lib/choose_repository.tcl:488 +msgid "Source Location:" +msgstr "Vị trà nguồn:" + +#: lib/choose_repository.tcl:497 +msgid "Target Directory:" +msgstr "ThÆ° mục Ä‘Ãch:" + +#: lib/choose_repository.tcl:507 +msgid "Clone Type:" +msgstr "Kiểu nhân bản:" + +#: lib/choose_repository.tcl:512 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "Tiêu chuẩn (Nhanh, Semi-Redundant, Hardlinks)" + +#: lib/choose_repository.tcl:517 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "Sao chép toà n bá»™ (Cháºm hÆ¡n, Redundant Backup)" + +#: lib/choose_repository.tcl:522 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "Chia sẻ (Nhanh nhất, Không nên dùng, No Backup)" + +#: lib/choose_repository.tcl:558 lib/choose_repository.tcl:605 +#: lib/choose_repository.tcl:751 lib/choose_repository.tcl:821 +#: lib/choose_repository.tcl:1059 lib/choose_repository.tcl:1067 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "Không phải là kho git: %s" + +#: lib/choose_repository.tcl:594 +msgid "Standard only available for local repository." +msgstr "Tiêu chuẩn chỉ sẵn sà ng vá»›i kho ná»™i bá»™." + +#: lib/choose_repository.tcl:598 +msgid "Shared only available for local repository." +msgstr "'Chia sẻ' chỉ sẵn sà ng vá»›i kho ná»™i bá»™." + +#: lib/choose_repository.tcl:619 +#, tcl-format +msgid "Location %s already exists." +msgstr "Miá»n địa phÆ°Æ¡ng %s đã sẵn có." + +#: lib/choose_repository.tcl:630 +msgid "Failed to configure origin" +msgstr "Gặp lá»—i khi cấu hình bản gốc" + +#: lib/choose_repository.tcl:642 +msgid "Counting objects" +msgstr "Äang đếm số đối tượng" + +#: lib/choose_repository.tcl:643 +msgid "buckets" +msgstr "xô" + +#: lib/choose_repository.tcl:667 +#, tcl-format +msgid "Unable to copy objects/info/alternates: %s" +msgstr "Không thể sao chép objects/info/alternates: %s" + +#: lib/choose_repository.tcl:703 +#, tcl-format +msgid "Nothing to clone from %s." +msgstr "Không có gì để nhân bản từ %s" + +#: lib/choose_repository.tcl:705 lib/choose_repository.tcl:919 +#: lib/choose_repository.tcl:931 +msgid "The 'master' branch has not been initialized." +msgstr "Nhánh 'master' chÆ°a được khởi tạo." + +#: lib/choose_repository.tcl:718 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "Liên kết cứng không sẵn sà ng. Trở lại chế Ä‘á»™ sao chép." + +#: lib/choose_repository.tcl:730 +#, tcl-format +msgid "Cloning from %s" +msgstr "Äang nhân bản từ %s" + +#: lib/choose_repository.tcl:761 +msgid "Copying objects" +msgstr "Äang chép các đối tượng" + +#: lib/choose_repository.tcl:762 +msgid "KiB" +msgstr "KiB" + +#: lib/choose_repository.tcl:786 +#, tcl-format +msgid "Unable to copy object: %s" +msgstr "Không thể chép đối tượng: %s" + +#: lib/choose_repository.tcl:796 +msgid "Linking objects" +msgstr "Äang liên kết các đối tượng" + +#: lib/choose_repository.tcl:797 +msgid "objects" +msgstr "đối tượng" + +#: lib/choose_repository.tcl:805 +#, tcl-format +msgid "Unable to hardlink object: %s" +msgstr "Không thể tạo liên kết cứng đối tượng: %s" + +#: lib/choose_repository.tcl:860 +msgid "Cannot fetch branches and objects. See console output for details." +msgstr "" +"Không thể lấy các nhánh và đối tượng. Xem kết xuất từ bảng Ä‘iá»u khiển để có " +"thêm thông tin." + +#: lib/choose_repository.tcl:871 +msgid "Cannot fetch tags. See console output for details." +msgstr "" +"Không thể lấy vá» các thẻ. Hãy xem kết xuất từ bảng Ä‘iá»u khiển để có thêm " +"thông tin chi tiết." + +#: lib/choose_repository.tcl:895 +msgid "Cannot determine HEAD. See console output for details." +msgstr "" +"Không thể dò tìm HEAD. Hãy xem kết xuất từ bảng Ä‘iá»u khiển để có thêm thông " +"tin chi tiết." + +#: lib/choose_repository.tcl:904 +#, tcl-format +msgid "Unable to cleanup %s" +msgstr "Không thể dá»n sạch %s" + +#: lib/choose_repository.tcl:910 +msgid "Clone failed." +msgstr "Gặp lá»—i khi nhân bản." + +#: lib/choose_repository.tcl:917 +msgid "No default branch obtained." +msgstr "Không tìm thấy nhánh mặc định." + +#: lib/choose_repository.tcl:928 +#, tcl-format +msgid "Cannot resolve %s as a commit." +msgstr "Không thể phân giải %s nhÆ° là má»™t lần chuyển giao." + +#: lib/choose_repository.tcl:940 +msgid "Creating working directory" +msgstr "Äang tạo thÆ° mục là m việc" + +#: lib/choose_repository.tcl:941 lib/index.tcl:70 lib/index.tcl:136 +#: lib/index.tcl:207 +msgid "files" +msgstr "táºp tin" + +#: lib/choose_repository.tcl:970 +msgid "Initial file checkout failed." +msgstr "Lấy ra táºp tin khởi tạo gặp lá»—i." + +#: lib/choose_repository.tcl:1014 +msgid "Open" +msgstr "Mở" + +#: lib/choose_repository.tcl:1024 +msgid "Repository:" +msgstr "Kho:" + +#: lib/choose_repository.tcl:1073 +#, tcl-format +msgid "Failed to open repository %s:" +msgstr "Gặp lá»—i khi mở kho %s:" + +#: lib/choose_rev.tcl:52 +msgid "This Detached Checkout" +msgstr "Äây là việc lấy ra bị tách rá»i" + +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "Biểu thức Ä‘iểm xét:" + +#: lib/choose_rev.tcl:72 +msgid "Local Branch" +msgstr "Nhánh ná»™i bá»™" + +#: lib/choose_rev.tcl:77 +msgid "Tracking Branch" +msgstr "Nhánh Theo dõi" + +#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544 +msgid "Tag" +msgstr "Thẻ" + +#: lib/choose_rev.tcl:321 +#, tcl-format +msgid "Invalid revision: %s" +msgstr "Äiểm xét duyệt không hợp lệ: %s" + +#: lib/choose_rev.tcl:342 +msgid "No revision selected." +msgstr "ChÆ°a chá»n Ä‘iểm xét duyệt." + +#: lib/choose_rev.tcl:350 +msgid "Revision expression is empty." +msgstr "Biểu thức chÃnh quy rá»—ng." + +#: lib/choose_rev.tcl:537 +msgid "Updated" +msgstr "Äã cáºp nháºt" + +#: lib/choose_rev.tcl:565 +msgid "URL" +msgstr "URL" + +#: lib/commit.tcl:9 +msgid "" +"There is nothing to amend.\n" +"\n" +"You are about to create the initial commit. There is no commit before this " +"to amend.\n" +msgstr "" +"Ở đây chẳng có gì để tu bổ cả.\n" +"\n" +"Bạn Ä‘ang tạo lần chuyển giao khởi tạo. Ở đây không có lần chuyển giao trÆ°á»›c " +"nà o để mà tu bổ.\n" + +#: lib/commit.tcl:18 +msgid "" +"Cannot amend while merging.\n" +"\n" +"You are currently in the middle of a merge that has not been fully " +"completed. You cannot amend the prior commit unless you first abort the " +"current merge activity.\n" +msgstr "" +"Không thể tu bổ trong khi hòa trá»™n.\n" +"\n" +"Bạn hiện Ä‘ang ở giữa quá trình hòa trôn, mà nó chÆ°a hoà n tất. Bạn không thể " +"tu bổ lần chuyển giao tiá»n nhiệm trừ phi bạn bãi bá» lần hòa trá»™n hiện Ä‘ang " +"kÃch hoạt.\n" + +#: lib/commit.tcl:48 +msgid "Error loading commit data for amend:" +msgstr "Gặp lá»—i khi tải dữ liệu chuyển giao cho lệnh tu bổ:" + +#: lib/commit.tcl:75 +msgid "Unable to obtain your identity:" +msgstr "Không thể lấy được định danh của bạn:" + +#: lib/commit.tcl:80 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "GIT_COMMITTER_IDENT không hợp lệ:" + +#: lib/commit.tcl:129 +#, tcl-format +msgid "warning: Tcl does not support encoding '%s'." +msgstr "cảnh báo: Tcl không há»— trợ bảng mã '%s'." + +#: lib/commit.tcl:149 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before another commit can be created.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Trạng thái quét không khá»›p vá»›i trạng thái kho.\n" +"\n" +"Có Git khác đã sá»a kho nà y kể từ lần quét cuối. Cần quét lại trÆ°á»›c khi thá»±c " +"hiện việc chuyển giao khác.\n" +"\n" +"Sẽ thá»±c hiện việc quét lại ngay bây giá»i.\n" + +#: lib/commit.tcl:173 +#, tcl-format +msgid "" +"Unmerged files cannot be committed.\n" +"\n" +"File %s has merge conflicts. You must resolve them and stage the file " +"before committing.\n" +msgstr "" +"Các táºp tin chÆ°a hòa trá»™n không thể được chuyển giao.\n" +"\n" +"Táºp tin %s có xung Ä‘á»™t hòa trá»™n. Bạn phải giải quyết chúng và đưa lên bệ " +"phóng trÆ°á»›c khi chuyển giao.\n" + +#: lib/commit.tcl:181 +#, tcl-format +msgid "" +"Unknown file state %s detected.\n" +"\n" +"File %s cannot be committed by this program.\n" +msgstr "" +"Tìm thấy trạng thái táºp tim không hiểu %s.\n" +"\n" +"Táºp tin %s không thể được chuyển giao bởi chÆ°Æ¡ng trình nà y.\n" + +#: lib/commit.tcl:189 +msgid "" +"No changes to commit.\n" +"\n" +"You must stage at least 1 file before you can commit.\n" +msgstr "" +"Không có thay đổi nà o cần chuyển giao.\n" +"\n" +"Bạn phải Ä‘Æ°a lên bệ phóng Ãt nhất là má»™t táºp tin trÆ°á»›c khi có thể chuyển " +"giao.\n" + +#: lib/commit.tcl:204 +msgid "" +"Please supply a commit message.\n" +"\n" +"A good commit message has the following format:\n" +"\n" +"- First line: Describe in one sentence what you did.\n" +"- Second line: Blank\n" +"- Remaining lines: Describe why this change is good.\n" +msgstr "" +"Hãy cung cấp lá»i chú giải cho lần chuyển giao.\n" +"\n" +"Lá»i chú giải tốt nhất nên có định dạng sau:\n" +"\n" +"- Dòng đầu tiên: Mô tả những gì bạn đã là m.\n" +"- Dòng thứ hai: Äể trống\n" +"- Các dòng còn lại: Mô tả xem vì sao những thay đổi nà y là cần thiết.\n" + +#: lib/commit.tcl:235 +msgid "Calling pre-commit hook..." +msgstr "Äang gá»i móc (hook) pre-commit..." + +#: lib/commit.tcl:250 +msgid "Commit declined by pre-commit hook." +msgstr "Lần chuyển giao bị khÆ°á»›c từ do móc pre-commit." + +#: lib/commit.tcl:269 +msgid "" +"You are about to commit on a detached head. This is a potentially dangerous " +"thing to do because if you switch to another branch you will lose your " +"changes and it can be difficult to retrieve them later from the reflog. You " +"should probably cancel this commit and create a new branch to continue.\n" +" \n" +" Do you really want to proceed with your Commit?" +msgstr "" +"Bạn thá»±c hiện chuyển giao ở chá»— đã tách rá»i khá»i các đầu. Äiá»u nà y là nguy " +"hiểm bởi nếu bạn chuyển sang nhánh khác thì bạn sẽ mất những thay đổi nà y và " +"việc lấy lại chúng từ reflog cÅ©ng khó khăn. Bạn gần nhÆ° chắc chắn là nên hủy " +"bá» lần chuyển giao nà y và tạo má»™t nhánh má»›i trÆ°á»›c khi tiếp tục.\n" +" \n" +" Bạn có thá»±c sá»± muốn tiếp tục chuyển giao?" + +#: lib/commit.tcl:290 +msgid "Calling commit-msg hook..." +msgstr "Äang gá»i móc commit-msg..." + +#: lib/commit.tcl:305 +msgid "Commit declined by commit-msg hook." +msgstr "Lần chuyển giao bị khÆ°á»›c từ do móc commit-msg." + +#: lib/commit.tcl:318 +msgid "Committing changes..." +msgstr "Chuyển giao các thay đổi..." + +#: lib/commit.tcl:334 +msgid "write-tree failed:" +msgstr "gặp lá»—i khi write-tree:" + +#: lib/commit.tcl:335 lib/commit.tcl:379 lib/commit.tcl:400 +msgid "Commit failed." +msgstr "Gặp lá»—i khi chuyển giao." + +#: lib/commit.tcl:352 +#, tcl-format +msgid "Commit %s appears to be corrupt" +msgstr "Lần chuyển giao %s có vẻ đã hÆ° há»ng" + +#: lib/commit.tcl:357 +msgid "" +"No changes to commit.\n" +"\n" +"No files were modified by this commit and it was not a merge commit.\n" +"\n" +"A rescan will be automatically started now.\n" +msgstr "" +"Không có thay đổi nà o để chuyển giao.\n" +"\n" +"Không có táºp tin nà o được sá»a bởi lần chuyển giao nà y và nó không phải là " +"lần chuyển giao hòa trá»™n.\n" +"\n" +"Sẽ thá»±c hiện việc quét lại ngay bây giá».\n" + +#: lib/commit.tcl:364 +msgid "No changes to commit." +msgstr "Không có thay đổi nà o để chuyển giao." + +#: lib/commit.tcl:378 +msgid "commit-tree failed:" +msgstr "commit-tree gặp lá»—i:" + +#: lib/commit.tcl:399 +msgid "update-ref failed:" +msgstr "cáºp nháºt tham chiếu thất bại:" + +#: lib/commit.tcl:492 +#, tcl-format +msgid "Created commit %s: %s" +msgstr "Lần chuyển giao đã tạo %s: %s" + +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "Äang chạy.. vui lòng đợi..." + +#: lib/console.tcl:186 +msgid "Success" +msgstr "Thà nh công" + +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "Lá»—i: Câu lệnh gặp lá»—i" + +#: lib/database.tcl:42 +msgid "Number of loose objects" +msgstr "Số lượng đối tượng bị mất" + +#: lib/database.tcl:43 +msgid "Disk space used by loose objects" +msgstr "Dung lượng Ä‘Ä©a được dùng bởi các đối tượng bị mất" + +#: lib/database.tcl:44 +msgid "Number of packed objects" +msgstr "Số lượng đối tượng được đóng gói" + +#: lib/database.tcl:45 +msgid "Number of packs" +msgstr "Số lượng gói" + +#: lib/database.tcl:46 +msgid "Disk space used by packed objects" +msgstr "Dung lượng Ä‘Ä©a được dùng bởi các đối tượng gói" + +#: lib/database.tcl:47 +msgid "Packed objects waiting for pruning" +msgstr "Các đối tượng gói chá» xén bá»›t" + +#: lib/database.tcl:48 +msgid "Garbage files" +msgstr "Các táºp tin rác" + +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "Nén cÆ¡ sở dữ liệu đối tượng" + +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "Äang kiểm tra cÆ¡ sở dữ liệu đối tượng bằng lệnh fsck" + +#: lib/database.tcl:107 +#, tcl-format +msgid "" +"This repository currently has approximately %i loose objects.\n" +"\n" +"To maintain optimal performance it is strongly recommended that you compress " +"the database.\n" +"\n" +"Compress the database now?" +msgstr "" +"Hiện kho nà y mất Æ°á»›c chừng khoảng %i đối tượng.\n" +"\n" +"Äể tối Æ°u hóa hiệu suất, khuyến nghị bạn nên nén cÆ¡ sở dữ liệu của mình " +"lại.\n" +"\n" +"Nén cÆ¡ sở dữ liệu chứ?" + +#: lib/date.tcl:25 +#, tcl-format +msgid "Invalid date from Git: %s" +msgstr "Ngà y tháng không hợp lệ từ Git: %s" + +#: lib/diff.tcl:64 +#, tcl-format +msgid "" +"No differences detected.\n" +"\n" +"%s has no changes.\n" +"\n" +"The modification date of this file was updated by another application, but " +"the content within the file was not changed.\n" +"\n" +"A rescan will be automatically started to find other files which may have " +"the same state." +msgstr "" +"Không tìm thấy khác biệt gì.\n" +"\n" +"%s không thay đổi.\n" +"\n" +"Thá»i gian sá»a đổi của táºp tin nà y được cáºp nháºt bởi ứng dụng khác, nhÆ°ng ná»™i " +"dung bên trong táºp tin thì không thay đổi.\n" +"\n" +"Sẽ thá»±c hiện quét lại má»™t cách tá»± Ä‘á»™ng để tìm các táºp tin khác cái mà có thể " +"có cùng tình trạng." + +#: lib/diff.tcl:104 +#, tcl-format +msgid "Loading diff of %s..." +msgstr "Äang tải diff của %s..." + +#: lib/diff.tcl:125 +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"NỘIBỘ: đã xoá\n" +"MÃYCHỦ:\n" + +#: lib/diff.tcl:130 +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"MÃYCHỦ: đã xoá\n" +"NỘIBỘ:\n" + +#: lib/diff.tcl:137 +msgid "LOCAL:\n" +msgstr "NỘI-BỘ:\n" + +#: lib/diff.tcl:140 +msgid "REMOTE:\n" +msgstr "MÃY-CHỦ:\n" + +#: lib/diff.tcl:202 lib/diff.tcl:340 +#, tcl-format +msgid "Unable to display %s" +msgstr "Không thể hiển thị %s" + +#: lib/diff.tcl:203 +msgid "Error loading file:" +msgstr "Lá»—i khi tải táºp tin:" + +#: lib/diff.tcl:210 +msgid "Git Repository (subproject)" +msgstr "Kho Git (dá»± án con)" + +#: lib/diff.tcl:222 +msgid "* Binary file (not showing content)." +msgstr "* Táºp tin nhị phân (không hiển thị ná»™i dung)." + +#: lib/diff.tcl:227 +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" +"* Táºp tin chÆ°a theo dõi là %d byte.\n" +"* Chỉ hiển thị %d byte đầu .\n" + +#: lib/diff.tcl:233 +#, tcl-format +msgid "" +"\n" +"* Untracked file clipped here by %s.\n" +"* To see the entire file, use an external editor.\n" +msgstr "" +"\n" +"* Táºp tin chÆ°a theo dõi được cắt tại đây bởi %s.\n" +"* Äể xem toà n bá»™ táºp tin, hãy dùng ứng dụng biên soạn bên ngoà i.\n" + +#: lib/diff.tcl:560 +msgid "Failed to unstage selected hunk." +msgstr "Gặp lá»—i khi bá» ra khá»i bệ phóng khối đã chá»n" + +#: lib/diff.tcl:567 +msgid "Failed to stage selected hunk." +msgstr "Gặp lá»—i khi Ä‘Æ°a lên bệ phóng khối đã chá»n" + +#: lib/diff.tcl:646 +msgid "Failed to unstage selected line." +msgstr "Gặp lá»—i khi bá» ra khá»i bệ phóng dòng đã chá»n" + +#: lib/diff.tcl:654 +msgid "Failed to stage selected line." +msgstr "Gặp lá»—i khi Ä‘Æ°a lên bệ phóng dòng đã chá»n" + +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "Mặc định" + +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "Hệ thống (%s)" + +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Khác" + +#: lib/error.tcl:20 lib/error.tcl:116 +msgid "error" +msgstr "lá»—i" + +#: lib/error.tcl:36 +msgid "warning" +msgstr "cảnh báo" + +#: lib/error.tcl:96 +msgid "You must correct the above errors before committing." +msgstr "Bạn phải sá»a các lá»—i trên trÆ°á»›c khi chuyển giao." + +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "Không thể bá» khóa bảng mục lục" + +#: lib/index.tcl:17 +msgid "Index Error" +msgstr "Lá»—i mục lục" + +#: lib/index.tcl:19 +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" +"Cáºp nháºt mục lục cho Git gặp lá»—i. Việc quét lại sẽ tá»± Ä‘á»™ng được khởi chạy để " +"đồng hóa lại vá»›i git-gui." + +#: lib/index.tcl:30 +msgid "Continue" +msgstr "Tiếp tục" + +#: lib/index.tcl:33 +msgid "Unlock Index" +msgstr "Bá» khóa mục lục" + +#: lib/index.tcl:298 +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "Bá» %s ra khá»i việc chuyển giao" + +#: lib/index.tcl:337 +msgid "Ready to commit." +msgstr "Äã chuyển giao rồi." + +#: lib/index.tcl:350 +#, tcl-format +msgid "Adding %s" +msgstr "Äang thêm %s" + +#: lib/index.tcl:380 +#, tcl-format +msgid "Stage %d untracked files?" +msgstr "ÄÆ°a %d táºp tin chÆ°a theo dõi lên bệ phóng để chuyển giao?" + +#: lib/index.tcl:428 +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "Hoà n nguyên các thay đổi trong táºp tin %s?" + +#: lib/index.tcl:430 +#, tcl-format +msgid "Revert changes in these %i files?" +msgstr "Hoà n nguyên các thay đổi trong %i táºp tin?" + +#: lib/index.tcl:438 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Má»i thay đổi chÆ°a được Ä‘Æ°a lên bệ phóng sẽ mất vÄ©nh viá»…n do lệnh revert." + +#: lib/index.tcl:441 +msgid "Do Nothing" +msgstr "Không là m gì" + +#: lib/index.tcl:459 +msgid "Reverting selected files" +msgstr "Äang hoà n nguyên các táºp tin đã chá»n" + +#: lib/index.tcl:463 +#, tcl-format +msgid "Reverting %s" +msgstr "Äang hoà n nguyên %s" + +#: lib/line.tcl:17 +msgid "Goto Line:" +msgstr "Nhảy đến dòng:" + +#: lib/line.tcl:23 +msgid "Go" +msgstr "Nhảy" + +#: lib/merge.tcl:13 +msgid "" +"Cannot merge while amending.\n" +"\n" +"You must finish amending this commit before starting any type of merge.\n" +msgstr "" +"Không thể hòa trá»™n trong khi tu bổ.\n" +"\n" +"Bạn phải hoà n tất việc tu bổ lần chuyển giao trÆ°á»›c khi bắt đầu bất kỳ kiểu " +"hòa trá»™n nà o.\n" + +#: lib/merge.tcl:27 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before a merge can be performed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Trạng thái quét không khá»›p vá»›i trạng thái kho.\n" +"\n" +"Có Git khác đã sá»a kho nà y kể từ lần quét cuối. Cần quét lại trÆ°á»›c khi thá»±c " +"hiện việc hòa trá»™n.\n" +"\n" +"Sẽ thá»±c hiện việc quét lại ngay bây giá»i.\n" + +#: lib/merge.tcl:45 +#, tcl-format +msgid "" +"You are in the middle of a conflicted merge.\n" +"\n" +"File %s has merge conflicts.\n" +"\n" +"You must resolve them, stage the file, and commit to complete the current " +"merge. Only then can you begin another merge.\n" +msgstr "" +"Bạn Ä‘ang ở giữa việc thay đổi.\n" +"\n" +"Táºp tin %s đã bị sá»a đổi.\n" +"\n" +"Bạn nên hoà n thiện lần chuyển giao hiện nay trÆ°á»›c khi hòa trá»™n. Chỉ có thế " +"bạn má»›i có thể bắt đầu hòa trá»™n cái .\n" + +#: lib/merge.tcl:55 +#, tcl-format +msgid "" +"You are in the middle of a change.\n" +"\n" +"File %s is modified.\n" +"\n" +"You should complete the current commit before starting a merge. Doing so " +"will help you abort a failed merge, should the need arise.\n" +msgstr "" +"Bạn Ä‘ang ở giữa việc thay đổi.\n" +"\n" +"Táºp tin %s đã bị sá»a đổi.\n" +"\n" +"Bạn nên hoà n thiện lần chuyển giao hiện nay trÆ°á»›c khi hòa trá»™n. Là m nhÆ° váºy " +"giúp bạn có thể loại bá» việc lá»—i trong hòa trá»™n.\n" + +#: lib/merge.tcl:108 +#, tcl-format +msgid "%s of %s" +msgstr "%s trên %s" + +#: lib/merge.tcl:122 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "Äang hòa trá»™n %s và %s..." + +#: lib/merge.tcl:133 +msgid "Merge completed successfully." +msgstr "Hòa trá»™n đã thá»±c hiện thà nh công." + +#: lib/merge.tcl:135 +msgid "Merge failed. Conflict resolution is required." +msgstr "Hòa trá»™n gặp lá»—i. Cần giải quyết các xung Ä‘á»™t trÆ°á»›c." + +#: lib/merge.tcl:160 +#, tcl-format +msgid "Merge Into %s" +msgstr "Hòa trá»™n và o %s" + +#: lib/merge.tcl:179 +msgid "Revision To Merge" +msgstr "Äiểm cần hòa trá»™n" + +#: lib/merge.tcl:214 +msgid "" +"Cannot abort while amending.\n" +"\n" +"You must finish amending this commit.\n" +msgstr "" +"Không thể hủy bá» trong khi Ä‘ang tu bổ.\n" +"\n" +"Bạn cần phải hoà n tất việc tu bổ lần chuyển giao nà y.\n" + +#: lib/merge.tcl:224 +msgid "" +"Abort merge?\n" +"\n" +"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with aborting the current merge?" +msgstr "" +"Bãi bá» hòa trá»™n?\n" +"\n" +"Bãi bá» hòa trá»™n hiện nay sẽ là m *TẤT CẢ* các thay đổi chÆ°a được chuyển giao " +"bị mất.\n" +"\n" +"Tiếp tục bãi bá» việc hòa trá»™n hiện tại?" + +#: lib/merge.tcl:230 +msgid "" +"Reset changes?\n" +"\n" +"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with resetting the current changes?" +msgstr "" +"Äặt lại má»i thay đổi?\n" +"\n" +"Việc đặt lại các thay đổi sẽ là m *MỌI* thay đổi chÆ°a chuyển giao biến mất.\n" +"\n" +"Vẫn tiếp tục đặt lại các thay đổi hiện tại?" + +#: lib/merge.tcl:241 +msgid "Aborting" +msgstr "Bãi bá»" + +#: lib/merge.tcl:241 +msgid "files reset" +msgstr "đặt lại các táºp tin" + +#: lib/merge.tcl:269 +msgid "Abort failed." +msgstr "Gặp lá»—i khi bãi bá»." + +#: lib/merge.tcl:271 +msgid "Abort completed. Ready." +msgstr "Äã bãi bá» xong. Sẵn sà ng." + +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Buá»™c phân giải thà nh nhánh cÆ¡ sở?" + +#: lib/mergetool.tcl:9 +msgid "Force resolution to this branch?" +msgstr "Buá»™c phân giải thà nh nhánh nà y?" + +#: lib/mergetool.tcl:10 +msgid "Force resolution to the other branch?" +msgstr "Buá»™c phân giải thà nh nhánh khác?" + +#: lib/mergetool.tcl:14 +#, tcl-format +msgid "" +"Note that the diff shows only conflicting changes.\n" +"\n" +"%s will be overwritten.\n" +"\n" +"This operation can be undone only by restarting the merge." +msgstr "" +"Chú ý là diff chỉ hiển thị những thay đổi xung Ä‘á»™t.\n" +"\n" +"%s sẽ bị ghi đè.\n" +"\n" +"Thao tác nà y chỉ có thể bá» dở bằng cách khởi Ä‘á»™ng lại việc hòa trá»™n." + +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "" +"Táºp tin %s có vẻ chÆ°a được giải quyết xung Ä‘á»™t, vẫn đánh dấu là cần chuyển " +"giao?" + +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Äang phân giải cho %s" + +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "Không thể phân giải xung Ä‘á»™t xóa hay liên kết dùng má»™t công cụ" + +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "Táºp tin xung Ä‘á»™t không tồn tại" + +#: lib/mergetool.tcl:246 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "Không phải là má»™t công cụ hòa trá»™n GUI: '%s'" + +#: lib/mergetool.tcl:275 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Không há»— trợ công cụ trá»™n '%s'" + +#: lib/mergetool.tcl:310 +msgid "Merge tool is already running, terminate it?" +msgstr "Công cụ hòa trá»™n Ä‘ang chạy rồi, chấm dứt nó?" + +#: lib/mergetool.tcl:330 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Gặp lá»—i khi truy lại phiên bản:\n" +"%s" + +#: lib/mergetool.tcl:350 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Không thể khởi chạy công cụ hòa trá»™n:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:354 +msgid "Running merge tool..." +msgstr "Äang chạy công cụ trá»™n..." + +#: lib/mergetool.tcl:382 lib/mergetool.tcl:390 +msgid "Merge tool failed." +msgstr "Công cụ trá»™n gặp lá»—i." + +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Bảng mã toà n cục không hợp lệ '%s'" + +#: lib/option.tcl:19 +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Bảng mã kho chứa không hợp lệ '%s'" + +#: lib/option.tcl:119 +msgid "Restore Defaults" +msgstr "Phục hồi thà nh mặc định" + +#: lib/option.tcl:123 +msgid "Save" +msgstr "Ghi lại" + +#: lib/option.tcl:133 +#, tcl-format +msgid "%s Repository" +msgstr "%s kho" + +#: lib/option.tcl:134 +msgid "Global (All Repositories)" +msgstr "Toà n cục (Má»i kho)" + +#: lib/option.tcl:140 +msgid "User Name" +msgstr "Tên ngÆ°á»i dùng" + +#: lib/option.tcl:141 +msgid "Email Address" +msgstr "Äịa chỉ thÆ° Ä‘iện tá»" + +#: lib/option.tcl:143 +msgid "Summarize Merge Commits" +msgstr "Tổng hợp vá» hòa trá»™n các lần chuyển giao" + +#: lib/option.tcl:144 +msgid "Merge Verbosity" +msgstr "Chi tiết việc hòa trá»™n" + +#: lib/option.tcl:145 +msgid "Show Diffstat After Merge" +msgstr "Hiển thị thống kê khác biệt sau hòa trá»™n" + +#: lib/option.tcl:146 +msgid "Use Merge Tool" +msgstr "Dùng Công cụ trá»™n" + +#: lib/option.tcl:148 +msgid "Trust File Modification Timestamps" +msgstr "Tin dấu vết thá»i gian sá»a đổi táºp tin" + +#: lib/option.tcl:149 +msgid "Prune Tracking Branches During Fetch" +msgstr "Xén các nhánh theo dõi trong khi lấy vá»" + +#: lib/option.tcl:150 +msgid "Match Tracking Branches" +msgstr "Khá»›p nhánh theo dõi" + +#: lib/option.tcl:151 +msgid "Use Textconv For Diffs and Blames" +msgstr "Dùng Textconv Cho Diffs và Blames" + +#: lib/option.tcl:152 +msgid "Blame Copy Only On Changed Files" +msgstr "Chỉ chép blame trên các táºp tin thay đổi" + +#: lib/option.tcl:153 +msgid "Maximum Length of Recent Repositories List" +msgstr "Số lượng kho má»›i dùng tối Ä‘a được lÆ°u trữ" + +#: lib/option.tcl:154 +msgid "Minimum Letters To Blame Copy On" +msgstr "Chữ tối thiểu để blame chép và o" + +#: lib/option.tcl:155 +msgid "Blame History Context Radius (days)" +msgstr "Bán kÃnh ngữ cảnh lịch sá» blame (ngà y)" + +#: lib/option.tcl:156 +msgid "Number of Diff Context Lines" +msgstr "Số dòng ná»™i dung Diff" + +#: lib/option.tcl:157 +msgid "Additional Diff Parameters" +msgstr "Äối số bổ xung cho Diff" + +#: lib/option.tcl:158 +msgid "Commit Message Text Width" +msgstr "Chiá»u rá»™ng của phần chú thÃch" + +#: lib/option.tcl:159 +msgid "New Branch Name Template" +msgstr "Mẫu tên nhánh má»›i" + +#: lib/option.tcl:160 +msgid "Default File Contents Encoding" +msgstr "Bảng mã dà nh cho ná»™i dung táºp tin mặc định" + +#: lib/option.tcl:161 +msgid "Warn before committing to a detached head" +msgstr "Cảnh báo trÆ°á»›c khi chuyển giao má»™t đầu bị tách rá»i" + +#: lib/option.tcl:162 +msgid "Staging of untracked files" +msgstr "Äánh dấu những táºp tin chÆ°a được theo dõi là cần chuyển giao" + +#: lib/option.tcl:163 +msgid "Show untracked files" +msgstr "Hiện các táºp tin chÆ°a được theo dõi" + +#: lib/option.tcl:209 +msgid "Change" +msgstr "Thay đổi" + +#: lib/option.tcl:253 +msgid "Spelling Dictionary:" +msgstr "Từ Ä‘iển chÃnh tả:" + +#: lib/option.tcl:283 +msgid "Change Font" +msgstr "Äổi phông chữ" + +#: lib/option.tcl:287 +#, tcl-format +msgid "Choose %s" +msgstr "Chá»n %s" + +#: lib/option.tcl:293 +msgid "pt." +msgstr "pt." + +#: lib/option.tcl:307 +msgid "Preferences" +msgstr "Cá nhân hóa" + +#: lib/option.tcl:344 +msgid "Failed to completely save options:" +msgstr "Gặp lá»—i khi hoà n tất ghi lại các tùy chá»n:" + +#: lib/remote_add.tcl:20 +msgid "Add Remote" +msgstr "Thêm máy chủ" + +#: lib/remote_add.tcl:25 +msgid "Add New Remote" +msgstr "Thêm máy chủ má»›i" + +#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 +msgid "Add" +msgstr "Thêm và o" + +#: lib/remote_add.tcl:39 +msgid "Remote Details" +msgstr "Chi tiết vá» máy chủ" + +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Vị trÃ:" + +#: lib/remote_add.tcl:60 +msgid "Further Action" +msgstr "Hà nh Ä‘á»™ng thêm" + +#: lib/remote_add.tcl:63 +msgid "Fetch Immediately" +msgstr "Lấy vá» ngay láºp tức" + +#: lib/remote_add.tcl:69 +msgid "Initialize Remote Repository and Push" +msgstr "Khởi tạo Kho máy chủ và đẩy dữ liệu lên" + +#: lib/remote_add.tcl:75 +msgid "Do Nothing Else Now" +msgstr "Không là m gì cả" + +#: lib/remote_add.tcl:100 +msgid "Please supply a remote name." +msgstr "Hãy cung cấp tên máy chủ." + +#: lib/remote_add.tcl:113 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "'%s' không phải là tên máy chủ được chấp nháºn." + +#: lib/remote_add.tcl:124 +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Gặp lá»—i khi thêm máy chủ '%s' của vị trà '%s'." + +#: lib/remote_add.tcl:132 lib/transport.tcl:6 +#, tcl-format +msgid "fetch %s" +msgstr "lấy vá» %s" + +#: lib/remote_add.tcl:133 +#, tcl-format +msgid "Fetching the %s" +msgstr "Äang lấy vá» %s" + +#: lib/remote_add.tcl:156 +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Không hiểu là m thế nà o để khởi tạo kho chứa tại vị trà '%s'." + +#: lib/remote_add.tcl:162 lib/transport.tcl:54 lib/transport.tcl:92 +#: lib/transport.tcl:110 +#, tcl-format +msgid "push %s" +msgstr "đẩy %s lên máy chủ" + +#: lib/remote_add.tcl:163 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Cà i đặt '%s' (tại %s)" + +#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 +msgid "Delete Branch Remotely" +msgstr "Xóa nhánh trên máy chủ" + +#: lib/remote_branch_delete.tcl:48 +msgid "From Repository" +msgstr "Từ Kho" + +#: lib/remote_branch_delete.tcl:51 lib/transport.tcl:165 +msgid "Remote:" +msgstr "Máy chủ:" + +#: lib/remote_branch_delete.tcl:72 lib/transport.tcl:187 +msgid "Arbitrary Location:" +msgstr "Äịa Ä‘iểm tùy ý:" + +#: lib/remote_branch_delete.tcl:88 +msgid "Branches" +msgstr "Nhánh" + +#: lib/remote_branch_delete.tcl:110 +msgid "Delete Only If" +msgstr "Chỉ xoá Nếu" + +#: lib/remote_branch_delete.tcl:112 +msgid "Merged Into:" +msgstr "Äã trá»™n và o:" + +#: lib/remote_branch_delete.tcl:153 +msgid "A branch is required for 'Merged Into'." +msgstr "Cần má»™t nhánh cho 'Hòa trá»™n và o'." + +#: lib/remote_branch_delete.tcl:185 +#, tcl-format +msgid "" +"The following branches are not completely merged into %s:\n" +"\n" +" - %s" +msgstr "" +"Các nhánh sau đây không được hòa trá»™n hoà n toà n và o %s:\n" +"\n" +" - %s" + +#: lib/remote_branch_delete.tcl:190 +#, tcl-format +msgid "" +"One or more of the merge tests failed because you have not fetched the " +"necessary commits. Try fetching from %s first." +msgstr "" +"Má»™t hay nhiá»u hÆ¡n kiểm tra hòa trá»™n không đạt bởi vì bạn đã không lấy vá» " +"những lần chuyển giao cần thiết. Hãy lấy vá» từ %s trÆ°á»›c đã." + +#: lib/remote_branch_delete.tcl:208 +msgid "Please select one or more branches to delete." +msgstr "Xin hãy chá»n má»™t hay nhiá»u nhánh cần xóa." + +#: lib/remote_branch_delete.tcl:227 +#, tcl-format +msgid "Deleting branches from %s" +msgstr "Äang xoá các nhánh từ %s" + +#: lib/remote_branch_delete.tcl:300 +msgid "No repository selected." +msgstr "ChÆ°a chá»n kho." + +#: lib/remote_branch_delete.tcl:305 +#, tcl-format +msgid "Scanning %s..." +msgstr "Äang quét: %s..." + +#: lib/remote.tcl:200 +msgid "Push to" +msgstr "Äẩy lên" + +#: lib/remote.tcl:218 +msgid "Remove Remote" +msgstr "Gỡ bá» Máy chủ" + +#: lib/remote.tcl:223 +msgid "Prune from" +msgstr "Xén từ" + +#: lib/remote.tcl:228 +msgid "Fetch from" +msgstr "Lấy vá» từ" + +#: lib/search.tcl:48 +msgid "Find:" +msgstr "Tìm:" + +#: lib/search.tcl:50 +msgid "Next" +msgstr "Tiếp" + +#: lib/search.tcl:51 +msgid "Prev" +msgstr "TrÆ°á»›c" + +#: lib/search.tcl:52 +msgid "RegExp" +msgstr "BTCQ" + +#: lib/search.tcl:54 +msgid "Case" +msgstr "Hoa" + +#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 +msgid "Cannot write shortcut:" +msgstr "Không thể ghi lối tắt:" + +#: lib/shortcut.tcl:137 +msgid "Cannot write icon:" +msgstr "Không thể ghi biểu tượng:" + +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "Không há»— trợ kiểm tra chÃnh tả" + +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "Kiểm tra chÃnh tả không sẵn sà ng" + +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "Cấu hình bá»™ soát chÃnh tả không hợp lệ" + +#: lib/spellcheck.tcl:70 +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "Äang hoà n nguyên từ Ä‘iển thà nh %s." + +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" +msgstr "Phần kiểm tra chÃnh tả đã gặp lá»—i khi khởi Ä‘á»™ng" + +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" +msgstr "Không chấp nháºn bá»™ kiểm tra chÃnh tả" + +#: lib/spellcheck.tcl:186 +msgid "No Suggestions" +msgstr "Không có gợi ý" + +#: lib/spellcheck.tcl:388 +msgid "Unexpected EOF from spell checker" +msgstr "Gặp kết thúc bất ngá» từ bá»™ kiểm tra chÃnh tả" + +#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "Kiểm tra chÃnh tả không thà nh công" + +#: lib/sshkey.tcl:31 +msgid "No keys found." +msgstr "Không tìm thấy khóa nà o." + +#: lib/sshkey.tcl:34 +#, tcl-format +msgid "Found a public key in: %s" +msgstr "Tìm thấy khoá công khai trong: %s" + +#: lib/sshkey.tcl:40 +msgid "Generate Key" +msgstr "Tạo khoá" + +#: lib/sshkey.tcl:58 +msgid "Copy To Clipboard" +msgstr "Chép và o clipboard" + +#: lib/sshkey.tcl:72 +msgid "Your OpenSSH Public Key" +msgstr "Khóa công OpenSSH của bạn" + +#: lib/sshkey.tcl:80 +msgid "Generating..." +msgstr "Äang tạo..." + +#: lib/sshkey.tcl:86 +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Không thể chạy ssh-keygen:\n" +"\n" +"%s" + +#: lib/sshkey.tcl:113 +msgid "Generation failed." +msgstr "Việc tạo khoá đã thất bại." + +#: lib/sshkey.tcl:120 +msgid "Generation succeeded, but no keys found." +msgstr "Việc tạo thà nh công nhÆ°ng lại không tìm thấy khóa." + +#: lib/sshkey.tcl:123 +#, tcl-format +msgid "Your key is in: %s" +msgstr "Khóa của bạn trong: %s" + +#: lib/status_bar.tcl:87 +#, tcl-format +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s ... %*i trong %*i %s (%3i%%)" + +#: lib/tools_dlg.tcl:22 +msgid "Add Tool" +msgstr "Thêm công cụ" + +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Thêm lệnh công cụ má»›i" + +#: lib/tools_dlg.tcl:34 +msgid "Add globally" +msgstr "Thêm toà n cục" + +#: lib/tools_dlg.tcl:46 +msgid "Tool Details" +msgstr "Chi tiết công cụ" + +#: lib/tools_dlg.tcl:49 +msgid "Use '/' separators to create a submenu tree:" +msgstr "Dùng dấu ngăn cách '/' để tạo cây trình Ä‘Æ¡n con:" + +#: lib/tools_dlg.tcl:60 +msgid "Command:" +msgstr "Lệnh:" + +#: lib/tools_dlg.tcl:71 +msgid "Show a dialog before running" +msgstr "Hiển thị há»™p thoại trÆ°á»›c khi chạy" + +#: lib/tools_dlg.tcl:77 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Há»i ngÆ°á»i dùng chá»n Ä‘iểm xem xét (đặt biến $REVISION)" + +#: lib/tools_dlg.tcl:82 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Há»i ngÆ°á»i dùng các đối số bổ xung thêm (đặt biến $ARGS)" + +#: lib/tools_dlg.tcl:89 +msgid "Don't show the command output window" +msgstr "Không hiển thị cá»a sổ kết xuất câu lệnh" + +#: lib/tools_dlg.tcl:94 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Chỉ chạy nếu diff được chá»n (biến $FILENAME không rá»—ng)" + +#: lib/tools_dlg.tcl:118 +msgid "Please supply a name for the tool." +msgstr "Hãy cung cấp tên cho công cụ." + +#: lib/tools_dlg.tcl:126 +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "Công cụ '%s' đã sẵn có." + +#: lib/tools_dlg.tcl:148 +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Không thể thêm công cụ:\n" +"%s" + +#: lib/tools_dlg.tcl:187 +msgid "Remove Tool" +msgstr "Gỡ bá» công cụ" + +#: lib/tools_dlg.tcl:193 +msgid "Remove Tool Commands" +msgstr "Gỡ bá» công cụ lệnh" + +#: lib/tools_dlg.tcl:198 +msgid "Remove" +msgstr "Gỡ bá»" + +#: lib/tools_dlg.tcl:231 +msgid "(Blue denotes repository-local tools)" +msgstr "(Các công cụ chỉ thị kho-ná»™i-bá»™ xanh)" + +#: lib/tools_dlg.tcl:292 +#, tcl-format +msgid "Run Command: %s" +msgstr "Chạy lệnh: %s" + +#: lib/tools_dlg.tcl:306 +msgid "Arguments" +msgstr "Äối số" + +#: lib/tools_dlg.tcl:341 +msgid "OK" +msgstr "Äồng ý" + +#: lib/tools.tcl:75 +#, tcl-format +msgid "Running %s requires a selected file." +msgstr "Chạy %s yêu cầu cần phải chá»n má»™t táºp tin." + +#: lib/tools.tcl:91 +#, tcl-format +msgid "Are you sure you want to run %1$s on file \"%2$s\"?" +msgstr "Bạn có chắc là muốn chạy %1$s trên táºp tin \"%2$s\" không?" + +#: lib/tools.tcl:95 +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Bạn có chắc là muốn chạy %s không?" + +#: lib/tools.tcl:116 +#, tcl-format +msgid "Tool: %s" +msgstr "Công cụ: %s" + +#: lib/tools.tcl:117 +#, tcl-format +msgid "Running: %s" +msgstr "Äang chạy: %s" + +#: lib/tools.tcl:155 +#, tcl-format +msgid "Tool completed successfully: %s" +msgstr "Công cụ được biên dịch thà nh công: %s" + +#: lib/tools.tcl:157 +#, tcl-format +msgid "Tool failed: %s" +msgstr "Công cụ gặp lá»—i: %s" + +#: lib/transport.tcl:7 +#, tcl-format +msgid "Fetching new changes from %s" +msgstr "Lấy các thay đổi má»›i từ %s" + +#: lib/transport.tcl:18 +#, tcl-format +msgid "remote prune %s" +msgstr "xén bá»›t trên máy chủ %s" + +#: lib/transport.tcl:19 +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "Xén bá»›t các nhánh theo dõi bị xóa từ %s" + +#: lib/transport.tcl:25 +msgid "fetch all remotes" +msgstr "lấy vá» từ tất cả các máy chủ" + +#: lib/transport.tcl:26 +msgid "Fetching new changes from all remotes" +msgstr "Äang lấy các thay đổi má»›i từ má»i máy chủ" + +#: lib/transport.tcl:40 +msgid "remote prune all remotes" +msgstr "xén bá»›t má»i máy chủ" + +#: lib/transport.tcl:41 +msgid "Pruning tracking branches deleted from all remotes" +msgstr "Xén tỉa các nhánh đã theo dõi bị xóa từ má»i máy chủ" + +#: lib/transport.tcl:55 +#, tcl-format +msgid "Pushing changes to %s" +msgstr "Äang đẩy các nhánh lên %s" + +#: lib/transport.tcl:93 +#, tcl-format +msgid "Mirroring to %s" +msgstr "Bản sao đến %s" + +#: lib/transport.tcl:111 +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "Äang (đẩy) %s %s lên %s" + +#: lib/transport.tcl:132 +msgid "Push Branches" +msgstr "Äẩy lên các nhánh" + +#: lib/transport.tcl:147 +msgid "Source Branches" +msgstr "Nhánh nguồn" + +#: lib/transport.tcl:162 +msgid "Destination Repository" +msgstr "Kho chứa Ä‘Ãch" + +#: lib/transport.tcl:205 +msgid "Transfer Options" +msgstr "Tùy chá»n truyá»n" + +#: lib/transport.tcl:207 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "Ép buá»™c ghi đè nhánh sẵn có (có thể sẽ loại bá» các thay đổi)" + +#: lib/transport.tcl:211 +msgid "Use thin pack (for slow network connections)" +msgstr "Dùng gói má»ng (dà nh cho kết nối mạng cháºm)" + +#: lib/transport.tcl:215 +msgid "Include tags" +msgstr "Bao gồm các thẻ" + +#~ msgid "Case-Sensitive" +#~ msgstr "Có phân biệt HOA/thÆ°á»ng" @@ -368,7 +368,7 @@ def getP4OpenedType(file): # Returns the perforce file type for the given file. result = p4_read_pipe(["opened", wildcard_encode(file)]) - match = re.match(".*\((.+)\)\r?$", result) + match = re.match(".*\((.+)\)( \*exclusive\*)?\r?$", result) if match: return match.group(1) else: @@ -740,17 +740,43 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent def originP4BranchesExist(): return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master") -def p4ChangesForPaths(depotPaths, changeRange): +def p4ChangesForPaths(depotPaths, changeRange, block_size): assert depotPaths - cmd = ['changes'] - for p in depotPaths: - cmd += ["%s...%s" % (p, changeRange)] - output = p4_read_pipe_lines(cmd) + assert block_size + + # Parse the change range into start and end + if changeRange is None or changeRange == '': + changeStart = '@1' + changeEnd = '#head' + else: + parts = changeRange.split(',') + assert len(parts) == 2 + changeStart = parts[0] + changeEnd = parts[1] + # Accumulate change numbers in a dictionary to avoid duplicates changes = {} - for line in output: - changeNum = int(line.split(" ")[1]) - changes[changeNum] = True + + for p in depotPaths: + # Retrieve changes a block at a time, to prevent running + # into a MaxScanRows error from the server. + start = changeStart + end = changeEnd + get_another_block = True + while get_another_block: + new_changes = [] + cmd = ['changes'] + cmd += ['-m', str(block_size)] + cmd += ["%s...%s,%s" % (p, start, end)] + for line in p4_read_pipe_lines(cmd): + changeNum = int(line.split(" ")[1]) + new_changes.append(changeNum) + changes[changeNum] = True + if len(new_changes) == block_size: + get_another_block = True + end = '@' + str(min(new_changes)) + else: + get_another_block = False changelist = changes.keys() changelist.sort() @@ -1911,7 +1937,10 @@ class P4Sync(Command, P4UserMap): optparse.make_option("--import-labels", dest="importLabels", action="store_true"), optparse.make_option("--import-local", dest="importIntoRemotes", action="store_false", help="Import into refs/heads/ , not refs/remotes"), - optparse.make_option("--max-changes", dest="maxChanges"), + optparse.make_option("--max-changes", dest="maxChanges", + help="Maximum number of changes to import"), + optparse.make_option("--changes-block-size", dest="changes_block_size", type="int", + help="Internal block size to use when iteratively calling p4 changes"), optparse.make_option("--keep-path", dest="keepRepoPath", action='store_true', help="Keep entire BRANCH/DIR/SUBDIR prefix during import"), optparse.make_option("--use-client-spec", dest="useClientSpec", action='store_true', @@ -1940,6 +1969,7 @@ class P4Sync(Command, P4UserMap): self.syncWithOrigin = True self.importIntoRemotes = True self.maxChanges = "" + self.changes_block_size = 500 self.keepRepoPath = False self.depotPaths = None self.p4BranchesInGit = [] @@ -2586,7 +2616,7 @@ class P4Sync(Command, P4UserMap): branchPrefix = self.depotPaths[0] + branch + "/" range = "@1,%s" % maxChange #print "prefix" + branchPrefix - changes = p4ChangesForPaths([branchPrefix], range) + changes = p4ChangesForPaths([branchPrefix], range, self.changes_block_size) if len(changes) <= 0: return False firstChange = changes[0] @@ -3002,7 +3032,7 @@ class P4Sync(Command, P4UserMap): if self.verbose: print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), self.changeRange) - changes = p4ChangesForPaths(self.depotPaths, self.changeRange) + changes = p4ChangesForPaths(self.depotPaths, self.changeRange, self.changes_block_size) if len(self.maxChanges) > 0: changes = changes[:min(int(self.maxChanges), len(changes))] diff --git a/git-pull.sh b/git-pull.sh index 4d4fc77b05..ad442264cb 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -240,7 +240,7 @@ test true = "$rebase" && { if ! git rev-parse -q --verify HEAD >/dev/null then # On an unborn branch - if test -f "$GIT_DIR/index" + if test -f "$(git rev-parse --git-path index)" then die "$(gettext "updating an unborn branch with changes added to the index")" fi diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index f7deeb096e..08e5d86fe5 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -642,9 +642,9 @@ do_next () { git notes copy --for-rewrite=rebase < "$rewritten_list" || true # we don't care if this copying failed } && - if test -x "$GIT_DIR"/hooks/post-rewrite && - test -s "$rewritten_list"; then - "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list" + hook="$(git rev-parse --git-path hooks/post-rewrite)" + if test -x "$hook" && test -s "$rewritten_list"; then + "$hook" rebase < "$rewritten_list" true # we don't care if this hook failed fi && warn "Successfully rebased and updated $head_name." diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index d3fb67d75b..2cc2a6d273 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -94,10 +94,8 @@ finish_rb_merge () { if test -s "$state_dir"/rewritten then git notes copy --for-rewrite=rebase <"$state_dir"/rewritten - if test -x "$GIT_DIR"/hooks/post-rewrite - then - "$GIT_DIR"/hooks/post-rewrite rebase <"$state_dir"/rewritten - fi + hook="$(git rev-parse --git-path hooks/post-rewrite)" + test -x "$hook" && "$hook" rebase <"$state_dir"/rewritten fi say All done. } diff --git a/git-rebase.sh b/git-rebase.sh index 55da9db818..fb935a03f3 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -202,9 +202,9 @@ run_specific_rebase () { run_pre_rebase_hook () { if test -z "$ok_to_skip_pre_rebase" && - test -x "$GIT_DIR/hooks/pre-rebase" + test -x "$(git rev-parse --git-path hooks/pre-rebase)" then - "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || + "$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} || die "$(gettext "The pre-rebase hook refused to rebase.")" fi } diff --git a/git-sh-setup.sh b/git-sh-setup.sh index c42c6e6365..4691fbcb64 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -344,7 +344,7 @@ git_dir_init () { echo >&2 "Unable to determine absolute path of git directory" exit 1 } - : ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"} + : ${GIT_OBJECT_DIRECTORY="$(git rev-parse --git-path objects)"} } if test -z "$NONGIT_OK" diff --git a/git-stash.sh b/git-stash.sh index d4cf818be9..6846b18dbc 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -20,7 +20,7 @@ require_work_tree cd_to_toplevel TMP="$GIT_DIR/.git-stash.$$" -TMPindex=${GIT_INDEX_FILE-"$GIT_DIR/index"}.stash.$$ +TMPindex=${GIT_INDEX_FILE-"$(git rev-parse --git-path index)"}.stash.$$ trap 'rm -f "$TMP-"* "$TMPindex"' 0 ref_stash=refs/stash @@ -184,7 +184,7 @@ store_stash () { fi # Make sure the reflog for stash is kept. - : >>"$GIT_DIR/logs/$ref_stash" + : >>"$(git rev-parse --git-path logs/$ref_stash)" git update-ref -m "$stash_msg" $ref_stash $w_commit ret=$? test $ret != 0 && test -z $quiet && @@ -259,7 +259,7 @@ save_stash () { say "$(gettext "No local changes to save")" exit 0 fi - test -f "$GIT_DIR/logs/$ref_stash" || + test -f "$(git rev-parse --git-path logs/$ref_stash)" || clear_stash || die "$(gettext "Cannot initialize stash")" create_stash "$stash_msg" $untracked @@ -382,7 +382,7 @@ static struct cmd_struct commands[] = { { "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE }, { "check-mailmap", cmd_check_mailmap, RUN_SETUP }, { "check-ref-format", cmd_check_ref_format }, - { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE }, + { "checkout", cmd_checkout, RUN_SETUP }, { "checkout-index", cmd_checkout_index, RUN_SETUP | NEED_WORK_TREE}, { "cherry", cmd_cherry, RUN_SETUP }, @@ -38,7 +38,7 @@ const signed char hexval_table[256] = { int get_sha1_hex(const char *hex, unsigned char *sha1) { int i; - for (i = 0; i < 20; i++) { + for (i = 0; i < GIT_SHA1_RAWSZ; i++) { unsigned int val; /* * hex[1]=='\0' is caught when val is checked below, @@ -56,15 +56,20 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) return 0; } +int get_oid_hex(const char *hex, struct object_id *oid) +{ + return get_sha1_hex(hex, oid->hash); +} + char *sha1_to_hex(const unsigned char *sha1) { static int bufno; - static char hexbuffer[4][41]; + static char hexbuffer[4][GIT_SHA1_HEXSZ + 1]; static const char hex[] = "0123456789abcdef"; char *buffer = hexbuffer[3 & ++bufno], *buf = buffer; int i; - for (i = 0; i < 20; i++) { + for (i = 0; i < GIT_SHA1_RAWSZ; i++) { unsigned int val = *sha1++; *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; @@ -73,3 +78,8 @@ char *sha1_to_hex(const unsigned char *sha1) return buffer; } + +char *oid_to_hex(const struct object_id *oid) +{ + return sha1_to_hex(oid->hash); +} diff --git a/line-log.c b/line-log.c index a490efea07..a5ed9e3642 100644 --- a/line-log.c +++ b/line-log.c @@ -575,7 +575,7 @@ parse_lines(struct commit *commit, const char *prefix, struct string_list *args) name_part = skip_range_arg(item->string); if (!name_part || *name_part != ':' || !name_part[1]) - die("-L argument '%s' not of the form start,end:file", + die("-L argument not 'start,end:file' or ':funcname:file': %s", item->string); range_part = xstrndup(item->string, name_part - item->string); name_part++; @@ -1099,6 +1099,7 @@ static int process_all_files(struct line_log_data **range_out, rg->pair = diff_filepair_dup(queue->queue[i]); memcpy(&rg->diff, pairdiff, sizeof(struct diff_ranges)); } + free(pairdiff); } return changed; diff --git a/log-tree.c b/log-tree.c index 2c1ed0fa90..cf4646b0f4 100644 --- a/log-tree.c +++ b/log-tree.c @@ -137,7 +137,7 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in static int add_graft_decoration(const struct commit_graft *graft, void *cb_data) { - struct commit *commit = lookup_commit(graft->sha1); + struct commit *commit = lookup_commit(graft->oid.hash); if (!commit) return 0; add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object); diff --git a/notes-merge.c b/notes-merge.c index 109ff4ef41..0b2b82c41f 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -280,7 +280,7 @@ static void check_notes_merge_worktree(struct notes_merge_options *o) "(%s exists).", git_path("NOTES_MERGE_*")); } - if (safe_create_leading_directories(git_path( + if (safe_create_leading_directories_const(git_path( NOTES_MERGE_WORKTREE "/.test"))) die_errno("unable to create directory %s", git_path(NOTES_MERGE_WORKTREE)); @@ -295,8 +295,8 @@ static void write_buf_to_worktree(const unsigned char *obj, const char *buf, unsigned long size) { int fd; - char *path = git_path(NOTES_MERGE_WORKTREE "/%s", sha1_to_hex(obj)); - if (safe_create_leading_directories(path)) + const char *path = git_path(NOTES_MERGE_WORKTREE "/%s", sha1_to_hex(obj)); + if (safe_create_leading_directories_const(path)) die_errno("unable to create directory for '%s'", path); if (file_exists(path)) die("found existing file at '%s'", path); @@ -41,7 +41,8 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle) len = strlen(str); for (i = 1; i < ARRAY_SIZE(object_type_strings); i++) - if (!strncmp(str, object_type_strings[i], len)) + if (!strncmp(str, object_type_strings[i], len) && + object_type_strings[i][len] == '\0') return i; if (gentle) diff --git a/pack-bitmap.c b/pack-bitmap.c index 365f9d92ed..62a98cc119 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -986,6 +986,8 @@ void test_bitmap_walk(struct rev_info *revs) fprintf(stderr, "OK!\n"); else fprintf(stderr, "Mismatch!\n"); + + free(result); } static int rebuild_bitmap(uint32_t *reposition, @@ -4,6 +4,7 @@ #include "cache.h" #include "strbuf.h" #include "string-list.h" +#include "dir.h" static int get_st_mode_bits(const char *path, int *mode) { @@ -16,11 +17,15 @@ static int get_st_mode_bits(const char *path, int *mode) static char bad_path[] = "/bad-path/"; -static char *get_pathname(void) +static struct strbuf *get_pathname(void) { - static char pathname_array[4][PATH_MAX]; + static struct strbuf pathname_array[4] = { + STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT + }; static int index; - return pathname_array[3 & ++index]; + struct strbuf *sb = &pathname_array[3 & ++index]; + strbuf_reset(sb); + return sb; } static char *cleanup_path(char *path) @@ -34,6 +39,13 @@ static char *cleanup_path(char *path) return path; } +static void strbuf_cleanup_path(struct strbuf *sb) +{ + char *path = cleanup_path(sb->buf); + if (path > sb->buf) + strbuf_remove(sb, 0, path - sb->buf); +} + char *mksnpath(char *buf, size_t n, const char *fmt, ...) { va_list args; @@ -49,85 +61,167 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...) return cleanup_path(buf); } -static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args) +static int dir_prefix(const char *buf, const char *dir) { - const char *git_dir = get_git_dir(); - size_t len; + int len = strlen(dir); + return !strncmp(buf, dir, len) && + (is_dir_sep(buf[len]) || buf[len] == '\0'); +} - len = strlen(git_dir); - if (n < len + 1) - goto bad; - memcpy(buf, git_dir, len); - if (len && !is_dir_sep(git_dir[len-1])) - buf[len++] = '/'; - len += vsnprintf(buf + len, n - len, fmt, args); - if (len >= n) - goto bad; - return cleanup_path(buf); -bad: - strlcpy(buf, bad_path, n); - return buf; +/* $buf =~ m|$dir/+$file| but without regex */ +static int is_dir_file(const char *buf, const char *dir, const char *file) +{ + int len = strlen(dir); + if (strncmp(buf, dir, len) || !is_dir_sep(buf[len])) + return 0; + while (is_dir_sep(buf[len])) + len++; + return !strcmp(buf + len, file); +} + +static void replace_dir(struct strbuf *buf, int len, const char *newdir) +{ + int newlen = strlen(newdir); + int need_sep = (buf->buf[len] && !is_dir_sep(buf->buf[len])) && + !is_dir_sep(newdir[newlen - 1]); + if (need_sep) + len--; /* keep one char, to be replaced with '/' */ + strbuf_splice(buf, 0, len, newdir, newlen); + if (need_sep) + buf->buf[newlen] = '/'; +} + +static const char *common_list[] = { + "/branches", "/hooks", "/info", "!/logs", "/lost-found", + "/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn", + "config", "!gc.pid", "packed-refs", "shallow", + NULL +}; + +static void update_common_dir(struct strbuf *buf, int git_dir_len) +{ + char *base = buf->buf + git_dir_len; + const char **p; + + if (is_dir_file(base, "logs", "HEAD") || + is_dir_file(base, "info", "sparse-checkout")) + return; /* keep this in $GIT_DIR */ + for (p = common_list; *p; p++) { + const char *path = *p; + int is_dir = 0; + if (*path == '!') + path++; + if (*path == '/') { + path++; + is_dir = 1; + } + if (is_dir && dir_prefix(base, path)) { + replace_dir(buf, git_dir_len, get_git_common_dir()); + return; + } + if (!is_dir && !strcmp(base, path)) { + replace_dir(buf, git_dir_len, get_git_common_dir()); + return; + } + } +} + +void report_linked_checkout_garbage(void) +{ + struct strbuf sb = STRBUF_INIT; + const char **p; + int len; + + if (!git_common_dir_env) + return; + strbuf_addf(&sb, "%s/", get_git_dir()); + len = sb.len; + for (p = common_list; *p; p++) { + const char *path = *p; + if (*path == '!') + continue; + strbuf_setlen(&sb, len); + strbuf_addstr(&sb, path); + if (file_exists(sb.buf)) + report_garbage("unused in linked checkout", sb.buf); + } + strbuf_release(&sb); +} + +static void adjust_git_path(struct strbuf *buf, int git_dir_len) +{ + const char *base = buf->buf + git_dir_len; + if (git_graft_env && is_dir_file(base, "info", "grafts")) + strbuf_splice(buf, 0, buf->len, + get_graft_file(), strlen(get_graft_file())); + else if (git_index_env && !strcmp(base, "index")) + strbuf_splice(buf, 0, buf->len, + get_index_file(), strlen(get_index_file())); + else if (git_db_env && dir_prefix(base, "objects")) + replace_dir(buf, git_dir_len + 7, get_object_directory()); + else if (git_common_dir_env) + update_common_dir(buf, git_dir_len); +} + +static void do_git_path(struct strbuf *buf, const char *fmt, va_list args) +{ + int gitdir_len; + strbuf_addstr(buf, get_git_dir()); + if (buf->len && !is_dir_sep(buf->buf[buf->len - 1])) + strbuf_addch(buf, '/'); + gitdir_len = buf->len; + strbuf_vaddf(buf, fmt, args); + adjust_git_path(buf, gitdir_len); + strbuf_cleanup_path(buf); } -char *git_snpath(char *buf, size_t n, const char *fmt, ...) +void strbuf_git_path(struct strbuf *sb, const char *fmt, ...) { - char *ret; va_list args; va_start(args, fmt); - ret = vsnpath(buf, n, fmt, args); + do_git_path(sb, fmt, args); va_end(args); - return ret; } -char *git_pathdup(const char *fmt, ...) +const char *git_path(const char *fmt, ...) { - char path[PATH_MAX], *ret; + struct strbuf *pathname = get_pathname(); va_list args; va_start(args, fmt); - ret = vsnpath(path, sizeof(path), fmt, args); + do_git_path(pathname, fmt, args); va_end(args); - return xstrdup(ret); + return pathname->buf; } -char *mkpathdup(const char *fmt, ...) +char *git_pathdup(const char *fmt, ...) { - char *path; - struct strbuf sb = STRBUF_INIT; + struct strbuf path = STRBUF_INIT; va_list args; - va_start(args, fmt); - strbuf_vaddf(&sb, fmt, args); + do_git_path(&path, fmt, args); va_end(args); - path = xstrdup(cleanup_path(sb.buf)); - - strbuf_release(&sb); - return path; + return strbuf_detach(&path, NULL); } -char *mkpath(const char *fmt, ...) +char *mkpathdup(const char *fmt, ...) { + struct strbuf sb = STRBUF_INIT; va_list args; - unsigned len; - char *pathname = get_pathname(); - va_start(args, fmt); - len = vsnprintf(pathname, PATH_MAX, fmt, args); + strbuf_vaddf(&sb, fmt, args); va_end(args); - if (len >= PATH_MAX) - return bad_path; - return cleanup_path(pathname); + strbuf_cleanup_path(&sb); + return strbuf_detach(&sb, NULL); } -char *git_path(const char *fmt, ...) +const char *mkpath(const char *fmt, ...) { - char *pathname = get_pathname(); va_list args; - char *ret; - + struct strbuf *pathname = get_pathname(); va_start(args, fmt); - ret = vsnpath(pathname, PATH_MAX, fmt, args); + strbuf_vaddf(pathname, fmt, args); va_end(args); - return ret; + return cleanup_path(pathname->buf); } void home_config_paths(char **global, char **xdg, char *file) @@ -158,43 +252,29 @@ void home_config_paths(char **global, char **xdg, char *file) free(to_free); } -char *git_path_submodule(const char *path, const char *fmt, ...) +const char *git_path_submodule(const char *path, const char *fmt, ...) { - char *pathname = get_pathname(); - struct strbuf buf = STRBUF_INIT; + struct strbuf *buf = get_pathname(); const char *git_dir; va_list args; - unsigned len; - len = strlen(path); - if (len > PATH_MAX-100) - return bad_path; + strbuf_addstr(buf, path); + if (buf->len && buf->buf[buf->len - 1] != '/') + strbuf_addch(buf, '/'); + strbuf_addstr(buf, ".git"); - strbuf_addstr(&buf, path); - if (len && path[len-1] != '/') - strbuf_addch(&buf, '/'); - strbuf_addstr(&buf, ".git"); - - git_dir = read_gitfile(buf.buf); + git_dir = read_gitfile(buf->buf); if (git_dir) { - strbuf_reset(&buf); - strbuf_addstr(&buf, git_dir); + strbuf_reset(buf); + strbuf_addstr(buf, git_dir); } - strbuf_addch(&buf, '/'); - - if (buf.len >= PATH_MAX) - return bad_path; - memcpy(pathname, buf.buf, buf.len + 1); - - strbuf_release(&buf); - len = strlen(pathname); + strbuf_addch(buf, '/'); va_start(args, fmt); - len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args); + strbuf_vaddf(buf, fmt, args); va_end(args); - if (len >= PATH_MAX) - return bad_path; - return cleanup_path(pathname); + strbuf_cleanup_path(buf); + return buf->buf; } int validate_headref(const char *path) diff --git a/progress.c b/progress.c index 412e6b1ecc..43d9228378 100644 --- a/progress.c +++ b/progress.c @@ -72,6 +72,11 @@ static void clear_progress_signal(void) progress_update = 0; } +static int is_foreground_fd(int fd) +{ + return getpgid(0) == tcgetpgrp(fd); +} + static int display(struct progress *progress, unsigned n, const char *done) { const char *eol, *tp; @@ -98,16 +103,21 @@ static int display(struct progress *progress, unsigned n, const char *done) unsigned percent = n * 100 / progress->total; if (percent != progress->last_percent || progress_update) { progress->last_percent = percent; - fprintf(stderr, "%s: %3u%% (%u/%u)%s%s", - progress->title, percent, n, - progress->total, tp, eol); - fflush(stderr); + if (is_foreground_fd(fileno(stderr)) || done) { + fprintf(stderr, "%s: %3u%% (%u/%u)%s%s", + progress->title, percent, n, + progress->total, tp, eol); + fflush(stderr); + } progress_update = 0; return 1; } } else if (progress_update) { - fprintf(stderr, "%s: %u%s%s", progress->title, n, tp, eol); - fflush(stderr); + if (is_foreground_fd(fileno(stderr)) || done) { + fprintf(stderr, "%s: %u%s%s", + progress->title, n, tp, eol); + fflush(stderr); + } progress_update = 0; return 1; } diff --git a/reachable.c b/reachable.c index a647267ae9..69fa6851da 100644 --- a/reachable.c +++ b/reachable.c @@ -142,10 +142,12 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs, data.revs = revs; data.timestamp = timestamp; - r = for_each_loose_object(add_recent_loose, &data); + r = for_each_loose_object(add_recent_loose, &data, + FOR_EACH_OBJECT_LOCAL_ONLY); if (r) return r; - return for_each_packed_object(add_recent_packed, &data); + return for_each_packed_object(add_recent_packed, &data, + FOR_EACH_OBJECT_LOCAL_ONLY); } void mark_reachable_objects(struct rev_info *revs, int mark_reflog, @@ -344,8 +344,6 @@ static struct ref_entry *create_ref_entry(const char *refname, if (check_name && check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) die("Reference has invalid format: '%s'", refname); - if (!check_name && !refname_is_safe(refname)) - die("Reference has invalid name: '%s'", refname); len = strlen(refname) + 1; ref = xmalloc(sizeof(struct ref_entry) + len); hashcpy(ref->u.value.sha1, sha1); @@ -1178,6 +1176,8 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir) int flag = REF_ISPACKED; if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { + if (!refname_is_safe(refname)) + die("packed refname is dangerous: %s", refname); hashclr(sha1); flag |= REF_BAD_NAME | REF_ISBROKEN; } @@ -1323,6 +1323,8 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir) } if (check_refname_format(refname.buf, REFNAME_ALLOW_ONELEVEL)) { + if (!refname_is_safe(refname.buf)) + die("loose refname is dangerous: %s", refname.buf); hashclr(sha1); flag |= REF_BAD_NAME | REF_ISBROKEN; } @@ -1382,7 +1384,7 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs, { int fd, len; char buffer[128], *p; - char *path; + const char *path; if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN) return -1; @@ -1475,7 +1477,11 @@ static int resolve_missing_loose_ref(const char *refname, } /* This function needs to return a meaningful errno on failure */ -const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned char *sha1, int *flags) +static const char *resolve_ref_unsafe_1(const char *refname, + int resolve_flags, + unsigned char *sha1, + int *flags, + struct strbuf *sb_path) { int depth = MAXDEPTH; ssize_t len; @@ -1506,7 +1512,7 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned bad_name = 1; } for (;;) { - char path[PATH_MAX]; + const char *path; struct stat st; char *buf; int fd; @@ -1516,7 +1522,9 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned return NULL; } - git_snpath(path, sizeof(path), "%s", refname); + strbuf_reset(sb_path); + strbuf_git_path(sb_path, "%s", refname); + path = sb_path->buf; /* * We might have to loop back here to avoid a race @@ -1643,6 +1651,16 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned } } +const char *resolve_ref_unsafe(const char *refname, int resolve_flags, + unsigned char *sha1, int *flags) +{ + struct strbuf sb_path = STRBUF_INIT; + const char *ret = resolve_ref_unsafe_1(refname, resolve_flags, + sha1, flags, &sb_path); + strbuf_release(&sb_path); + return ret; +} + char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags) { return xstrdup_or_null(resolve_ref_unsafe(ref, resolve_flags, sha1, flags)); @@ -2274,7 +2292,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, const struct string_list *skip, unsigned int flags, int *type_p) { - char *ref_file; + const char *ref_file; const char *orig_refname = refname; struct ref_lock *lock; int last_errno = 0; @@ -2343,7 +2361,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, ref_file = git_path("%s", refname); retry: - switch (safe_create_leading_directories(ref_file)) { + switch (safe_create_leading_directories_const(ref_file)) { case SCLD_OK: break; /* success */ case SCLD_VANISHED: @@ -2721,7 +2739,7 @@ static int rename_tmp_log(const char *newrefname) int attempts_remaining = 4; retry: - switch (safe_create_leading_directories(git_path("logs/%s", newrefname))) { + switch (safe_create_leading_directories_const(git_path("logs/%s", newrefname))) { case SCLD_OK: break; /* success */ case SCLD_VANISHED: @@ -2907,11 +2925,15 @@ static int copy_msg(char *buf, const char *msg) } /* This function must set a meaningful errno on failure */ -int log_ref_setup(const char *refname, char *logfile, int bufsize) +int log_ref_setup(const char *refname, struct strbuf *sb_logfile) { int logfd, oflags = O_APPEND | O_WRONLY; + char *logfile; - git_snpath(logfile, bufsize, "logs/%s", refname); + strbuf_git_path(sb_logfile, "logs/%s", refname); + logfile = sb_logfile->buf; + /* make sure the rest of the function can't change "logfile" */ + sb_logfile = NULL; if (log_all_ref_updates && (starts_with(refname, "refs/heads/") || starts_with(refname, "refs/remotes/") || @@ -2982,18 +3004,22 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1, return 0; } -static int log_ref_write(const char *refname, const unsigned char *old_sha1, - const unsigned char *new_sha1, const char *msg) +static int log_ref_write_1(const char *refname, const unsigned char *old_sha1, + const unsigned char *new_sha1, const char *msg, + struct strbuf *sb_log_file) { int logfd, result, oflags = O_APPEND | O_WRONLY; - char log_file[PATH_MAX]; + char *log_file; if (log_all_ref_updates < 0) log_all_ref_updates = !is_bare_repository(); - result = log_ref_setup(refname, log_file, sizeof(log_file)); + result = log_ref_setup(refname, sb_log_file); if (result) return result; + log_file = sb_log_file->buf; + /* make sure the rest of the function can't change "log_file" */ + sb_log_file = NULL; logfd = open(log_file, oflags); if (logfd < 0) @@ -3016,6 +3042,15 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1, return 0; } +static int log_ref_write(const char *refname, const unsigned char *old_sha1, + const unsigned char *new_sha1, const char *msg) +{ + struct strbuf sb = STRBUF_INIT; + int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb); + strbuf_release(&sb); + return ret; +} + int is_branch(const char *refname) { return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/"); @@ -191,7 +191,7 @@ extern int peel_ref(const char *refname, unsigned char *sha1); /* * Setup reflog before using. Set errno to something meaningful on failure. */ -int log_ref_setup(const char *refname, char *logfile, int bufsize); +int log_ref_setup(const char *refname, struct strbuf *logfile); /** Reads log for the value of ref during at_time. **/ extern int read_ref_at(const char *refname, unsigned int flags, diff --git a/revision.c b/revision.c index 6399a0412c..7ddbaa083e 100644 --- a/revision.c +++ b/revision.c @@ -345,14 +345,24 @@ static struct commit *handle_commit(struct rev_info *revs, die("%s is unknown object", name); } -static int everybody_uninteresting(struct commit_list *orig) +static int everybody_uninteresting(struct commit_list *orig, + struct commit **interesting_cache) { struct commit_list *list = orig; + + if (*interesting_cache) { + struct commit *commit = *interesting_cache; + if (!(commit->object.flags & UNINTERESTING)) + return 0; + } + while (list) { struct commit *commit = list->item; list = list->next; if (commit->object.flags & UNINTERESTING) continue; + if (interesting_cache) + *interesting_cache = commit; return 0; } return 1; @@ -940,7 +950,8 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) /* How many extra uninteresting commits we want to see.. */ #define SLOP 5 -static int still_interesting(struct commit_list *src, unsigned long date, int slop) +static int still_interesting(struct commit_list *src, unsigned long date, int slop, + struct commit **interesting_cache) { /* * No source list at all? We're definitely done.. @@ -959,7 +970,7 @@ static int still_interesting(struct commit_list *src, unsigned long date, int sl * Does the source list still have interesting commits in * it? Definitely not done.. */ - if (!everybody_uninteresting(src)) + if (!everybody_uninteresting(src, interesting_cache)) return SLOP; /* Ok, we're closing in.. */ @@ -1078,6 +1089,7 @@ static int limit_list(struct rev_info *revs) struct commit_list *newlist = NULL; struct commit_list **p = &newlist; struct commit_list *bottom = NULL; + struct commit *interesting_cache = NULL; if (revs->ancestry_path) { bottom = collect_bottom_commits(list); @@ -1094,6 +1106,9 @@ static int limit_list(struct rev_info *revs) list = list->next; free(entry); + if (commit == interesting_cache) + interesting_cache = NULL; + if (revs->max_age != -1 && (commit->date < revs->max_age)) obj->flags |= UNINTERESTING; if (add_parents_to_list(revs, commit, &list, NULL) < 0) @@ -1102,7 +1117,7 @@ static int limit_list(struct rev_info *revs) mark_parents_uninteresting(commit); if (revs->show_all) p = &commit_list_insert(commit, p)->next; - slop = still_interesting(list, date, slop); + slop = still_interesting(list, date, slop, &interesting_cache); if (slop) continue; /* If showing all, add the whole pending list to the end */ diff --git a/run-command.c b/run-command.c index aad03ab705..4d73e90fad 100644 --- a/run-command.c +++ b/run-command.c @@ -795,9 +795,9 @@ int finish_async(struct async *async) #endif } -char *find_hook(const char *name) +const char *find_hook(const char *name) { - char *path = git_path("hooks/%s", name); + const char *path = git_path("hooks/%s", name); if (access(path, X_OK) < 0) path = NULL; diff --git a/run-command.h b/run-command.h index 263b9662ad..1103805af1 100644 --- a/run-command.h +++ b/run-command.h @@ -52,7 +52,7 @@ int start_command(struct child_process *); int finish_command(struct child_process *); int run_command(struct child_process *); -extern char *find_hook(const char *name); +extern const char *find_hook(const char *name); LAST_ARG_MUST_BE_NULL extern int run_hook_le(const char *const *env, const char *name, ...); extern int run_hook_ve(const char *const *env, const char *name, va_list args); diff --git a/send-pack.c b/send-pack.c index 189bdde0c2..2a64fec949 100644 --- a/send-pack.c +++ b/send-pack.c @@ -182,7 +182,7 @@ static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *c { struct strbuf *sb = cb; if (graft->nr_parent == -1) - packet_buf_write(sb, "shallow %s\n", sha1_to_hex(graft->sha1)); + packet_buf_write(sb, "shallow %s\n", oid_to_hex(&graft->oid)); return 0; } @@ -308,6 +308,28 @@ static int atomic_push_failure(struct send_pack_args *args, failing_ref->name, failing_ref->status); } +#define NONCE_LEN_LIMIT 256 + +static void reject_invalid_nonce(const char *nonce, int len) +{ + int i = 0; + + if (NONCE_LEN_LIMIT <= len) + die("the receiving end asked to sign an invalid nonce <%.*s>", + len, nonce); + + for (i = 0; i < len; i++) { + int ch = nonce[i] & 0xFF; + if (isalnum(ch) || + ch == '-' || ch == '.' || + ch == '/' || ch == '+' || + ch == '=' || ch == '_') + continue; + die("the receiving end asked to sign an invalid nonce <%.*s>", + len, nonce); + } +} + int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, @@ -354,6 +376,7 @@ int send_pack(struct send_pack_args *args, push_cert_nonce = server_feature_value("push-cert", &len); if (!push_cert_nonce) die(_("the receiving end does not support --signed push")); + reject_invalid_nonce(push_cert_nonce, len); push_cert_nonce = xmemdupz(push_cert_nonce, len); } @@ -224,6 +224,36 @@ void verify_non_filename(const char *prefix, const char *arg) "'git <command> [<revision>...] -- [<file>...]'", arg); } +int get_common_dir(struct strbuf *sb, const char *gitdir) +{ + struct strbuf data = STRBUF_INIT; + struct strbuf path = STRBUF_INIT; + const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT); + int ret = 0; + if (git_common_dir) { + strbuf_addstr(sb, git_common_dir); + return 1; + } + strbuf_addf(&path, "%s/commondir", gitdir); + if (file_exists(path.buf)) { + if (strbuf_read_file(&data, path.buf, 0) <= 0) + die_errno(_("failed to read %s"), path.buf); + while (data.len && (data.buf[data.len - 1] == '\n' || + data.buf[data.len - 1] == '\r')) + data.len--; + data.buf[data.len] = '\0'; + strbuf_reset(&path); + if (!is_absolute_path(data.buf)) + strbuf_addf(&path, "%s/", gitdir); + strbuf_addbuf(&path, &data); + strbuf_addstr(sb, real_path(path.buf)); + ret = 1; + } else + strbuf_addstr(sb, gitdir); + strbuf_release(&data); + strbuf_release(&path); + return ret; +} /* * Test if it looks like we're at a git directory. @@ -238,31 +268,40 @@ void verify_non_filename(const char *prefix, const char *arg) */ int is_git_directory(const char *suspect) { - char path[PATH_MAX]; - size_t len = strlen(suspect); + struct strbuf path = STRBUF_INIT; + int ret = 0; + size_t len; - if (PATH_MAX <= len + strlen("/objects")) - die("Too long path: %.*s", 60, suspect); - strcpy(path, suspect); + /* Check worktree-related signatures */ + strbuf_addf(&path, "%s/HEAD", suspect); + if (validate_headref(path.buf)) + goto done; + + strbuf_reset(&path); + get_common_dir(&path, suspect); + len = path.len; + + /* Check non-worktree-related signatures */ if (getenv(DB_ENVIRONMENT)) { if (access(getenv(DB_ENVIRONMENT), X_OK)) - return 0; + goto done; } else { - strcpy(path + len, "/objects"); - if (access(path, X_OK)) - return 0; + strbuf_setlen(&path, len); + strbuf_addstr(&path, "/objects"); + if (access(path.buf, X_OK)) + goto done; } - strcpy(path + len, "/refs"); - if (access(path, X_OK)) - return 0; - - strcpy(path + len, "/HEAD"); - if (validate_headref(path)) - return 0; + strbuf_setlen(&path, len); + strbuf_addstr(&path, "/refs"); + if (access(path.buf, X_OK)) + goto done; - return 1; + ret = 1; +done: + strbuf_release(&path); + return ret; } int is_inside_git_dir(void) @@ -304,9 +343,28 @@ void setup_work_tree(void) initialized = 1; } +static int check_repo_format(const char *var, const char *value, void *cb) +{ + if (strcmp(var, "core.repositoryformatversion") == 0) + repository_format_version = git_config_int(var, value); + else if (strcmp(var, "core.sharedrepository") == 0) + shared_repository = git_config_perm(var, value); + return 0; +} + static int check_repository_format_gently(const char *gitdir, int *nongit_ok) { - char repo_config[PATH_MAX+1]; + struct strbuf sb = STRBUF_INIT; + const char *repo_config; + config_fn_t fn; + int ret = 0; + + if (get_common_dir(&sb, gitdir)) + fn = check_repo_format; + else + fn = check_repository_format_version; + strbuf_addstr(&sb, "/config"); + repo_config = sb.buf; /* * git_config() can't be used here because it calls git_pathdup() @@ -317,8 +375,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok) * Use a gentler version of git_config() to check if this repo * is a good one. */ - snprintf(repo_config, PATH_MAX, "%s/config", gitdir); - git_config_early(check_repository_format_version, NULL, repo_config); + git_config_early(fn, NULL, repo_config); if (GIT_REPO_VERSION < repository_format_version) { if (!nongit_ok) die ("Expected git repo version <= %d, found %d", @@ -327,9 +384,21 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok) GIT_REPO_VERSION, repository_format_version); warning("Please upgrade Git"); *nongit_ok = -1; - return -1; + ret = -1; } - return 0; + strbuf_release(&sb); + 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/gitfile", gitdir); + if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL)) + write_file(path.buf, 0, "%s\n", gitfile); + strbuf_release(&path); } /* @@ -380,6 +449,8 @@ const char *read_gitfile(const char *path) if (!is_git_directory(dir)) die("Not a git repository: %s", dir); + + update_linked_gitdir(path, dir); path = real_path(dir); free(buf); @@ -799,11 +870,10 @@ int git_config_perm(const char *var, const char *value) int check_repository_format_version(const char *var, const char *value, void *cb) { - if (strcmp(var, "core.repositoryformatversion") == 0) - repository_format_version = git_config_int(var, value); - else if (strcmp(var, "core.sharedrepository") == 0) - shared_repository = git_config_perm(var, value); - else if (strcmp(var, "core.bare") == 0) { + int ret = check_repo_format(var, value, cb); + if (ret) + return ret; + if (strcmp(var, "core.bare") == 0) { is_bare_repository_cfg = git_config_bool(var, value); if (is_bare_repository_cfg == 1) inside_work_tree = -1; diff --git a/sha1_file.c b/sha1_file.c index 88f06bac92..7634917e4e 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -405,7 +405,7 @@ void add_to_alternates_file(const char *reference) { struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR); - char *alt = mkpath("%s\n", reference); + const char *alt = mkpath("%s\n", reference); write_or_die(fd, alt, strlen(alt)); if (commit_lock_file(lock)) die("could not close alternates file"); @@ -2473,10 +2473,8 @@ static int fill_pack_entry(const unsigned char *sha1, * answer, as it may have been deleted since the index was * loaded! */ - if (!is_pack_valid(p)) { - warning("packfile %s cannot be accessed", p->pack_name); + if (!is_pack_valid(p)) return 0; - } e->offset = offset; e->p = p; hashcpy(e->sha1, sha1); @@ -2999,7 +2997,14 @@ static int freshen_loose_object(const unsigned char *sha1) static int freshen_packed_object(const unsigned char *sha1) { struct pack_entry e; - return find_pack_entry(sha1, &e) && freshen_file(e.p->pack_name); + if (!find_pack_entry(sha1, &e)) + return 0; + if (e.p->freshened) + return 1; + if (!freshen_file(e.p->pack_name)) + return 0; + e.p->freshened = 1; + return 1; } int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1) @@ -3014,7 +3019,7 @@ int write_sha1_file(const void *buf, unsigned long len, const char *type, unsign write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen); if (returnsha1) hashcpy(returnsha1, sha1); - if (freshen_loose_object(sha1) || freshen_packed_object(sha1)) + if (freshen_packed_object(sha1) || freshen_loose_object(sha1)) return 0; return write_loose_object(sha1, hdr, hdrlen, buf, len, 0); } @@ -3418,7 +3423,7 @@ static int loose_from_alt_odb(struct alternate_object_database *alt, return r; } -int for_each_loose_object(each_loose_object_fn cb, void *data) +int for_each_loose_object(each_loose_object_fn cb, void *data, unsigned flags) { struct loose_alt_odb_data alt; int r; @@ -3428,6 +3433,9 @@ int for_each_loose_object(each_loose_object_fn cb, void *data) if (r) return r; + if (flags & FOR_EACH_OBJECT_LOCAL_ONLY) + return 0; + alt.cb = cb; alt.data = data; return foreach_alt_odb(loose_from_alt_odb, &alt); @@ -3452,13 +3460,15 @@ static int for_each_object_in_pack(struct packed_git *p, each_packed_object_fn c return r; } -int for_each_packed_object(each_packed_object_fn cb, void *data) +int for_each_packed_object(each_packed_object_fn cb, void *data, unsigned flags) { struct packed_git *p; int r = 0; prepare_packed_git(); for (p = packed_git; p; p = p->next) { + if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local) + continue; r = for_each_object_in_pack(p, cb, data); if (r) break; @@ -31,7 +31,7 @@ int register_shallow(const unsigned char *sha1) xmalloc(sizeof(struct commit_graft)); struct commit *commit = lookup_commit(sha1); - hashcpy(graft->sha1, sha1); + hashcpy(graft->oid.hash, sha1); graft->nr_parent = -1; if (commit && commit->object.parsed) commit->parents = NULL; @@ -159,11 +159,11 @@ struct write_shallow_data { static int write_one_shallow(const struct commit_graft *graft, void *cb_data) { struct write_shallow_data *data = cb_data; - const char *hex = sha1_to_hex(graft->sha1); + const char *hex = oid_to_hex(&graft->oid); if (graft->nr_parent != -1) return 0; if (data->flags & SEEN_ONLY) { - struct commit *c = lookup_commit(graft->sha1); + struct commit *c = lookup_commit(graft->oid.hash); if (!c || !(c->object.flags & SEEN)) { if (data->flags & VERBOSE) printf("Removing %s from .git/shallow\n", @@ -282,7 +282,7 @@ static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *c { int fd = *(int *)cb; if (graft->nr_parent == -1) - packet_write(fd, "shallow %s\n", sha1_to_hex(graft->sha1)); + packet_write(fd, "shallow %s\n", oid_to_hex(&graft->oid)); return 0; } @@ -435,6 +435,47 @@ int strbuf_getcwd(struct strbuf *sb) return -1; } +#ifdef HAVE_GETDELIM +int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) +{ + ssize_t r; + + if (feof(fp)) + return EOF; + + strbuf_reset(sb); + + /* Translate slopbuf to NULL, as we cannot call realloc on it */ + if (!sb->alloc) + sb->buf = NULL; + r = getdelim(&sb->buf, &sb->alloc, term, fp); + + if (r > 0) { + sb->len = r; + return 0; + } + assert(r == -1); + + /* + * Normally we would have called xrealloc, which will try to free + * memory and recover. But we have no way to tell getdelim() to do so. + * Worse, we cannot try to recover ENOMEM ourselves, because we have + * no idea how many bytes were read by getdelim. + * + * Dying here is reasonable. It mirrors what xrealloc would do on + * catastrophic memory failure. We skip the opportunity to free pack + * memory and retry, but that's unlikely to help for a malloc small + * enough to hold a single line of input, anyway. + */ + if (errno == ENOMEM) + die("Out of memory, getdelim failed"); + + /* Restore slopbuf that we moved out of the way before */ + if (!sb->buf) + strbuf_init(sb, 0); + return EOF; +} +#else int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) { int ch; @@ -443,18 +484,22 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) return EOF; strbuf_reset(sb); - while ((ch = fgetc(fp)) != EOF) { - strbuf_grow(sb, 1); + flockfile(fp); + while ((ch = getc_unlocked(fp)) != EOF) { + if (!strbuf_avail(sb)) + strbuf_grow(sb, 1); sb->buf[sb->len++] = ch; if (ch == term) break; } + funlockfile(fp); if (ch == EOF && sb->len == 0) return EOF; sb->buf[sb->len] = '\0'; return 0; } +#endif int strbuf_getline(struct strbuf *sb, FILE *fp, int term) { @@ -205,7 +205,8 @@ extern int strbuf_cmp(const struct strbuf *, const struct strbuf *); */ static inline void strbuf_addch(struct strbuf *sb, int c) { - strbuf_grow(sb, 1); + if (!strbuf_avail(sb)) + strbuf_grow(sb, 1); sb->buf[sb->len++] = c; sb->buf[sb->len] = '\0'; } diff --git a/submodule.c b/submodule.c index c0e6c81fc4..d491e6a771 100644 --- a/submodule.c +++ b/submodule.c @@ -1100,16 +1100,11 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir) struct strbuf file_name = STRBUF_INIT; struct strbuf rel_path = STRBUF_INIT; const char *real_work_tree = xstrdup(real_path(work_tree)); - FILE *fp; /* Update gitfile */ strbuf_addf(&file_name, "%s/.git", work_tree); - fp = fopen(file_name.buf, "w"); - if (!fp) - die(_("Could not create git link %s"), file_name.buf); - fprintf(fp, "gitdir: %s\n", relative_path(git_dir, real_work_tree, - &rel_path)); - fclose(fp); + write_file(file_name.buf, 1, "gitdir: %s\n", + relative_path(git_dir, real_work_tree, &rel_path)); /* Update core.worktree setting */ strbuf_reset(&file_name); diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index c0143a0a70..93605f42f2 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -19,6 +19,14 @@ relative_path() { "test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'" } +test_git_path() { + test_expect_success "git-path $1 $2 => $3" " + $1 git rev-parse --git-path $2 >actual && + echo $3 >expect && + test_cmp expect actual + " +} + # On Windows, we are using MSYS's bash, which mangles the paths. # Absolute paths are anchored at the MSYS installation directory, # which means that the path / accounts for this many characters: @@ -244,4 +252,32 @@ relative_path "<null>" "<empty>" ./ relative_path "<null>" "<null>" ./ relative_path "<null>" /foo/a/b ./ +test_git_path A=B info/grafts .git/info/grafts +test_git_path GIT_GRAFT_FILE=foo info/grafts foo +test_git_path GIT_GRAFT_FILE=foo info/////grafts foo +test_git_path GIT_INDEX_FILE=foo index foo +test_git_path GIT_INDEX_FILE=foo index/foo .git/index/foo +test_git_path GIT_INDEX_FILE=foo index2 .git/index2 +test_expect_success 'setup fake objects directory foo' 'mkdir foo' +test_git_path GIT_OBJECT_DIRECTORY=foo objects foo +test_git_path GIT_OBJECT_DIRECTORY=foo objects/foo foo/foo +test_git_path GIT_OBJECT_DIRECTORY=foo objects2 .git/objects2 +test_expect_success 'setup common repository' 'git --git-dir=bar init' +test_git_path GIT_COMMON_DIR=bar index .git/index +test_git_path GIT_COMMON_DIR=bar HEAD .git/HEAD +test_git_path GIT_COMMON_DIR=bar logs/HEAD .git/logs/HEAD +test_git_path GIT_COMMON_DIR=bar objects bar/objects +test_git_path GIT_COMMON_DIR=bar objects/bar bar/objects/bar +test_git_path GIT_COMMON_DIR=bar info/exclude bar/info/exclude +test_git_path GIT_COMMON_DIR=bar info/grafts bar/info/grafts +test_git_path GIT_COMMON_DIR=bar info/sparse-checkout .git/info/sparse-checkout +test_git_path GIT_COMMON_DIR=bar remotes/bar bar/remotes/bar +test_git_path GIT_COMMON_DIR=bar branches/bar bar/branches/bar +test_git_path GIT_COMMON_DIR=bar logs/refs/heads/master bar/logs/refs/heads/master +test_git_path GIT_COMMON_DIR=bar refs/heads/master bar/refs/heads/master +test_git_path GIT_COMMON_DIR=bar hooks/me bar/hooks/me +test_git_path GIT_COMMON_DIR=bar config bar/config +test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs +test_git_path GIT_COMMON_DIR=bar shallow bar/shallow + test_done diff --git a/t/t0302-credential-store.sh b/t/t0302-credential-store.sh index f61b40c69b..0979df93a1 100755 --- a/t/t0302-credential-store.sh +++ b/t/t0302-credential-store.sh @@ -6,4 +6,118 @@ test_description='credential-store tests' helper_test store +test_expect_success 'when xdg file does not exist, xdg file not created' ' + test_path_is_missing "$HOME/.config/git/credentials" && + test -s "$HOME/.git-credentials" +' + +test_expect_success 'setup xdg file' ' + rm -f "$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + >"$HOME/.config/git/credentials" +' + +helper_test store + +test_expect_success 'when xdg file exists, home file not created' ' + test -s "$HOME/.config/git/credentials" && + test_path_is_missing "$HOME/.git-credentials" +' + +test_expect_success 'setup custom xdg file' ' + rm -f "$HOME/.git-credentials" && + rm -f "$HOME/.config/git/credentials" && + mkdir -p "$HOME/xdg/git" && + >"$HOME/xdg/git/credentials" +' + +XDG_CONFIG_HOME="$HOME/xdg" +export XDG_CONFIG_HOME +helper_test store +unset XDG_CONFIG_HOME + +test_expect_success 'if custom xdg file exists, home and xdg files not created' ' + test_when_finished "rm -f $HOME/xdg/git/credentials" && + test -s "$HOME/xdg/git/credentials" && + test_path_is_missing "$HOME/.git-credentials" && + test_path_is_missing "$HOME/.config/git/credentials" +' + +test_expect_success 'get: use home file if both home and xdg files have matches' ' + echo "https://home-user:home-pass@example.com" >"$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + echo "https://xdg-user:xdg-pass@example.com" >"$HOME/.config/git/credentials" && + check fill store <<-\EOF + protocol=https + host=example.com + -- + protocol=https + host=example.com + username=home-user + password=home-pass + -- + EOF +' + +test_expect_success 'get: use xdg file if home file has no matches' ' + >"$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + echo "https://xdg-user:xdg-pass@example.com" >"$HOME/.config/git/credentials" && + check fill store <<-\EOF + protocol=https + host=example.com + -- + protocol=https + host=example.com + username=xdg-user + password=xdg-pass + -- + EOF +' + +test_expect_success POSIXPERM 'get: use xdg file if home file is unreadable' ' + echo "https://home-user:home-pass@example.com" >"$HOME/.git-credentials" && + chmod -r "$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + echo "https://xdg-user:xdg-pass@example.com" >"$HOME/.config/git/credentials" && + check fill store <<-\EOF + protocol=https + host=example.com + -- + protocol=https + host=example.com + username=xdg-user + password=xdg-pass + -- + EOF +' + +test_expect_success 'store: if both xdg and home files exist, only store in home file' ' + >"$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + >"$HOME/.config/git/credentials" && + check approve store <<-\EOF && + protocol=https + host=example.com + username=store-user + password=store-pass + EOF + echo "https://store-user:store-pass@example.com" >expected && + test_cmp expected "$HOME/.git-credentials" && + test_must_be_empty "$HOME/.config/git/credentials" +' + + +test_expect_success 'erase: erase matching credentials from both xdg and home files' ' + echo "https://home-user:home-pass@example.com" >"$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + echo "https://xdg-user:xdg-pass@example.com" >"$HOME/.config/git/credentials" && + check reject store <<-\EOF && + protocol=https + host=example.com + EOF + test_must_be_empty "$HOME/.git-credentials" && + test_must_be_empty "$HOME/.config/git/credentials" +' + test_done diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index f83df8eb8b..ebb3a69c8c 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -201,4 +201,12 @@ test_expect_success 'corrupt tag' ' test_must_fail git hash-object -t tag --stdin </dev/null ' +test_expect_success 'hash-object complains about bogus type name' ' + test_must_fail git hash-object -t bogus --stdin </dev/null +' + +test_expect_success 'hash-object complains about truncated type name' ' + test_must_fail git hash-object -t bl --stdin </dev/null +' + test_done diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh index 468e85621a..16d0b8bd1a 100755 --- a/t/t1430-bad-ref-name.sh +++ b/t/t1430-bad-ref-name.sh @@ -68,6 +68,14 @@ test_expect_success 'branch -D cannot delete non-ref in .git dir' ' test_cmp expect .git/my-private-file ' +test_expect_success 'branch -D cannot delete ref in .git dir' ' + git rev-parse HEAD >.git/my-private-file && + git rev-parse HEAD >expect && + git branch foo/legit && + test_must_fail git branch -D foo////./././../../../my-private-file && + test_cmp expect .git/my-private-file +' + test_expect_success 'branch -D cannot delete absolute path' ' git branch -f extra && test_must_fail git branch -D "$(pwd)/.git/refs/heads/extra" && diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index 8f36aa9fc4..cc5b870e58 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -346,4 +346,81 @@ test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' test_cmp expected actual ' +test_expect_success 'Multi-worktree setup' ' + mkdir work && + mkdir -p repo.git/repos/foo && + cp repo.git/HEAD repo.git/index repo.git/repos/foo && + test_might_fail cp repo.git/sharedindex.* repo.git/repos/foo && + sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE +' + +test_expect_success 'GIT_DIR set (1)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'GIT_DIR set (2)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'Auto discovery' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data1 && + git add data1 && + git ls-files --full-name :/ | grep data1 >actual && + echo work/data1 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_DIR/common overrides core.worktree' ' + mkdir elsewhere && + git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" && + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data2 && + git add data2 && + git ls-files --full-name :/ | grep data2 >actual && + echo work/data2 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + echo haha >data3 && + git --git-dir=../.git --work-tree=. add data3 && + git ls-files --full-name -- :/ | grep data3 >actual && + echo data3 >expect && + test_cmp expect actual + ) +' + test_done diff --git a/t/t1509/prepare-chroot.sh b/t/t1509/prepare-chroot.sh index 62691172e3..6d47e2c725 100755 --- a/t/t1509/prepare-chroot.sh +++ b/t/t1509/prepare-chroot.sh @@ -14,25 +14,45 @@ xmkdir() { R="$1" +[ "$(id -u)" -eq 0 ] && die "This script should not be run as root, what if it does rm -rf /?" [ -n "$R" ] || die "usage: prepare-chroot.sh <root>" [ -x git ] || die "This script needs to be executed at git source code's top directory" -[ -x /bin/busybox ] || die "You need busybox" +if [ -x /bin/busybox ]; then + BB=/bin/busybox +elif [ -x /usr/bin/busybox ]; then + BB=/usr/bin/busybox +else + die "You need busybox" +fi xmkdir "$R" "$R/bin" "$R/etc" "$R/lib" "$R/dev" -[ -c "$R/dev/null" ] || die "/dev/null is missing. Do mknod $R/dev/null c 1 3 && chmod 666 $R/dev/null" +touch "$R/dev/null" echo "root:x:0:0:root:/:/bin/sh" > "$R/etc/passwd" echo "$(id -nu):x:$(id -u):$(id -g)::$(pwd)/t:/bin/sh" >> "$R/etc/passwd" echo "root::0:root" > "$R/etc/group" echo "$(id -ng)::$(id -g):$(id -nu)" >> "$R/etc/group" -[ -x "$R/bin/busybox" ] || cp /bin/busybox "$R/bin/busybox" -[ -x "$R/bin/sh" ] || ln -s /bin/busybox "$R/bin/sh" -[ -x "$R/bin/su" ] || ln -s /bin/busybox "$R/bin/su" +[ -x "$R$BB" ] || cp $BB "$R/bin/busybox" +for cmd in sh su ls expr tr basename rm mkdir mv id uname dirname cat true sed diff; do + ln -f -s /bin/busybox "$R/bin/$cmd" +done mkdir -p "$R$(pwd)" rsync --exclude-from t/t1509/excludes -Ha . "$R$(pwd)" -ldd git | grep '/' | sed 's,.*\s\(/[^ ]*\).*,\1,' | while read i; do - mkdir -p "$R$(dirname $i)" - cp "$i" "$R/$i" +# Fake perl to reduce dependency, t1509 does not use perl, but some +# env might slip through, see test-lib.sh, unset.*PERL_PATH +sed 's|^PERL_PATH=.*|PERL_PATH=/bin/true|' GIT-BUILD-OPTIONS > "$R$(pwd)/GIT-BUILD-OPTIONS" +for cmd in git $BB;do + ldd $cmd | grep '/' | sed 's,.*\s\(/[^ ]*\).*,\1,' | while read i; do + mkdir -p "$R$(dirname $i)" + cp "$i" "$R/$i" + done done -echo "Execute this in root: 'chroot $R /bin/su - $(id -nu)'" +cat <<EOF +All is set up in $R, execute t1509 with the following commands: + +sudo chroot $R /bin/su - $(id -nu) +IKNOWWHATIAMDOING=YES ./t1509-root-worktree.sh -v -i + +When you are done, simply delete $R to clean up +EOF diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh index e1b2a99f10..33c1a587b3 100755 --- a/t/t1510-repo-setup.sh +++ b/t/t1510-repo-setup.sh @@ -106,6 +106,7 @@ setup_env () { expect () { cat >"$1/expected" <<-EOF setup: git_dir: $2 + setup: git_common_dir: $2 setup: worktree: $3 setup: cwd: $4 setup: prefix: $5 diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh new file mode 100755 index 0000000000..f8e4df4818 --- /dev/null +++ b/t/t2025-checkout-to.sh @@ -0,0 +1,129 @@ +#!/bin/sh + +test_description='test git checkout --to' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit init +' + +test_expect_success 'checkout --to not updating paths' ' + test_must_fail git checkout --to -- init.t +' + +test_expect_success 'checkout --to an existing worktree' ' + mkdir -p existing/subtree && + test_must_fail git checkout --detach --to existing master +' + +test_expect_success 'checkout --to an existing empty worktree' ' + mkdir existing_empty && + git checkout --detach --to existing_empty master +' + +test_expect_success 'checkout --to refuses to checkout locked branch' ' + test_must_fail git checkout --to zere master && + ! test -d zere && + ! test -d .git/worktrees/zere +' + +test_expect_success 'checkout --to a new worktree' ' + git rev-parse HEAD >expect && + git checkout --detach --to here master && + ( + cd here && + test_cmp ../init.t init.t && + test_must_fail git symbolic-ref HEAD && + git rev-parse HEAD >actual && + test_cmp ../expect actual && + git fsck + ) +' + +test_expect_success 'checkout --to a new worktree from a subdir' ' + ( + mkdir sub && + cd sub && + git checkout --detach --to here master && + cd here && + test_cmp ../../init.t init.t + ) +' + +test_expect_success 'checkout --to from a linked checkout' ' + ( + cd here && + git checkout --detach --to nested-here master && + cd nested-here && + git fsck + ) +' + +test_expect_success 'checkout --to a new worktree creating new branch' ' + git checkout --to there -b newmaster master && + ( + cd there && + test_cmp ../init.t init.t && + git symbolic-ref HEAD >actual && + echo refs/heads/newmaster >expect && + test_cmp expect actual && + git fsck + ) +' + +test_expect_success 'die the same branch is already checked out' ' + ( + cd here && + test_must_fail git checkout newmaster + ) +' + +test_expect_success 'not die the same branch is already checked out' ' + ( + cd here && + git checkout --ignore-other-worktrees --to anothernewmaster newmaster + ) +' + +test_expect_success 'not die on re-checking out current branch' ' + ( + cd there && + git checkout newmaster + ) +' + +test_expect_success 'checkout --to from a bare repo' ' + ( + git clone --bare . bare && + cd bare && + git checkout --to ../there2 -b bare-master master + ) +' + +test_expect_success 'checkout from a bare repo without --to' ' + ( + cd bare && + test_must_fail git checkout master + ) +' + +test_expect_success 'checkout with grafts' ' + test_when_finished rm .git/info/grafts && + test_commit abc && + SHA1=`git rev-parse HEAD` && + test_commit def && + test_commit xyz && + echo "`git rev-parse HEAD` $SHA1" >.git/info/grafts && + cat >expected <<-\EOF && + xyz + abc + EOF + git log --format=%s -2 >actual && + test_cmp expected actual && + git checkout --detach --to grafted master && + git --git-dir=grafted/.git log --format=%s -2 >actual && + test_cmp expected actual +' + +test_done diff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh new file mode 100755 index 0000000000..1821a480c5 --- /dev/null +++ b/t/t2026-prune-linked-checkouts.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +test_description='prune $GIT_DIR/worktrees' + +. ./test-lib.sh + +test_expect_success initialize ' + git commit --allow-empty -m init +' + +test_expect_success 'prune --worktrees on normal repo' ' + git prune --worktrees && + test_must_fail git prune --worktrees abc +' + +test_expect_success 'prune files inside $GIT_DIR/worktrees' ' + mkdir .git/worktrees && + : >.git/worktrees/abc && + git prune --worktrees --verbose >actual && + cat >expect <<EOF && +Removing worktrees/abc: not a valid directory +EOF + test_i18ncmp expect actual && + ! test -f .git/worktrees/abc && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories without gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + cat >expect <<EOF && +Removing worktrees/def: gitdir file does not exist +EOF + git prune --worktrees --verbose >actual && + test_i18ncmp expect actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success SANITY 'prune directories with unreadable gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + : >.git/worktrees/def/gitdir && + chmod u-r .git/worktrees/def/gitdir && + git prune --worktrees --verbose >actual && + test_i18ngrep "Removing worktrees/def: unable to read gitdir file" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories with invalid gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + : >.git/worktrees/def/gitdir && + git prune --worktrees --verbose >actual && + test_i18ngrep "Removing worktrees/def: invalid gitdir file" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories with gitdir pointing to nowhere' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir && + git prune --worktrees --verbose >actual && + test_i18ngrep "Removing worktrees/def: gitdir file points to non-existent location" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'not prune locked checkout' ' + test_when_finished rm -r .git/worktrees && + mkdir -p .git/worktrees/ghi && + : >.git/worktrees/ghi/locked && + git prune --worktrees && + test -d .git/worktrees/ghi +' + +test_expect_success 'not prune recent checkouts' ' + test_when_finished rm -r .git/worktrees && + mkdir zz && + mkdir -p .git/worktrees/jlm && + echo "$(pwd)"/zz >.git/worktrees/jlm/gitdir && + rmdir zz && + git prune --worktrees --verbose --expire=2.days.ago && + test -d .git/worktrees/jlm +' + +test_expect_success 'not prune proper checkouts' ' + test_when_finished rm -r .git/worktrees && + git checkout "--to=$PWD/nop" --detach master && + git prune --worktrees && + test -d .git/worktrees/nop +' + +test_done diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 075ece6db1..6eb83211b5 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -55,4 +55,38 @@ test_expect_success 'git diff --no-index executed outside repo gives correct err ) ' +test_expect_success 'diff D F and diff F D' ' + ( + cd repo && + echo in-repo >a && + echo non-repo >../non/git/a && + mkdir sub && + echo sub-repo >sub/a && + + test_must_fail git diff --no-index sub/a ../non/git/a >expect && + test_must_fail git diff --no-index sub/a ../non/git/ >actual && + test_cmp expect actual && + + test_must_fail git diff --no-index a ../non/git/a >expect && + test_must_fail git diff --no-index a ../non/git/ >actual && + test_cmp expect actual && + + test_must_fail git diff --no-index ../non/git/a a >expect && + test_must_fail git diff --no-index ../non/git a >actual && + test_cmp expect actual + ) +' + +test_expect_success 'turning a file into a directory' ' + ( + cd non/git && + mkdir d e e/sub && + echo 1 >d/sub && + echo 2 >e/sub/file && + printf "D\td/sub\nA\te/sub/file\n" >expect && + test_must_fail git diff --no-index --name-status d e >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh index 0901b30982..4451127eb2 100755 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@ -54,14 +54,14 @@ canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset test_bad_opts "-L" "switch.*requires a value" -test_bad_opts "-L b.c" "argument.*not of the form" -test_bad_opts "-L 1:" "argument.*not of the form" +test_bad_opts "-L b.c" "argument not .start,end:file" +test_bad_opts "-L 1:" "argument not .start,end:file" test_bad_opts "-L 1:nonexistent" "There is no path" test_bad_opts "-L 1:simple" "There is no path" -test_bad_opts "-L '/foo:b.c'" "argument.*not of the form" +test_bad_opts "-L '/foo:b.c'" "argument not .start,end:file" test_bad_opts "-L 1000:b.c" "has only.*lines" test_bad_opts "-L 1,1000:b.c" "has only.*lines" -test_bad_opts "-L :b.c" "argument.*not of the form" +test_bad_opts "-L :b.c" "argument not .start,end:file" test_bad_opts "-L :foo:b.c" "no match" test_expect_success '-L X (X == nlines)' ' diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 692d71738b..3a9b77576f 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -576,13 +576,16 @@ do do for h in host user@host user@[::1] user@::1 do - test_expect_success "fetch-pack --diag-url $p://$h/$r" ' - check_prot_host_port_path $p://$h/$r $p "$h" NONE "/$r" - ' - # "/~" -> "~" conversion - test_expect_success "fetch-pack --diag-url $p://$h/~$r" ' - check_prot_host_port_path $p://$h/~$r $p "$h" NONE "~$r" - ' + for c in "" : + do + test_expect_success "fetch-pack --diag-url $p://$h$c/$r" ' + check_prot_host_port_path $p://$h/$r $p "$h" NONE "/$r" + ' + # "/~" -> "~" conversion + test_expect_success "fetch-pack --diag-url $p://$h$c/~$r" ' + check_prot_host_port_path $p://$h/~$r $p "$h" NONE "~$r" + ' + done done for h in host User@host User@[::1] do diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 02b40b117f..1befc453a3 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -387,14 +387,17 @@ do done #with ssh:// scheme -test_expect_success 'clone ssh://host.xz/home/user/repo' ' - test_clone_url "ssh://host.xz/home/user/repo" host.xz "/home/user/repo" -' - -# from home directory -test_expect_success 'clone ssh://host.xz/~repo' ' - test_clone_url "ssh://host.xz/~repo" host.xz "~repo" +#ignore trailing colon +for tcol in "" : +do + test_expect_success "clone ssh://host.xz$tcol/home/user/repo" ' + test_clone_url "ssh://host.xz$tcol/home/user/repo" host.xz /home/user/repo + ' + # from home directory + test_expect_success "clone ssh://host.xz$tcol/~repo" ' + test_clone_url "ssh://host.xz$tcol/~repo" host.xz "~repo" ' +done # with port number test_expect_success 'clone ssh://host.xz:22/home/user/repo' ' @@ -407,9 +410,9 @@ test_expect_success 'clone ssh://host.xz:22/~repo' ' ' #IPv6 -for tuah in ::1 [::1] user@::1 user@[::1] [user@::1] +for tuah in ::1 [::1] [::1]: user@::1 user@[::1] user@[::1]: [user@::1] [user@::1]: do - ehost=$(echo $tuah | tr -d "[]") + ehost=$(echo $tuah | sed -e "s/1]:/1]/ "| tr -d "[]") test_expect_success "clone ssh://$tuah/home/user/repo" " test_clone_url ssh://$tuah/home/user/repo $ehost /home/user/repo " diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh index 460789b4d8..cdc0747bf0 100755 --- a/t/t7061-wtstatus-ignore.sh +++ b/t/t7061-wtstatus-ignore.sh @@ -20,6 +20,15 @@ test_expect_success 'status untracked directory with --ignored' ' test_cmp expected actual ' +test_expect_success 'same with gitignore starting with BOM' ' + printf "\357\273\277ignored\n" >.gitignore && + mkdir -p untracked && + : >untracked/ignored && + : >untracked/uncommitted && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + cat >expected <<\EOF ?? .gitignore ?? actual diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh new file mode 100755 index 0000000000..8f30aed6cc --- /dev/null +++ b/t/t7410-submodule-checkout-to.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +test_description='Combination of submodules and multiple workdirs' + +. ./test-lib.sh + +base_path=$(pwd -P) + +test_expect_success 'setup: make origin' \ + 'mkdir -p origin/sub && ( cd origin/sub && git init && + echo file1 >file1 && + git add file1 && + git commit -m file1 ) && + mkdir -p origin/main && ( cd origin/main && git init && + git submodule add ../sub && + git commit -m "add sub" ) && + ( cd origin/sub && + echo file1updated >file1 && + git add file1 && + git commit -m "file1 updated" ) && + ( cd origin/main/sub && git pull ) && + ( cd origin/main && + git add sub && + git commit -m "sub updated" )' + +test_expect_success 'setup: clone' \ + 'mkdir clone && ( cd clone && + git clone --recursive "$base_path/origin/main")' + +rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q "HEAD~1") +rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1") + +test_expect_success 'checkout main' \ + 'mkdir default_checkout && + (cd clone/main && + git checkout --to "$base_path/default_checkout/main" "$rev1_hash_main")' + +test_expect_failure 'can see submodule diffs just after checkout' \ + '(cd default_checkout/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_expect_success 'checkout main and initialize independed clones' \ + 'mkdir fully_cloned_submodule && + (cd clone/main && + git checkout --to "$base_path/fully_cloned_submodule/main" "$rev1_hash_main") && + (cd fully_cloned_submodule/main && git submodule update)' + +test_expect_success 'can see submodule diffs after independed cloning' \ + '(cd fully_cloned_submodule/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_done diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index 95f4421f71..99bb71b89c 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -132,6 +132,9 @@ test_expect_success 'detect copies' ' cd "$git" && git config git-p4.skipSubmitEdit true && + echo "file8" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && cp file2 file8 && git add file8 && git commit -a -m "Copy file2 to file8" && @@ -140,6 +143,10 @@ test_expect_success 'detect copies' ' p4 filelog //depot/file8 && p4 filelog //depot/file8 | test_must_fail grep -q "branch from" && + echo "file9" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && + cp file2 file9 && git add file9 && git commit -a -m "Copy file2 to file9" && @@ -149,25 +156,39 @@ test_expect_success 'detect copies' ' p4 filelog //depot/file9 && p4 filelog //depot/file9 | test_must_fail grep -q "branch from" && + echo "file10" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && + echo "file2" >>file2 && cp file2 file10 && git add file2 file10 && git commit -a -m "Modify and copy file2 to file10" && git diff-tree -r -C HEAD && + src=$(git diff-tree -r -C HEAD | sed 1d | sed 2d | cut -f2) && + test "$src" = file2 && git p4 submit && p4 filelog //depot/file10 && - p4 filelog //depot/file10 | grep -q "branch from //depot/file" && + p4 filelog //depot/file10 | grep -q "branch from //depot/file2" && + + echo "file11" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && cp file2 file11 && git add file11 && git commit -a -m "Copy file2 to file11" && git diff-tree -r -C --find-copies-harder HEAD && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && + test "$src" = file2 && git config git-p4.detectCopiesHarder true && git p4 submit && p4 filelog //depot/file11 && - p4 filelog //depot/file11 | grep -q "branch from //depot/file" && + p4 filelog //depot/file11 | grep -q "branch from //depot/file2" && + + echo "file12" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && cp file2 file12 && echo "some text" >>file12 && @@ -177,15 +198,16 @@ test_expect_success 'detect copies' ' level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - case "$src" in - file10 | file11) : ;; # happy - *) false ;; # not - && + test "$src" = file2 && git config git-p4.detectCopies $(($level + 2)) && git p4 submit && p4 filelog //depot/file12 && p4 filelog //depot/file12 | test_must_fail grep -q "branch from" && + echo "file13" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && + cp file2 file13 && echo "different text" >>file13 && git add file13 && @@ -194,14 +216,11 @@ test_expect_success 'detect copies' ' level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - case "$src" in - file10 | file11 | file12) : ;; # happy - *) false ;; # not - && + test "$src" = file2 && git config git-p4.detectCopies $(($level - 2)) && git p4 submit && p4 filelog //depot/file13 && - p4 filelog //depot/file13 | grep -q "branch from //depot/file" + p4 filelog //depot/file13 | grep -q "branch from //depot/file2" ) ' diff --git a/t/t9816-git-p4-locked.sh b/t/t9816-git-p4-locked.sh index e71e543343..d048bd33fa 100755 --- a/t/t9816-git-p4-locked.sh +++ b/t/t9816-git-p4-locked.sh @@ -35,13 +35,13 @@ test_expect_success 'edit with lock not taken' ' ) ' -test_expect_failure 'add with lock not taken' ' +test_expect_success 'add with lock not taken' ' test_when_finished cleanup_git && git p4 clone --dest="$git" //depot && ( cd "$git" && echo line1 >>add-lock-not-taken && - git add file2 && + git add add-lock-not-taken && git commit -m "add add-lock-not-taken" && git config git-p4.skipSubmitEdit true && git p4 submit --verbose @@ -107,7 +107,7 @@ test_expect_failure 'chmod with lock taken' ' ) ' -test_expect_failure 'copy with lock taken' ' +test_expect_success 'copy with lock taken' ' lock_in_another_client && test_when_finished cleanup_git && test_when_finished "cd \"$cli\" && p4 revert file2 && rm -f file2" && @@ -130,8 +130,8 @@ test_expect_failure 'move with lock taken' ' git p4 clone --dest="$git" //depot && ( cd "$git" && - git mv file1 file2 && - git commit -m "mv file1 to file2" && + git mv file1 file3 && + git commit -m "mv file1 to file3" && git config git-p4.skipSubmitEdit true && git config git-p4.detectRenames true && git p4 submit --verbose diff --git a/t/t9818-git-p4-block.sh b/t/t9818-git-p4-block.sh new file mode 100755 index 0000000000..153b20afbd --- /dev/null +++ b/t/t9818-git-p4-block.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +test_description='git p4 fetching changes in multiple blocks' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create a repo with ~100 changes' ' + ( + cd "$cli" && + >file.txt && + p4 add file.txt && + p4 submit -d "Add file.txt" && + for i in $(test_seq 0 9) + do + >outer$i.txt && + p4 add outer$i.txt && + p4 submit -d "Adding outer$i.txt" && + for j in $(test_seq 0 9) + do + p4 edit file.txt && + echo $i$j >file.txt && + p4 submit -d "Commit $i$j" || exit + done || exit + done + ) +' + +test_expect_success 'Clone the repo' ' + git p4 clone --dest="$git" --changes-block-size=10 --verbose //depot@all +' + +test_expect_success 'All files are present' ' + echo file.txt >expected && + test_write_lines outer0.txt outer1.txt outer2.txt outer3.txt outer4.txt >>expected && + test_write_lines outer5.txt outer6.txt outer7.txt outer8.txt outer9.txt >>expected && + ls "$git" >current && + test_cmp expected current +' + +test_expect_success 'file.txt is correct' ' + echo 99 >expected && + test_cmp expected "$git/file.txt" +' + +test_expect_success 'Correct number of commits' ' + (cd "$git" && git log --oneline) >log && + test_line_count = 111 log +' + +test_expect_success 'Previous version of file.txt is correct' ' + (cd "$git" && git checkout HEAD^^) && + echo 97 >expected && + test_cmp expected "$git/file.txt" +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 0698ce7908..8f8858a5f0 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -478,7 +478,7 @@ test_external_without_stderr () { test_path_is_file () { if ! test -f "$1" then - echo "File $1 doesn't exist. $*" + echo "File $1 doesn't exist. $2" false fi } @@ -486,7 +486,7 @@ test_path_is_file () { test_path_is_dir () { if ! test -d "$1" then - echo "Directory $1 doesn't exist. $*" + echo "Directory $1 doesn't exist. $2" false fi } diff --git a/templates/hooks--applypatch-msg.sample b/templates/hooks--applypatch-msg.sample index 8b2a2fe84f..a5d7b84a67 100755 --- a/templates/hooks--applypatch-msg.sample +++ b/templates/hooks--applypatch-msg.sample @@ -10,6 +10,6 @@ # To enable this hook, rename this file to "applypatch-msg". . git-sh-setup -test -x "$GIT_DIR/hooks/commit-msg" && - exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} : diff --git a/templates/hooks--pre-applypatch.sample b/templates/hooks--pre-applypatch.sample index b1f187c2e9..4142082bcb 100755 --- a/templates/hooks--pre-applypatch.sample +++ b/templates/hooks--pre-applypatch.sample @@ -9,6 +9,6 @@ # To enable this hook, rename this file to "pre-applypatch". . git-sh-setup -test -x "$GIT_DIR/hooks/pre-commit" && - exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} : @@ -310,6 +310,7 @@ void trace_repo_setup(const char *prefix) prefix = "(null)"; trace_printf_key(&key, "setup: git_dir: %s\n", quote_crnl(get_git_dir())); + trace_printf_key(&key, "setup: git_common_dir: %s\n", quote_crnl(get_git_common_dir())); trace_printf_key(&key, "setup: worktree: %s\n", quote_crnl(git_work_tree)); trace_printf_key(&key, "setup: cwd: %s\n", quote_crnl(cwd)); trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix)); diff --git a/transport.c b/transport.c index eca9b8c817..f080e93dcd 100644 --- a/transport.c +++ b/transport.c @@ -283,7 +283,6 @@ static int write_one_ref(const char *name, const unsigned char *sha1, { struct strbuf *buf = data; int len = buf->len; - FILE *f; /* when called via for_each_ref(), flags is non-zero */ if (flags && !starts_with(name, "refs/heads/") && @@ -292,10 +291,9 @@ static int write_one_ref(const char *name, const unsigned char *sha1, strbuf_addstr(buf, name); if (safe_create_leading_directories(buf->buf) || - !(f = fopen(buf->buf, "w")) || - fprintf(f, "%s\n", sha1_to_hex(sha1)) < 0 || - fclose(f)) - return error("problems writing temporary file %s", buf->buf); + write_file(buf->buf, 0, "%s\n", sha1_to_hex(sha1))) + return error("problems writing temporary file %s: %s", + buf->buf, strerror(errno)); strbuf_setlen(buf, len); return 0; } diff --git a/tree-diff.c b/tree-diff.c index e7b378c8b2..290a1da4ce 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -64,7 +64,7 @@ static int emit_diff_first_parent_only(struct diff_options *opt, struct combine_ { struct combine_diff_parent *p0 = &p->parent[0]; if (p->mode && p0->mode) { - opt->change(opt, p0->mode, p->mode, p0->sha1, p->sha1, + opt->change(opt, p0->mode, p->mode, p0->oid.hash, p->oid.hash, 1, 1, p->path, 0, 0); } else { @@ -74,11 +74,11 @@ static int emit_diff_first_parent_only(struct diff_options *opt, struct combine_ if (p->mode) { addremove = '+'; - sha1 = p->sha1; + sha1 = p->oid.hash; mode = p->mode; } else { addremove = '-'; - sha1 = p0->sha1; + sha1 = p0->oid.hash; mode = p0->mode; } @@ -151,7 +151,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last, memcpy(p->path + base->len, path, pathlen); p->path[len] = 0; p->mode = mode; - hashcpy(p->sha1, sha1 ? sha1 : null_sha1); + hashcpy(p->oid.hash, sha1 ? sha1 : null_sha1); return p; } @@ -238,7 +238,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p, } p->parent[i].mode = mode_i; - hashcpy(p->parent[i].sha1, sha1_i ? sha1_i : null_sha1); + hashcpy(p->parent[i].oid.hash, sha1_i ? sha1_i : null_sha1); } keep = 1; diff --git a/upload-pack.c b/upload-pack.c index aa84576500..745fda8515 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -74,7 +74,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data) { FILE *fp = cb_data; if (graft->nr_parent == -1) - fprintf(fp, "--shallow %s\n", sha1_to_hex(graft->sha1)); + fprintf(fp, "--shallow %s\n", oid_to_hex(&graft->oid)); return 0; } @@ -633,3 +633,14 @@ int is_hfs_dotgit(const char *path) return 1; } + +const char utf8_bom[] = "\357\273\277"; + +int skip_utf8_bom(char **text, size_t len) +{ + if (len < strlen(utf8_bom) || + memcmp(*text, utf8_bom, strlen(utf8_bom))) + return 0; + *text += strlen(utf8_bom); + return 1; +} @@ -13,6 +13,9 @@ int same_encoding(const char *, const char *); __attribute__((format (printf, 2, 3))) int utf8_fprintf(FILE *, const char *, ...); +extern const char utf8_bom[]; +extern int skip_utf8_bom(char **, size_t); + void strbuf_add_wrapped_text(struct strbuf *buf, const char *text, int indent, int indent2, int width); void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len, @@ -564,3 +564,34 @@ char *xgetcwd(void) die_errno(_("unable to get current working directory")); return strbuf_detach(&sb, NULL); } + +int write_file(const char *path, int fatal, const char *fmt, ...) +{ + struct strbuf sb = STRBUF_INIT; + va_list params; + int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + if (fatal) + die_errno(_("could not open %s for writing"), path); + return -1; + } + va_start(params, fmt); + strbuf_vaddf(&sb, fmt, params); + va_end(params); + if (write_in_full(fd, sb.buf, sb.len) != sb.len) { + int err = errno; + close(fd); + strbuf_release(&sb); + errno = err; + if (fatal) + die_errno(_("could not write to %s"), path); + return -1; + } + strbuf_release(&sb); + if (close(fd)) { + if (fatal) + die_errno(_("could not close %s"), path); + return -1; + } + return 0; +} |