diff options
83 files changed, 4849 insertions, 1006 deletions
diff --git a/Documentation/RelNotes/1.7.4.2.txt b/Documentation/RelNotes/1.7.4.2.txt index 991dae4811..ef4ce1fcd3 100644 --- a/Documentation/RelNotes/1.7.4.2.txt +++ b/Documentation/RelNotes/1.7.4.2.txt @@ -12,6 +12,10 @@ Fixes since v1.7.4.1 tiny packfiles. We now close the file descriptor early when the entire packfile fits inside one mmap window. + * "git bisect visualize" tried to run "gitk" in windowing + environments even when "gitk" is not installed, resulting in a + strange error message. + * "git clone /no/such/path" did not fail correctly. * "git commit" did not correctly error out when the user asked to use a @@ -45,6 +49,9 @@ Fixes since v1.7.4.1 * gitweb's "highlight" interface mishandled tabs. + * gitweb didn't understand timezones with GMT offset that is not + multiple of a whole hour. + * gitweb had a few forward-incompatible syntactic constructs and also used incorrect variable when showing the file mode in a diff. diff --git a/Documentation/RelNotes/1.7.5.txt b/Documentation/RelNotes/1.7.5.txt index b917d0bcf0..24f5d8c4a4 100644 --- a/Documentation/RelNotes/1.7.5.txt +++ b/Documentation/RelNotes/1.7.5.txt @@ -15,6 +15,9 @@ Updates since v1.7.4 * The codebase is getting prepared for i18n/l10n; no translated/translatable strings in the code yet. + * The bash completion script can now complete symmetric difference + for "git diff" command, e.g. "git diff ...bra<TAB>". + * "git apply -v" reports offset lines when the patch does not apply at the exact location recorded in the diff output. @@ -43,6 +46,11 @@ Updates since v1.7.4 reached, without spewing unnecessary error messages that complain about the server response it never got. + * "git fetch" vs "git upload-pack" transfer learned 'no-done' + protocol extension to save one round-trip after the content + negotiation is done. This saves one HTTP RPC, reducing the overall + latency for a trivial fetch. + * "git grep -f <filename>" learned to treat "-" as "read from the standard input stream". @@ -52,6 +60,11 @@ Updates since v1.7.4 * "git log" type commands now understand globbing pathspecs. You can say "git log -- '*.txt'" for example. + * "git log" family of commands learned --cherry and --cherry-mark + options that can be used to view two diverged branches while omitting + or highlighting equivalent changes that appear on both sides of a + symmetric difference (e.g. "log --cherry A...B"). + * "git mergetool" learned how to drive "beyond compare 3" as well. * "git rerere forget" without pathspec used to forget all the saved @@ -93,8 +106,22 @@ release, unless otherwise noted. in the working tree that are in the way in order to check out paths under it from the named branch (js/checkout-untracked-symlink). + * "git fetch" from a client that is mostly following the remote + needlessly told all of its refs to the server for both sides to + compute the set of objects that need to be transferred efficiently, + instead of stopping when the server heard enough. In a project with + many tags, this turns out to be extremely wasteful, especially over + the smart HTTP transport (sp/maint-{upload,fetch}-pack-stop-early~1). + + * "git fetch" run from a repository that uses the same repository as + its alternate object store as the repository it is fetching from + did not tell the server that it already has access to objects + reachable from the refs in their common alternate object store, + causing it to fetch unnecessary objects (jc/maint-fetch-alt). + --- exec >/var/tmp/1 O=v1.7.4.1-352-gcdc3466 +O=v1.7.4.1-414-gaeb2aaa echo O=$(git describe 'master') git shortlog --no-merges ^maint ^$O master diff --git a/Documentation/config.txt b/Documentation/config.txt index 701fba92dc..8ea55d46ad 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -558,6 +558,12 @@ core.sparseCheckout:: Enable "sparse checkout" feature. See section "Sparse checkout" in linkgit:git-read-tree[1] for more information. +core.abbrev:: + Set the length object names are abbreviated to. If unspecified, + many commands abbreviate to 7 hexdigits, which may not be enough + for abbreviated object names to stay unique for sufficiently long + time. + add.ignore-errors:: add.ignoreErrors:: Tells 'git add' to continue adding files when some files cannot be diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 621b720091..6b1b5af64e 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -173,9 +173,9 @@ aborts in the middle. You can recover from this in one of two ways: the index file to bring it into a state that the patch should have produced. Then run the command with the '--resolved' option. -The command refuses to process new mailboxes while the `.git/rebase-apply` -directory exists, so if you decide to start over from scratch, -run `rm -f -r .git/rebase-apply` before running the command with mailbox +The command refuses to process new mailboxes until the current +operation is finished, so if you decide to start over from scratch, +run `git am --abort` before running the command with mailbox names. Before any patches are applied, ORIG_HEAD is set to the tip of the diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt index 4b4b096ce5..7b7bafba0c 100644 --- a/Documentation/git-bisect.txt +++ b/Documentation/git-bisect.txt @@ -279,53 +279,68 @@ $ git bisect start HEAD origin -- # HEAD is bad, origin is good $ git bisect run make test # "make test" builds and tests ------------ -* Automatically bisect a broken test suite: +* Automatically bisect a broken test case: + ------------ $ cat ~/test.sh #!/bin/sh -make || exit 125 # this skips broken builds -make test # "make test" runs the test suite -$ git bisect start v1.3 v1.1 -- # v1.3 is bad, v1.1 is good +make || exit 125 # this skips broken builds +~/check_test_case.sh # does the test case pass? +$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10 $ git bisect run ~/test.sh ------------ + Here we use a "test.sh" custom script. In this script, if "make" fails, we skip the current commit. +"check_test_case.sh" should "exit 0" if the test case passes, +and "exit 1" otherwise. + -It is safer to use a custom script outside the repository to prevent -interactions between the bisect, make and test processes and the -script. -+ -"make test" should "exit 0", if the test suite passes, and -"exit 1" otherwise. +It is safer if both "test.sh" and "check_test_case.sh" are +outside the repository to prevent interactions between the bisect, +make and test processes and the scripts. -* Automatically bisect a broken test case: +* Automatically bisect with temporary modifications (hot-fix): + ------------ $ cat ~/test.sh #!/bin/sh -make || exit 125 # this skips broken builds -~/check_test_case.sh # does the test case passes ? -$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10 -$ git bisect run ~/test.sh + +# tweak the working tree by merging the hot-fix branch +# and then attempt a build +if git merge --no-commit hot-fix && + make +then + # run project specific test and report its status + ~/check_test_case.sh + status=$? +else + # tell the caller this is untestable + status=125 +fi + +# undo the tweak to allow clean flipping to the next commit +git reset --hard + +# return control +exit $status ------------ + -Here "check_test_case.sh" should "exit 0" if the test case passes, -and "exit 1" otherwise. -+ -It is safer if both "test.sh" and "check_test_case.sh" scripts are -outside the repository to prevent interactions between the bisect, -make and test processes and the scripts. +This applies modifications from a hot-fix branch before each test run, +e.g. in case your build or test environment changed so that older +revisions may need a fix which newer ones have already. (Make sure the +hot-fix branch is based off a commit which is contained in all revisions +which you are bisecting, so that the merge does not pull in too much, or +use `git cherry-pick` instead of `git merge`.) -* Automatically bisect a broken test suite: +* Automatically bisect a broken test case: + ------------ $ git bisect start HEAD HEAD~10 -- # culprit is among the last 10 $ git bisect run sh -c "make || exit 125; ~/check_test_case.sh" ------------ + -Does the same as the previous example, but on a single line. +This shows that you can do without a run script if you write the test +on a single line. SEE ALSO -------- diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 5ce4d7fd0b..b08dfbc3c4 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -31,6 +31,9 @@ SYNOPSIS [ \--parents ] [ \--timestamp ] [ \--left-right ] + [ \--left-only ] + [ \--right-only ] + [ \--cherry-mark ] [ \--cherry-pick ] [ \--encoding[=<encoding>] ] [ \--(author|committer|grep)=<pattern> ] diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 09860de9c2..5c6850f048 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -151,6 +151,11 @@ ifdef::git-rev-list[] to /dev/null as the output does not have to be formatted. endif::git-rev-list[] +--cherry-mark:: + + Like `--cherry-pick` (see below) but mark equivalent commits + with `=` rather than omitting them, and inequivalent ones with `+`. + --cherry-pick:: Omit any commit that introduces the same change as @@ -165,6 +170,27 @@ from the other branch (for example, "3rd on b" may be cherry-picked from branch A). With this option, such pairs of commits are excluded from the output. +--left-only:: +--right-only:: + + List only commits on the respective side of a symmetric range, + i.e. only those which would be marked `<` resp. `>` by + `--left-right`. ++ +For example, `--cherry-pick --right-only A...B` omits those +commits from `B` which are in `A` or are patch-equivalent to a commit in +`A`. In other words, this lists the `{plus}` commits from `git cherry A B`. +More precisely, `--cherry-pick --right-only --no-merges` gives the exact +list. + +--cherry:: + + A synonym for `--right-only --cherry-mark --no-merges`; useful to + limit the output to the commits on our side and mark those that + have been applied to the other side of a forked history with + `git log --cherry upstream...mybranch`, similar to + `git cherry upstream mybranch`. + -g:: --walk-reflogs:: diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt new file mode 100644 index 0000000000..7b233ca196 --- /dev/null +++ b/Documentation/technical/index-format.txt @@ -0,0 +1,185 @@ +GIT index format +================ + += The git index file has the following format + + All binary numbers are in network byte order. Version 2 is described + here unless stated otherwise. + + - A 12-byte header consisting of + + 4-byte signature: + The signature is { 'D', 'I', 'R', 'C' } (stands for "dircache") + + 4-byte version number: + The current supported versions are 2 and 3. + + 32-bit number of index entries. + + - A number of sorted index entries (see below). + + - Extensions + + Extensions are identified by signature. Optional extensions can + be ignored if GIT does not understand them. + + GIT currently supports cached tree and resolve undo extensions. + + 4-byte extension signature. If the first byte is 'A'..'Z' the + extension is optional and can be ignored. + + 32-bit size of the extension + + Extension data + + - 160-bit SHA-1 over the content of the index file before this + checksum. + +== Index entry + + Index entries are sorted in ascending order on the name field, + interpreted as a string of unsigned bytes (i.e. memcmp() order, no + localization, no special casing of directory separator '/'). Entries + with the same name are sorted by their stage field. + + 32-bit ctime seconds, the last time a file's metadata changed + this is stat(2) data + + 32-bit ctime nanosecond fractions + this is stat(2) data + + 32-bit mtime seconds, the last time a file's data changed + this is stat(2) data + + 32-bit mtime nanosecond fractions + this is stat(2) data + + 32-bit dev + this is stat(2) data + + 32-bit ino + this is stat(2) data + + 32-bit mode, split into (high to low bits) + + 4-bit object type + valid values in binary are 1000 (regular file), 1010 (symbolic link) + and 1110 (gitlink) + + 3-bit unused + + 9-bit unix permission. Only 0755 and 0644 are valid for regular files. + Symbolic links and gitlinks have value 0 in this field. + + 32-bit uid + this is stat(2) data + + 32-bit gid + this is stat(2) data + + 32-bit file size + This is the on-disk size from stat(2), truncated to 32-bit. + + 160-bit SHA-1 for the represented object + + A 16-bit 'flags' field split into (high to low bits) + + 1-bit assume-valid flag + + 1-bit extended flag (must be zero in version 2) + + 2-bit stage (during merge) + + 12-bit name length if the length is less than 0xFFF; otherwise 0xFFF + is stored in this field. + + (Version 3) A 16-bit field, only applicable if the "extended flag" + above is 1, split into (high to low bits). + + 1-bit reserved for future + + 1-bit skip-worktree flag (used by sparse checkout) + + 1-bit intent-to-add flag (used by "git add -N") + + 13-bit unused, must be zero + + Entry path name (variable length) relative to top level directory + (without leading slash). '/' is used as path separator. The special + path components ".", ".." and ".git" (without quotes) are disallowed. + Trailing slash is also disallowed. + + The exact encoding is undefined, but the '.' and '/' characters + are encoded in 7-bit ASCII and the encoding cannot contain a NUL + byte (iow, this is a UNIX pathname). + + 1-8 nul bytes as necessary to pad the entry to a multiple of eight bytes + while keeping the name NUL-terminated. + +== Extensions + +=== Cached tree + + Cached tree extension contains pre-computed hashes for trees that can + be derived from the index. It helps speed up tree object generation + from index for a new commit. + + When a path is updated in index, the path must be invalidated and + removed from tree cache. + + The signature for this extension is { 'T', 'R', 'E', 'E' }. + + A series of entries fill the entire extension; each of which + consists of: + + - NUL-terminated path component (relative to its parent directory); + + - ASCII decimal number of entries in the index that is covered by the + tree this entry represents (entry_count); + + - A space (ASCII 32); + + - ASCII decimal number that represents the number of subtrees this + tree has; + + - A newline (ASCII 10); and + + - 160-bit object name for the object that would result from writing + this span of index as a tree. + + An entry can be in an invalidated state and is represented by having -1 + in the entry_count field. + + The entries are written out in the top-down, depth-first order. The + first entry represents the root level of the repository, followed by the + first subtree---let's call this A---of the root level (with its name + relative to the root level), followed by the first subtree of A (with + its name relative to A), ... + +=== Resolve undo + + A conflict is represented in the index as a set of higher stage entries. + When a conflict is resolved (e.g. with "git add path"), these higher + stage entries will be removed and a stage-0 entry with proper resoluton + is added. + + When these higher stage entries are removed, they are saved in the + resolve undo extension, so that conflicts can be recreated (e.g. with + "git checkout -m"), in case users want to redo a conflict resolution + from scratch. + + The signature for this extension is { 'R', 'E', 'U', 'C' }. + + A series of entries fill the entire extension; each of which + consists of: + + - NUL-terminated pathname the entry describes (relative to the root of + the repository, i.e. full pathname); + + - Three NUL-terminated ASCII octal numbers, entry mode of entries in + stage 1 to 3 (a missing stage is represented by "0" in this field); + and + + - At most three 160-bit object names of the entry in stages from 1 to 3 + (nothing is written for a missing stage). + @@ -45,11 +45,6 @@ all:: # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks # d_type in struct dirent (Cygwin 1.5, fixed in Cygwin 1.7). # -# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) -# do not support the 'size specifiers' introduced by C99, namely ll, hh, -# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). -# some C compilers supported these specifiers prior to C99 as an extension. -# # Define NO_STRCASESTR if you don't have strcasestr. # # Define NO_MEMMEM if you don't have memmem. @@ -878,7 +873,6 @@ ifeq ($(uname_S),SunOS) NO_UNSETENV = YesPlease NO_SETENV = YesPlease NO_STRLCPY = YesPlease - NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease GIT_TEST_CMP = cmp endif @@ -889,21 +883,18 @@ ifeq ($(uname_S),SunOS) NO_UNSETENV = YesPlease NO_SETENV = YesPlease NO_STRLCPY = YesPlease - NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease GIT_TEST_CMP = cmp endif ifeq ($(uname_R),5.8) NO_UNSETENV = YesPlease NO_SETENV = YesPlease - NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease GIT_TEST_CMP = cmp endif ifeq ($(uname_R),5.9) NO_UNSETENV = YesPlease NO_SETENV = YesPlease - NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease GIT_TEST_CMP = cmp endif @@ -1083,7 +1074,6 @@ ifeq ($(uname_S),Windows) NO_MEMMEM = YesPlease # NEEDS_LIBICONV = YesPlease NO_ICONV = YesPlease - NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease NO_STRTOULL = YesPlease NO_MKDTEMP = YesPlease @@ -1160,7 +1150,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MEMMEM = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease - NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease NO_MKDTEMP = YesPlease NO_MKSTEMPS = YesPlease @@ -1363,9 +1352,6 @@ endif ifdef NO_NSEC BASIC_CFLAGS += -DNO_NSEC endif -ifdef NO_C99_FORMAT - BASIC_CFLAGS += -DNO_C99_FORMAT -endif ifdef SNPRINTF_RETURNS_BOGUS COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS COMPAT_OBJS += compat/snprintf.o @@ -51,19 +51,12 @@ DEFINE_ALLOCATOR(commit, struct commit) DEFINE_ALLOCATOR(tag, struct tag) DEFINE_ALLOCATOR(object, union any_object) -#ifdef NO_C99_FORMAT -#define SZ_FMT "%u" -#else -#define SZ_FMT "%zu" -#endif - static void report(const char *name, unsigned int count, size_t size) { - fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size); + fprintf(stderr, "%10s: %8u (%"PRIuMAX" kB)\n", + name, count, (uintmax_t) size); } -#undef SZ_FMT - #define REPORT(name) \ report(#name, name##_allocs, name##_allocs*sizeof(struct name) >> 10) @@ -478,11 +478,6 @@ int git_attr_system(void) return !git_env_bool("GIT_ATTR_NOSYSTEM", 0); } -int git_attr_global(void) -{ - return !git_env_bool("GIT_ATTR_NOGLOBAL", 0); -} - static int git_attr_config(const char *var, const char *value, void *dummy) { if (!strcmp(var, "core.attributesfile")) @@ -511,7 +506,7 @@ static void bootstrap_attr_stack(void) } git_config(git_attr_config, NULL); - if (git_attr_global() && attributes_file) { + if (attributes_file) { elem = read_attr_from_file(attributes_file, 1); if (elem) { elem->origin = NULL; diff --git a/builtin/checkout.c b/builtin/checkout.c index 2bf02f2841..686d0ffd30 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -603,13 +603,26 @@ static int add_one_ref_to_rev_list_arg(const char *refname, return 0; } +static int clear_commit_marks_from_one_ref(const char *refname, + const unsigned char *sha1, + int flags, + void *cb_data) +{ + struct commit *commit = lookup_commit_reference_gently(sha1, 1); + if (commit) + clear_commit_marks(commit, -1); + return 0; +} static void describe_one_orphan(struct strbuf *sb, struct commit *commit) { struct pretty_print_context ctx = { 0 }; parse_commit(commit); - strbuf_addstr(sb, " - "); + strbuf_addstr(sb, " "); + strbuf_addstr(sb, + find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV)); + strbuf_addch(sb, ' '); pretty_print_commit(CMIT_FMT_ONELINE, commit, sb, &ctx); strbuf_addch(sb, '\n'); } @@ -674,6 +687,9 @@ static void orphaned_commit_warning(struct commit *commit) suggest_reattach(commit, &revs); else describe_detached_head("Previous HEAD position was", commit); + + clear_commit_marks(commit, -1); + for_each_ref(clear_commit_marks_from_one_ref, NULL); } static int switch_branches(struct checkout_opts *opts, struct branch_info *new) diff --git a/builtin/commit.c b/builtin/commit.c index 3979b823ef..54b20497b1 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1203,13 +1203,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL); fd = hold_locked_index(&index_lock, 0); - if (0 <= fd) { - if (active_cache_changed && - !write_cache(fd, active_cache, active_nr)) - commit_locked_index(&index_lock); - else - rollback_lock_file(&index_lock); - } + if (0 <= fd) + update_index_if_able(&the_index, &index_lock); s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; s.ignore_submodule_arg = ignore_submodule_arg; diff --git a/builtin/config.c b/builtin/config.c index 76be0b786f..3e3c528497 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -160,7 +160,7 @@ static int get_value(const char *key_, const char *regex_) if (!local) { const char *home = getenv("HOME"); local = repo_config = git_pathdup("config"); - if (git_config_global() && home) + if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); if (git_config_system()) system_wide = git_etc_gitconfig(); diff --git a/builtin/describe.c b/builtin/describe.c index 3ba26dc819..4afd1504a6 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -21,7 +21,7 @@ static int debug; /* Display lots of verbose info */ static int all; /* Any valid ref can be used */ static int tags; /* Allow lightweight tags */ static int longformat; -static int abbrev = DEFAULT_ABBREV; +static int abbrev = -1; /* unspecified */ static int max_candidates = 10; static struct hash_table names; static int have_util; @@ -420,7 +420,11 @@ int cmd_describe(int argc, const char **argv, const char *prefix) OPT_END(), }; + git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, describe_usage, 0); + if (abbrev < 0) + abbrev = DEFAULT_ABBREV; + if (max_candidates < 0) max_candidates = 0; else if (max_candidates > MAX_TAGS) diff --git a/builtin/diff.c b/builtin/diff.c index 4c9deb28ec..655a013ed0 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -197,12 +197,7 @@ static void refresh_index_quietly(void) discard_cache(); read_cache(); refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED); - - if (active_cache_changed && - !write_cache(fd, active_cache, active_nr)) - commit_locked_index(lock_file); - - rollback_lock_file(lock_file); + update_index_if_able(&the_index, lock_file); } static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv) diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index ef398620af..bf9990ce15 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -9,11 +9,13 @@ #include "fetch-pack.h" #include "remote.h" #include "run-command.h" +#include "transport.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; static int unpack_limit = 100; static int prefer_ofs_delta = 1; +static int no_done = 0; static struct fetch_pack_args args = { /* .uploadpack = */ "git-upload-pack", }; @@ -217,14 +219,39 @@ static void send_request(int fd, struct strbuf *buf) safe_write(fd, buf->buf, buf->len); } +static void insert_one_alternate_ref(const struct ref *ref, void *unused) +{ + rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL); +} + +static void insert_alternate_refs(void) +{ + foreach_alt_odb(refs_from_alternate_cb, insert_one_alternate_ref); +} + +#define INITIAL_FLUSH 16 +#define LARGE_FLUSH 1024 + +static int next_flush(int count) +{ + if (count < INITIAL_FLUSH * 2) + count += INITIAL_FLUSH; + else if (count < LARGE_FLUSH) + count <<= 1; + else + count += LARGE_FLUSH; + return count; +} + static int find_common(int fd[2], unsigned char *result_sha1, struct ref *refs) { int fetching; - int count = 0, flushes = 0, retval; + int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval; const unsigned char *sha1; unsigned in_vain = 0; int got_continue = 0; + int got_ready = 0; struct strbuf req_buf = STRBUF_INIT; size_t state_len = 0; @@ -235,6 +262,7 @@ static int find_common(int fd[2], unsigned char *result_sha1, marked = 1; for_each_ref(rev_list_insert_ref, NULL); + insert_alternate_refs(); fetching = 0; for ( ; refs ; refs = refs->next) { @@ -262,6 +290,7 @@ static int find_common(int fd[2], unsigned char *result_sha1, struct strbuf c = STRBUF_INIT; if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); if (multi_ack == 1) strbuf_addstr(&c, " multi_ack"); + if (no_done) strbuf_addstr(&c, " no-done"); if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k"); if (use_sideband == 1) strbuf_addstr(&c, " side-band"); if (args.use_thin_pack) strbuf_addstr(&c, " thin-pack"); @@ -332,19 +361,20 @@ static int find_common(int fd[2], unsigned char *result_sha1, if (args.verbose) fprintf(stderr, "have %s\n", sha1_to_hex(sha1)); in_vain++; - if (!(31 & ++count)) { + if (flush_at <= ++count) { int ack; packet_buf_flush(&req_buf); send_request(fd[1], &req_buf); strbuf_setlen(&req_buf, state_len); flushes++; + flush_at = next_flush(count); /* * We keep one window "ahead" of the other side, and * will wait for an ACK only on the next one */ - if (!args.stateless_rpc && count == 32) + if (!args.stateless_rpc && count == INITIAL_FLUSH) continue; consume_shallow_list(fd[0]); @@ -379,6 +409,10 @@ static int find_common(int fd[2], unsigned char *result_sha1, retval = 0; in_vain = 0; got_continue = 1; + if (ack == ACK_ready) { + rev_list = NULL; + got_ready = 1; + } break; } } @@ -392,8 +426,10 @@ static int find_common(int fd[2], unsigned char *result_sha1, } } done: - packet_buf_write(&req_buf, "done\n"); - send_request(fd[1], &req_buf); + if (!got_ready || !no_done) { + packet_buf_write(&req_buf, "done\n"); + send_request(fd[1], &req_buf); + } if (args.verbose) fprintf(stderr, "done\n"); if (retval != 0) { @@ -696,6 +732,11 @@ static struct ref *do_fetch_pack(int fd[2], if (args.verbose) fprintf(stderr, "Server supports multi_ack_detailed\n"); multi_ack = 2; + if (server_supports("no-done")) { + if (args.verbose) + fprintf(stderr, "Server supports no-done\n"); + no_done = 1; + } } else if (server_supports("multi_ack")) { if (args.verbose) diff --git a/builtin/mktag.c b/builtin/mktag.c index d0ccbb2222..324a267163 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -34,12 +34,6 @@ static int verify_object(const unsigned char *sha1, const char *expected_type) return ret; } -#ifdef NO_C99_FORMAT -#define PD_FMT "%d" -#else -#define PD_FMT "%td" -#endif - static int verify_tag(char *buffer, unsigned long size) { int typelen; @@ -69,15 +63,18 @@ static int verify_tag(char *buffer, unsigned long size) /* Verify tag-line */ tag_line = strchr(type_line, '\n'); if (!tag_line) - return error("char" PD_FMT ": could not find next \"\\n\"", type_line - buffer); + return error("char%"PRIuMAX": could not find next \"\\n\"", + (uintmax_t) (type_line - buffer)); tag_line++; if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n') - return error("char" PD_FMT ": no \"tag \" found", tag_line - buffer); + return error("char%"PRIuMAX": no \"tag \" found", + (uintmax_t) (tag_line - buffer)); /* Get the actual type */ typelen = tag_line - type_line - strlen("type \n"); if (typelen >= sizeof(type)) - return error("char" PD_FMT ": type too long", type_line+5 - buffer); + return error("char%"PRIuMAX": type too long", + (uintmax_t) (type_line+5 - buffer)); memcpy(type, type_line+5, typelen); type[typelen] = 0; @@ -94,15 +91,16 @@ static int verify_tag(char *buffer, unsigned long size) break; if (c > ' ') continue; - return error("char" PD_FMT ": could not verify tag name", tag_line - buffer); + return error("char%"PRIuMAX": could not verify tag name", + (uintmax_t) (tag_line - buffer)); } /* Verify the tagger line */ tagger_line = tag_line; if (memcmp(tagger_line, "tagger ", 7)) - return error("char" PD_FMT ": could not find \"tagger \"", - tagger_line - buffer); + return error("char%"PRIuMAX": could not find \"tagger \"", + (uintmax_t) (tagger_line - buffer)); /* * Check for correct form for name and email @@ -114,44 +112,42 @@ static int verify_tag(char *buffer, unsigned long size) if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) || strpbrk(tagger_line, "<>\n") != lb+1 || strpbrk(lb+2, "><\n ") != rb) - return error("char" PD_FMT ": malformed tagger field", - tagger_line - buffer); + return error("char%"PRIuMAX": malformed tagger field", + (uintmax_t) (tagger_line - buffer)); /* Check for author name, at least one character, space is acceptable */ if (lb == tagger_line) - return error("char" PD_FMT ": missing tagger name", - tagger_line - buffer); + return error("char%"PRIuMAX": missing tagger name", + (uintmax_t) (tagger_line - buffer)); /* timestamp, 1 or more digits followed by space */ tagger_line = rb + 2; if (!(len = strspn(tagger_line, "0123456789"))) - return error("char" PD_FMT ": missing tag timestamp", - tagger_line - buffer); + return error("char%"PRIuMAX": missing tag timestamp", + (uintmax_t) (tagger_line - buffer)); tagger_line += len; if (*tagger_line != ' ') - return error("char" PD_FMT ": malformed tag timestamp", - tagger_line - buffer); + return error("char%"PRIuMAX": malformed tag timestamp", + (uintmax_t) (tagger_line - buffer)); tagger_line++; /* timezone, 5 digits [+-]hhmm, max. 1400 */ if (!((tagger_line[0] == '+' || tagger_line[0] == '-') && strspn(tagger_line+1, "0123456789") == 4 && tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400)) - return error("char" PD_FMT ": malformed tag timezone", - tagger_line - buffer); + return error("char%"PRIuMAX": malformed tag timezone", + (uintmax_t) (tagger_line - buffer)); tagger_line += 6; /* Verify the blank line separating the header from the body */ if (*tagger_line != '\n') - return error("char" PD_FMT ": trailing garbage in tag header", - tagger_line - buffer); + return error("char%"PRIuMAX": trailing garbage in tag header", + (uintmax_t) (tagger_line - buffer)); /* The actual stuff afterwards we don't care about.. */ return 0; } -#undef PD_FMT - int cmd_mktag(int argc, const char **argv, const char *prefix) { struct strbuf buf = STRBUF_INIT; diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index d8e2c5fca7..27050e7c16 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -731,43 +731,14 @@ static int delete_only(struct command *commands) return 1; } -static int add_refs_from_alternate(struct alternate_object_database *e, void *unused) +static void add_one_alternate_ref(const struct ref *ref, void *unused) { - char *other; - size_t len; - struct remote *remote; - struct transport *transport; - const struct ref *extra; - - e->name[-1] = '\0'; - other = xstrdup(real_path(e->base)); - e->name[-1] = '/'; - len = strlen(other); - - while (other[len-1] == '/') - other[--len] = '\0'; - if (len < 8 || memcmp(other + len - 8, "/objects", 8)) - return 0; - /* Is this a git repository with refs? */ - memcpy(other + len - 8, "/refs", 6); - if (!is_directory(other)) - return 0; - other[len - 8] = '\0'; - remote = remote_get(other); - transport = transport_get(remote, other); - for (extra = transport_get_remote_refs(transport); - extra; - extra = extra->next) { - add_extra_ref(".have", extra->old_sha1, 0); - } - transport_disconnect(transport); - free(other); - return 0; + add_extra_ref(".have", ref->old_sha1, 0); } static void add_alternate_refs(void) { - foreach_alt_odb(add_refs_from_alternate, NULL); + foreach_alt_odb(refs_from_alternate_cb, add_one_alternate_ref); } int cmd_receive_pack(int argc, const char **argv, const char *prefix) diff --git a/builtin/rev-list.c b/builtin/rev-list.c index ba27d39f97..f458cb7587 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -64,18 +64,8 @@ static void show_commit(struct commit *commit, void *data) if (info->header_prefix) fputs(info->header_prefix, stdout); - if (!revs->graph) { - if (commit->object.flags & BOUNDARY) - putchar('-'); - else if (commit->object.flags & UNINTERESTING) - putchar('^'); - else if (revs->left_right) { - if (commit->object.flags & SYMMETRIC_LEFT) - putchar('<'); - else - putchar('>'); - } - } + if (!revs->graph) + fputs(get_revision_mark(revs, commit), stdout); if (revs->abbrev_commit && revs->abbrev) fputs(find_unique_abbrev(commit->object.sha1, revs->abbrev), stdout); @@ -543,6 +543,7 @@ extern NORETURN void unable_to_lock_index_die(const char *path, int err); extern int hold_lock_file_for_update(struct lock_file *, const char *path, int); extern int hold_lock_file_for_append(struct lock_file *, const char *path, int); extern int commit_lock_file(struct lock_file *); +extern void update_index_if_able(struct index_state *, struct lock_file *); extern int hold_locked_index(struct lock_file *, int); extern int commit_locked_index(struct lock_file *); @@ -556,6 +557,7 @@ extern int trust_executable_bit; extern int trust_ctime; extern int quote_path_fully; extern int has_symlinks; +extern int minimum_abbrev, default_abbrev; extern int ignore_case; extern int assume_unchanged; extern int prefer_symlink_refs; @@ -725,6 +727,7 @@ int set_shared_perm(const char *path, int mode); #define adjust_shared_perm(path) set_shared_perm((path), 0) int safe_create_leading_directories(char *path); int safe_create_leading_directories_const(const char *path); +int mkdir_in_gitdir(const char *path); extern char *expand_user_path(const char *path); char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) @@ -775,8 +778,8 @@ static inline unsigned int hexval(unsigned char c) } /* Convert to/from hex/sha1 representation */ -#define MINIMUM_ABBREV 4 -#define DEFAULT_ABBREV 7 +#define MINIMUM_ABBREV minimum_abbrev +#define DEFAULT_ABBREV default_abbrev struct object_context { unsigned char tree[20]; @@ -1022,7 +1025,6 @@ extern const char *git_etc_gitconfig(void); extern int check_repository_format_version(const char *var, const char *value, void *cb); extern int git_env_bool(const char *, int); extern int git_config_system(void); -extern int git_config_global(void); extern int config_error_nonbool(const char *); extern const char *get_log_output_encoding(void); extern const char *get_commit_output_encoding(void); @@ -523,6 +523,14 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.abbrev")) { + int abbrev = git_config_int(var, value); + if (abbrev < minimum_abbrev || abbrev > 40) + return -1; + default_abbrev = abbrev; + return 0; + } + if (!strcmp(var, "core.loosecompression")) { int level = git_config_int(var, value); if (level == -1) @@ -825,11 +833,6 @@ int git_config_system(void) return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0); } -int git_config_global(void) -{ - return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0); -} - int git_config_from_parameters(config_fn_t fn, void *data) { static int loaded_environment; @@ -861,7 +864,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) } home = getenv("HOME"); - if (git_config_global() && home) { + if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { ret += git_config_from_file(fn, user_config, data); diff --git a/config.mak.in b/config.mak.in index 9614973057..e378534cbd 100644 --- a/config.mak.in +++ b/config.mak.in @@ -43,7 +43,6 @@ NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@ NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@ NO_SOCKADDR_STORAGE=@NO_SOCKADDR_STORAGE@ NO_IPV6=@NO_IPV6@ -NO_C99_FORMAT=@NO_C99_FORMAT@ NO_HSTRERROR=@NO_HSTRERROR@ NO_STRCASESTR=@NO_STRCASESTR@ NO_STRTOK_R=@NO_STRTOK_R@ diff --git a/configure.ac b/configure.ac index 20039c546f..dd0790725b 100644 --- a/configure.ac +++ b/configure.ac @@ -686,30 +686,6 @@ AC_CHECK_TYPE([struct addrinfo],[ ]) AC_SUBST(NO_IPV6) # -# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) -# do not support the 'size specifiers' introduced by C99, namely ll, hh, -# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). -# some C compilers supported these specifiers prior to C99 as an extension. -AC_CACHE_CHECK([whether formatted IO functions support C99 size specifiers], - [ac_cv_c_c99_format], -[# Actually git uses only %z (%zu) in alloc.c, and %t (%td) in mktag.c -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], - [[char buf[64]; - if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5) - return 1; - else if (strcmp(buf, "12345")) - return 2;]])], - [ac_cv_c_c99_format=yes], - [ac_cv_c_c99_format=no]) -]) -if test $ac_cv_c_c99_format = no; then - NO_C99_FORMAT=YesPlease -else - NO_C99_FORMAT= -fi -AC_SUBST(NO_C99_FORMAT) -# # Define NO_REGEX if you have no or inferior regex support in your C library. AC_CACHE_CHECK([whether the platform regex can handle null bytes], [ac_cv_c_excellent_regex], [ diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index ccdc172a06..1b589fadbb 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -664,11 +664,14 @@ __git_compute_merge_strategies () : ${__git_merge_strategies:=$(__git_list_merge_strategies)} } -__git_complete_file () +__git_complete_revlist_file () { local pfx ls ref cur _get_comp_words_by_ref -n =: cur case "$cur" in + *..?*:*) + return + ;; ?*:*) ref="${cur%%:*}" cur="${cur#*:}" @@ -682,7 +685,7 @@ __git_complete_file () *) ls="$ref" ;; - esac + esac case "$COMP_WORDBREAKS" in *:*) : great ;; @@ -707,17 +710,6 @@ __git_complete_file () s/^.* //')" \ -- "$cur")) ;; - *) - __gitcomp "$(__git_refs)" - ;; - esac -} - -__git_complete_revlist () -{ - local pfx cur - _get_comp_words_by_ref -n =: cur - case "$cur" in *...*) pfx="${cur%...*}..." cur="${cur#*...}" @@ -734,6 +726,17 @@ __git_complete_revlist () esac } + +__git_complete_file () +{ + __git_complete_revlist_file +} + +__git_complete_revlist () +{ + __git_complete_revlist_file +} + __git_complete_remote_or_refspec () { local cur words cword @@ -1356,7 +1359,7 @@ _git_diff () return ;; esac - __git_complete_file + __git_complete_revlist_file } __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff @@ -1508,7 +1511,7 @@ _git_help () ;; esac __git_compute_all_commands - __gitcomp "$__git_all_commands + __gitcomp "$__git_all_commands $(__git_aliases) attributes cli core-tutorial cvs-migration diffcore gitk glossary hooks ignore modules repository-layout tutorial tutorial-2 diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 7cb479c5e1..3881515034 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -333,9 +333,13 @@ def gitBranchExists(branch): return proc.wait() == 0; _gitConfig = {} -def gitConfig(key): +def gitConfig(key, args = None): # set args to "--bool", for instance if not _gitConfig.has_key(key): - _gitConfig[key] = read_pipe("git config %s" % key, ignore_error=True).strip() + argsFilter = "" + if args != None: + argsFilter = "%s " % args + cmd = "git config %s%s" % (argsFilter, key) + _gitConfig[key] = read_pipe(cmd, ignore_error=True).strip() return _gitConfig[key] def p4BranchesInGit(branchesAreInRemotes = True): @@ -452,6 +456,19 @@ def p4ChangesForPaths(depotPaths, changeRange): changelist.sort() return changelist +def p4PathStartsWith(path, prefix): + # This method tries to remedy a potential mixed-case issue: + # + # If UserA adds //depot/DirA/file1 + # and UserB adds //depot/dira/file2 + # + # we may or may not have a problem. If you have core.ignorecase=true, + # we treat DirA and dira as the same directory + ignorecase = gitConfig("core.ignorecase", "--bool") == "true" + if ignorecase: + return path.lower().startswith(prefix.lower()) + return path.startswith(prefix) + class Command: def __init__(self): self.usage = "usage: %prog [options]" @@ -599,7 +616,7 @@ class P4Submit(Command): lastTab = path.rfind("\t") if lastTab != -1: path = path[:lastTab] - if not path.startswith(self.depotPath): + if not p4PathStartsWith(path, self.depotPath): continue else: inFilesSection = False @@ -937,11 +954,11 @@ class P4Sync(Command): path = commit["depotFile%s" % fnum] if [p for p in self.cloneExclude - if path.startswith (p)]: + if p4PathStartsWith(path, p)]: found = False else: found = [p for p in self.depotPaths - if path.startswith (p)] + if p4PathStartsWith(path, p)] if not found: fnum = fnum + 1 continue @@ -976,7 +993,7 @@ class P4Sync(Command): prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])] for p in prefixes: - if path.startswith(p): + if p4PathStartsWith(path, p): path = path[len(p):] return path @@ -987,7 +1004,7 @@ class P4Sync(Command): while commit.has_key("depotFile%s" % fnum): path = commit["depotFile%s" % fnum] found = [p for p in self.depotPaths - if path.startswith (p)] + if p4PathStartsWith(path, p)] if not found: fnum = fnum + 1 continue @@ -1140,10 +1157,10 @@ class P4Sync(Command): # create a commit. new_files = [] for f in files: - if [p for p in branchPrefixes if f['path'].startswith(p)]: + if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]: new_files.append (f) else: - sys.stderr.write("Ignoring file outside of prefix: %s\n" % path) + sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path']) self.gitStream.write("commit %s\n" % branch) # gitStream.write("mark :%s\n" % details["change"]) @@ -1304,7 +1321,7 @@ class P4Sync(Command): source = paths[0] destination = paths[1] ## HACK - if source.startswith(self.depotPaths[0]) and destination.startswith(self.depotPaths[0]): + if p4PathStartsWith(source, self.depotPaths[0]) and p4PathStartsWith(destination, self.depotPaths[0]): source = source[len(self.depotPaths[0]):-4] destination = destination[len(self.depotPaths[0]):-4] @@ -1763,7 +1780,9 @@ class P4Sync(Command): changes.sort() else: - if not isinstance(self, P4Clone) and not self.p4BranchesInGit: + # catch "git-p4 sync" with no new branches, in a repo that + # does not have any existing git-p4 branches + if len(args) == 0 and not self.p4BranchesInGit: die("No remote p4 branches. Perhaps you never did \"git p4 clone\" in here."); if self.verbose: print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), diff --git a/diff-lib.c b/diff-lib.c index 1e22992cb1..2870de400e 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -103,7 +103,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option) unsigned dirty_submodule = 0; if (DIFF_OPT_TST(&revs->diffopt, QUICK) && - DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) + !revs->diffopt.filter && + DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) break; if (!ce_path_match(ce, &revs->prune_data)) diff --git a/environment.c b/environment.c index cc670b1562..f4549d3f7b 100644 --- a/environment.c +++ b/environment.c @@ -15,6 +15,7 @@ int user_ident_explicitly_given; int trust_executable_bit = 1; int trust_ctime = 1; int has_symlinks = 1; +int minimum_abbrev = 4, default_abbrev = 7; int ignore_case; int assume_unchanged; int prefer_symlink_refs; diff --git a/git-bisect.sh b/git-bisect.sh index c21e33c8d1..415a8d04cc 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -288,10 +288,12 @@ bisect_visualize() { if test $# = 0 then - case "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in - '') set git log ;; - set*) set gitk ;; - esac + if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" && + type gitk >/dev/null 2>&1; then + set gitk + else + set git log + fi else case "$1" in git*|tig) ;; diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index d3acf0d213..fd6a43d0a2 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -93,6 +93,25 @@ if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} { package require msgcat +# Check for Windows 7 MUI language pack (missed by msgcat < 1.4.4) +if {[tk windowingsystem] eq "win32" + && [package vcompare [package provide msgcat] 1.4.4] < 0 +} then { + proc _mc_update_locale {} { + set key {HKEY_CURRENT_USER\Control Panel\Desktop} + if {![catch { + package require registry + set uilocale [registry get $key "PreferredUILanguages"] + msgcat::ConvertLocale [string map {- _} [lindex $uilocale 0]] + } uilocale]} { + if {[string length $uilocale] > 0} { + msgcat::mclocale $uilocale + } + } + } + _mc_update_locale +} + proc _mc_trim {fmt} { set cmk [string first @@ $fmt] if {$cmk > 0} { @@ -139,6 +158,10 @@ if {$_trace >= 0} { set _trace 0 } +# variable for the last merged branch (useful for a default when deleting +# branches). +set _last_merged_branch {} + proc shellpath {} { global _shellpath env if {[string match @@* $_shellpath]} { @@ -1448,13 +1471,17 @@ proc rescan_stage2 {fd after} { close $fd } - set ls_others [list --exclude-per-directory=.gitignore] - if {[have_info_exclude]} { - lappend ls_others "--exclude-from=[gitdir info exclude]" - } - set user_exclude [get_config core.excludesfile] - if {$user_exclude ne {} && [file readable $user_exclude]} { - lappend ls_others "--exclude-from=$user_exclude" + if {[package vsatisfies $::_git_version 1.6.3]} { + set ls_others [list --exclude-standard] + } else { + set ls_others [list --exclude-per-directory=.gitignore] + if {[have_info_exclude]} { + lappend ls_others "--exclude-from=[gitdir info exclude]" + } + set user_exclude [get_config core.excludesfile] + if {$user_exclude ne {} && [file readable $user_exclude]} { + lappend ls_others "--exclude-from=[file normalize $user_exclude]" + } } set buf_rdi {} @@ -1958,8 +1985,8 @@ static unsigned char file_merge_bits[] = { } -maskdata $filemask image create bitmap file_statechange -background white -foreground green -data { -#define file_merge_width 14 -#define file_merge_height 15 +#define file_statechange_width 14 +#define file_statechange_height 15 static unsigned char file_statechange_bits[] = { 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x62, 0x10, 0x62, 0x10, 0xba, 0x11, 0xba, 0x11, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, @@ -1993,7 +2020,11 @@ foreach i { {MD {mc "Staged for commit, missing"}} {_T {mc "File type changed, not staged"}} + {MT {mc "File type changed, old type staged for commit"}} + {AT {mc "File type changed, old type staged for commit"}} {T_ {mc "File type changed, staged"}} + {TM {mc "File type change staged, modification not staged"}} + {TD {mc "File type change staged, file missing"}} {_O {mc "Untracked, not staged"}} {A_ {mc "Staged for commit"}} @@ -3331,6 +3362,8 @@ foreach {n c} {0 black 1 red4 2 green4 3 yellow4 4 blue4 5 magenta4 6 cyan4 7 gr } $ui_diff tag configure clr1 -font font_diffbold +$ui_diff tag conf d_info -foreground blue -font font_diffbold + $ui_diff tag conf d_cr -elide true $ui_diff tag conf d_@ -font font_diffbold $ui_diff tag conf d_+ -foreground {#00a000} @@ -3351,13 +3384,13 @@ $ui_diff tag conf d_s- \ -foreground red \ -background ivory1 -$ui_diff tag conf d<<<<<<< \ +$ui_diff tag conf d< \ -foreground orange \ -font font_diffbold -$ui_diff tag conf d======= \ +$ui_diff tag conf d= \ -foreground orange \ -font font_diffbold -$ui_diff tag conf d>>>>>>> \ +$ui_diff tag conf d> \ -foreground orange \ -font font_diffbold @@ -3533,8 +3566,8 @@ proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} { || $current_diff_path eq {} || {__} eq $state || {_O} eq $state - || {_T} eq $state - || {T_} eq $state + || [string match {?T} $state] + || [string match {T?} $state] || [has_textconv $current_diff_path]} { set s disabled } else { diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl index c2415729e0..a8c6223511 100644 --- a/git-gui/lib/browser.tcl +++ b/git-gui/lib/browser.tcl @@ -121,7 +121,7 @@ method _parent {} { if {$browser_stack eq {}} { regsub {:.*$} $browser_path {:} browser_path } else { - regsub {/[^/]+$} $browser_path {} browser_path + regsub {/[^/]+/$} $browser_path {/} browser_path } set browser_status [mc "Loading %s..." $browser_path] _ls $this [lindex $parent 0] [lindex $parent 1] diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index fae119286d..657f7d5dc1 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -214,14 +214,6 @@ constructor pick {} { } } -proc _home {} { - if {[catch {set h $::env(HOME)}] - || ![file isdirectory $h]} { - set h . - } - return $h -} - method _center {} { set nx [winfo reqwidth $top] set ny [winfo reqheight $top] @@ -420,7 +412,7 @@ method _new_local_path {} { if {$local_path ne {}} { set p [file dirname $local_path] } else { - set p [_home] + set p [pwd] } set p [tk_chooseDirectory \ @@ -541,7 +533,7 @@ method _open_origin {} { if {$origin_url ne {} && [file isdirectory $origin_url]} { set p $origin_url } else { - set p [_home] + set p [pwd] } set p [tk_chooseDirectory \ @@ -1042,7 +1034,7 @@ method _open_local_path {} { if {$local_path ne {}} { set p $local_path } else { - set p [_home] + set p [pwd] } set p [tk_chooseDirectory \ diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl index 7f459cd564..5ce46877bf 100644 --- a/git-gui/lib/commit.tcl +++ b/git-gui/lib/commit.tcl @@ -161,11 +161,12 @@ The rescan will be automatically started now. # set files_ready 0 foreach path [array names file_states] { - switch -glob -- [lindex $file_states($path) 0] { + set s $file_states($path) + switch -glob -- [lindex $s 0] { _? {continue} A? - D? - - T_ - + T? - M? {set files_ready 1} _U - U? { @@ -452,7 +453,11 @@ A rescan will be automatically started now. } AM - AD - + AT - + TM - + TD - MM - + MT - MD { set file_states($path) [list \ _[string index $m 1] \ diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index dcf0711be0..cf8a95ec34 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -122,22 +122,22 @@ proc show_unmerged_diff {cont_info} { if {$merge_stages(2) eq {}} { set is_conflict_diff 1 lappend current_diff_queue \ - [list [mc "LOCAL: deleted\nREMOTE:\n"] d======= \ + [list [mc "LOCAL: deleted\nREMOTE:\n"] d= \ [list ":1:$current_diff_path" ":3:$current_diff_path"]] } elseif {$merge_stages(3) eq {}} { set is_conflict_diff 1 lappend current_diff_queue \ - [list [mc "REMOTE: deleted\nLOCAL:\n"] d======= \ + [list [mc "REMOTE: deleted\nLOCAL:\n"] d= \ [list ":1:$current_diff_path" ":2:$current_diff_path"]] } elseif {[lindex $merge_stages(1) 0] eq {120000} || [lindex $merge_stages(2) 0] eq {120000} || [lindex $merge_stages(3) 0] eq {120000}} { set is_conflict_diff 1 lappend current_diff_queue \ - [list [mc "LOCAL:\n"] d======= \ + [list [mc "LOCAL:\n"] d= \ [list ":1:$current_diff_path" ":2:$current_diff_path"]] lappend current_diff_queue \ - [list [mc "REMOTE:\n"] d======= \ + [list [mc "REMOTE:\n"] d= \ [list ":1:$current_diff_path" ":3:$current_diff_path"]] } else { start_show_diff $cont_info @@ -208,32 +208,32 @@ proc show_other_diff {path w m cont_info} { $ui_diff insert end [append \ "* " \ [mc "Git Repository (subproject)"] \ - "\n"] d_@ + "\n"] d_info } elseif {![catch {set type [exec file $path]}]} { set n [string length $path] if {[string equal -length $n $path $type]} { set type [string range $type $n end] regsub {^:?\s*} $type {} type } - $ui_diff insert end "* $type\n" d_@ + $ui_diff insert end "* $type\n" d_info } if {[string first "\0" $content] != -1} { $ui_diff insert end \ [mc "* Binary file (not showing content)."] \ - d_@ + d_info } else { if {$sz > $max_sz} { $ui_diff insert end [mc \ "* Untracked file is %d bytes. * Showing only first %d bytes. -" $sz $max_sz] d_@ +" $sz $max_sz] d_info } $ui_diff insert end $content if {$sz > $max_sz} { $ui_diff insert end [mc " * Untracked file clipped here by %s. * To see the entire file, use an external editor. -" [appname]] d_@ +" [appname]] d_info } } $ui_diff conf -state disabled @@ -253,6 +253,19 @@ proc show_other_diff {path w m cont_info} { } } +proc get_conflict_marker_size {path} { + set size 7 + catch { + set fd_rc [eval [list git_read check-attr "conflict-marker-size" -- $path]] + set ret [gets $fd_rc line] + close $fd_rc + if {$ret > 0} { + regexp {.*: conflict-marker-size: (\d+)$} $line line size + } + } + return $size +} + proc start_show_diff {cont_info {add_opts {}}} { global file_states file_lists global is_3way_diff is_submodule_diff diff_active repo_config @@ -268,6 +281,7 @@ proc start_show_diff {cont_info {add_opts {}}} { set is_submodule_diff 0 set diff_active 1 set current_diff_header {} + set conflict_size [get_conflict_marker_size $path] set cmd [list] if {$w eq $ui_index} { @@ -329,7 +343,7 @@ proc start_show_diff {cont_info {add_opts {}}} { -blocking 0 \ -encoding [get_path_encoding $path] \ -translation lf - fileevent $fd readable [list read_diff $fd $cont_info] + fileevent $fd readable [list read_diff $fd $conflict_size $cont_info] } proc parse_color_line {line} { @@ -337,19 +351,27 @@ proc parse_color_line {line} { set result "" set markup [list] set regexp {\033\[((?:\d+;)*\d+)?m} + set need_reset 0 while {[regexp -indices -start $start $regexp $line match code]} { foreach {begin end} $match break append result [string range $line $start [expr {$begin - 1}]] - lappend markup [string length $result] \ - [eval [linsert $code 0 string range $line]] + set pos [string length $result] + set col [eval [linsert $code 0 string range $line]] set start [incr end] + if {$col eq "0" || $col eq ""} { + if {!$need_reset} continue + set need_reset 0 + } else { + set need_reset 1 + } + lappend markup $pos $col } append result [string range $line $start end] if {[llength $markup] < 4} {set markup {}} return [list $result $markup] } -proc read_diff {fd cont_info} { +proc read_diff {fd conflict_size cont_info} { global ui_diff diff_active is_submodule_diff global is_3way_diff is_conflict_diff current_diff_header global current_diff_queue @@ -360,37 +382,50 @@ proc read_diff {fd cont_info} { foreach {line markup} [parse_color_line $line] break set line [string map {\033 ^} $line] - # -- Cleanup uninteresting diff header lines. + set tags {} + + # -- Check for start of diff header. + if { [string match {diff --git *} $line] + || [string match {diff --cc *} $line] + || [string match {diff --combined *} $line]} { + set ::current_diff_inheader 1 + } + + # -- Check for end of diff header (any hunk line will do this). + # + if {[regexp {^@@+ } $line]} {set ::current_diff_inheader 0} + + # -- Automatically detect if this is a 3 way diff. # + if {[string match {@@@ *} $line]} {set is_3way_diff 1} + if {$::current_diff_inheader} { + + # -- These two lines stop a diff header and shouldn't be in there + if { [string match {Binary files * and * differ} $line] + || [regexp {^\* Unmerged path } $line]} { + set ::current_diff_inheader 0 + } else { + append current_diff_header $line "\n" + } + + # -- Cleanup uninteresting diff header lines. + # if { [string match {diff --git *} $line] || [string match {diff --cc *} $line] || [string match {diff --combined *} $line] || [string match {--- *} $line] - || [string match {+++ *} $line]} { - append current_diff_header $line "\n" + || [string match {+++ *} $line] + || [string match {index *} $line]} { continue } - } - if {[string match {index *} $line]} continue - if {$line eq {deleted file mode 120000}} { - set line "deleted symlink" - } - set ::current_diff_inheader 0 - # -- Automatically detect if this is a 3 way diff. - # - if {[string match {@@@ *} $line]} {set is_3way_diff 1} + # -- Name it symlink, not 120000 + # Note, that the original line is in $current_diff_header + regsub {^(deleted|new) file mode 120000} $line {\1 symlink} line - if {[string match {mode *} $line] - || [string match {new file *} $line] - || [regexp {^(old|new) mode *} $line] - || [string match {deleted file *} $line] - || [string match {deleted symlink} $line] - || [string match {Binary files * and * differ} $line] - || $line eq {\ No newline at end of file} - || [regexp {^\* Unmerged path } $line]} { - set tags {} + } elseif { $line eq {\ No newline at end of file}} { + # -- Handle some special lines } elseif {$is_3way_diff} { set op [string range $line 0 1] switch -- $op { @@ -402,7 +437,9 @@ proc read_diff {fd cont_info} { {- } {set tags d_-s} {--} {set tags d_--} {++} { - if {[regexp {^\+\+([<>]{7} |={7})} $line _g op]} { + set regexp [string map [list %conflict_size $conflict_size]\ + {^\+\+([<>=]){%conflict_size}(?: |$)}] + if {[regexp $regexp $line _g op]} { set is_conflict_diff 1 set line [string replace $line 0 1 { }] set tags d$op @@ -418,10 +455,10 @@ proc read_diff {fd cont_info} { } elseif {$is_submodule_diff} { if {$line == ""} continue if {[regexp {^Submodule } $line]} { - set tags d_@ + set tags d_info } elseif {[regexp {^\* } $line]} { set line [string replace $line 0 1 {Submodule }] - set tags d_@ + set tags d_info } else { set op [string range $line 0 2] switch -- $op { @@ -441,7 +478,9 @@ proc read_diff {fd cont_info} { {@} {set tags d_@} {-} {set tags d_-} {+} { - if {[regexp {^\+([<>]{7} |={7})} $line _g op]} { + set regexp [string map [list %conflict_size $conflict_size]\ + {^\+([<>=]){%conflict_size}(?: |$)}] + if {[regexp $regexp $line _g op]} { set is_conflict_diff 1 set tags d$op } else { diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl index e9db0c4989..5d7bbf23ed 100644 --- a/git-gui/lib/index.tcl +++ b/git-gui/lib/index.tcl @@ -103,8 +103,11 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} { set s $file_states($path) switch -glob -- [lindex $s 0] { A? {set new _O} - M? {set new _M} + MT - + TM - T_ {set new _T} + M? {set new _M} + TD - D_ {set new _D} D? {set new _?} ?? {continue} @@ -167,7 +170,10 @@ proc write_update_index {fd pathList totalCnt batch after} { AD {set new __} ?D {set new D_} _O - + AT - AM {set new A_} + TM - + MT - _T {set new T_} _U - U? { @@ -261,7 +267,7 @@ proc unstage_helper {txt paths} { switch -glob -- [lindex $file_states($path) 0] { A? - M? - - T_ - + T? - D? { lappend pathList $path if {$path eq $current_diff_path} { diff --git a/git-gui/lib/merge.tcl b/git-gui/lib/merge.tcl index 5cded2341c..460d32fa22 100644 --- a/git-gui/lib/merge.tcl +++ b/git-gui/lib/merge.tcl @@ -83,6 +83,7 @@ method _visualize {} { method _start {} { global HEAD current_branch remote_url + global _last_merged_branch set name [_rev $this] if {$name eq {}} { @@ -109,6 +110,7 @@ method _start {} { regsub ^refs/heads/ $branch {} branch puts $fh "$cmit\t\tbranch '$branch' of $remote" close $fh + set _last_merged_branch $branch set cmd [list git] lappend cmd merge diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl index 3fe90e6970..3c8e73bceb 100644 --- a/git-gui/lib/mergetool.tcl +++ b/git-gui/lib/mergetool.tcl @@ -175,43 +175,56 @@ proc merge_resolve_tool2 {} { # Build the command line switch -- $tool { - kdiff3 { + araxis { if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Base)" \ - --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE"] + set cmdline [list "$merge_tool_path" -wait -merge -3 -a1 \ + -title1:"'$MERGED (Base)'" -title2:"'$MERGED (Local)'" \ + -title3:"'$MERGED (Remote)'" \ + "$BASE" "$LOCAL" "$REMOTE" "$MERGED"] } else { - set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Local)" \ - --L2 "$MERGED (Remote)" -o "$MERGED" "$LOCAL" "$REMOTE"] + set cmdline [list "$merge_tool_path" -wait -2 \ + -title1:"'$MERGED (Local)'" -title2:"'$MERGED (Remote)'" \ + "$LOCAL" "$REMOTE" "$MERGED"] } } - tkdiff { + bc3 { if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"] + set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" -mergeoutput="$MERGED"] } else { - set cmdline [list "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"] + set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -mergeoutput="$MERGED"] } } - meld { - set cmdline [list "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"] + ecmerge { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"] + } else { + set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"] + } + } + emerge { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" -f emerge-files-with-ancestor-command \ + "$LOCAL" "$REMOTE" "$BASE" "$basename"] + } else { + set cmdline [list "$merge_tool_path" -f emerge-files-command \ + "$LOCAL" "$REMOTE" "$basename"] + } } gvimdiff { set cmdline [list "$merge_tool_path" -f "$LOCAL" "$MERGED" "$REMOTE"] } - xxdiff { + kdiff3 { if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" -X --show-merged-pane \ - -R {Accel.SaveAsMerged: "Ctrl-S"} \ - -R {Accel.Search: "Ctrl+F"} \ - -R {Accel.SearchForward: "Ctrl-G"} \ - --merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"] + set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Base)" \ + --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE"] } else { - set cmdline [list "$merge_tool_path" -X --show-merged-pane \ - -R {Accel.SaveAsMerged: "Ctrl-S"} \ - -R {Accel.Search: "Ctrl+F"} \ - -R {Accel.SearchForward: "Ctrl-G"} \ - --merged-file "$MERGED" "$LOCAL" "$REMOTE"] + set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Local)" \ + --L2 "$MERGED (Remote)" -o "$MERGED" "$LOCAL" "$REMOTE"] } } + meld { + set cmdline [list "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"] + } opendiff { if {$base_stage ne {}} { set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED"] @@ -219,22 +232,20 @@ proc merge_resolve_tool2 {} { set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED"] } } - ecmerge { - if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"] - } else { - set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"] - } + p4merge { + set cmdline [list "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED"] } - emerge { + tkdiff { if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" -f emerge-files-with-ancestor-command \ - "$LOCAL" "$REMOTE" "$BASE" "$basename"] + set cmdline [list "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"] } else { - set cmdline [list "$merge_tool_path" -f emerge-files-command \ - "$LOCAL" "$REMOTE" "$basename"] + set cmdline [list "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"] } } + vimdiff { + error_popup [mc "Not a GUI merge tool: '%s'" $tool] + return + } winmerge { if {$base_stage ne {}} { # This tool does not support 3-way merges. @@ -245,25 +256,21 @@ proc merge_resolve_tool2 {} { -dl "Theirs File" -dr "Mine File" "$REMOTE" "$LOCAL" "$MERGED"] } } - araxis { + xxdiff { if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" -wait -merge -3 -a1 \ - -title1:"'$MERGED (Base)'" -title2:"'$MERGED (Local)'" \ - -title3:"'$MERGED (Remote)'" \ - "$BASE" "$LOCAL" "$REMOTE" "$MERGED"] + set cmdline [list "$merge_tool_path" -X --show-merged-pane \ + -R {Accel.SaveAsMerged: "Ctrl-S"} \ + -R {Accel.Search: "Ctrl+F"} \ + -R {Accel.SearchForward: "Ctrl-G"} \ + --merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"] } else { - set cmdline [list "$merge_tool_path" -wait -2 \ - -title1:"'$MERGED (Local)'" -title2:"'$MERGED (Remote)'" \ - "$LOCAL" "$REMOTE" "$MERGED"] + set cmdline [list "$merge_tool_path" -X --show-merged-pane \ + -R {Accel.SaveAsMerged: "Ctrl-S"} \ + -R {Accel.Search: "Ctrl+F"} \ + -R {Accel.SearchForward: "Ctrl-G"} \ + --merged-file "$MERGED" "$LOCAL" "$REMOTE"] } } - p4merge { - set cmdline [list "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED"] - } - vimdiff { - error_popup [mc "Not a GUI merge tool: '%s'" $tool] - return - } default { error_popup [mc "Unsupported merge tool '%s'" $tool] return diff --git a/git-gui/lib/remote.tcl b/git-gui/lib/remote.tcl index b92b429cf7..5e4e7f4c83 100644 --- a/git-gui/lib/remote.tcl +++ b/git-gui/lib/remote.tcl @@ -157,22 +157,7 @@ proc add_fetch_entry {r} { } if {$enable} { - if {![winfo exists $fetch_m]} { - menu $remove_m - $remote_m insert 0 cascade \ - -label [mc "Remove Remote"] \ - -menu $remove_m - - menu $prune_m - $remote_m insert 0 cascade \ - -label [mc "Prune from"] \ - -menu $prune_m - - menu $fetch_m - $remote_m insert 0 cascade \ - -label [mc "Fetch from"] \ - -menu $fetch_m - } + make_sure_remote_submenues_exist $remote_m $fetch_m add command \ -label $r \ @@ -222,6 +207,70 @@ proc add_push_entry {r} { } } +proc make_sure_remote_submenues_exist {remote_m} { + set fetch_m $remote_m.fetch + set prune_m $remote_m.prune + set remove_m $remote_m.remove + + if {![winfo exists $fetch_m]} { + menu $remove_m + $remote_m insert 0 cascade \ + -label [mc "Remove Remote"] \ + -menu $remove_m + + menu $prune_m + $remote_m insert 0 cascade \ + -label [mc "Prune from"] \ + -menu $prune_m + + menu $fetch_m + $remote_m insert 0 cascade \ + -label [mc "Fetch from"] \ + -menu $fetch_m + } +} + +proc update_all_remotes_menu_entry {} { + global all_remotes + + if {[git-version < 1.6.6]} { return } + + set have_remote 0 + foreach r $all_remotes { + incr have_remote + } + + set remote_m .mbar.remote + set fetch_m $remote_m.fetch + set prune_m $remote_m.prune + if {$have_remote > 1} { + make_sure_remote_submenues_exist $remote_m + if {[$fetch_m entrycget end -label] ne "All"} { + + $fetch_m insert end separator + $fetch_m insert end command \ + -label "All" \ + -command fetch_from_all + + $prune_m insert end separator + $prune_m insert end command \ + -label "All" \ + -command prune_from_all + } + } else { + if {[winfo exists $fetch_m]} { + if {[$fetch_m entrycget end -label] eq "All"} { + + delete_from_menu $fetch_m end + delete_from_menu $fetch_m end + + delete_from_menu $prune_m end + delete_from_menu $prune_m end + } + } + } +} + proc populate_remotes_menu {} { global all_remotes @@ -229,6 +278,8 @@ proc populate_remotes_menu {} { add_fetch_entry $r add_push_entry $r } + + update_all_remotes_menu_entry } proc add_single_remote {name location} { @@ -244,6 +295,8 @@ proc add_single_remote {name location} { add_fetch_entry $name add_push_entry $name + + update_all_remotes_menu_entry } proc delete_from_menu {menu name} { @@ -264,8 +317,8 @@ proc remove_remote {name} { unset repo_config(remote.$name.push) } - set i [lsearch -exact all_remotes $name] - lreplace all_remotes $i $i + set i [lsearch -exact $all_remotes $name] + set all_remotes [lreplace $all_remotes $i $i] set remote_m .mbar.remote delete_from_menu $remote_m.fetch $name @@ -273,4 +326,6 @@ proc remove_remote {name} { delete_from_menu $remote_m.remove $name # Not all remotes are in the push menu catch { delete_from_menu $remote_m.push $name } + + update_all_remotes_menu_entry } diff --git a/git-gui/lib/remote_branch_delete.tcl b/git-gui/lib/remote_branch_delete.tcl index f872a3d89d..fcc06d03a1 100644 --- a/git-gui/lib/remote_branch_delete.tcl +++ b/git-gui/lib/remote_branch_delete.tcl @@ -251,7 +251,7 @@ method _write_url {args} { set urltype url } method _write_check_head {args} { set checktype head } method _write_head_list {args} { - global current_branch + global current_branch _last_merged_branch $head_m delete 0 end foreach abr $head_list { @@ -267,6 +267,13 @@ method _write_head_list {args} { set check_head $current_branch } } + set lmb [lsearch -exact -sorted $head_list $_last_merged_branch] + if {$lmb >= 0} { + $w.heads.l conf -state normal + $w.heads.l select set $lmb + $w.heads.l yview $lmb + $w.heads.l conf -state disabled + } } method _write_urltype {args} { diff --git a/git-gui/lib/transport.tcl b/git-gui/lib/transport.tcl index 60e3a642c5..7fad9b7d91 100644 --- a/git-gui/lib/transport.tcl +++ b/git-gui/lib/transport.tcl @@ -20,6 +20,35 @@ proc prune_from {remote} { console::exec $w [list git remote prune $remote] } +proc fetch_from_all {} { + set w [console::new \ + [mc "fetch all remotes"] \ + [mc "Fetching new changes from all remotes"]] + + set cmd [list git fetch --all] + if {[is_config_true gui.pruneduringfetch]} { + lappend cmd --prune + } + + console::exec $w $cmd +} + +proc prune_from_all {} { + global all_remotes + + set w [console::new \ + [mc "remote prune all remotes"] \ + [mc "Pruning tracking branches deleted from all remotes"]] + + set cmd [list git remote prune] + + foreach r $all_remotes { + lappend cmd $r + } + + console::exec $w $cmd +} + proc push_to {remote} { set w [console::new \ [mc "push %s" $remote] \ @@ -123,6 +152,7 @@ proc do_push_anywhere {} { $w.source.l insert end $h if {$h eq $current_branch} { $w.source.l select set end + $w.source.l yview end } } pack $w.source.l -side left -fill both -expand 1 @@ -135,7 +165,9 @@ proc do_push_anywhere {} { -value remote \ -variable push_urltype if {$use_ttk} { - ttk::combobox $w.dest.remote_m -textvariable push_remote \ + ttk::combobox $w.dest.remote_m -state readonly \ + -exportselection false \ + -textvariable push_remote \ -values $all_remotes } else { eval tk_optionMenu $w.dest.remote_m push_remote $all_remotes diff --git a/git-gui/po/glossary/pt_br.po b/git-gui/po/glossary/pt_br.po new file mode 100644 index 0000000000..eb039b2b49 --- /dev/null +++ b/git-gui/po/glossary/pt_br.po @@ -0,0 +1,169 @@ +# Translation of git-gui to Brazilian Portuguese +# Copyright (C) 2007 Shawn Pearce, et al. +# This file is distributed under the same license as the git-gui package. +# +# Alexandre Erwin Ittner <alexandre@ittner.com.br>, 2010. +msgid "" +msgstr "" +"Project-Id-Version: git-gui\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-01-26 15:47-0800\n" +"PO-Revision-Date: 2010-09-18 11:09-0300\n" +"Last-Translator: Alexandre Erwin Ittner <alexandre@ittner.com.br>\n" +"Language-Team: Brazilian Portuguese <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)" +msgid "" +"English Term (Dear translator: This file will never be visible to the user!)" +msgstr "" + +#. "" +msgid "amend" +msgstr "corrigir" + +#. "" +msgid "annotate" +msgstr "anotar" + +#. "A 'branch' is an active line of development." +msgid "branch [noun]" +msgstr "ramo" + +#. "" +msgid "branch [verb]" +msgstr "ramificar" + +#. "" +msgid "checkout [noun]" +msgstr "checkout" + +#. "The action of updating the working tree to a revision which was stored in the object database." +msgid "checkout [verb]" +msgstr "efetuar checkout" + +#. "" +msgid "clone [verb]" +msgstr "clonar" + +#. "A single point in the git history." +msgid "commit [noun]" +msgstr "revisão" + +#. "The action of storing a new snapshot of the project's state in the git history." +msgid "commit [verb]" +msgstr "salvar revisão" + +#. "" +msgid "diff [noun]" +msgstr "diff" + +#. "" +msgid "diff [verb]" +msgstr "comparar" + +#. "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have." +msgid "fast forward merge" +msgstr "mesclagem rápida" + +#. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too." +msgid "fetch" +msgstr "receber" + +#. "One context of consecutive lines in a whole patch, which consists of many such hunks" +msgid "hunk" +msgstr "trecho" + +#. "A collection of files. The index is a stored version of your working tree." +msgid "index (in git-gui: staging area)" +msgstr "índice" + +#. "A successful merge results in the creation of a new commit representing the result of the merge." +msgid "merge [noun]" +msgstr "mesclagem" + +#. "To bring the contents of another branch into the current branch." +msgid "merge [verb]" +msgstr "mesclar" + +#. "" +msgid "message" +msgstr "descrição da revisão" + +#. "Deletes all stale tracking branches under <name>. These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in 'remotes/<name>'." +msgid "prune" +msgstr "limpar" + +#. "Pulling a branch means to fetch it and merge it." +msgid "pull" +msgstr "receber e mesclar" + +#. "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)" +msgid "push" +msgstr "enviar" + +#. "" +msgid "redo" +msgstr "refazer" + +#. "An other repository ('remote'). One might have a set of remotes whose branches one tracks." +msgid "remote" +msgstr "repositório remoto" + +#. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)" +msgid "repository" +msgstr "repositório" + +#. "" +msgid "reset" +msgstr "descartar, redefinir" + +#. "" +msgid "revert" +msgstr "reverter" + +#. "A particular state of files and directories which was stored in the object database." +msgid "revision" +msgstr "revisão" + +#. "" +msgid "sign off" +msgstr "assinar embaixo" + +#. "" +msgid "staging area" +msgstr "???" + +#. "" +msgid "status" +msgstr "status" + +#. "A ref pointing to a tag or commit object" +msgid "tag [noun]" +msgstr "etiqueta" + +#. "" +msgid "tag [verb]" +msgstr "marcar etiqueta" + +#. "A regular git branch that is used to follow changes from another repository." +msgid "tracking branch" +msgstr "ramo de rastreamento" + +#. "" +msgid "undo" +msgstr "desfazer" + +#. "" +msgid "update" +msgstr "atualizar" + +#. "" +msgid "verify" +msgstr "verificar" + +#. "The tree of actual checked out files." +msgid "working copy, working tree" +msgstr "cópia de trabalho, árvore de trabalho" diff --git a/git-gui/po/pt_br.po b/git-gui/po/pt_br.po new file mode 100644 index 0000000000..b175b9791e --- /dev/null +++ b/git-gui/po/pt_br.po @@ -0,0 +1,2568 @@ +# Translation of git-gui to Brazilian Portuguese +# Copyright (C) 2007 Shawn Pearce, et al. +# This file is distributed under the same license as the git-gui package. +# +# Alexandre Erwin Ittner <alexandre@ittner.com.br>, 2010. +msgid "" +msgstr "" +"Project-Id-Version: git-gui\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-01-26 15:47-0800\n" +"PO-Revision-Date: 2010-09-18 11:09-0300\n" +"Last-Translator: Alexandre Erwin Ittner <alexandre@ittner.com.br>\n" +"Language-Team: Brazilian Portuguese <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: git-gui.sh:41 git-gui.sh:793 git-gui.sh:807 git-gui.sh:820 git-gui.sh:903 +#: git-gui.sh:922 +msgid "git-gui: fatal error" +msgstr "git-gui: erro fatal" + +#: git-gui.sh:743 +#, tcl-format +msgid "Invalid font specified in %s:" +msgstr "Fonte inválida indicada em %s:" + +#: git-gui.sh:779 +msgid "Main Font" +msgstr "Fonte principal" + +#: git-gui.sh:780 +msgid "Diff/Console Font" +msgstr "Fonte para o diff/console" + +#: git-gui.sh:794 +msgid "Cannot find git in PATH." +msgstr "Impossível encontrar o git no \"PATH\"" + +#: git-gui.sh:821 +msgid "Cannot parse Git version string:" +msgstr "Impossível interpretar a versão do git:" + +#: git-gui.sh:839 +#, 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 "" +"Não foi possível determinar a versão do git:\n" +"\n" +"%s afirmar que sua versão é \"%s\".\n" +"\n" +"%s exige o Git 1.5.0 ou posterior.\n" +"\n" +"Assumir que '%s' é a versão 1.5.0?\n" + +#: git-gui.sh:1128 +msgid "Git directory not found:" +msgstr "Diretório do Git não encontrado:" + +#: git-gui.sh:1146 +msgid "Cannot move to top of working directory:" +msgstr "Impossível mover para o início do diretório de trabalho:" + +#: git-gui.sh:1154 +msgid "Cannot use bare repository:" +msgstr "Impossível usar repositório puro:" + +#: git-gui.sh:1162 +msgid "No working directory" +msgstr "Sem diretório de trabalho" + +#: git-gui.sh:1334 lib/checkout_op.tcl:306 +msgid "Refreshing file status..." +msgstr "Atualizando estado dos arquivos..." + +#: git-gui.sh:1390 +msgid "Scanning for modified files ..." +msgstr "Procurando por arquivos modificados ..." + +#: git-gui.sh:1454 +msgid "Calling prepare-commit-msg hook..." +msgstr "Executando hook \"prepare-commit-msg\"..." + +#: git-gui.sh:1471 +msgid "Commit declined by prepare-commit-msg hook." +msgstr "O script \"prepare-commit-msg\" negou a criação de uma nova revisão" + +#: git-gui.sh:1629 lib/browser.tcl:246 +msgid "Ready." +msgstr "Pronto." + +#: git-gui.sh:1787 +#, tcl-format +msgid "Displaying only %s of %s files." +msgstr "Exibindo apenas %s de %s arquivos." + +#: git-gui.sh:1913 +msgid "Unmodified" +msgstr "Não modificado" + +#: git-gui.sh:1915 +msgid "Modified, not staged" +msgstr "Modificado, não marcado" + +#: git-gui.sh:1916 git-gui.sh:1924 +msgid "Staged for commit" +msgstr "Marcado para uma nova revisão" + +#: git-gui.sh:1917 git-gui.sh:1925 +msgid "Portions staged for commit" +msgstr "Trechos marcados para revisão" + +#: git-gui.sh:1918 git-gui.sh:1926 +msgid "Staged for commit, missing" +msgstr "Marcado para revisão, faltando" + +#: git-gui.sh:1920 +msgid "File type changed, not staged" +msgstr "Tipo do arquivo modificado, não marcado" + +#: git-gui.sh:1921 +msgid "File type changed, staged" +msgstr "Tipo do arquivo modificado, marcado" + +#: git-gui.sh:1923 +msgid "Untracked, not staged" +msgstr "Não monitorado, não marcado" + +#: git-gui.sh:1928 +msgid "Missing" +msgstr "Faltando" + +#: git-gui.sh:1929 +msgid "Staged for removal" +msgstr "Marcado para remoção" + +#: git-gui.sh:1930 +msgid "Staged for removal, still present" +msgstr "Marcado para remoção, ainda presente" + +#: git-gui.sh:1932 git-gui.sh:1933 git-gui.sh:1934 git-gui.sh:1935 +#: git-gui.sh:1936 git-gui.sh:1937 +msgid "Requires merge resolution" +msgstr "Requer resolução de conflitos" + +#: git-gui.sh:1972 +msgid "Starting gitk... please wait..." +msgstr "Iniciando gitk... Aguarde..." + +#: git-gui.sh:1984 +msgid "Couldn't find gitk in PATH" +msgstr "Impossível encontrar o gitk no PATH" + +#: git-gui.sh:2043 +msgid "Couldn't find git gui in PATH" +msgstr "Impossível encontrar o \"git gui\" no PATH" + +#: git-gui.sh:2455 lib/choose_repository.tcl:36 +msgid "Repository" +msgstr "Repositório" + +#: git-gui.sh:2456 +msgid "Edit" +msgstr "Editar" + +#: git-gui.sh:2458 lib/choose_rev.tcl:561 +msgid "Branch" +msgstr "Ramo" + +#: git-gui.sh:2461 lib/choose_rev.tcl:548 +msgid "Commit@@noun" +msgstr "Revisão" + +#: git-gui.sh:2464 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 +msgid "Merge" +msgstr "Mesclar" + +#: git-gui.sh:2465 lib/choose_rev.tcl:557 +msgid "Remote" +msgstr "Remoto" + +#: git-gui.sh:2468 +msgid "Tools" +msgstr "Ferramentas" + +#: git-gui.sh:2477 +msgid "Explore Working Copy" +msgstr "Explorar cópia de trabalho" + +#: git-gui.sh:2483 +msgid "Browse Current Branch's Files" +msgstr "Explorar arquivos do ramo atual" + +#: git-gui.sh:2487 +msgid "Browse Branch Files..." +msgstr "Explorar arquivos do ramo..." + +#: git-gui.sh:2492 +msgid "Visualize Current Branch's History" +msgstr "Visualizar histórico do ramo atual" + +#: git-gui.sh:2496 +msgid "Visualize All Branch History" +msgstr "Visualizar histórico de todos os ramos" + +#: git-gui.sh:2503 +#, tcl-format +msgid "Browse %s's Files" +msgstr "Explorar arquivos de %s" + +#: git-gui.sh:2505 +#, tcl-format +msgid "Visualize %s's History" +msgstr "Visualizar histórico de %s" + +#: git-gui.sh:2510 lib/database.tcl:27 lib/database.tcl:67 +msgid "Database Statistics" +msgstr "Estatísticas do banco de dados" + +#: git-gui.sh:2513 lib/database.tcl:34 +msgid "Compress Database" +msgstr "Compactar banco de dados" + +#: git-gui.sh:2516 +msgid "Verify Database" +msgstr "Verificar banco de dados" + +#: git-gui.sh:2523 git-gui.sh:2527 git-gui.sh:2531 lib/shortcut.tcl:8 +#: lib/shortcut.tcl:40 lib/shortcut.tcl:72 +msgid "Create Desktop Icon" +msgstr "Criar ícone na área de trabalho" + +#: git-gui.sh:2539 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 +msgid "Quit" +msgstr "Sair" + +#: git-gui.sh:2547 +msgid "Undo" +msgstr "Desfazer" + +#: git-gui.sh:2550 +msgid "Redo" +msgstr "Refazer" + +#: git-gui.sh:2554 git-gui.sh:3109 +msgid "Cut" +msgstr "Recortar" + +#: git-gui.sh:2557 git-gui.sh:3112 git-gui.sh:3186 git-gui.sh:3259 +#: lib/console.tcl:69 +msgid "Copy" +msgstr "Copiar" + +#: git-gui.sh:2560 git-gui.sh:3115 +msgid "Paste" +msgstr "Colar" + +#: git-gui.sh:2563 git-gui.sh:3118 lib/branch_delete.tcl:26 +#: lib/remote_branch_delete.tcl:38 +msgid "Delete" +msgstr "Apagar" + +#: git-gui.sh:2567 git-gui.sh:3122 git-gui.sh:3263 lib/console.tcl:71 +msgid "Select All" +msgstr "Selecionar tudo" + +#: git-gui.sh:2576 +msgid "Create..." +msgstr "Criar..." + +#: git-gui.sh:2582 +msgid "Checkout..." +msgstr "Checkout..." + +#: git-gui.sh:2588 +msgid "Rename..." +msgstr "Renomear..." + +#: git-gui.sh:2593 +msgid "Delete..." +msgstr "Apagar..." + +#: git-gui.sh:2598 +msgid "Reset..." +msgstr "Redefinir..." + +#: git-gui.sh:2608 +msgid "Done" +msgstr "Pronto" + +#: git-gui.sh:2610 +msgid "Commit@@verb" +msgstr "Salvar revisão" + +#: git-gui.sh:2619 git-gui.sh:3050 +msgid "New Commit" +msgstr "Nova revisão" + +#: git-gui.sh:2627 git-gui.sh:3057 +msgid "Amend Last Commit" +msgstr "Corrigir última revisão" + +#: git-gui.sh:2637 git-gui.sh:3011 lib/remote_branch_delete.tcl:99 +msgid "Rescan" +msgstr "Atualizar" + +#: git-gui.sh:2643 +msgid "Stage To Commit" +msgstr "Marcar para revisão" + +#: git-gui.sh:2649 +msgid "Stage Changed Files To Commit" +msgstr "Marcar arquivos modificados" + +#: git-gui.sh:2655 +msgid "Unstage From Commit" +msgstr "Desmarcar" + +#: git-gui.sh:2661 lib/index.tcl:412 +msgid "Revert Changes" +msgstr "Reverter mudanças" + +#: git-gui.sh:2669 git-gui.sh:3310 git-gui.sh:3341 +msgid "Show Less Context" +msgstr "Mostrar menos contexto" + +#: git-gui.sh:2673 git-gui.sh:3314 git-gui.sh:3345 +msgid "Show More Context" +msgstr "Mostrar mais contexto" + +#: git-gui.sh:2680 git-gui.sh:3024 git-gui.sh:3133 +msgid "Sign Off" +msgstr "Assinar embaixo" + +#: git-gui.sh:2696 +msgid "Local Merge..." +msgstr "Mesclar localmente..." + +#: git-gui.sh:2701 +msgid "Abort Merge..." +msgstr "Abortar mesclagem..." + +#: git-gui.sh:2713 git-gui.sh:2741 +msgid "Add..." +msgstr "Adicionar..." + +#: git-gui.sh:2717 +msgid "Push..." +msgstr "Enviar..." + +#: git-gui.sh:2721 +msgid "Delete Branch..." +msgstr "Apagar ramo..." + +#: git-gui.sh:2731 git-gui.sh:3292 +msgid "Options..." +msgstr "Opções..." + +#: git-gui.sh:2742 +msgid "Remove..." +msgstr "Remover..." + +#: git-gui.sh:2751 lib/choose_repository.tcl:50 +msgid "Help" +msgstr "Ajuda" + +#: git-gui.sh:2755 git-gui.sh:2759 lib/about.tcl:14 +#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 +#, tcl-format +msgid "About %s" +msgstr "Sobre o %s" + +#: git-gui.sh:2783 +msgid "Online Documentation" +msgstr "Ajuda online" + +#: git-gui.sh:2786 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 +msgid "Show SSH Key" +msgstr "Mostrar chave SSH" + +#: git-gui.sh:2893 +#, tcl-format +msgid "fatal: cannot stat path %s: No such file or directory" +msgstr "" +"erro fatal: impossível executar \"stat\" em %s: Arquivo ou diretório não " +"encontrado" + +#: git-gui.sh:2926 +msgid "Current Branch:" +msgstr "Ramo atual:" + +#: git-gui.sh:2947 +msgid "Staged Changes (Will Commit)" +msgstr "Mudanças marcadas" + +#: git-gui.sh:2967 +msgid "Unstaged Changes" +msgstr "Mudanças não marcadas" + +#: git-gui.sh:3017 +msgid "Stage Changed" +msgstr "Marcar alterados" + +#: git-gui.sh:3036 lib/transport.tcl:104 lib/transport.tcl:193 +msgid "Push" +msgstr "Enviar" + +#: git-gui.sh:3071 +msgid "Initial Commit Message:" +msgstr "Descrição da revisão inicial:" + +#: git-gui.sh:3072 +msgid "Amended Commit Message:" +msgstr "Descrição da revisão corrigida:" + +#: git-gui.sh:3073 +msgid "Amended Initial Commit Message:" +msgstr "Descrição da revisão inicial corrigida:" + +#: git-gui.sh:3074 +msgid "Amended Merge Commit Message:" +msgstr "Descrição da revisão de mescla corrigida:" + +#: git-gui.sh:3075 +msgid "Merge Commit Message:" +msgstr "Descrição da revisão de mescla:" + +#: git-gui.sh:3076 +msgid "Commit Message:" +msgstr "Descrição da revisão:" + +#: git-gui.sh:3125 git-gui.sh:3267 lib/console.tcl:73 +msgid "Copy All" +msgstr "Copiar todos" + +#: git-gui.sh:3149 lib/blame.tcl:104 +msgid "File:" +msgstr "Arquivo:" + +#: git-gui.sh:3255 +msgid "Refresh" +msgstr "Atualizar" + +#: git-gui.sh:3276 +msgid "Decrease Font Size" +msgstr "Reduzir tamanho da fonte" + +#: git-gui.sh:3280 +msgid "Increase Font Size" +msgstr "Aumentar tamanho da fonte" + +#: git-gui.sh:3288 lib/blame.tcl:281 +msgid "Encoding" +msgstr "Codificação" + +#: git-gui.sh:3299 +msgid "Apply/Reverse Hunk" +msgstr "Aplicar/reverter trecho" + +#: git-gui.sh:3304 +msgid "Apply/Reverse Line" +msgstr "Aplicar/reverter linha" + +#: git-gui.sh:3323 +msgid "Run Merge Tool" +msgstr "Executar ferramenta de mescla" + +#: git-gui.sh:3328 +msgid "Use Remote Version" +msgstr "Usar versão remota" + +#: git-gui.sh:3332 +msgid "Use Local Version" +msgstr "Usar versão local" + +#: git-gui.sh:3336 +msgid "Revert To Base" +msgstr "Reverter para a versão-base" + +#: git-gui.sh:3354 +msgid "Visualize These Changes In The Submodule" +msgstr "Visualizar estas mudanças no sub-módulo" + +#: git-gui.sh:3358 +msgid "Visualize Current Branch History In The Submodule" +msgstr "Visualizar histórico do ramo atual no sub-módulo" + +#: git-gui.sh:3362 +msgid "Visualize All Branch History In The Submodule" +msgstr "Visualizar histórico de todos os camos no sub-módulo" + +#: git-gui.sh:3367 +msgid "Start git gui In The Submodule" +msgstr "Iniciar \"git gui\" no sub-módulo" + +#: git-gui.sh:3389 +msgid "Unstage Hunk From Commit" +msgstr "Desmarcar trecho para revisão" + +#: git-gui.sh:3391 +msgid "Unstage Lines From Commit" +msgstr "Desmarcar linhas para revisão" + +#: git-gui.sh:3393 +msgid "Unstage Line From Commit" +msgstr "Desmarcar linha para revisão" + +#: git-gui.sh:3396 +msgid "Stage Hunk For Commit" +msgstr "Marcar trecho para revisão" + +#: git-gui.sh:3398 +msgid "Stage Lines For Commit" +msgstr "Marcar linhas para revisão" + +#: git-gui.sh:3400 +msgid "Stage Line For Commit" +msgstr "Marcar linha para revisão" + +#: git-gui.sh:3424 +msgid "Initializing..." +msgstr "Iniciando..." + +#: git-gui.sh:3541 +#, 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 "" +"Possíveis problemas com as variáveis de ambiente.\n" +"\n" +"As seguintes variáveis de ambiente provavelmente serão\n" +"ignoradas por qualquer sub-processo do Git executado por\n" +"%s:\n" + +#: git-gui.sh:3570 +msgid "" +"\n" +"This is due to a known issue with the\n" +"Tcl binary distributed by Cygwin." +msgstr "" +"\n" +"Isto se deve a um problema conhecido com os binários da Tcl \n" +"distribuídos com o Cygwin" + +#: git-gui.sh:3575 +#, 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" +"Uma boa alternativa para %s\n" +"é colocar os valores para o nome de usuário e e-mail\n" +"no seu arquivo \"~/.gitconfig\"\n" + +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui - uma interface gráfica para o Git" + +#: lib/blame.tcl:72 +msgid "File Viewer" +msgstr "Visualizador de arquivos" + +#: lib/blame.tcl:78 +msgid "Commit:" +msgstr "Revisão:" + +#: lib/blame.tcl:271 +msgid "Copy Commit" +msgstr "Copiar revisão" + +#: lib/blame.tcl:275 +msgid "Find Text..." +msgstr "Procurar texto..." + +#: lib/blame.tcl:284 +msgid "Do Full Copy Detection" +msgstr "Executar detecção completa de cópias" + +#: lib/blame.tcl:288 +msgid "Show History Context" +msgstr "Mostrar contexto do histórico" + +#: lib/blame.tcl:291 +msgid "Blame Parent Commit" +msgstr "Anotar revisão anterior" + +#: lib/blame.tcl:450 +#, tcl-format +msgid "Reading %s..." +msgstr "Lendo %s..." + +#: lib/blame.tcl:557 +msgid "Loading copy/move tracking annotations..." +msgstr "Carregando anotações de cópia/movimentação..." + +#: lib/blame.tcl:577 +msgid "lines annotated" +msgstr "linhas anotadas" + +#: lib/blame.tcl:769 +msgid "Loading original location annotations..." +msgstr "Carregando anotações originais..." + +#: lib/blame.tcl:772 +msgid "Annotation complete." +msgstr "Anotação completa." + +#: lib/blame.tcl:802 +msgid "Busy" +msgstr "Ocupado" + +#: lib/blame.tcl:803 +msgid "Annotation process is already running." +msgstr "O processo de anotação já está em execução" + +#: lib/blame.tcl:842 +msgid "Running thorough copy detection..." +msgstr "Executando detecção de cópia..." + +#: lib/blame.tcl:910 +msgid "Loading annotation..." +msgstr "Carregando anotações..." + +#: lib/blame.tcl:963 +msgid "Author:" +msgstr "Autor:" + +#: lib/blame.tcl:967 +msgid "Committer:" +msgstr "Revisor:" + +#: lib/blame.tcl:972 +msgid "Original File:" +msgstr "Arquivo original:" + +#: lib/blame.tcl:1020 +msgid "Cannot find HEAD commit:" +msgstr "Impossível encontrar revisão HEAD:" + +#: lib/blame.tcl:1075 +msgid "Cannot find parent commit:" +msgstr "Impossível encontrar revisão anterior:" + +#: lib/blame.tcl:1090 +msgid "Unable to display parent" +msgstr "Impossível exibir revisão anterior" + +#: lib/blame.tcl:1091 lib/diff.tcl:320 +msgid "Error loading diff:" +msgstr "Erro ao carregar as diferenças:" + +#: lib/blame.tcl:1231 +msgid "Originally By:" +msgstr "Originalmente por:" + +#: lib/blame.tcl:1237 +msgid "In File:" +msgstr "No arquivo:" + +#: lib/blame.tcl:1242 +msgid "Copied Or Moved Here By:" +msgstr "Copiado ou movido para cá por:" + +#: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19 +msgid "Checkout Branch" +msgstr "Efetuar checkout do ramo" + +#: lib/branch_checkout.tcl:23 +msgid "Checkout" +msgstr "Checkout" + +#: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35 +#: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282 +#: lib/checkout_op.tcl:579 lib/choose_font.tcl:43 lib/merge.tcl:172 +#: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42 +#: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352 +#: lib/transport.tcl:108 +msgid "Cancel" +msgstr "Cancelar" + +#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328 +msgid "Revision" +msgstr "Revisão" + +#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280 +msgid "Options" +msgstr "Opções" + +#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "Obter ramo de rastreamento" + +#: lib/branch_checkout.tcl:44 +msgid "Detach From Local Branch" +msgstr "Separar do ramo local" + +#: lib/branch_create.tcl:22 +msgid "Create Branch" +msgstr "Criar ramo" + +#: lib/branch_create.tcl:27 +msgid "Create New Branch" +msgstr "Criar novo ramo" + +#: lib/branch_create.tcl:31 lib/choose_repository.tcl:381 +msgid "Create" +msgstr "Criar" + +#: lib/branch_create.tcl:40 +msgid "Branch Name" +msgstr "Nome do ramo" + +#: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50 +msgid "Name:" +msgstr "Nome:" + +#: lib/branch_create.tcl:58 +msgid "Match Tracking Branch Name" +msgstr "Coincidir nome do ramo de rastreamento" + +#: lib/branch_create.tcl:66 +msgid "Starting Revision" +msgstr "Revisão inicial" + +#: lib/branch_create.tcl:72 +msgid "Update Existing Branch:" +msgstr "Atualizar ramo existente:" + +#: lib/branch_create.tcl:75 +msgid "No" +msgstr "Não" + +#: lib/branch_create.tcl:80 +msgid "Fast Forward Only" +msgstr "Somente se for um avanço rápido" + +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571 +msgid "Reset" +msgstr "Redefinir" + +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "Efetuar checkout após a criação" + +#: lib/branch_create.tcl:131 +msgid "Please select a tracking branch." +msgstr "Selecione um ramo de rastreamento." + +#: lib/branch_create.tcl:140 +#, tcl-format +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "O ramo de rastreamento %s não é um ramo do repositório remoto." + +#: lib/branch_create.tcl:153 lib/branch_rename.tcl:86 +msgid "Please supply a branch name." +msgstr "Indique um nome para o ramo." + +#: lib/branch_create.tcl:164 lib/branch_rename.tcl:106 +#, tcl-format +msgid "'%s' is not an acceptable branch name." +msgstr "\"%s\" não é um nome de ramo válido" + +#: lib/branch_delete.tcl:15 +msgid "Delete Branch" +msgstr "Apagar ramo" + +#: lib/branch_delete.tcl:20 +msgid "Delete Local Branch" +msgstr "Apagar ramo local" + +#: lib/branch_delete.tcl:37 +msgid "Local Branches" +msgstr "Ramos locais" + +#: lib/branch_delete.tcl:52 +msgid "Delete Only If Merged Into" +msgstr "Apagar somente se mesclado em" + +#: lib/branch_delete.tcl:54 lib/remote_branch_delete.tcl:119 +msgid "Always (Do not perform merge checks)" +msgstr "Forçar exclusão (não verificar se o ramo foi mesclado)" + +#: lib/branch_delete.tcl:103 +#, tcl-format +msgid "The following branches are not completely merged into %s:" +msgstr "Os ramos seguintes não foram completamente mesclados em %s:" + +#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:217 +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" +"Recuperar ramos apagados é difícil.\n" +"\n" +"Apagar os ramos selecionados?" + +#: lib/branch_delete.tcl:141 +#, tcl-format +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" +"Erro ao apagar ramos:\n" +"%s" + +#: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22 +msgid "Rename Branch" +msgstr "Renomear ramo" + +#: lib/branch_rename.tcl:26 +msgid "Rename" +msgstr "Renomear" + +#: lib/branch_rename.tcl:36 +msgid "Branch:" +msgstr "Ramo:" + +#: lib/branch_rename.tcl:39 +msgid "New Name:" +msgstr "Novo nome:" + +#: lib/branch_rename.tcl:75 +msgid "Please select a branch to rename." +msgstr "Selecione um ramo para renomear." + +#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:202 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "O ramo \"%s\" já existe." + +#: lib/branch_rename.tcl:117 +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "Erro ao renomear \"%s\"." + +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "Inciando..." + +#: lib/browser.tcl:26 +msgid "File Browser" +msgstr "Navegador de arquivos" + +#: lib/browser.tcl:126 lib/browser.tcl:143 +#, tcl-format +msgid "Loading %s..." +msgstr "Carregando %s..." + +#: lib/browser.tcl:187 +msgid "[Up To Parent]" +msgstr "[Subir]" + +#: lib/browser.tcl:267 lib/browser.tcl:273 +msgid "Browse Branch Files" +msgstr "Explorar arquivos do ramo" + +#: lib/browser.tcl:278 lib/choose_repository.tcl:398 +#: lib/choose_repository.tcl:486 lib/choose_repository.tcl:497 +#: lib/choose_repository.tcl:1028 +msgid "Browse" +msgstr "Explorar" + +#: lib/checkout_op.tcl:85 +#, tcl-format +msgid "Fetching %s from %s" +msgstr "Obtendo %s de %s" + +#: lib/checkout_op.tcl:133 +#, tcl-format +msgid "fatal: Cannot resolve %s" +msgstr "Erro fatal: impossível resolver %s" + +#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:31 +#: lib/sshkey.tcl:53 +msgid "Close" +msgstr "Fechar" + +#: lib/checkout_op.tcl:175 +#, tcl-format +msgid "Branch '%s' does not exist." +msgstr "O ramo \"%s\" não existe." + +#: lib/checkout_op.tcl:194 +#, tcl-format +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "Erro ao configurar git-pull simplificado para \"%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 "" +"O ramo \"%s\" já existe.\n" +"\n" +"Não é possível avançá-lo para %s.\n" +"É preciso mesclar." + +#: lib/checkout_op.tcl:243 +#, tcl-format +msgid "Merge strategy '%s' not supported." +msgstr "Estratégia de mesclagem \"%s\" não suportada." + +#: lib/checkout_op.tcl:262 +#, tcl-format +msgid "Failed to update '%s'." +msgstr "Erro ao atualizar \"%s\"." + +#: lib/checkout_op.tcl:274 +msgid "Staging area (index) is already locked." +msgstr "A área de marcação (staging area, index) já está bloqueada." + +#: 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 "" +"O último estado lido não confere com o estado atual.\n" +"\n" +"Outro programa do Git modificou o repositório desde a última leitura. Uma " +"atualização deve ser executada antes de alterar o ramo atual.\n" +"\n" +"A atualização começará automaticamente agora.\n" + +#: lib/checkout_op.tcl:345 +#, tcl-format +msgid "Updating working directory to '%s'..." +msgstr "Atualizando diretório de trabalho para \"%s\"..." + +#: lib/checkout_op.tcl:346 +msgid "files checked out" +msgstr "arquivos retirados" + +#: lib/checkout_op.tcl:376 +#, tcl-format +msgid "Aborted checkout of '%s' (file level merging is required)." +msgstr "Checkout de \"%s\" abortado (é preciso mesclar alguns arquivos)" + +#: lib/checkout_op.tcl:377 +msgid "File level merge required." +msgstr "Mesclagem de arquivos necessária." + +#: lib/checkout_op.tcl:381 +#, tcl-format +msgid "Staying on branch '%s'." +msgstr "Permanecendo no ramo \"%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 "" +"Você não está mais em um ramo local\n" +"\n" +"Se você deseja um ramo, crie um agora a partir deste checkout." + +#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 +#, tcl-format +msgid "Checked out '%s'." +msgstr "Checkout de \"%s\" concluído." + +#: lib/checkout_op.tcl:535 +#, tcl-format +msgid "Resetting '%s' to '%s' will lose the following commits:" +msgstr "Redefinir \"%s\" para \"%s\" provocará a perda das seguintes revisões:" + +#: lib/checkout_op.tcl:557 +msgid "Recovering lost commits may not be easy." +msgstr "Recuperar revisões perdidas pode não ser fácil." + +#: lib/checkout_op.tcl:562 +#, tcl-format +msgid "Reset '%s'?" +msgstr "Redefinir \"%s\"?" + +#: lib/checkout_op.tcl:567 lib/merge.tcl:164 lib/tools_dlg.tcl:343 +msgid "Visualize" +msgstr "Visualizar" + +#: 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 "" +"Erro ao definir o ramo atual.\n" +"\n" +"Este diretório de trabalho está incompleto. Foi possível atualizar seus " +"arquivos, mas houve uma falha ao atualizar os arquivos internos do Git.\n" +"\n" +"Isto não deveria ter acontecido, %s terminará agora." + +#: lib/choose_font.tcl:39 +msgid "Select" +msgstr "Selecionar" + +#: lib/choose_font.tcl:53 +msgid "Font Family" +msgstr "Tipo da fonte" + +#: lib/choose_font.tcl:74 +msgid "Font Size" +msgstr "Tamanho da fonte" + +#: lib/choose_font.tcl:91 +msgid "Font Example" +msgstr "Exemplo" + +#: lib/choose_font.tcl:103 +msgid "" +"This is example text.\n" +"If you like this text, it can be your font." +msgstr "" +"Este é um texto de exemplo.\n" +"Se você gostar deste texto, esta pode ser sua fonte." + +#: lib/choose_repository.tcl:28 +msgid "Git Gui" +msgstr "Git Gui" + +#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:386 +msgid "Create New Repository" +msgstr "Criar novo repositório" + +#: lib/choose_repository.tcl:93 +msgid "New..." +msgstr "Novo..." + +#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:471 +msgid "Clone Existing Repository" +msgstr "Clonar repositório existente" + +#: lib/choose_repository.tcl:106 +msgid "Clone..." +msgstr "Clonar..." + +#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:1016 +msgid "Open Existing Repository" +msgstr "Abrir repositório existente" + +#: lib/choose_repository.tcl:119 +msgid "Open..." +msgstr "Abrir..." + +#: lib/choose_repository.tcl:132 +msgid "Recent Repositories" +msgstr "Repositórios recentes" + +#: lib/choose_repository.tcl:138 +msgid "Open Recent Repository:" +msgstr "Abrir repositório recente:" + +#: lib/choose_repository.tcl:306 lib/choose_repository.tcl:313 +#: lib/choose_repository.tcl:320 +#, tcl-format +msgid "Failed to create repository %s:" +msgstr "Erro ao criar repositório %s:" + +#: lib/choose_repository.tcl:391 +msgid "Directory:" +msgstr "Diretório:" + +#: lib/choose_repository.tcl:423 lib/choose_repository.tcl:550 +#: lib/choose_repository.tcl:1052 +msgid "Git Repository" +msgstr "Repositório Git" + +#: lib/choose_repository.tcl:448 +#, tcl-format +msgid "Directory %s already exists." +msgstr "O diretório %s já existe." + +#: lib/choose_repository.tcl:452 +#, tcl-format +msgid "File %s already exists." +msgstr "O arquivo %s já existe." + +#: lib/choose_repository.tcl:466 +msgid "Clone" +msgstr "Clonar" + +#: lib/choose_repository.tcl:479 +msgid "Source Location:" +msgstr "Origem:" + +#: lib/choose_repository.tcl:490 +msgid "Target Directory:" +msgstr "Diretório de destino:" + +#: lib/choose_repository.tcl:502 +msgid "Clone Type:" +msgstr "Tipo de clonagem:" + +#: lib/choose_repository.tcl:508 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "Padrão (rápida, semi-redundante, com hardlinks)" + +#: lib/choose_repository.tcl:514 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "Cópia completa (mais lenta, backup redundante)" + +#: lib/choose_repository.tcl:520 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "Compartilhada (A mais rápida, não recomendada, sem backup)" + +#: lib/choose_repository.tcl:556 lib/choose_repository.tcl:603 +#: lib/choose_repository.tcl:749 lib/choose_repository.tcl:819 +#: lib/choose_repository.tcl:1058 lib/choose_repository.tcl:1066 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "Este não é um repositório do Git: %s" + +#: lib/choose_repository.tcl:592 +msgid "Standard only available for local repository." +msgstr "Clonagens padrões só são possíveis em repositórios locais." + +#: lib/choose_repository.tcl:596 +msgid "Shared only available for local repository." +msgstr "Clonagens parciais só são possíveis em repositórios locais." + +#: lib/choose_repository.tcl:617 +#, tcl-format +msgid "Location %s already exists." +msgstr "O local %s já existe." + +#: lib/choose_repository.tcl:628 +msgid "Failed to configure origin" +msgstr "Erro ao configurar origem" + +#: lib/choose_repository.tcl:640 +msgid "Counting objects" +msgstr "Contando objetos" + +#: lib/choose_repository.tcl:641 +msgid "buckets" +msgstr "buckets" + +#: lib/choose_repository.tcl:665 +#, tcl-format +msgid "Unable to copy objects/info/alternates: %s" +msgstr "Erro ao copiar objetos ou informações adicionais: %s" + +#: lib/choose_repository.tcl:701 +#, tcl-format +msgid "Nothing to clone from %s." +msgstr "Não há nada para clonar em %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 "O ramo \"master\" não foi inicializado." + +#: lib/choose_repository.tcl:716 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "Não foi possível criar hardlinks, usando cópias convencionais." + +#: lib/choose_repository.tcl:728 +#, tcl-format +msgid "Cloning from %s" +msgstr "Clonando de %s" + +#: lib/choose_repository.tcl:759 +msgid "Copying objects" +msgstr "Copiando objetos" + +#: lib/choose_repository.tcl:760 +msgid "KiB" +msgstr "KiB" + +#: lib/choose_repository.tcl:784 +#, tcl-format +msgid "Unable to copy object: %s" +msgstr "Não foi possível copiar o objeto: %s" + +#: lib/choose_repository.tcl:794 +msgid "Linking objects" +msgstr "Ligando objetos" + +#: lib/choose_repository.tcl:795 +msgid "objects" +msgstr "objetos" + +#: lib/choose_repository.tcl:803 +#, tcl-format +msgid "Unable to hardlink object: %s" +msgstr "Não foi possível ligar o objeto: %s" + +#: lib/choose_repository.tcl:858 +msgid "Cannot fetch branches and objects. See console output for details." +msgstr "" +"Não foi possível receber ramos ou objetos. Veja a saída do console para " +"detalhes." + +#: lib/choose_repository.tcl:869 +msgid "Cannot fetch tags. See console output for details." +msgstr "" +"Não foi possível receber as etiquetas. Veja a saída do console para detalhes." + +#: lib/choose_repository.tcl:893 +msgid "Cannot determine HEAD. See console output for details." +msgstr "" +"Não foi possível determinar a etiqueta HEAD. Veja a saída do console para " +"detalhes." + +#: lib/choose_repository.tcl:902 +#, tcl-format +msgid "Unable to cleanup %s" +msgstr "Não foi possível limpar %s" + +#: lib/choose_repository.tcl:908 +msgid "Clone failed." +msgstr "A clonagem falhou." + +#: lib/choose_repository.tcl:915 +msgid "No default branch obtained." +msgstr "O ramo padrão não foi recebido." + +#: lib/choose_repository.tcl:926 +#, tcl-format +msgid "Cannot resolve %s as a commit." +msgstr "Não foi possível resolver %s como uma revisão." + +#: lib/choose_repository.tcl:938 +msgid "Creating working directory" +msgstr "Criando diretório de trabalho." + +#: lib/choose_repository.tcl:939 lib/index.tcl:67 lib/index.tcl:130 +#: lib/index.tcl:198 +msgid "files" +msgstr "arquivos" + +#: lib/choose_repository.tcl:968 +msgid "Initial file checkout failed." +msgstr "Erro ao efetuar checkout inicial." + +#: lib/choose_repository.tcl:1011 +msgid "Open" +msgstr "Abrir" + +#: lib/choose_repository.tcl:1021 +msgid "Repository:" +msgstr "Repositório:" + +#: lib/choose_repository.tcl:1072 +#, tcl-format +msgid "Failed to open repository %s:" +msgstr "Erro ao abrir o repositório %s:" + +#: lib/choose_rev.tcl:53 +msgid "This Detached Checkout" +msgstr "Este checkout" + +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "Expressão de revisão:" + +#: lib/choose_rev.tcl:74 +msgid "Local Branch" +msgstr "Ramo local" + +#: lib/choose_rev.tcl:79 +msgid "Tracking Branch" +msgstr "Ramo de rastreamento" + +#: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538 +msgid "Tag" +msgstr "Etiqueta" + +#: lib/choose_rev.tcl:317 +#, tcl-format +msgid "Invalid revision: %s" +msgstr "Revisão inválida: %s" + +#: lib/choose_rev.tcl:338 +msgid "No revision selected." +msgstr "Nenhuma revisão selecionada." + +#: lib/choose_rev.tcl:346 +msgid "Revision expression is empty." +msgstr "A expressão de revisão está vazia." + +#: lib/choose_rev.tcl:531 +msgid "Updated" +msgstr "Atualizado" + +#: lib/choose_rev.tcl:559 +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 "" +"Não há nada para corrigir.\n" +"\n" +"Você está prestes a criar uma revisão inicial. Não há revisão anterior para " +"corrigir.\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 "" +"Não é possível corrigir durante uma mesclagem.\n" +"\n" +"Você está em meio a uma operação de mesclagem que não foi completada. Não é " +"possível corrigir a revisão anterior a menos que você aborte a mescla atual " +"antes.\n" + +#: lib/commit.tcl:48 +msgid "Error loading commit data for amend:" +msgstr "Erro ao carregar dados da revisão para corrigir:" + +#: lib/commit.tcl:75 +msgid "Unable to obtain your identity:" +msgstr "Não foi possível obter a sua identidade:" + +#: lib/commit.tcl:80 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "Variável \"GIT_COMMITTER_IDENT\" inválida:" + +#: lib/commit.tcl:129 +#, tcl-format +msgid "warning: Tcl does not support encoding '%s'." +msgstr "aviso: O Tcl não suporta a codificação \"%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 "" +"O último estado lido não confere com o estado atual.\n" +"\n" +"Outro programa do Git modificou o repositório desde a última leitura. Uma " +"atualização deve ser executada antes de criar outra revisão.\n" +"\n" +"A atualização começará automaticamente agora.\n" + +#: lib/commit.tcl:172 +#, 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 "" +"Não é possível salvar revisões para arquivos não mesclados.\n" +"\n" +"O arquivo %s possui conflitos de mesclagem. Você deve resolvê-los e marcar o " +"arquivo antes de salvar a revisão.\n" + +#: lib/commit.tcl:180 +#, tcl-format +msgid "" +"Unknown file state %s detected.\n" +"\n" +"File %s cannot be committed by this program.\n" +msgstr "" +"Estado desconhecido detectado para o arquivo %s.\n" +"\n" +"Este programa não pode salvar uma revisão para o arquivo %s.\n" + +#: lib/commit.tcl:188 +msgid "" +"No changes to commit.\n" +"\n" +"You must stage at least 1 file before you can commit.\n" +msgstr "" +"Não há mudanças para salvar.\n" +"\n" +"Você deve marcar ao menos um arquivo antes de salvar a revisão.\n" + +#: lib/commit.tcl:203 +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 "" +"Por favor, indique uma descrição para a revisão.\n" +"\n" +"Uma boa descrição tem o seguinte formato:\n" +"\n" +"- Primeira linha: descreve, em uma única frase, o que você fez.\n" +"- Segunda linha: em branco.\n" +"- Demais linhas: Descreve detalhadamente a revisão.\n" + +#: lib/commit.tcl:234 +msgid "Calling pre-commit hook..." +msgstr "Executando script \"pre-commit\"..." + +#: lib/commit.tcl:249 +msgid "Commit declined by pre-commit hook." +msgstr "A revisão foi bloqueada pelo script \"pre-commit\"." + +#: lib/commit.tcl:272 +msgid "Calling commit-msg hook..." +msgstr "Executando script \"commit-msg\"..." + +#: lib/commit.tcl:287 +msgid "Commit declined by commit-msg hook." +msgstr "Revisão bloqueada pelo script \"commit-msg\"." + +#: lib/commit.tcl:300 +msgid "Committing changes..." +msgstr "Salvando revisão..." + +#: lib/commit.tcl:316 +msgid "write-tree failed:" +msgstr "write-tree falhou:" + +#: lib/commit.tcl:317 lib/commit.tcl:361 lib/commit.tcl:382 +msgid "Commit failed." +msgstr "A revisão falhou." + +#: lib/commit.tcl:334 +#, tcl-format +msgid "Commit %s appears to be corrupt" +msgstr "A revisão %s parece estar corrompida." + +#: 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 "" +"Não há alterações para salvar.\n" +"\n" +"Nenhum arquivo foi modificado e esta não é uma revisão de mesclagem.\n" +"\n" +"Uma atualização será executada automaticamente agora.\n" + +#: lib/commit.tcl:346 +msgid "No changes to commit." +msgstr "Não há alterações para salvar." + +#: lib/commit.tcl:360 +msgid "commit-tree failed:" +msgstr "commit-tree falhou:" + +#: lib/commit.tcl:381 +msgid "update-ref failed:" +msgstr "update-ref falhou:" + +#: lib/commit.tcl:469 +#, tcl-format +msgid "Created commit %s: %s" +msgstr "Revisão %s criada: %s" + +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "Trabalhando... aguarde..." + +#: lib/console.tcl:186 +msgid "Success" +msgstr "Sucesso" + +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "Erro: o comando falhou" + +#: lib/database.tcl:43 +msgid "Number of loose objects" +msgstr "Número de objetos soltos" + +#: lib/database.tcl:44 +msgid "Disk space used by loose objects" +msgstr "Espaço ocupado pelos objetos soltos" + +#: lib/database.tcl:45 +msgid "Number of packed objects" +msgstr "Número de objetos compactados" + +#: lib/database.tcl:46 +msgid "Number of packs" +msgstr "Número de pacotes" + +#: lib/database.tcl:47 +msgid "Disk space used by packed objects" +msgstr "Espaço ocupado pelos objetos compactados" + +#: lib/database.tcl:48 +msgid "Packed objects waiting for pruning" +msgstr "Objetos compactados aguardando eliminação" + +#: lib/database.tcl:49 +msgid "Garbage files" +msgstr "Arquivos de lixo" + +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "Compactando banco de dados de objetos" + +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "Verificando banco de dados de objetos com 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 "" +"Este repositório possui aproximadamente %i objetos soltos.\n" +"\n" +"Para manter o desempenho ótimo é altamente recomendado que você compacte o " +"banco de dados.\n" +"\n" +"Compactar o banco de dados agora?" + +#: lib/date.tcl:25 +#, tcl-format +msgid "Invalid date from Git: %s" +msgstr "Data inválida recebida do 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 "" +"Nenhuma diferença foi detectada.\n" +"\n" +"%s não possui mudanças.\n" +"\n" +"A data de modificação deste arquivo foi atualizada por outro aplicativo, mas " +"o conteúdo do arquivo não foi alterado.\n" +"\n" +"Uma atualização ser executada para encontrar outros arquivos que possam ter " +"o mesmo estado." + +#: lib/diff.tcl:104 +#, tcl-format +msgid "Loading diff of %s..." +msgstr "Carregando diferenças de %s..." + +#: lib/diff.tcl:125 +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"Local: apagado\n" +"Remoto:\n" + +#: lib/diff.tcl:130 +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"Remoto: apagado\n" +"Local:\n" + +#: lib/diff.tcl:137 +msgid "LOCAL:\n" +msgstr "Local:\n" + +#: lib/diff.tcl:140 +msgid "REMOTE:\n" +msgstr "Remoto:\n" + +#: lib/diff.tcl:202 lib/diff.tcl:319 +#, tcl-format +msgid "Unable to display %s" +msgstr "Impossível exibir %s" + +#: lib/diff.tcl:203 +msgid "Error loading file:" +msgstr "Erro ao carregar o arquivo:" + +#: lib/diff.tcl:210 +msgid "Git Repository (subproject)" +msgstr "Repositório Git (sub-projeto)" + +#: lib/diff.tcl:222 +msgid "* Binary file (not showing content)." +msgstr "* Arquivo binário (conteúdo não exibido)." + +#: lib/diff.tcl:227 +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" +"* O arquivo não rastreado possui %d bytes.\n" +"* Exibindo apenas os primeiros %d bytes.\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" +"* O arquivo não rastreado foi cortado aqui por %s.\n" +"* Para ver o arquivo completo, use um editor externo.\n" + +#: lib/diff.tcl:482 +msgid "Failed to unstage selected hunk." +msgstr "Erro ao desmarcar o trecho selecionado." + +#: lib/diff.tcl:489 +msgid "Failed to stage selected hunk." +msgstr "Erro ao marcar o trecho selecionado." + +#: lib/diff.tcl:568 +msgid "Failed to unstage selected line." +msgstr "Erro ao desmarcar a linha selecionada." + +#: lib/diff.tcl:576 +msgid "Failed to stage selected line." +msgstr "Erro ao marcar a linha selecionada." + +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "Padrão" + +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "Sistema (%s)" + +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Outro" + +#: lib/error.tcl:20 lib/error.tcl:114 +msgid "error" +msgstr "Erro" + +#: lib/error.tcl:36 +msgid "warning" +msgstr "aviso" + +#: lib/error.tcl:94 +msgid "You must correct the above errors before committing." +msgstr "Você precisa corrigir os erros acima antes de salvar a revisão." + +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "Impossível desbloquear o índice." + +#: lib/index.tcl:15 +msgid "Index Error" +msgstr "Erro no índice" + +#: lib/index.tcl:17 +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" +"A atualização do índice do Git falhou. Uma atualização será executada " +"automaticamente para ressincronizar o Git GUI" + +#: lib/index.tcl:28 +msgid "Continue" +msgstr "Continuar" + +#: lib/index.tcl:31 +msgid "Unlock Index" +msgstr "Desbloquear índice" + +#: lib/index.tcl:289 +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "Desmarcando %s para revisão" + +#: lib/index.tcl:328 +msgid "Ready to commit." +msgstr "Pronto para salvar a revisão." + +#: lib/index.tcl:341 +#, tcl-format +msgid "Adding %s" +msgstr "Adicionando %s" + +#: lib/index.tcl:398 +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "Reverter as alterações no arquivo %s?" + +#: lib/index.tcl:400 +#, tcl-format +msgid "Revert changes in these %i files?" +msgstr "Reverter as alterações nestes %i arquivos?" + +#: lib/index.tcl:408 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Qualquer alteração não marcada será permanentemente perdida na reversão." + +#: lib/index.tcl:411 +msgid "Do Nothing" +msgstr "Não fazer nada" + +#: lib/index.tcl:429 +msgid "Reverting selected files" +msgstr "Revertendo os arquivos selecionados" + +#: lib/index.tcl:433 +#, tcl-format +msgid "Reverting %s" +msgstr "Revertendo %s" + +#: 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 "" +"Não é possível mesclar durante uma correção.\n" +"\n" +"Você deve concluir a correção antes de começar qualquer mesclagem.\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 "" +"O último estado lido não confere com o estado atual.\n" +"\n" +"Outro programa do Git modificou o repositório desde a última leitura. Uma " +"atualização deve ser executada antes de efetuar uma mesclagem.\n" +"\n" +"A atualização começará automaticamente agora.\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 "" +"Há uma mesclagem com conflitos em progresso.\n" +"\n" +"O arquivo %s possui conflitos de mesclagem.\n" +"\n" +"Você deve resolvê-los, marcar o arquivo e salvar a revisão para completar a " +"mesclagem atual. Só então você poderá começar outra.\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 "" +"Você está em meio a uma mudança.\n" +"\n" +"O arquivo %s foi modificado.\n" +"\n" +"Você deve completar e salvar a revisão atual antes de começar uma mesclagem. " +"Ao fazê-lo, você poderá abortar a mesclagem caso haja algum erro.\n" + +#: lib/merge.tcl:107 +#, tcl-format +msgid "%s of %s" +msgstr "%s de %s" + +#: lib/merge.tcl:120 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "Mesclando %s e %s..." + +#: lib/merge.tcl:131 +msgid "Merge completed successfully." +msgstr "Mesclagem completada com sucesso." + +#: lib/merge.tcl:133 +msgid "Merge failed. Conflict resolution is required." +msgstr "A mesclagem falhou. É necessário resolver conflitos." + +#: lib/merge.tcl:158 +#, tcl-format +msgid "Merge Into %s" +msgstr "Mesclar em %s" + +#: lib/merge.tcl:177 +msgid "Revision To Merge" +msgstr "Revisão para mesclar" + +#: lib/merge.tcl:212 +msgid "" +"Cannot abort while amending.\n" +"\n" +"You must finish amending this commit.\n" +msgstr "" +"Não é possível abortar durante uma correção.\n" +"\n" +"Você precisa finalizar a correção desta revisão.\n" + +#: 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 "" +"Abortar mesclagem?\n" +"\n" +"Abortar a mesclagem atual implicará na perda de *TODAS* as mudanças não " +"salvas.\n" +"\n" +"Abortar a mesclagem atual?" + +#: 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 "" +"Descartar as mudanças?\n" +"\n" +"Ao fazê-lo, *TODAS* as alterações não salvas serão perdidas.\n" +"\n" +"Continuar e descartar as mudanças atuais?" + +#: lib/merge.tcl:239 +msgid "Aborting" +msgstr "Abortando" + +#: lib/merge.tcl:239 +msgid "files reset" +msgstr "arquivos redefindos" + +#: lib/merge.tcl:267 +msgid "Abort failed." +msgstr "A tentativa de abortar a operação falhou" + +#: lib/merge.tcl:269 +msgid "Abort completed. Ready." +msgstr "Operação abortada com sucesso. Pronto." + +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Forçar a resolução para a versão base?" + +#: lib/mergetool.tcl:9 +msgid "Force resolution to this branch?" +msgstr "Forçar resolução para este ramo?" + +#: lib/mergetool.tcl:10 +msgid "Force resolution to the other branch?" +msgstr "Forçar resolução para o outro ramo?" + +#: 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 "" +"Note que o diff mostra apenas as mudanças conflitantes.\n" +"\n" +"%s será sobrescrito.\n" +"\n" +"Caso necessário, será preciso reiniciar a mesclagem para desfazer esta " +"operação." + +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "O arquivo %s parece ter conflitos não resolvidos. Marcar mesmo assim?" + +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Adicionando resolução para %s" + +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "" +"Impossível resolver conflitos envolvendo exclusão ou links de arquivos com " +"esta ferramenta." + +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "O arquivo conflitante não existe" + +#: lib/mergetool.tcl:264 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "Não é uma ferramenta de mesclagem gráfica: \"%s\"" + +#: lib/mergetool.tcl:268 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Ferramenta de mesclagem não suportada \"%s\"" + +#: lib/mergetool.tcl:303 +msgid "Merge tool is already running, terminate it?" +msgstr "A ferramenta de mesclagem já está em execução. Finalizar?" + +#: lib/mergetool.tcl:323 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Erro ao obter as versões:\n" +"%s" + +#: lib/mergetool.tcl:343 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Não foi possível iniciar a ferramenta de mesclagem:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:347 +msgid "Running merge tool..." +msgstr "Executando ferramenta de mesclagem..." + +#: lib/mergetool.tcl:375 lib/mergetool.tcl:383 +msgid "Merge tool failed." +msgstr "Ferramenta de mesclagem falhou." + +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Codificação global inválida \"%s\"" + +#: lib/option.tcl:19 +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Codificação do repositório inválida \"%s\"" + +#: lib/option.tcl:117 +msgid "Restore Defaults" +msgstr "Restaurar padrões" + +#: lib/option.tcl:121 +msgid "Save" +msgstr "Salvar" + +#: lib/option.tcl:131 +#, tcl-format +msgid "%s Repository" +msgstr "Repositório %s" + +#: lib/option.tcl:132 +msgid "Global (All Repositories)" +msgstr "Global (todos os repositórios)" + +#: lib/option.tcl:138 +msgid "User Name" +msgstr "Nome do usuário" + +#: lib/option.tcl:139 +msgid "Email Address" +msgstr "Endereço de e-mail" + +#: lib/option.tcl:141 +msgid "Summarize Merge Commits" +msgstr "Exibir sumário das revisões de mesclagem" + +#: lib/option.tcl:142 +msgid "Merge Verbosity" +msgstr "Nível de detalhamento da mesclagem" + +#: lib/option.tcl:143 +msgid "Show Diffstat After Merge" +msgstr "Exibir estatísticas após mesclagens" + +#: lib/option.tcl:144 +msgid "Use Merge Tool" +msgstr "Usar ferramenta de mesclagem" + +#: lib/option.tcl:146 +msgid "Trust File Modification Timestamps" +msgstr "Confiar nas datas de modificação dos arquivos" + +#: lib/option.tcl:147 +msgid "Prune Tracking Branches During Fetch" +msgstr "Eliminar ramos de rastreamento ao receber" + +#: lib/option.tcl:148 +msgid "Match Tracking Branches" +msgstr "Coincidir ramos de rastreamento" + +#: lib/option.tcl:149 +msgid "Blame Copy Only On Changed Files" +msgstr "Detectar cópias somente em arquivos modificados" + +#: lib/option.tcl:150 +msgid "Minimum Letters To Blame Copy On" +msgstr "Número mínimo de letras para detectar cópias" + +#: lib/option.tcl:151 +msgid "Blame History Context Radius (days)" +msgstr "Extensão do contexto de detecção (em dias)" + +#: lib/option.tcl:152 +msgid "Number of Diff Context Lines" +msgstr "Número de linhas para o diff contextual" + +#: lib/option.tcl:153 +msgid "Commit Message Text Width" +msgstr "Largura do texto da descrição da revisão" + +#: lib/option.tcl:154 +msgid "New Branch Name Template" +msgstr "Modelo de nome para novos ramos" + +#: lib/option.tcl:155 +msgid "Default File Contents Encoding" +msgstr "Codificação padrão dos arquivos" + +#: lib/option.tcl:203 +msgid "Change" +msgstr "Alterar" + +#: lib/option.tcl:230 +msgid "Spelling Dictionary:" +msgstr "Dicionário para o verificador ortográfico:" + +#: lib/option.tcl:254 +msgid "Change Font" +msgstr "Mudar fonte" + +#: lib/option.tcl:258 +#, tcl-format +msgid "Choose %s" +msgstr "Escolher %s" + +#: lib/option.tcl:264 +msgid "pt." +msgstr "pt." + +#: lib/option.tcl:278 +msgid "Preferences" +msgstr "Preferências" + +#: lib/option.tcl:314 +msgid "Failed to completely save options:" +msgstr "Houve um erro ao salvar as opções:" + +#: lib/remote.tcl:163 +msgid "Remove Remote" +msgstr "Excluir" + +#: lib/remote.tcl:168 +msgid "Prune from" +msgstr "Limpar de" + +#: lib/remote.tcl:173 +msgid "Fetch from" +msgstr "Receber de" + +#: lib/remote.tcl:215 +msgid "Push to" +msgstr "Enviar para" + +#: lib/remote_add.tcl:19 +msgid "Add Remote" +msgstr "Adicionar repositório remoto" + +#: lib/remote_add.tcl:24 +msgid "Add New Remote" +msgstr "Adicionar novo repositório remoto" + +#: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 +msgid "Add" +msgstr "Adicionar" + +#: lib/remote_add.tcl:37 +msgid "Remote Details" +msgstr "Detalhes do repositório remoto" + +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Local:" + +#: lib/remote_add.tcl:62 +msgid "Further Action" +msgstr "Ações adicionais" + +#: lib/remote_add.tcl:65 +msgid "Fetch Immediately" +msgstr "Receber imediatamente" + +#: lib/remote_add.tcl:71 +msgid "Initialize Remote Repository and Push" +msgstr "Inicializar repositório remoto e enviar" + +#: lib/remote_add.tcl:77 +msgid "Do Nothing Else Now" +msgstr "Não fazer nada agora" + +#: lib/remote_add.tcl:101 +msgid "Please supply a remote name." +msgstr "Por favor, indique um nome para o repositório remoto." + +#: lib/remote_add.tcl:114 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "\"%s\" não é um nome válido para um repositório remoto." + +#: lib/remote_add.tcl:125 +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Erro ao adicionar repositório remoto \"%s\" do local \"%s\":" + +#: lib/remote_add.tcl:133 lib/transport.tcl:6 +#, tcl-format +msgid "fetch %s" +msgstr "receber %s" + +#: lib/remote_add.tcl:134 +#, tcl-format +msgid "Fetching the %s" +msgstr "Recebendo o %s" + +#: lib/remote_add.tcl:157 +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Não sabe como inicializar o repositório remoto em \"%s\"." + +#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63 +#: lib/transport.tcl:81 +#, tcl-format +msgid "push %s" +msgstr "enviar %s" + +#: lib/remote_add.tcl:164 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Configurando %s (em %s)" + +#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 +msgid "Delete Branch Remotely" +msgstr "Apagar ramo remoto" + +#: lib/remote_branch_delete.tcl:47 +msgid "From Repository" +msgstr "Do repositório" + +#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134 +msgid "Remote:" +msgstr "Remoto:" + +#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149 +msgid "Arbitrary Location:" +msgstr "Outro local:" + +#: lib/remote_branch_delete.tcl:84 +msgid "Branches" +msgstr "Ramos" + +#: lib/remote_branch_delete.tcl:109 +msgid "Delete Only If" +msgstr "Apagar somente se" + +#: lib/remote_branch_delete.tcl:111 +msgid "Merged Into:" +msgstr "Mesclado em:" + +#: lib/remote_branch_delete.tcl:152 +msgid "A branch is required for 'Merged Into'." +msgstr "É preciso indicar um ramo para \"Mesclado em\"." + +#: lib/remote_branch_delete.tcl:184 +#, tcl-format +msgid "" +"The following branches are not completely merged into %s:\n" +"\n" +" - %s" +msgstr "" +"Os seguintes ramos não estão inteiramente mesclados em %s:\n" +"\n" +" - %s" + +#: lib/remote_branch_delete.tcl:189 +#, 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 "" +"Um ou mais testes de mesclagem falharam porque você não possui as revisões " +"necessárias. Tente receber revisões de %s primeiro." + +#: lib/remote_branch_delete.tcl:207 +msgid "Please select one or more branches to delete." +msgstr "Por favor selecione um ou mais ramos para apagar." + +#: lib/remote_branch_delete.tcl:226 +#, tcl-format +msgid "Deleting branches from %s" +msgstr "Apagar ramos de %s" + +#: lib/remote_branch_delete.tcl:292 +msgid "No repository selected." +msgstr "Nenhum repositório foi selecionado." + +#: lib/remote_branch_delete.tcl:297 +#, tcl-format +msgid "Scanning %s..." +msgstr "Atualizando %s..." + +#: lib/search.tcl:21 +msgid "Find:" +msgstr "Encontrar:" + +#: lib/search.tcl:23 +msgid "Next" +msgstr "Próximo" + +#: lib/search.tcl:24 +msgid "Prev" +msgstr "Anterior" + +#: lib/search.tcl:25 +msgid "Case-Sensitive" +msgstr "Sensível a maiúsculas/minúsculas" + +#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 +msgid "Cannot write shortcut:" +msgstr "Não foi possível gravar o atalho:" + +#: lib/shortcut.tcl:137 +msgid "Cannot write icon:" +msgstr "Não foi possível gravar o ícone:" + +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "Verificador ortográfico não suportado" + +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "Verificação ortográfica indisponível" + +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "Configuração do verificador ortográfico inválida" + +#: lib/spellcheck.tcl:70 +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "Revertendo dicionário para %s." + +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" +msgstr "O verificador ortográfico falhou sem relatar nenhum erro" + +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" +msgstr "Verificador ortográfico não reconhecido" + +#: lib/spellcheck.tcl:186 +msgid "No Suggestions" +msgstr "Sem sugestões" + +#: lib/spellcheck.tcl:388 +msgid "Unexpected EOF from spell checker" +msgstr "Final de arquivo inesperado recebido do verificador ortográfico" + +#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "A verificação ortográfica falhou" + +#: lib/sshkey.tcl:31 +msgid "No keys found." +msgstr "Nenhuma chave encontrada" + +#: lib/sshkey.tcl:34 +#, tcl-format +msgid "Found a public key in: %s" +msgstr "Chave pública encontrada em: %s" + +#: lib/sshkey.tcl:40 +msgid "Generate Key" +msgstr "Gerar chave" + +#: lib/sshkey.tcl:56 +msgid "Copy To Clipboard" +msgstr "Copiar para a área de transferência" + +#: lib/sshkey.tcl:70 +msgid "Your OpenSSH Public Key" +msgstr "Sua chave pública OpenSSH" + +#: lib/sshkey.tcl:78 +msgid "Generating..." +msgstr "Gerando..." + +#: lib/sshkey.tcl:84 +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Impossível iniciar ssh-keygen:\n" +"\n" +"%s" + +#: lib/sshkey.tcl:111 +msgid "Generation failed." +msgstr "A geração da chave falhou." + +#: lib/sshkey.tcl:118 +msgid "Generation succeded, but no keys found." +msgstr "A geração da chave foi bem-sucedida, mas nenhuma chave foi encontrada." + +#: lib/sshkey.tcl:121 +#, tcl-format +msgid "Your key is in: %s" +msgstr "Sua chave em: %s" + +#: lib/status_bar.tcl:83 +#, tcl-format +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s ... %*i de %*i %s (%3i%%)" + +#: lib/tools.tcl:75 +#, tcl-format +msgid "Running %s requires a selected file." +msgstr "É preciso selecionar um arquivo para executar %s." + +#: lib/tools.tcl:90 +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Você tem certeza que deseja executar %s?" + +#: lib/tools.tcl:110 +#, tcl-format +msgid "Tool: %s" +msgstr "Ferramenta: %s" + +#: lib/tools.tcl:111 +#, tcl-format +msgid "Running: %s" +msgstr "Executando: %s" + +#: lib/tools.tcl:149 +#, tcl-format +msgid "Tool completed successfully: %s" +msgstr "Execução completada com sucesso: %s" + +#: lib/tools.tcl:151 +#, tcl-format +msgid "Tool failed: %s" +msgstr "Ferramenta falhou: %s" + +#: lib/tools_dlg.tcl:22 +msgid "Add Tool" +msgstr "Adicionar ferramenta" + +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Adicionar novo comando de ferramenta" + +#: lib/tools_dlg.tcl:33 +msgid "Add globally" +msgstr "Adicionar globalmente" + +#: lib/tools_dlg.tcl:45 +msgid "Tool Details" +msgstr "Detalhes da ferramenta" + +#: lib/tools_dlg.tcl:48 +msgid "Use '/' separators to create a submenu tree:" +msgstr "Use o separador \"/\" para criar uma árvore de sub-menus:" + +#: lib/tools_dlg.tcl:61 +msgid "Command:" +msgstr "Comando:" + +#: lib/tools_dlg.tcl:74 +msgid "Show a dialog before running" +msgstr "Exibir uma caixa de diálogo antes de executar" + +#: lib/tools_dlg.tcl:80 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Solicitar a seleção de uma revisão (a variável $REVISION)" + +#: lib/tools_dlg.tcl:85 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Solicitar argumentos adicionais (define a variável $ARGS)" + +#: lib/tools_dlg.tcl:92 +msgid "Don't show the command output window" +msgstr "Não exibir a janela de saída do comando" + +#: lib/tools_dlg.tcl:97 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Executar apenas se houver um diff selecionado ($FILENAME não-vazio)" + +#: lib/tools_dlg.tcl:121 +msgid "Please supply a name for the tool." +msgstr "Por favor, indique um nome para a ferramenta." + +#: lib/tools_dlg.tcl:129 +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "A ferramenta \"%s\" já existe." + +#: lib/tools_dlg.tcl:151 +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Não foi possível adicionar a ferramenta:\n" +"%s" + +#: lib/tools_dlg.tcl:190 +msgid "Remove Tool" +msgstr "Excluir ferramenta" + +#: lib/tools_dlg.tcl:196 +msgid "Remove Tool Commands" +msgstr "Excluir comando de ferramenta" + +#: lib/tools_dlg.tcl:200 +msgid "Remove" +msgstr "Excluir" + +#: lib/tools_dlg.tcl:236 +msgid "(Blue denotes repository-local tools)" +msgstr "(Azul indica ferramentas do repositório local)" + +#: lib/tools_dlg.tcl:297 +#, tcl-format +msgid "Run Command: %s" +msgstr "Executar comando: %s" + +#: lib/tools_dlg.tcl:311 +msgid "Arguments" +msgstr "Argumentos" + +#: lib/tools_dlg.tcl:348 +msgid "OK" +msgstr "OK" + +#: lib/transport.tcl:7 +#, tcl-format +msgid "Fetching new changes from %s" +msgstr "Recebendo novas mudanças de %s" + +#: lib/transport.tcl:18 +#, tcl-format +msgid "remote prune %s" +msgstr "Limpar %s" + +#: lib/transport.tcl:19 +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "Limpando ramos excluídos de %s" + +#: lib/transport.tcl:26 +#, tcl-format +msgid "Pushing changes to %s" +msgstr "Enviando mudanças para %s" + +#: lib/transport.tcl:64 +#, tcl-format +msgid "Mirroring to %s" +msgstr "Duplicando para %s" + +#: lib/transport.tcl:82 +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "Enviando %s %s para %s" + +#: lib/transport.tcl:100 +msgid "Push Branches" +msgstr "Enviar ramos" + +#: lib/transport.tcl:114 +msgid "Source Branches" +msgstr "Ramos de origem" + +#: lib/transport.tcl:131 +msgid "Destination Repository" +msgstr "Repositório de destino" + +#: lib/transport.tcl:169 +msgid "Transfer Options" +msgstr "Opções de transferência" + +#: lib/transport.tcl:171 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "Sobrescrever ramos existentes (pode descartar mudanças)" + +#: lib/transport.tcl:175 +msgid "Use thin pack (for slow network connections)" +msgstr "Usar compactação minimalista (para redes lentas)" + +#: lib/transport.tcl:179 +msgid "Include tags" +msgstr "Incluir etiquetas" diff --git a/git-gui/po/ru.po b/git-gui/po/ru.po index 364c074c50..30f4b77dac 100644 --- a/git-gui/po/ru.po +++ b/git-gui/po/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: git-gui\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-12-08 08:31-0800\n" +"POT-Creation-Date: 2010-01-26 15:47-0800\n" "PO-Revision-Date: 2007-10-22 22:30-0200\n" "Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n" "Language-Team: Russian Translation <git@vger.kernel.org>\n" @@ -15,33 +15,33 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: git-gui.sh:41 git-gui.sh:737 git-gui.sh:751 git-gui.sh:764 git-gui.sh:847 -#: git-gui.sh:866 +#: git-gui.sh:41 git-gui.sh:793 git-gui.sh:807 git-gui.sh:820 git-gui.sh:903 +#: git-gui.sh:922 msgid "git-gui: fatal error" msgstr "git-gui: критическая ошибка" -#: git-gui.sh:689 +#: git-gui.sh:743 #, tcl-format msgid "Invalid font specified in %s:" msgstr "В %s установлен неверный шрифт:" -#: git-gui.sh:723 +#: git-gui.sh:779 msgid "Main Font" msgstr "Шрифт интерфейса" -#: git-gui.sh:724 +#: git-gui.sh:780 msgid "Diff/Console Font" msgstr "Шрифт консоли и изменений (diff)" -#: git-gui.sh:738 +#: git-gui.sh:794 msgid "Cannot find git in PATH." msgstr "git не найден в PATH." -#: git-gui.sh:765 +#: git-gui.sh:821 msgid "Cannot parse Git version string:" msgstr "Невозможно распознать строку версии Git: " -#: git-gui.sh:783 +#: git-gui.sh:839 #, tcl-format msgid "" "Git version cannot be determined.\n" @@ -60,450 +60,474 @@ msgstr "" "\n" "Принять '%s' как версию 1.5.0?\n" -#: git-gui.sh:1062 +#: git-gui.sh:1128 msgid "Git directory not found:" msgstr "Каталог Git не найден:" -#: git-gui.sh:1069 +#: git-gui.sh:1146 msgid "Cannot move to top of working directory:" msgstr "Невозможно перейти к корню рабочего каталога репозитория: " -#: git-gui.sh:1076 -msgid "Cannot use funny .git directory:" -msgstr "Каталог .git испорчен: " +#: git-gui.sh:1154 +msgid "Cannot use bare repository:" +msgstr "Невозможно использование репозитория без рабочего каталога:" -#: git-gui.sh:1081 +#: git-gui.sh:1162 msgid "No working directory" msgstr "Отсутствует рабочий каталог" -#: git-gui.sh:1247 lib/checkout_op.tcl:305 +#: git-gui.sh:1334 lib/checkout_op.tcl:306 msgid "Refreshing file status..." msgstr "Обновление информации о состоянии файлов..." -#: git-gui.sh:1303 +#: git-gui.sh:1390 msgid "Scanning for modified files ..." msgstr "Поиск измененных файлов..." -#: git-gui.sh:1367 +#: git-gui.sh:1454 msgid "Calling prepare-commit-msg hook..." msgstr "Вызов программы поддержки репозитория prepare-commit-msg..." -#: git-gui.sh:1384 +#: git-gui.sh:1471 msgid "Commit declined by prepare-commit-msg hook." msgstr "" "Сохранение прервано программой поддержки репозитория prepare-commit-msg" -#: git-gui.sh:1542 lib/browser.tcl:246 +#: git-gui.sh:1629 lib/browser.tcl:246 msgid "Ready." msgstr "Готово." -#: git-gui.sh:1726 +#: git-gui.sh:1787 #, tcl-format msgid "Displaying only %s of %s files." msgstr "Показано %s из %s файлов." -#: git-gui.sh:1819 +#: git-gui.sh:1913 msgid "Unmodified" msgstr "Не изменено" -#: git-gui.sh:1821 +#: git-gui.sh:1915 msgid "Modified, not staged" msgstr "Изменено, не подготовлено" -#: git-gui.sh:1822 git-gui.sh:1830 +#: git-gui.sh:1916 git-gui.sh:1924 msgid "Staged for commit" msgstr "Подготовлено для сохранения" -#: git-gui.sh:1823 git-gui.sh:1831 +#: git-gui.sh:1917 git-gui.sh:1925 msgid "Portions staged for commit" msgstr "Части, подготовленные для сохранения" -#: git-gui.sh:1824 git-gui.sh:1832 +#: git-gui.sh:1918 git-gui.sh:1926 msgid "Staged for commit, missing" msgstr "Подготовлено для сохранения, отсутствует" -#: git-gui.sh:1826 +#: git-gui.sh:1920 msgid "File type changed, not staged" msgstr "Тип файла изменён, не подготовлено" -#: git-gui.sh:1827 +#: git-gui.sh:1921 msgid "File type changed, staged" msgstr "Тип файла изменён, подготовлено" -#: git-gui.sh:1829 +#: git-gui.sh:1923 msgid "Untracked, not staged" msgstr "Не отслеживается, не подготовлено" -#: git-gui.sh:1834 +#: git-gui.sh:1928 msgid "Missing" msgstr "Отсутствует" -#: git-gui.sh:1835 +#: git-gui.sh:1929 msgid "Staged for removal" msgstr "Подготовлено для удаления" -#: git-gui.sh:1836 +#: git-gui.sh:1930 msgid "Staged for removal, still present" msgstr "Подготовлено для удаления, еще не удалено" -#: git-gui.sh:1838 git-gui.sh:1839 git-gui.sh:1840 git-gui.sh:1841 -#: git-gui.sh:1842 git-gui.sh:1843 +#: git-gui.sh:1932 git-gui.sh:1933 git-gui.sh:1934 git-gui.sh:1935 +#: git-gui.sh:1936 git-gui.sh:1937 msgid "Requires merge resolution" msgstr "Требуется разрешение конфликта при слиянии" -#: git-gui.sh:1878 +#: git-gui.sh:1972 msgid "Starting gitk... please wait..." msgstr "Запускается gitk... Подождите, пожалуйста..." -#: git-gui.sh:1887 +#: git-gui.sh:1984 msgid "Couldn't find gitk in PATH" msgstr "gitk не найден в PATH." -#: git-gui.sh:2280 lib/choose_repository.tcl:36 +#: git-gui.sh:2043 +msgid "Couldn't find git gui in PATH" +msgstr "git gui не найден в PATH." + +#: git-gui.sh:2455 lib/choose_repository.tcl:36 msgid "Repository" msgstr "Репозиторий" -#: git-gui.sh:2281 +#: git-gui.sh:2456 msgid "Edit" msgstr "Редактировать" -#: git-gui.sh:2283 lib/choose_rev.tcl:561 +#: git-gui.sh:2458 lib/choose_rev.tcl:561 msgid "Branch" msgstr "Ветвь" -#: git-gui.sh:2286 lib/choose_rev.tcl:548 +#: git-gui.sh:2461 lib/choose_rev.tcl:548 msgid "Commit@@noun" msgstr "Состояние" -#: git-gui.sh:2289 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 +#: git-gui.sh:2464 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 msgid "Merge" msgstr "Слияние" -#: git-gui.sh:2290 lib/choose_rev.tcl:557 +#: git-gui.sh:2465 lib/choose_rev.tcl:557 msgid "Remote" msgstr "Внешние репозитории" -#: git-gui.sh:2293 +#: git-gui.sh:2468 msgid "Tools" msgstr "Вспомогательные операции" -#: git-gui.sh:2302 +#: git-gui.sh:2477 msgid "Explore Working Copy" msgstr "Просмотр рабочего каталога" -#: git-gui.sh:2307 +#: git-gui.sh:2483 msgid "Browse Current Branch's Files" msgstr "Просмотреть файлы текущей ветви" -#: git-gui.sh:2311 +#: git-gui.sh:2487 msgid "Browse Branch Files..." msgstr "Показать файлы ветви..." -#: git-gui.sh:2316 +#: git-gui.sh:2492 msgid "Visualize Current Branch's History" msgstr "Показать историю текущей ветви" -#: git-gui.sh:2320 +#: git-gui.sh:2496 msgid "Visualize All Branch History" msgstr "Показать историю всех ветвей" -#: git-gui.sh:2327 +#: git-gui.sh:2503 #, tcl-format msgid "Browse %s's Files" msgstr "Показать файлы ветви %s" -#: git-gui.sh:2329 +#: git-gui.sh:2505 #, tcl-format msgid "Visualize %s's History" msgstr "Показать историю ветви %s" -#: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67 +#: git-gui.sh:2510 lib/database.tcl:27 lib/database.tcl:67 msgid "Database Statistics" msgstr "Статистика базы данных" -#: git-gui.sh:2337 lib/database.tcl:34 +#: git-gui.sh:2513 lib/database.tcl:34 msgid "Compress Database" msgstr "Сжать базу данных" -#: git-gui.sh:2340 +#: git-gui.sh:2516 msgid "Verify Database" msgstr "Проверить базу данных" -#: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7 -#: lib/shortcut.tcl:39 lib/shortcut.tcl:71 +#: git-gui.sh:2523 git-gui.sh:2527 git-gui.sh:2531 lib/shortcut.tcl:8 +#: lib/shortcut.tcl:40 lib/shortcut.tcl:72 msgid "Create Desktop Icon" msgstr "Создать ярлык на рабочем столе" -#: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 +#: git-gui.sh:2539 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 msgid "Quit" msgstr "Выход" -#: git-gui.sh:2371 +#: git-gui.sh:2547 msgid "Undo" msgstr "Отменить" -#: git-gui.sh:2374 +#: git-gui.sh:2550 msgid "Redo" msgstr "Повторить" -#: git-gui.sh:2378 git-gui.sh:2937 +#: git-gui.sh:2554 git-gui.sh:3109 msgid "Cut" msgstr "Вырезать" -#: git-gui.sh:2381 git-gui.sh:2940 git-gui.sh:3014 git-gui.sh:3096 +#: git-gui.sh:2557 git-gui.sh:3112 git-gui.sh:3186 git-gui.sh:3259 #: lib/console.tcl:69 msgid "Copy" msgstr "Копировать" -#: git-gui.sh:2384 git-gui.sh:2943 +#: git-gui.sh:2560 git-gui.sh:3115 msgid "Paste" msgstr "Вставить" -#: git-gui.sh:2387 git-gui.sh:2946 lib/branch_delete.tcl:26 +#: git-gui.sh:2563 git-gui.sh:3118 lib/branch_delete.tcl:26 #: lib/remote_branch_delete.tcl:38 msgid "Delete" msgstr "Удалить" -#: git-gui.sh:2391 git-gui.sh:2950 git-gui.sh:3100 lib/console.tcl:71 +#: git-gui.sh:2567 git-gui.sh:3122 git-gui.sh:3263 lib/console.tcl:71 msgid "Select All" msgstr "Выделить все" -#: git-gui.sh:2400 +#: git-gui.sh:2576 msgid "Create..." msgstr "Создать..." -#: git-gui.sh:2406 +#: git-gui.sh:2582 msgid "Checkout..." msgstr "Перейти..." -#: git-gui.sh:2412 +#: git-gui.sh:2588 msgid "Rename..." msgstr "Переименовать..." -#: git-gui.sh:2417 +#: git-gui.sh:2593 msgid "Delete..." msgstr "Удалить..." -#: git-gui.sh:2422 +#: git-gui.sh:2598 msgid "Reset..." msgstr "Сбросить..." -#: git-gui.sh:2432 +#: git-gui.sh:2608 msgid "Done" msgstr "Завершено" -#: git-gui.sh:2434 +#: git-gui.sh:2610 msgid "Commit@@verb" msgstr "Сохранить" -#: git-gui.sh:2443 git-gui.sh:2878 +#: git-gui.sh:2619 git-gui.sh:3050 msgid "New Commit" msgstr "Новое состояние" -#: git-gui.sh:2451 git-gui.sh:2885 +#: git-gui.sh:2627 git-gui.sh:3057 msgid "Amend Last Commit" msgstr "Исправить последнее состояние" -#: git-gui.sh:2461 git-gui.sh:2839 lib/remote_branch_delete.tcl:99 +#: git-gui.sh:2637 git-gui.sh:3011 lib/remote_branch_delete.tcl:99 msgid "Rescan" msgstr "Перечитать" -#: git-gui.sh:2467 +#: git-gui.sh:2643 msgid "Stage To Commit" msgstr "Подготовить для сохранения" -#: git-gui.sh:2473 +#: git-gui.sh:2649 msgid "Stage Changed Files To Commit" msgstr "Подготовить измененные файлы для сохранения" -#: git-gui.sh:2479 +#: git-gui.sh:2655 msgid "Unstage From Commit" msgstr "Убрать из подготовленного" -#: git-gui.sh:2484 lib/index.tcl:410 +#: git-gui.sh:2661 lib/index.tcl:412 msgid "Revert Changes" msgstr "Отменить изменения" -#: git-gui.sh:2491 git-gui.sh:3083 +#: git-gui.sh:2669 git-gui.sh:3310 git-gui.sh:3341 msgid "Show Less Context" msgstr "Меньше контекста" -#: git-gui.sh:2495 git-gui.sh:3087 +#: git-gui.sh:2673 git-gui.sh:3314 git-gui.sh:3345 msgid "Show More Context" msgstr "Больше контекста" -#: git-gui.sh:2502 git-gui.sh:2852 git-gui.sh:2961 +#: git-gui.sh:2680 git-gui.sh:3024 git-gui.sh:3133 msgid "Sign Off" msgstr "Вставить Signed-off-by" -#: git-gui.sh:2518 +#: git-gui.sh:2696 msgid "Local Merge..." msgstr "Локальное слияние..." -#: git-gui.sh:2523 +#: git-gui.sh:2701 msgid "Abort Merge..." msgstr "Прервать слияние..." -#: git-gui.sh:2535 git-gui.sh:2575 +#: git-gui.sh:2713 git-gui.sh:2741 msgid "Add..." msgstr "Добавить..." -#: git-gui.sh:2539 +#: git-gui.sh:2717 msgid "Push..." msgstr "Отправить..." -#: git-gui.sh:2543 +#: git-gui.sh:2721 msgid "Delete Branch..." msgstr "Удалить ветвь..." -#: git-gui.sh:2553 git-gui.sh:2589 lib/about.tcl:14 -#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 -#, tcl-format -msgid "About %s" -msgstr "О %s" - -#: git-gui.sh:2557 -msgid "Preferences..." -msgstr "Настройки..." - -#: git-gui.sh:2565 git-gui.sh:3129 +#: git-gui.sh:2731 git-gui.sh:3292 msgid "Options..." msgstr "Настройки..." -#: git-gui.sh:2576 +#: git-gui.sh:2742 msgid "Remove..." msgstr "Удалить..." -#: git-gui.sh:2585 lib/choose_repository.tcl:50 +#: git-gui.sh:2751 lib/choose_repository.tcl:50 msgid "Help" msgstr "Помощь" -#: git-gui.sh:2611 +#: git-gui.sh:2755 git-gui.sh:2759 lib/about.tcl:14 +#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 +#, tcl-format +msgid "About %s" +msgstr "О %s" + +#: git-gui.sh:2783 msgid "Online Documentation" msgstr "Документация в интернете" -#: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 +#: git-gui.sh:2786 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 msgid "Show SSH Key" msgstr "Показать ключ SSH" -#: git-gui.sh:2721 +#: git-gui.sh:2893 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" msgstr "критическая ошибка: %s: нет такого файла или каталога" -#: git-gui.sh:2754 +#: git-gui.sh:2926 msgid "Current Branch:" msgstr "Текущая ветвь:" -#: git-gui.sh:2775 +#: git-gui.sh:2947 msgid "Staged Changes (Will Commit)" msgstr "Подготовлено (будет сохранено)" -#: git-gui.sh:2795 +#: git-gui.sh:2967 msgid "Unstaged Changes" msgstr "Изменено (не будет сохранено)" -#: git-gui.sh:2845 +#: git-gui.sh:3017 msgid "Stage Changed" msgstr "Подготовить все" -#: git-gui.sh:2864 lib/transport.tcl:104 lib/transport.tcl:193 +#: git-gui.sh:3036 lib/transport.tcl:104 lib/transport.tcl:193 msgid "Push" msgstr "Отправить" -#: git-gui.sh:2899 +#: git-gui.sh:3071 msgid "Initial Commit Message:" msgstr "Комментарий к первому состоянию:" -#: git-gui.sh:2900 +#: git-gui.sh:3072 msgid "Amended Commit Message:" msgstr "Комментарий к исправленному состоянию:" -#: git-gui.sh:2901 +#: git-gui.sh:3073 msgid "Amended Initial Commit Message:" msgstr "Комментарий к исправленному первоначальному состоянию:" -#: git-gui.sh:2902 +#: git-gui.sh:3074 msgid "Amended Merge Commit Message:" msgstr "Комментарий к исправленному слиянию:" -#: git-gui.sh:2903 +#: git-gui.sh:3075 msgid "Merge Commit Message:" msgstr "Комментарий к слиянию:" -#: git-gui.sh:2904 +#: git-gui.sh:3076 msgid "Commit Message:" msgstr "Комментарий к состоянию:" -#: git-gui.sh:2953 git-gui.sh:3104 lib/console.tcl:73 +#: git-gui.sh:3125 git-gui.sh:3267 lib/console.tcl:73 msgid "Copy All" msgstr "Копировать все" -#: git-gui.sh:2977 lib/blame.tcl:104 +#: git-gui.sh:3149 lib/blame.tcl:104 msgid "File:" msgstr "Файл:" -#: git-gui.sh:3092 +#: git-gui.sh:3255 msgid "Refresh" msgstr "Обновить" -#: git-gui.sh:3113 +#: git-gui.sh:3276 msgid "Decrease Font Size" msgstr "Уменьшить размер шрифта" -#: git-gui.sh:3117 +#: git-gui.sh:3280 msgid "Increase Font Size" msgstr "Увеличить размер шрифта" -#: git-gui.sh:3125 lib/blame.tcl:281 +#: git-gui.sh:3288 lib/blame.tcl:281 msgid "Encoding" msgstr "Кодировка" -#: git-gui.sh:3136 +#: git-gui.sh:3299 msgid "Apply/Reverse Hunk" msgstr "Применить/Убрать изменение" -#: git-gui.sh:3141 +#: git-gui.sh:3304 msgid "Apply/Reverse Line" msgstr "Применить/Убрать строку" -#: git-gui.sh:3151 +#: git-gui.sh:3323 msgid "Run Merge Tool" msgstr "Запустить программу слияния" -#: git-gui.sh:3156 +#: git-gui.sh:3328 msgid "Use Remote Version" msgstr "Взять внешнюю версию" -#: git-gui.sh:3160 +#: git-gui.sh:3332 msgid "Use Local Version" msgstr "Взять локальную версию" -#: git-gui.sh:3164 +#: git-gui.sh:3336 msgid "Revert To Base" msgstr "Отменить изменения" -#: git-gui.sh:3183 +#: git-gui.sh:3354 +msgid "Visualize These Changes In The Submodule" +msgstr "" + +#: git-gui.sh:3358 +msgid "Visualize Current Branch History In The Submodule" +msgstr "Показать историю текущей ветви подмодуля" + +#: git-gui.sh:3362 +msgid "Visualize All Branch History In The Submodule" +msgstr "Показать историю всех ветвей подмодуля" + +#: git-gui.sh:3367 +msgid "Start git gui In The Submodule" +msgstr "" + +#: git-gui.sh:3389 msgid "Unstage Hunk From Commit" msgstr "Не сохранять часть" -#: git-gui.sh:3184 +#: git-gui.sh:3391 +msgid "Unstage Lines From Commit" +msgstr "Убрать строки из подготовленного" + +#: git-gui.sh:3393 msgid "Unstage Line From Commit" msgstr "Убрать строку из подготовленного" -#: git-gui.sh:3186 +#: git-gui.sh:3396 msgid "Stage Hunk For Commit" msgstr "Подготовить часть для сохранения" -#: git-gui.sh:3187 +#: git-gui.sh:3398 +msgid "Stage Lines For Commit" +msgstr "Подготовить строки для сохранения" + +#: git-gui.sh:3400 msgid "Stage Line For Commit" msgstr "Подготовить строку для сохранения" -#: git-gui.sh:3210 +#: git-gui.sh:3424 msgid "Initializing..." msgstr "Инициализация..." -#: git-gui.sh:3315 +#: git-gui.sh:3541 #, tcl-format msgid "" "Possible environment issues exist.\n" @@ -520,7 +544,7 @@ msgstr "" "запущенными из %s\n" "\n" -#: git-gui.sh:3345 +#: git-gui.sh:3570 msgid "" "\n" "This is due to a known issue with the\n" @@ -530,7 +554,7 @@ msgstr "" "Это известная проблема с Tcl,\n" "распространяемым Cygwin." -#: git-gui.sh:3350 +#: git-gui.sh:3575 #, tcl-format msgid "" "\n" @@ -640,7 +664,7 @@ msgstr "Невозможно найти состояние предка:" msgid "Unable to display parent" msgstr "Не могу показать предка" -#: lib/blame.tcl:1091 lib/diff.tcl:297 +#: lib/blame.tcl:1091 lib/diff.tcl:320 msgid "Error loading diff:" msgstr "Ошибка загрузки изменений:" @@ -666,7 +690,7 @@ msgstr "Перейти" #: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35 #: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282 -#: lib/checkout_op.tcl:544 lib/choose_font.tcl:43 lib/merge.tcl:172 +#: lib/checkout_op.tcl:579 lib/choose_font.tcl:43 lib/merge.tcl:172 #: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42 #: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352 #: lib/transport.tcl:108 @@ -697,7 +721,7 @@ msgstr "Создание ветви" msgid "Create New Branch" msgstr "Создать новую ветвь" -#: lib/branch_create.tcl:31 lib/choose_repository.tcl:377 +#: lib/branch_create.tcl:31 lib/choose_repository.tcl:381 msgid "Create" msgstr "Создать" @@ -729,7 +753,7 @@ msgstr "Нет" msgid "Fast Forward Only" msgstr "Только Fast Forward" -#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536 +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571 msgid "Reset" msgstr "Сброс" @@ -771,8 +795,8 @@ msgstr "Локальные ветви" msgid "Delete Only If Merged Into" msgstr "Удалить только в случае, если было слияние с" -#: lib/branch_delete.tcl:54 -msgid "Always (Do not perform merge test.)" +#: lib/branch_delete.tcl:54 lib/remote_branch_delete.tcl:119 +msgid "Always (Do not perform merge checks)" msgstr "Всегда (не выполнять проверку на слияние)" #: lib/branch_delete.tcl:103 @@ -780,6 +804,16 @@ msgstr "Всегда (не выполнять проверку на слияни msgid "The following branches are not completely merged into %s:" msgstr "Ветви, которые не полностью сливаются с %s:" +#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:217 +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" +"Восстановить удаленные ветви сложно.\n" +"\n" +"Продолжить?" + #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -809,7 +843,7 @@ msgstr "Новое название:" msgid "Please select a branch to rename." msgstr "Укажите ветвь для переименования." -#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:201 +#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:202 #, tcl-format msgid "Branch '%s' already exists." msgstr "Ветвь '%s' уже существует." @@ -840,38 +874,38 @@ msgstr "[На уровень выше]" msgid "Browse Branch Files" msgstr "Показать файлы ветви" -#: lib/browser.tcl:278 lib/choose_repository.tcl:394 -#: lib/choose_repository.tcl:480 lib/choose_repository.tcl:491 -#: lib/choose_repository.tcl:995 +#: lib/browser.tcl:278 lib/choose_repository.tcl:398 +#: lib/choose_repository.tcl:486 lib/choose_repository.tcl:497 +#: lib/choose_repository.tcl:1028 msgid "Browse" msgstr "Показать" -#: lib/checkout_op.tcl:84 +#: lib/checkout_op.tcl:85 #, tcl-format msgid "Fetching %s from %s" msgstr "Получение %s из %s " -#: lib/checkout_op.tcl:132 +#: lib/checkout_op.tcl:133 #, tcl-format msgid "fatal: Cannot resolve %s" msgstr "критическая ошибка: невозможно разрешить %s" -#: lib/checkout_op.tcl:145 lib/console.tcl:81 lib/database.tcl:31 +#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:31 #: lib/sshkey.tcl:53 msgid "Close" msgstr "Закрыть" -#: lib/checkout_op.tcl:174 +#: lib/checkout_op.tcl:175 #, tcl-format msgid "Branch '%s' does not exist." msgstr "Ветвь '%s' не существует " -#: lib/checkout_op.tcl:193 +#: lib/checkout_op.tcl:194 #, tcl-format msgid "Failed to configure simplified git-pull for '%s'." msgstr "Ошибка создания упрощённой конфигурации git pull для '%s'." -#: lib/checkout_op.tcl:228 +#: lib/checkout_op.tcl:229 #, tcl-format msgid "" "Branch '%s' already exists.\n" @@ -884,21 +918,21 @@ msgstr "" "Она не может быть прокручена(fast-forward) к %s.\n" "Требуется слияние." -#: lib/checkout_op.tcl:242 +#: lib/checkout_op.tcl:243 #, tcl-format msgid "Merge strategy '%s' not supported." msgstr "Неизвестная стратегия слияния: '%s'." -#: lib/checkout_op.tcl:261 +#: lib/checkout_op.tcl:262 #, tcl-format msgid "Failed to update '%s'." msgstr "Не удалось обновить '%s'." -#: lib/checkout_op.tcl:273 +#: lib/checkout_op.tcl:274 msgid "Staging area (index) is already locked." msgstr "Рабочая область заблокирована другим процессом." -#: lib/checkout_op.tcl:288 +#: lib/checkout_op.tcl:289 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -914,30 +948,30 @@ msgstr "" "\n" "Это будет сделано сейчас автоматически.\n" -#: lib/checkout_op.tcl:344 +#: lib/checkout_op.tcl:345 #, tcl-format msgid "Updating working directory to '%s'..." msgstr "Обновление рабочего каталога из '%s'..." -#: lib/checkout_op.tcl:345 +#: lib/checkout_op.tcl:346 msgid "files checked out" msgstr "файлы извлечены" -#: lib/checkout_op.tcl:375 +#: lib/checkout_op.tcl:376 #, tcl-format msgid "Aborted checkout of '%s' (file level merging is required)." msgstr "Прерван переход на '%s' (требуется слияние содержания файлов)" -#: lib/checkout_op.tcl:376 +#: lib/checkout_op.tcl:377 msgid "File level merge required." msgstr "Требуется слияние содержания файлов." -#: lib/checkout_op.tcl:380 +#: lib/checkout_op.tcl:381 #, tcl-format msgid "Staying on branch '%s'." msgstr "Ветвь '%s' остается текущей." -#: lib/checkout_op.tcl:451 +#: lib/checkout_op.tcl:452 msgid "" "You are no longer on a local branch.\n" "\n" @@ -949,30 +983,30 @@ msgstr "" "Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, " "начиная с 'Текущего отсоединенного состояния'." -#: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472 +#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 #, tcl-format msgid "Checked out '%s'." msgstr "Ветвь '%s' сделана текущей." -#: lib/checkout_op.tcl:500 +#: lib/checkout_op.tcl:535 #, tcl-format msgid "Resetting '%s' to '%s' will lose the following commits:" msgstr "Сброс '%s' в '%s' приведет к потере следующих сохраненных состояний: " -#: lib/checkout_op.tcl:522 +#: lib/checkout_op.tcl:557 msgid "Recovering lost commits may not be easy." msgstr "Восстановить потерянные сохраненные состояния будет сложно." -#: lib/checkout_op.tcl:527 +#: lib/checkout_op.tcl:562 #, tcl-format msgid "Reset '%s'?" msgstr "Сбросить '%s'?" -#: lib/checkout_op.tcl:532 lib/merge.tcl:164 lib/tools_dlg.tcl:343 +#: lib/checkout_op.tcl:567 lib/merge.tcl:164 lib/tools_dlg.tcl:343 msgid "Visualize" msgstr "Наглядно" -#: lib/checkout_op.tcl:600 +#: lib/checkout_op.tcl:635 #, tcl-format msgid "" "Failed to set current branch.\n" @@ -1017,7 +1051,7 @@ msgstr "" msgid "Git Gui" msgstr "Git Gui" -#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:382 +#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:386 msgid "Create New Repository" msgstr "Создать новый репозиторий" @@ -1025,7 +1059,7 @@ msgstr "Создать новый репозиторий" msgid "New..." msgstr "Новый..." -#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465 +#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:471 msgid "Clone Existing Repository" msgstr "Склонировать существующий репозиторий" @@ -1033,7 +1067,7 @@ msgstr "Склонировать существующий репозиторий msgid "Clone..." msgstr "Склонировать..." -#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983 +#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:1016 msgid "Open Existing Repository" msgstr "Выбрать существующий репозиторий" @@ -1049,194 +1083,194 @@ msgstr "Недавние репозитории" msgid "Open Recent Repository:" msgstr "Открыть последний репозиторий" -#: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309 -#: lib/choose_repository.tcl:316 +#: lib/choose_repository.tcl:306 lib/choose_repository.tcl:313 +#: lib/choose_repository.tcl:320 #, tcl-format msgid "Failed to create repository %s:" msgstr "Не удалось создать репозиторий %s:" -#: lib/choose_repository.tcl:387 +#: lib/choose_repository.tcl:391 msgid "Directory:" msgstr "Каталог:" -#: lib/choose_repository.tcl:417 lib/choose_repository.tcl:544 -#: lib/choose_repository.tcl:1017 +#: lib/choose_repository.tcl:423 lib/choose_repository.tcl:550 +#: lib/choose_repository.tcl:1052 msgid "Git Repository" msgstr "Репозиторий" -#: lib/choose_repository.tcl:442 +#: lib/choose_repository.tcl:448 #, tcl-format msgid "Directory %s already exists." msgstr "Каталог '%s' уже существует." -#: lib/choose_repository.tcl:446 +#: lib/choose_repository.tcl:452 #, tcl-format msgid "File %s already exists." msgstr "Файл '%s' уже существует." -#: lib/choose_repository.tcl:460 +#: lib/choose_repository.tcl:466 msgid "Clone" msgstr "Склонировать" -#: lib/choose_repository.tcl:473 +#: lib/choose_repository.tcl:479 msgid "Source Location:" msgstr "Исходное положение:" -#: lib/choose_repository.tcl:484 +#: lib/choose_repository.tcl:490 msgid "Target Directory:" msgstr "Каталог назначения:" -#: lib/choose_repository.tcl:496 +#: lib/choose_repository.tcl:502 msgid "Clone Type:" msgstr "Тип клона:" -#: lib/choose_repository.tcl:502 +#: lib/choose_repository.tcl:508 msgid "Standard (Fast, Semi-Redundant, Hardlinks)" msgstr "Стандартный (Быстрый, полуизбыточный, \"жесткие\" ссылки)" -#: lib/choose_repository.tcl:508 +#: lib/choose_repository.tcl:514 msgid "Full Copy (Slower, Redundant Backup)" msgstr "Полная копия (Медленный, создает резервную копию)" -#: lib/choose_repository.tcl:514 +#: lib/choose_repository.tcl:520 msgid "Shared (Fastest, Not Recommended, No Backup)" msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)" -#: lib/choose_repository.tcl:550 lib/choose_repository.tcl:597 -#: lib/choose_repository.tcl:743 lib/choose_repository.tcl:813 -#: lib/choose_repository.tcl:1023 lib/choose_repository.tcl:1031 +#: lib/choose_repository.tcl:556 lib/choose_repository.tcl:603 +#: lib/choose_repository.tcl:749 lib/choose_repository.tcl:819 +#: lib/choose_repository.tcl:1058 lib/choose_repository.tcl:1066 #, tcl-format msgid "Not a Git repository: %s" msgstr "Каталог не является репозиторием: %s" -#: lib/choose_repository.tcl:586 +#: lib/choose_repository.tcl:592 msgid "Standard only available for local repository." msgstr "Стандартный клон возможен только для локального репозитория." -#: lib/choose_repository.tcl:590 +#: lib/choose_repository.tcl:596 msgid "Shared only available for local repository." msgstr "Общий клон возможен только для локального репозитория." -#: lib/choose_repository.tcl:611 +#: lib/choose_repository.tcl:617 #, tcl-format msgid "Location %s already exists." msgstr "Путь '%s' уже существует." -#: lib/choose_repository.tcl:622 +#: lib/choose_repository.tcl:628 msgid "Failed to configure origin" msgstr "Не могу сконфигурировать исходный репозиторий." -#: lib/choose_repository.tcl:634 +#: lib/choose_repository.tcl:640 msgid "Counting objects" msgstr "Считаю объекты" -#: lib/choose_repository.tcl:635 +#: lib/choose_repository.tcl:641 msgid "buckets" msgstr "" -#: lib/choose_repository.tcl:659 +#: lib/choose_repository.tcl:665 #, tcl-format msgid "Unable to copy objects/info/alternates: %s" msgstr "Не могу скопировать objects/info/alternates: %s" -#: lib/choose_repository.tcl:695 +#: lib/choose_repository.tcl:701 #, tcl-format msgid "Nothing to clone from %s." msgstr "Нечего клонировать с %s." -#: lib/choose_repository.tcl:697 lib/choose_repository.tcl:911 -#: lib/choose_repository.tcl:923 +#: lib/choose_repository.tcl:703 lib/choose_repository.tcl:917 +#: lib/choose_repository.tcl:929 msgid "The 'master' branch has not been initialized." msgstr "Не инициализирована ветвь 'master'." -#: lib/choose_repository.tcl:710 +#: lib/choose_repository.tcl:716 msgid "Hardlinks are unavailable. Falling back to copying." msgstr "\"Жесткие ссылки\" недоступны. Будет использовано копирование." -#: lib/choose_repository.tcl:722 +#: lib/choose_repository.tcl:728 #, tcl-format msgid "Cloning from %s" msgstr "Клонирование %s" -#: lib/choose_repository.tcl:753 +#: lib/choose_repository.tcl:759 msgid "Copying objects" msgstr "Копирование objects" -#: lib/choose_repository.tcl:754 +#: lib/choose_repository.tcl:760 msgid "KiB" msgstr "КБ" -#: lib/choose_repository.tcl:778 +#: lib/choose_repository.tcl:784 #, tcl-format msgid "Unable to copy object: %s" msgstr "Не могу скопировать объект: %s" -#: lib/choose_repository.tcl:788 +#: lib/choose_repository.tcl:794 msgid "Linking objects" msgstr "Создание ссылок на objects" -#: lib/choose_repository.tcl:789 +#: lib/choose_repository.tcl:795 msgid "objects" msgstr "объекты" -#: lib/choose_repository.tcl:797 +#: lib/choose_repository.tcl:803 #, tcl-format msgid "Unable to hardlink object: %s" msgstr "Не могу \"жестко связать\" объект: %s" -#: lib/choose_repository.tcl:852 +#: lib/choose_repository.tcl:858 msgid "Cannot fetch branches and objects. See console output for details." msgstr "" "Не могу получить ветви и объекты. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:863 +#: lib/choose_repository.tcl:869 msgid "Cannot fetch tags. See console output for details." msgstr "Не могу получить метки. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:887 +#: lib/choose_repository.tcl:893 msgid "Cannot determine HEAD. See console output for details." msgstr "Не могу определить HEAD. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:896 +#: lib/choose_repository.tcl:902 #, tcl-format msgid "Unable to cleanup %s" msgstr "Не могу очистить %s" -#: lib/choose_repository.tcl:902 +#: lib/choose_repository.tcl:908 msgid "Clone failed." msgstr "Клонирование не удалось." -#: lib/choose_repository.tcl:909 +#: lib/choose_repository.tcl:915 msgid "No default branch obtained." msgstr "Не было получено ветви по умолчанию." -#: lib/choose_repository.tcl:920 +#: lib/choose_repository.tcl:926 #, tcl-format msgid "Cannot resolve %s as a commit." msgstr "Не могу распознать %s как состояние." -#: lib/choose_repository.tcl:932 +#: lib/choose_repository.tcl:938 msgid "Creating working directory" msgstr "Создаю рабочий каталог" -#: lib/choose_repository.tcl:933 lib/index.tcl:65 lib/index.tcl:128 -#: lib/index.tcl:196 +#: lib/choose_repository.tcl:939 lib/index.tcl:67 lib/index.tcl:130 +#: lib/index.tcl:198 msgid "files" msgstr "файлов" -#: lib/choose_repository.tcl:962 +#: lib/choose_repository.tcl:968 msgid "Initial file checkout failed." msgstr "Не удалось получить начальное состояние файлов репозитория." -#: lib/choose_repository.tcl:978 +#: lib/choose_repository.tcl:1011 msgid "Open" msgstr "Открыть" -#: lib/choose_repository.tcl:988 +#: lib/choose_repository.tcl:1021 msgid "Repository:" msgstr "Репозиторий:" -#: lib/choose_repository.tcl:1037 +#: lib/choose_repository.tcl:1072 #, tcl-format msgid "Failed to open repository %s:" msgstr "Не удалось открыть репозиторий %s:" @@ -1318,7 +1352,12 @@ msgstr "Невозможно получить информацию об авто msgid "Invalid GIT_COMMITTER_IDENT:" msgstr "Неверный GIT_COMMITTER_IDENT:" -#: lib/commit.tcl:132 +#: lib/commit.tcl:129 +#, tcl-format +msgid "warning: Tcl does not support encoding '%s'." +msgstr "предупреждение: Tcl не поддерживает кодировку '%s'." + +#: lib/commit.tcl:149 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -1334,7 +1373,7 @@ msgstr "" "\n" "Это будет сделано сейчас автоматически.\n" -#: lib/commit.tcl:155 +#: lib/commit.tcl:172 #, tcl-format msgid "" "Unmerged files cannot be committed.\n" @@ -1342,12 +1381,12 @@ msgid "" "File %s has merge conflicts. You must resolve them and stage the file " "before committing.\n" msgstr "" -"Нельзя сохранить файлы с незавершённой операцей слияния.\n" +"Нельзя сохранить файлы с незавершённой операцией слияния.\n" "\n" "Для файла %s возник конфликт слияния. Разрешите конфликт и добавьте к " "подготовленным файлам перед сохранением.\n" -#: lib/commit.tcl:163 +#: lib/commit.tcl:180 #, tcl-format msgid "" "Unknown file state %s detected.\n" @@ -1358,7 +1397,7 @@ msgstr "" "\n" "Файл %s не может быть сохранен данной программой.\n" -#: lib/commit.tcl:171 +#: lib/commit.tcl:188 msgid "" "No changes to commit.\n" "\n" @@ -1368,7 +1407,7 @@ msgstr "" "\n" "Подготовьте хотя бы один файл до создания сохраненного состояния.\n" -#: lib/commit.tcl:186 +#: lib/commit.tcl:203 msgid "" "Please supply a commit message.\n" "\n" @@ -1386,45 +1425,40 @@ msgstr "" "- вторая строка пустая\n" "- оставшиеся строки: опишите, что дают ваши изменения.\n" -#: lib/commit.tcl:210 -#, tcl-format -msgid "warning: Tcl does not support encoding '%s'." -msgstr "предупреждение: Tcl не поддерживает кодировку '%s'." - -#: lib/commit.tcl:226 +#: lib/commit.tcl:234 msgid "Calling pre-commit hook..." msgstr "Вызов программы поддержки репозитория pre-commit..." -#: lib/commit.tcl:241 +#: lib/commit.tcl:249 msgid "Commit declined by pre-commit hook." msgstr "Сохранение прервано программой поддержки репозитория pre-commit" -#: lib/commit.tcl:264 +#: lib/commit.tcl:272 msgid "Calling commit-msg hook..." msgstr "Вызов программы поддержки репозитория commit-msg..." -#: lib/commit.tcl:279 +#: lib/commit.tcl:287 msgid "Commit declined by commit-msg hook." msgstr "Сохранение прервано программой поддержки репозитория commit-msg" -#: lib/commit.tcl:292 +#: lib/commit.tcl:300 msgid "Committing changes..." msgstr "Сохранение изменений..." -#: lib/commit.tcl:308 +#: lib/commit.tcl:316 msgid "write-tree failed:" msgstr "Программа write-tree завершилась с ошибкой:" -#: lib/commit.tcl:309 lib/commit.tcl:353 lib/commit.tcl:373 +#: lib/commit.tcl:317 lib/commit.tcl:361 lib/commit.tcl:382 msgid "Commit failed." msgstr "Сохранить состояние не удалось." -#: lib/commit.tcl:326 +#: lib/commit.tcl:334 #, tcl-format msgid "Commit %s appears to be corrupt" msgstr "Состояние %s выглядит поврежденным" -#: lib/commit.tcl:331 +#: lib/commit.tcl:339 msgid "" "No changes to commit.\n" "\n" @@ -1438,19 +1472,19 @@ msgstr "" "\n" "Сейчас автоматически запустится перечитывание репозитория.\n" -#: lib/commit.tcl:338 +#: lib/commit.tcl:346 msgid "No changes to commit." -msgstr "Отуствуют измения для сохранения." +msgstr "Отсутствуют изменения для сохранения." -#: lib/commit.tcl:352 +#: lib/commit.tcl:360 msgid "commit-tree failed:" msgstr "Программа commit-tree завершилась с ошибкой:" -#: lib/commit.tcl:372 +#: lib/commit.tcl:381 msgid "update-ref failed:" msgstr "Программа update-ref завершилась с ошибкой:" -#: lib/commit.tcl:460 +#: lib/commit.tcl:469 #, tcl-format msgid "Created commit %s: %s" msgstr "Создано состояние %s: %s " @@ -1503,20 +1537,19 @@ msgstr "Сжатие базы объектов" msgid "Verifying the object database with fsck-objects" msgstr "Проверка базы объектов при помощи fsck" -#: lib/database.tcl:108 +#: 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 when more than %i loose objects exist.\n" +"the database.\n" "\n" "Compress the database now?" msgstr "" "Этот репозиторий сейчас содержит примерно %i свободных объектов\n" "\n" -"Для лучшей производительности рекомендуется сжать базу данных, когда есть " -"более %i несвязанных объектов.\n" +"Для лучшей производительности рекомендуется сжать базу данных.\n" "\n" "Сжать базу данных сейчас?" @@ -1525,7 +1558,7 @@ msgstr "" msgid "Invalid date from Git: %s" msgstr "Неправильная дата в репозитории: %s" -#: lib/diff.tcl:59 +#: lib/diff.tcl:64 #, tcl-format msgid "" "No differences detected.\n" @@ -1540,19 +1573,19 @@ msgid "" msgstr "" "Изменений не обнаружено.\n" "\n" -"в %s отутствуют изменения.\n" +"в %s отсутствуют изменения.\n" "\n" "Дата изменения файла была обновлена другой программой, но содержимое файла " "осталось прежним.\n" "\n" "Сейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы." -#: lib/diff.tcl:99 +#: lib/diff.tcl:104 #, tcl-format msgid "Loading diff of %s..." msgstr "Загрузка изменений в %s..." -#: lib/diff.tcl:120 +#: lib/diff.tcl:125 msgid "" "LOCAL: deleted\n" "REMOTE:\n" @@ -1560,7 +1593,7 @@ msgstr "" "ЛОКАЛЬНО: удалён\n" "ВНЕШНИЙ:\n" -#: lib/diff.tcl:125 +#: lib/diff.tcl:130 msgid "" "REMOTE: deleted\n" "LOCAL:\n" @@ -1568,41 +1601,41 @@ msgstr "" "ВНЕШНИЙ: удалён\n" "ЛОКАЛЬНО:\n" -#: lib/diff.tcl:132 +#: lib/diff.tcl:137 msgid "LOCAL:\n" msgstr "ЛОКАЛЬНО:\n" -#: lib/diff.tcl:135 +#: lib/diff.tcl:140 msgid "REMOTE:\n" msgstr "ВНЕШНИЙ:\n" -#: lib/diff.tcl:197 lib/diff.tcl:296 +#: lib/diff.tcl:202 lib/diff.tcl:319 #, tcl-format msgid "Unable to display %s" msgstr "Не могу показать %s" -#: lib/diff.tcl:198 +#: lib/diff.tcl:203 msgid "Error loading file:" msgstr "Ошибка загрузки файла:" -#: lib/diff.tcl:205 +#: lib/diff.tcl:210 msgid "Git Repository (subproject)" msgstr "Репозиторий Git (подпроект)" -#: lib/diff.tcl:217 +#: lib/diff.tcl:222 msgid "* Binary file (not showing content)." msgstr "* Двоичный файл (содержимое не показано)" -#: lib/diff.tcl:222 +#: lib/diff.tcl:227 #, tcl-format msgid "" "* Untracked file is %d bytes.\n" "* Showing only first %d bytes.\n" msgstr "" -"* Размер неподготовленого файла %d байт.\n" +"* Размер неподготовленного файла %d байт.\n" "* Показано первых %d байт.\n" -#: lib/diff.tcl:228 +#: lib/diff.tcl:233 #, tcl-format msgid "" "\n" @@ -1610,22 +1643,22 @@ msgid "" "* To see the entire file, use an external editor.\n" msgstr "" "\n" -"* Неподготовленый файл обрезан: %s.\n" +"* Неподготовленный файл обрезан: %s.\n" "* Чтобы увидеть весь файл, используйте программу-редактор.\n" -#: lib/diff.tcl:436 +#: lib/diff.tcl:482 msgid "Failed to unstage selected hunk." msgstr "Не удалось исключить выбранную часть." -#: lib/diff.tcl:443 +#: lib/diff.tcl:489 msgid "Failed to stage selected hunk." msgstr "Не удалось подготовить к сохранению выбранную часть." -#: lib/diff.tcl:509 +#: lib/diff.tcl:568 msgid "Failed to unstage selected line." msgstr "Не удалось исключить выбранную строку." -#: lib/diff.tcl:517 +#: lib/diff.tcl:576 msgid "Failed to stage selected line." msgstr "Не удалось подготовить к сохранению выбранную строку." @@ -1662,15 +1695,15 @@ msgstr "Не удалось разблокировать индекс" msgid "Index Error" msgstr "Ошибка в индексе" -#: lib/index.tcl:21 +#: lib/index.tcl:17 msgid "" "Updating the Git index failed. A rescan will be automatically started to " "resynchronize git-gui." msgstr "" -"Не удалось обновить индекс Git. Состояние репозитория будетперечитано " +"Не удалось обновить индекс Git. Состояние репозитория будет перечитано " "автоматически." -#: lib/index.tcl:27 +#: lib/index.tcl:28 msgid "Continue" msgstr "Продолжить" @@ -1678,45 +1711,45 @@ msgstr "Продолжить" msgid "Unlock Index" msgstr "Разблокировать индекс" -#: lib/index.tcl:287 +#: lib/index.tcl:289 #, tcl-format msgid "Unstaging %s from commit" msgstr "Удаление %s из подготовленного" -#: lib/index.tcl:326 +#: lib/index.tcl:328 msgid "Ready to commit." msgstr "Подготовлено для сохранения" -#: lib/index.tcl:339 +#: lib/index.tcl:341 #, tcl-format msgid "Adding %s" msgstr "Добавление %s..." -#: lib/index.tcl:396 +#: lib/index.tcl:398 #, tcl-format msgid "Revert changes in file %s?" msgstr "Отменить изменения в файле %s?" -#: lib/index.tcl:398 +#: lib/index.tcl:400 #, tcl-format msgid "Revert changes in these %i files?" msgstr "Отменить изменения в %i файле(-ах)?" -#: lib/index.tcl:406 +#: lib/index.tcl:408 msgid "Any unstaged changes will be permanently lost by the revert." msgstr "" "Любые изменения, не подготовленные к сохранению, будут потеряны при данной " "операции." -#: lib/index.tcl:409 +#: lib/index.tcl:411 msgid "Do Nothing" msgstr "Ничего не делать" -#: lib/index.tcl:427 +#: lib/index.tcl:429 msgid "Reverting selected files" -msgstr "Удаление изменений в выбраных файлах" +msgstr "Удаление изменений в выбранных файлах" -#: lib/index.tcl:431 +#: lib/index.tcl:433 #, tcl-format msgid "Reverting %s" msgstr "Отмена изменений в %s" @@ -1778,7 +1811,7 @@ msgstr "" "\n" "Файл %s изменен.\n" "\n" -"Подготовьте и сохраните измения перед началом слияния. В случае " +"Подготовьте и сохраните изменения перед началом слияния. В случае " "необходимости это позволит прервать операцию слияния.\n" #: lib/merge.tcl:107 @@ -1893,7 +1926,7 @@ msgstr "" #, tcl-format msgid "File %s seems to have unresolved conflicts, still stage?" msgstr "" -"Файл %s кажется содержит необработаные конфликты. Продолжить подготовку к " +"Файл %s, похоже, содержит необработанные конфликты. Продолжить подготовку к " "сохранению?" #: lib/mergetool.tcl:60 @@ -2152,7 +2185,7 @@ msgstr "Получение %s" #: lib/remote_add.tcl:157 #, tcl-format msgid "Do not know how to initialize repository at location '%s'." -msgstr "Невозможно инициалировать репозиторий в '%s'." +msgstr "Невозможно инициализировать репозиторий в '%s'." #: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63 #: lib/transport.tcl:81 @@ -2179,7 +2212,7 @@ msgstr "внешний:" #: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149 msgid "Arbitrary Location:" -msgstr "Указаное положение:" +msgstr "Указанное положение:" #: lib/remote_branch_delete.tcl:84 msgid "Branches" @@ -2193,10 +2226,6 @@ msgstr "Удалить только в случае, если" msgid "Merged Into:" msgstr "Слияние с:" -#: lib/remote_branch_delete.tcl:119 -msgid "Always (Do not perform merge checks)" -msgstr "Всегда (не выполнять проверку на слияние)" - #: lib/remote_branch_delete.tcl:152 msgid "A branch is required for 'Merged Into'." msgstr "Для опции 'Слияние с' требуется указать ветвь." @@ -2225,26 +2254,16 @@ msgstr "" msgid "Please select one or more branches to delete." msgstr "Укажите одну или несколько ветвей для удаления." -#: lib/remote_branch_delete.tcl:216 -msgid "" -"Recovering deleted branches is difficult.\n" -"\n" -"Delete the selected branches?" -msgstr "" -"Восстановить удаленные ветви сложно.\n" -"\n" -"Продолжить?" - #: lib/remote_branch_delete.tcl:226 #, tcl-format msgid "Deleting branches from %s" msgstr "Удаление ветвей из %s" -#: lib/remote_branch_delete.tcl:286 +#: lib/remote_branch_delete.tcl:292 msgid "No repository selected." msgstr "Не указан репозиторий." -#: lib/remote_branch_delete.tcl:291 +#: lib/remote_branch_delete.tcl:297 #, tcl-format msgid "Scanning %s..." msgstr "Перечитывание %s... " @@ -2265,11 +2284,11 @@ msgstr "Обратно" msgid "Case-Sensitive" msgstr "Игн. большие/маленькие" -#: lib/shortcut.tcl:20 lib/shortcut.tcl:61 +#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 msgid "Cannot write shortcut:" msgstr "Невозможно записать ссылку:" -#: lib/shortcut.tcl:136 +#: lib/shortcut.tcl:137 msgid "Cannot write icon:" msgstr "Невозможно записать значок:" @@ -2292,11 +2311,11 @@ msgstr "Словарь вернут к %s." #: lib/spellcheck.tcl:73 msgid "Spell checker silently failed on startup" -msgstr "Программа проверки правописания не смогла запустится" +msgstr "Программа проверки правописания не смогла запуститься" #: lib/spellcheck.tcl:80 msgid "Unrecognized spell checker" -msgstr "Нераспознаная программа проверки правописания" +msgstr "Нераспознанная программа проверки правописания" #: lib/spellcheck.tcl:186 msgid "No Suggestions" @@ -2412,7 +2431,7 @@ msgstr "Описание вспомогательной операции" #: lib/tools_dlg.tcl:48 msgid "Use '/' separators to create a submenu tree:" -msgstr "Испольуйте '/' для создания подменю" +msgstr "Используйте '/' для создания подменю" #: lib/tools_dlg.tcl:61 msgid "Command:" diff --git a/git-stash.sh b/git-stash.sh index 7561b374d2..a305fb19f1 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -12,12 +12,14 @@ USAGE="list [<options>] SUBDIRECTORY_OK=Yes OPTIONS_SPEC= +START_DIR=`pwd` . git-sh-setup require_work_tree cd_to_toplevel TMP="$GIT_DIR/.git-stash.$$" -trap 'rm -f "$TMP-*"' 0 +TMPindex=${GIT_INDEX_FILE-"$GIT_DIR/index"}.stash.$$ +trap 'rm -f "$TMP-"* "$TMPindex"' 0 ref_stash=refs/stash @@ -81,14 +83,12 @@ create_stash () { # state of the working tree w_tree=$( ( - rm -f "$TMP-index" && - cp -p ${GIT_INDEX_FILE-"$GIT_DIR/index"} "$TMP-index" && - GIT_INDEX_FILE="$TMP-index" && + git read-tree --index-output="$TMPindex" -m $i_tree && + GIT_INDEX_FILE="$TMPindex" && export GIT_INDEX_FILE && - git read-tree -m $i_tree && git diff --name-only -z HEAD | git update-index -z --add --remove --stdin && git write-tree && - rm -f "$TMP-index" + rm -f "$TMPindex" ) ) || die "Cannot save the current worktree state" @@ -394,7 +394,7 @@ apply_stash () { then squelch='>/dev/null 2>&1' fi - eval "git status $squelch" || : + (cd "$START_DIR" && eval "git status $squelch") || : else # Merge conflict; keep the exit status from merge-recursive status=$? diff --git a/git-svn.perl b/git-svn.perl index 177dd259cd..a5857c1ad4 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -5734,7 +5734,7 @@ sub cmd_show_log { my (@k, $c, $d, $stat); my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; while (<$log>) { - if (/^${esc_color}commit -?($::sha1_short)/o) { + if (/^${esc_color}commit (- )?($::sha1_short)/o) { my $cmt = $1; if ($c && cmt_showable($c) && $c->{r} != $r_last) { $r_last = $c->{r}; diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9dccfb01d6..ee69ea683a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1199,11 +1199,15 @@ if (defined caller) { # -full => 0|1 - use absolute/full URL ($my_uri/$my_url as base) # -replay => 1 - start from a current view (replay with modifications) # -path_info => 0|1 - don't use/use path_info URL (if possible) +# -anchor => ANCHOR - add #ANCHOR to end of URL, implies -replay if used alone sub href { my %params = @_; # default is to use -absolute url() i.e. $my_uri my $href = $params{-full} ? $my_url : $my_uri; + # implicit -replay, must be first of implicit params + $params{-replay} = 1 if (keys %params == 1 && $params{-anchor}); + $params{'project'} = $project unless exists $params{'project'}; if ($params{-replay}) { @@ -1314,6 +1318,10 @@ sub href { # final transformation: trailing spaces must be escaped (URI-encoded) $href =~ s/(\s+)$/CGI::escape($1)/e; + if ($params{-anchor}) { + $href .= "#".esc_param($params{-anchor}); + } + return $href; } @@ -2913,8 +2921,10 @@ sub parse_date { $date{'iso-8601'} = sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ", 1900+$year, 1+$mon, $mday, $hour ,$min, $sec; - $tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/; - my $local = $epoch + ((int $1 + ($2/60)) * 3600); + my ($tz_sign, $tz_hour, $tz_min) = + ($tz =~ m/^([-+])(\d\d)(\d\d)$/); + $tz_sign = ($tz_sign eq '-' ? -1 : +1); + my $local = $epoch + $tz_sign*((($tz_hour*60) + $tz_min)*60); ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($local); $date{'hour_local'} = $hour; $date{'minute_local'} = $min; @@ -4335,7 +4345,8 @@ sub git_difftree_body { # link to patch $patchno++; print "<td class=\"link\">" . - $cgi->a({-href => "#patch$patchno"}, "patch") . + $cgi->a({-href => href(-anchor=>"patch$patchno")}, + "patch") . " | " . "</td>\n"; } @@ -4432,8 +4443,9 @@ sub git_difftree_body { if ($action eq 'commitdiff') { # link to patch $patchno++; - print $cgi->a({-href => "#patch$patchno"}, "patch"); - print " | "; + print $cgi->a({-href => href(-anchor=>"patch$patchno")}, + "patch") . + " | "; } print $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'}, hash_base=>$hash, file_name=>$diff->{'file'})}, @@ -4452,8 +4464,9 @@ sub git_difftree_body { if ($action eq 'commitdiff') { # link to patch $patchno++; - print $cgi->a({-href => "#patch$patchno"}, "patch"); - print " | "; + print $cgi->a({-href => href(-anchor=>"patch$patchno")}, + "patch") . + " | "; } print $cgi->a({-href => href(action=>"blob", hash=>$diff->{'from_id'}, hash_base=>$parent, file_name=>$diff->{'file'})}, @@ -4494,7 +4507,8 @@ sub git_difftree_body { if ($action eq 'commitdiff') { # link to patch $patchno++; - print $cgi->a({-href => "#patch$patchno"}, "patch") . + print $cgi->a({-href => href(-anchor=>"patch$patchno")}, + "patch") . " | "; } elsif ($diff->{'to_id'} ne $diff->{'from_id'}) { # "commit" view and modified file (not onlu mode changed) @@ -4539,7 +4553,8 @@ sub git_difftree_body { if ($action eq 'commitdiff') { # link to patch $patchno++; - print $cgi->a({-href => "#patch$patchno"}, "patch") . + print $cgi->a({-href => href(-anchor=>"patch$patchno")}, + "patch") . " | "; } elsif ($diff->{'to_id'} ne $diff->{'from_id'}) { # "commit" view and modified file (not only pure rename or copy) @@ -798,22 +798,9 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb) } /* - * If revs->left_right is set, print '<' for commits that - * come from the left side, and '>' for commits from the right - * side. + * get_revision_mark() handles all other cases without assert() */ - if (graph->revs && graph->revs->left_right) { - if (graph->commit->object.flags & SYMMETRIC_LEFT) - strbuf_addch(sb, '<'); - else - strbuf_addch(sb, '>'); - return; - } - - /* - * Print '*' in all other cases - */ - strbuf_addch(sb, '*'); + strbuf_addstr(sb, get_revision_mark(graph->revs, graph->commit)); } /* diff --git a/list-objects.c b/list-objects.c index 61f6cc98d9..838b6a732e 100644 --- a/list-objects.c +++ b/list-objects.c @@ -173,7 +173,12 @@ void traverse_commit_list(struct rev_info *revs, strbuf_init(&base, PATH_MAX); while ((commit = get_revision(revs)) != NULL) { - add_pending_tree(revs, commit->tree); + /* + * an uninteresting boundary commit may not have its tree + * parsed yet, but we are not going to show them anyway + */ + if (commit->tree) + add_pending_tree(revs, commit->tree); show_commit(commit, data); } for (i = 0; i < revs->pending.nr; i++) { diff --git a/log-tree.c b/log-tree.c index b46ed3baef..2a1e3a94c9 100644 --- a/log-tree.c +++ b/log-tree.c @@ -380,18 +380,8 @@ void show_log(struct rev_info *opt) if (!opt->verbose_header) { graph_show_commit(opt->graph); - if (!opt->graph) { - if (commit->object.flags & BOUNDARY) - putchar('-'); - else if (commit->object.flags & UNINTERESTING) - putchar('^'); - else if (opt->left_right) { - if (commit->object.flags & SYMMETRIC_LEFT) - putchar('<'); - else - putchar('>'); - } - } + if (!opt->graph) + put_revision_mark(opt, commit); fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout); if (opt->print_parents) show_parents(commit, abbrev_commit); @@ -448,18 +438,8 @@ void show_log(struct rev_info *opt) if (opt->commit_format != CMIT_FMT_ONELINE) fputs("commit ", stdout); - if (!opt->graph) { - if (commit->object.flags & BOUNDARY) - putchar('-'); - else if (commit->object.flags & UNINTERESTING) - putchar('^'); - else if (opt->left_right) { - if (commit->object.flags & SYMMETRIC_LEFT) - putchar('<'); - else - putchar('>'); - } - } + if (!opt->graph) + put_revision_mark(opt, commit); fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout); if (opt->print_parents) @@ -876,11 +876,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder, c->abbrev_parent_hashes.off; return 1; case 'm': /* left/right/bottom */ - strbuf_addch(sb, (commit->object.flags & BOUNDARY) - ? '-' - : (commit->object.flags & SYMMETRIC_LEFT) - ? '<' - : '>'); + strbuf_addstr(sb, get_revision_mark(NULL, commit)); return 1; case 'd': format_decoration(sb, commit); diff --git a/read-cache.c b/read-cache.c index 98d526bd48..f38471cac3 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1547,6 +1547,31 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce) return result; } +static int has_racy_timestamp(struct index_state *istate) +{ + int entries = istate->cache_nr; + int i; + + for (i = 0; i < entries; i++) { + struct cache_entry *ce = istate->cache[i]; + if (is_racy_timestamp(istate, ce)) + return 1; + } + return 0; +} + +/* + * Opportunisticly update the index but do not complain if we can't + */ +void update_index_if_able(struct index_state *istate, struct lock_file *lockfile) +{ + if ((istate->cache_changed || has_racy_timestamp(istate)) && + !write_index(istate, lockfile->fd)) + commit_locked_index(lockfile); + else + rollback_lock_file(lockfile); +} + int write_index(struct index_state *istate, int newfd) { git_SHA_CTX c; @@ -590,8 +590,7 @@ static int is_rerere_enabled(void) if (rerere_enabled < 0) return rr_cache_exists; - if (!rr_cache_exists && - (mkdir(rr_cache, 0777) || adjust_shared_perm(rr_cache))) + if (!rr_cache_exists && mkdir_in_gitdir(rr_cache)) die("Could not create directory %s", rr_cache); return 1; } diff --git a/revision.c b/revision.c index 86d2470489..e96c281d1f 100644 --- a/revision.c +++ b/revision.c @@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) int left_count = 0, right_count = 0; int left_first; struct patch_ids ids; + unsigned cherry_flag; /* First count the commits on the left and on the right */ for (p = list; p; p = p->next) { @@ -572,6 +573,9 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) commit->util = add_commit_patch_id(commit, &ids); } + /* either cherry_mark or cherry_pick are true */ + cherry_flag = revs->cherry_mark ? PATCHSAME : SHOWN; + /* Check the other side */ for (p = list; p; p = p->next) { struct commit *commit = p->item; @@ -594,7 +598,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) if (!id) continue; id->seen = 1; - commit->object.flags |= SHOWN; + commit->object.flags |= cherry_flag; } /* Now check the original side for seen ones */ @@ -606,7 +610,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) if (!ent) continue; if (ent->seen) - commit->object.flags |= SHOWN; + commit->object.flags |= cherry_flag; commit->util = NULL; } @@ -729,6 +733,23 @@ static struct commit_list *collect_bottom_commits(struct commit_list *list) return bottom; } +/* Assumes either left_only or right_only is set */ +static void limit_left_right(struct commit_list *list, struct rev_info *revs) +{ + struct commit_list *p; + + for (p = list; p; p = p->next) { + struct commit *commit = p->item; + + if (revs->right_only) { + if (commit->object.flags & SYMMETRIC_LEFT) + commit->object.flags |= SHOWN; + } else /* revs->left_only is set */ + if (!(commit->object.flags & SYMMETRIC_LEFT)) + commit->object.flags |= SHOWN; + } +} + static int limit_list(struct rev_info *revs) { int slop = SLOP; @@ -781,9 +802,12 @@ static int limit_list(struct rev_info *revs) show(revs, newlist); show_early_output = NULL; } - if (revs->cherry_pick) + if (revs->cherry_pick || revs->cherry_mark) cherry_pick_list(newlist, revs); + if (revs->left_only || revs->right_only) + limit_left_right(newlist, revs); + if (bottom) { limit_to_ancestry(bottom, newlist); free_commit_list(bottom); @@ -1260,9 +1284,32 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->boundary = 1; } else if (!strcmp(arg, "--left-right")) { revs->left_right = 1; + } else if (!strcmp(arg, "--left-only")) { + if (revs->right_only) + die("--left-only is incompatible with --right-only" + " or --cherry"); + revs->left_only = 1; + } else if (!strcmp(arg, "--right-only")) { + if (revs->left_only) + die("--right-only is incompatible with --left-only"); + revs->right_only = 1; + } else if (!strcmp(arg, "--cherry")) { + if (revs->left_only) + die("--cherry is incompatible with --left-only"); + revs->cherry_mark = 1; + revs->right_only = 1; + revs->no_merges = 1; + revs->limited = 1; } else if (!strcmp(arg, "--count")) { revs->count = 1; + } else if (!strcmp(arg, "--cherry-mark")) { + if (revs->cherry_pick) + die("--cherry-mark is incompatible with --cherry-pick"); + revs->cherry_mark = 1; + revs->limited = 1; /* needs limit_list() */ } else if (!strcmp(arg, "--cherry-pick")) { + if (revs->cherry_mark) + die("--cherry-pick is incompatible with --cherry-mark"); revs->cherry_pick = 1; revs->limited = 1; } else if (!strcmp(arg, "--objects")) { @@ -2232,3 +2279,32 @@ struct commit *get_revision(struct rev_info *revs) graph_update(revs->graph, c); return c; } + +char *get_revision_mark(const struct rev_info *revs, const struct commit *commit) +{ + if (commit->object.flags & BOUNDARY) + return "-"; + else if (commit->object.flags & UNINTERESTING) + return "^"; + else if (commit->object.flags & PATCHSAME) + return "="; + else if (!revs || revs->left_right) { + if (commit->object.flags & SYMMETRIC_LEFT) + return "<"; + else + return ">"; + } else if (revs->graph) + return "*"; + else if (revs->cherry_mark) + return "+"; + return ""; +} + +void put_revision_mark(const struct rev_info *revs, const struct commit *commit) +{ + char *mark = get_revision_mark(revs, commit); + if (!strlen(mark)) + return; + fputs(mark, stdout); + putchar(' '); +} diff --git a/revision.h b/revision.h index 82509dd1d9..ae948601f9 100644 --- a/revision.h +++ b/revision.h @@ -14,7 +14,8 @@ #define CHILD_SHOWN (1u<<6) #define ADDED (1u<<7) /* Parents already parsed and added? */ #define SYMMETRIC_LEFT (1u<<8) -#define ALL_REV_FLAGS ((1u<<9)-1) +#define PATCHSAME (1u<<9) +#define ALL_REV_FLAGS ((1u<<10)-1) #define DECORATE_SHORT_REFS 1 #define DECORATE_FULL_REFS 2 @@ -59,6 +60,8 @@ struct rev_info { boundary:2, count:1, left_right:1, + left_only:1, + right_only:1, rewrite_parents:1, print_parents:1, show_source:1, @@ -66,6 +69,7 @@ struct rev_info { reverse:1, reverse_output_stage:1, cherry_pick:1, + cherry_mark:1, bisect:1, ancestry_path:1, first_parent_only:1; @@ -163,6 +167,8 @@ extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags, extern int prepare_revision_walk(struct rev_info *revs); extern struct commit *get_revision(struct rev_info *revs); +extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit); +extern void put_revision_mark(const struct rev_info *revs, const struct commit *commit); extern void mark_parents_uninteresting(struct commit *commit); extern void mark_tree_uninteresting(struct tree *tree); diff --git a/run-command.c b/run-command.c index f91e446c86..8619c769a9 100644 --- a/run-command.c +++ b/run-command.c @@ -67,21 +67,26 @@ static int child_notifier = -1; static void notify_parent(void) { - ssize_t unused; - unused = write(child_notifier, "", 1); + /* + * execvp failed. If possible, we'd like to let start_command + * know, so failures like ENOENT can be handled right away; but + * otherwise, finish_command will still report the error. + */ + if (write(child_notifier, "", 1)) + ; /* yes, dear gcc -D_FORTIFY_SOURCE, there was an error. */ } static NORETURN void die_child(const char *err, va_list params) { char msg[4096]; - ssize_t unused; int len = vsnprintf(msg, sizeof(msg), err, params); if (len > sizeof(msg)) len = sizeof(msg); - unused = write(child_err, "fatal: ", 7); - unused = write(child_err, msg, len); - unused = write(child_err, "\n", 1); + if (write(child_err, "fatal: ", 7) || + write(child_err, msg, len) || + write(child_err, "\n", 1)) + ; /* yes, gcc -D_FORTIFY_SOURCE, we know there was an error. */ exit(128); } #endif diff --git a/sha1_file.c b/sha1_file.c index b4fcca8ffd..df0edbad1e 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -26,13 +26,8 @@ #endif #endif -#ifdef NO_C99_FORMAT -#define SZ_FMT "lu" -static unsigned long sz_fmt(size_t s) { return (unsigned long)s; } -#else -#define SZ_FMT "zu" -static size_t sz_fmt(size_t s) { return s; } -#endif +#define SZ_FMT PRIuMAX +static inline uintmax_t sz_fmt(size_t s) { return s; } const unsigned char null_sha1[20]; @@ -73,6 +68,35 @@ static struct cached_object *find_cached_object(const unsigned char *sha1) return NULL; } +int mkdir_in_gitdir(const char *path) +{ + if (mkdir(path, 0777)) { + int saved_errno = errno; + struct stat st; + struct strbuf sb = STRBUF_INIT; + + if (errno != EEXIST) + return -1; + /* + * Are we looking at a path in a symlinked worktree + * whose original repository does not yet have it? + * e.g. .git/rr-cache pointing at its original + * repository in which the user hasn't performed any + * conflict resolution yet? + */ + if (lstat(path, &st) || !S_ISLNK(st.st_mode) || + strbuf_readlink(&sb, path, st.st_size) || + !is_absolute_path(sb.buf) || + mkdir(sb.buf, 0777)) { + strbuf_release(&sb); + errno = saved_errno; + return -1; + } + strbuf_release(&sb); + } + return adjust_shared_perm(path); +} + int safe_create_leading_directories(char *path) { char *pos = path + offset_1st_component(path); diff --git a/t/t0001-init.sh b/t/t0001-init.sh index f684993211..ce4ba1379e 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -47,7 +47,7 @@ test_expect_success 'plain nested in bare' ' test_expect_success 'plain through aliased command, outside any git repo' ' ( - sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL && + sane_unset GIT_DIR GIT_WORK_TREE && HOME=$(pwd)/alias-config && export HOME && mkdir alias-config && @@ -231,7 +231,6 @@ test_expect_success 'init with init.templatedir set' ' git config -f "$test_config" init.templatedir "${HOME}/templatedir-source" && mkdir templatedir-set && cd templatedir-set && - sane_unset GIT_CONFIG_NOGLOBAL && sane_unset GIT_TEMPLATE_DIR && NO_SET_GIT_TEMPLATE_DIR=t && export NO_SET_GIT_TEMPLATE_DIR && @@ -243,7 +242,6 @@ test_expect_success 'init with init.templatedir set' ' test_expect_success 'init --bare/--shared overrides system/global config' ' ( test_config="$HOME"/.gitconfig && - sane_unset GIT_CONFIG_NOGLOBAL && git config -f "$test_config" core.bare false && git config -f "$test_config" core.sharedRepository 0640 && mkdir init-bare-shared-override && @@ -258,7 +256,6 @@ test_expect_success 'init --bare/--shared overrides system/global config' ' test_expect_success 'init honors global core.sharedRepository' ' ( test_config="$HOME"/.gitconfig && - sane_unset GIT_CONFIG_NOGLOBAL && git config -f "$test_config" core.sharedRepository 0666 && mkdir shared-honor-global && cd shared-honor-global && diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index 550fad0823..1dbe1c9b08 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -53,7 +53,7 @@ long_read_test () { } >input & } && test-line-buffer input <<-EOF >output && - read $readsize + binary $readsize copy $copysize EOF kill $! && @@ -71,23 +71,23 @@ test_expect_success 'setup: have pipes?' ' ' test_expect_success 'hello world' ' - echo HELLO >expect && + echo ">HELLO" >expect && test-line-buffer <<-\EOF >actual && - read 6 + binary 6 HELLO EOF test_cmp expect actual ' test_expect_success PIPE '0-length read, no input available' ' - >expect && + printf ">" >expect && rm -f input && mkfifo input && { sleep 100 >input & } && test-line-buffer input <<-\EOF >actual && - read 0 + binary 0 copy 0 EOF kill $! && @@ -95,9 +95,9 @@ test_expect_success PIPE '0-length read, no input available' ' ' test_expect_success '0-length read, send along greeting' ' - echo HELLO >expect && + echo ">HELLO" >expect && test-line-buffer <<-\EOF >actual && - read 0 + binary 0 copy 6 HELLO EOF @@ -105,7 +105,7 @@ test_expect_success '0-length read, send along greeting' ' ' test_expect_success PIPE '1-byte read, no input available' ' - printf "%s" ab >expect && + printf ">%s" ab >expect && rm -f input && mkfifo input && { @@ -116,7 +116,7 @@ test_expect_success PIPE '1-byte read, no input available' ' } >input & } && test-line-buffer input <<-\EOF >actual && - read 1 + binary 1 copy 1 EOF kill $! && @@ -140,15 +140,6 @@ test_expect_success 'read from file descriptor' ' test_cmp expect actual ' -test_expect_success 'buffer_read_string copes with null byte' ' - >expect && - q_to_nul <<-\EOF | test-line-buffer >actual && - read 2 - Q - EOF - test_cmp expect actual -' - test_expect_success 'skip, copy null byte' ' echo Q | q_to_nul >expect && q_to_nul <<-\EOF | test-line-buffer >actual && @@ -170,18 +161,18 @@ test_expect_success 'read null byte' ' ' test_expect_success 'long reads are truncated' ' - echo foo >expect && + echo ">foo" >expect && test-line-buffer <<-\EOF >actual && - read 5 + binary 5 foo EOF test_cmp expect actual ' test_expect_success 'long copies are truncated' ' - printf "%s\n" "" foo >expect && + printf "%s\n" ">" foo >expect && test-line-buffer <<-\EOF >actual && - read 1 + binary 1 copy 5 foo diff --git a/t/t1021-rerere-in-workdir.sh b/t/t1021-rerere-in-workdir.sh new file mode 100755 index 0000000000..301e071ff7 --- /dev/null +++ b/t/t1021-rerere-in-workdir.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +test_description='rerere run in a workdir' +. ./test-lib.sh + +test_expect_success SYMLINKS setup ' + git config rerere.enabled true && + >world && + git add world && + test_tick && + git commit -m initial && + + echo hello >world && + test_tick && + git commit -a -m hello && + + git checkout -b side HEAD^ && + echo goodbye >world && + test_tick && + git commit -a -m goodbye && + + git checkout master +' + +test_expect_success SYMLINKS 'rerere in workdir' ' + rm -rf .git/rr-cache && + "$SHELL_PATH" "$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" . work && + ( + cd work && + test_must_fail git merge side && + git rerere status >actual && + echo world >expect && + test_cmp expect actual + ) +' + +# This fails because we don't resolve relative symlink in mkdir_in_gitdir() +# For the purpose of helping contrib/workdir/git-new-workdir users, we do not +# have to support relative symlinks, but it might be nicer to make this work +# with a relative symbolic link someday. +test_expect_failure SYMLINKS 'rerere in workdir (relative)' ' + rm -rf .git/rr-cache && + "$SHELL_PATH" "$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" . krow && + ( + cd krow && + rm -f .git/rr-cache && + ln -s ../.git/rr-cache .git/rr-cache && + test_must_fail git merge side && + git rerere status >actual && + echo world >expect && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh index 00421453ba..569b27fe8d 100755 --- a/t/t2020-checkout-detach.sh +++ b/t/t2020-checkout-detach.sh @@ -11,6 +11,14 @@ check_not_detached () { git symbolic-ref -q HEAD >/dev/null } +ORPHAN_WARNING='you are leaving .* commit.*behind' +check_orphan_warning() { + grep "$ORPHAN_WARNING" "$1" +} +check_no_orphan_warning() { + ! grep "$ORPHAN_WARNING" "$1" +} + reset () { git checkout master && check_not_detached @@ -19,6 +27,8 @@ reset () { test_expect_success 'setup' ' test_commit one && test_commit two && + test_commit three && git tag -d three && + test_commit four && git tag -d four && git branch branch && git tag tag ' @@ -92,4 +102,41 @@ test_expect_success 'checkout --detach moves HEAD' ' git diff --exit-code two ' +test_expect_success 'checkout warns on orphan commits' ' + reset && + git checkout --detach two && + echo content >orphan && + git add orphan && + git commit -a -m orphan && + git checkout master 2>stderr && + check_orphan_warning stderr +' + +test_expect_success 'checkout does not warn leaving ref tip' ' + reset && + git checkout --detach two && + git checkout master 2>stderr && + check_no_orphan_warning stderr +' + +test_expect_success 'checkout does not warn leaving reachable commit' ' + reset && + git checkout --detach HEAD^ && + git checkout master 2>stderr && + check_no_orphan_warning stderr +' + +cat >expect <<'EOF' +Your branch is behind 'master' by 1 commit, and can be fast-forwarded. +EOF +test_expect_success 'tracking count is accurate after orphan check' ' + reset && + git branch child master^ && + git config branch.child.remote . && + git config branch.child.merge refs/heads/master && + git checkout child^ && + git checkout child >stdout && + test_cmp expect stdout +' + test_done diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 6fd560ccf1..f62aaf5816 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -556,4 +556,23 @@ test_expect_success 'stash branch should not drop the stash if the branch exists git rev-parse stash@{0} -- ' +test_expect_success 'stash apply shows status same as git status (relative to current directory)' ' + git stash clear && + echo 1 >subdir/subfile1 && + echo 2 >subdir/subfile2 && + git add subdir/subfile1 && + git commit -m subdir && + ( + cd subdir && + echo x >subfile1 && + echo x >../file && + git status >../expect && + git stash && + sane_unset GIT_MERGE_VERBOSITY && + git stash apply + ) | + sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..." + test_cmp expect actual +' + test_done diff --git a/t/t4040-whitespace-status.sh b/t/t4040-whitespace-status.sh index a30b03bcf2..abc49348b1 100755 --- a/t/t4040-whitespace-status.sh +++ b/t/t4040-whitespace-status.sh @@ -60,4 +60,11 @@ test_expect_success 'diff-files -b -p --exit-code' ' git diff-files -b -p --exit-code ' +test_expect_success 'diff-files --diff-filter --quiet' ' + git reset --hard && + rm a/d && + echo x >>b/e && + test_must_fail git diff-files --diff-filter=M --quiet +' + test_done diff --git a/t/t5501-fetch-push-alternates.sh b/t/t5501-fetch-push-alternates.sh new file mode 100755 index 0000000000..b5ced8483a --- /dev/null +++ b/t/t5501-fetch-push-alternates.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +test_description='fetch/push involving alternates' +. ./test-lib.sh + +count_objects () { + loose=0 inpack=0 + eval "$( + git count-objects -v | + sed -n -e 's/^count: \(.*\)/loose=\1/p' \ + -e 's/^in-pack: \(.*\)/inpack=\1/p' + )" && + echo $(( $loose + $inpack )) +} + + +test_expect_success setup ' + ( + git init original && + cd original && + i=0 && + while test $i -le 100 + do + echo "$i" >count && + git add count && + git commit -m "$i" || exit + i=$(($i + 1)) + done + ) && + ( + git clone --reference=original "file:///$(pwd)/original" one && + cd one && + echo Z >count && + git add count && + git commit -m Z && + count_objects >../one.count + ) && + A=$(pwd)/original/.git/objects && + git init receiver && + echo "$A" >receiver/.git/objects/info/alternates && + git init fetcher && + echo "$A" >fetcher/.git/objects/info/alternates +' + +test_expect_success 'pushing into a repository with the same alternate' ' + ( + cd one && + git push ../receiver master:refs/heads/it + ) && + ( + cd receiver && + count_objects >../receiver.count + ) && + test_cmp one.count receiver.count +' + +test_expect_success 'fetching from a repository with the same alternate' ' + ( + cd fetcher && + git fetch ../one master:refs/heads/it && + count_objects >../fetcher.count + ) && + test_cmp one.count fetcher.count +' + +test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 987e0c8463..3ca275cc67 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -164,7 +164,6 @@ test_expect_success 'clone a void' ' test_expect_success 'clone respects global branch.autosetuprebase' ' ( test_config="$HOME/.gitconfig" && - unset GIT_CONFIG_NOGLOBAL && git config -f "$test_config" branch.autosetuprebase remote && rm -fr dst && git clone src dst && diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh index b565638e92..cacf3de6c9 100755 --- a/t/t6007-rev-list-cherry-pick-file.sh +++ b/t/t6007-rev-list-cherry-pick-file.sh @@ -4,13 +4,14 @@ test_description='test git rev-list --cherry-pick -- file' . ./test-lib.sh -# A---B +# A---B---D---F # \ # \ -# C +# C---E # # B changes a file foo.c, adding a line of text. C changes foo.c as # well as bar.c, but the change in foo.c was identical to change B. +# D and C change bar in the same way, E and F differently. test_expect_success setup ' echo Hallo > foo && @@ -25,11 +26,26 @@ test_expect_success setup ' test_tick && git commit -m "C" && git tag C && + echo Dello > bar && + git add bar && + test_tick && + git commit -m "E" && + git tag E && git checkout master && git checkout branch foo && test_tick && git commit -m "B" && - git tag B + git tag B && + echo Cello > bar && + git add bar && + test_tick && + git commit -m "D" && + git tag D && + echo Nello > bar && + git add bar && + test_tick && + git commit -m "F" && + git tag F ' cat >expect <<EOF @@ -53,8 +69,92 @@ test_expect_success '--cherry-pick foo comes up empty' ' test -z "$(git rev-list --left-right --cherry-pick B...C -- foo)" ' +cat >expect <<EOF +>tags/C +EOF + test_expect_success '--cherry-pick bar does not come up empty' ' - ! test -z "$(git rev-list --left-right --cherry-pick B...C -- bar)" + git rev-list --left-right --cherry-pick B...C -- bar > actual && + git name-rev --stdin --name-only --refs="*tags/*" \ + < actual > actual.named && + test_cmp actual.named expect +' + +test_expect_success 'bar does not come up empty' ' + git rev-list --left-right B...C -- bar > actual && + git name-rev --stdin --name-only --refs="*tags/*" \ + < actual > actual.named && + test_cmp actual.named expect +' + +cat >expect <<EOF +<tags/F +>tags/E +EOF + +test_expect_success '--cherry-pick bar does not come up empty (II)' ' + git rev-list --left-right --cherry-pick F...E -- bar > actual && + git name-rev --stdin --name-only --refs="*tags/*" \ + < actual > actual.named && + test_cmp actual.named expect +' + +cat >expect <<EOF ++tags/F +=tags/D ++tags/E +=tags/C +EOF + +test_expect_success '--cherry-mark' ' + git rev-list --cherry-mark F...E -- bar > actual && + git name-rev --stdin --name-only --refs="*tags/*" \ + < actual > actual.named && + test_cmp actual.named expect +' + +cat >expect <<EOF +<tags/F +=tags/D +>tags/E +=tags/C +EOF + +test_expect_success '--cherry-mark --left-right' ' + git rev-list --cherry-mark --left-right F...E -- bar > actual && + git name-rev --stdin --name-only --refs="*tags/*" \ + < actual > actual.named && + test_cmp actual.named expect +' + +cat >expect <<EOF +tags/E +EOF + +test_expect_success '--cherry-pick --right-only' ' + git rev-list --cherry-pick --right-only F...E -- bar > actual && + git name-rev --stdin --name-only --refs="*tags/*" \ + < actual > actual.named && + test_cmp actual.named expect +' + +test_expect_success '--cherry-pick --left-only' ' + git rev-list --cherry-pick --left-only E...F -- bar > actual && + git name-rev --stdin --name-only --refs="*tags/*" \ + < actual > actual.named && + test_cmp actual.named expect +' + +cat >expect <<EOF ++tags/E +=tags/C +EOF + +test_expect_success '--cherry' ' + git rev-list --cherry F...E -- bar > actual && + git name-rev --stdin --name-only --refs="*tags/*" \ + < actual > actual.named && + test_cmp actual.named expect ' test_expect_success '--cherry-pick with independent, but identical branches' ' @@ -75,11 +175,8 @@ cat >expect <<EOF 1 2 EOF -# Insert an extra commit to break the symmetry test_expect_success '--count --left-right' ' - git checkout branch && - test_commit D && - git rev-list --count --left-right B...D > actual && + git rev-list --count --left-right C...D > actual && test_cmp expect actual ' diff --git a/t/t6110-rev-list-sparse.sh b/t/t6110-rev-list-sparse.sh new file mode 100755 index 0000000000..656ac7fe9d --- /dev/null +++ b/t/t6110-rev-list-sparse.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +test_description='operations that cull histories in unusual ways' +. ./test-lib.sh + +test_expect_success setup ' + test_commit A && + test_commit B && + test_commit C && + git checkout -b side HEAD^ && + test_commit D && + test_commit E && + git merge master +' + +test_expect_success 'rev-list --first-parent --boundary' ' + git rev-list --first-parent --boundary HEAD^.. +' + +test_done diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh index 5f731a1177..c86e298d08 100755 --- a/t/t7607-merge-overwrite.sh +++ b/t/t7607-merge-overwrite.sh @@ -122,7 +122,7 @@ test_expect_success 'will not overwrite untracked file in leading path' ' rm -f sub sub2 ' -test_expect_failure SYMLINKS 'will not overwrite untracked symlink in leading path' ' +test_expect_success SYMLINKS 'will not overwrite untracked symlink in leading path' ' git reset --hard c0 && rm -rf sub && mkdir sub2 && @@ -150,6 +150,7 @@ test_expect_success 'will not overwrite untracked file on unborn branch' ' git rm -fr . && git checkout --orphan new && cp important c0.c && + test_when_finished "rm c0.c" && test_must_fail git merge c0 2>out && test_cmp out expect && test_path_is_missing .git/MERGE_HEAD && @@ -164,7 +165,7 @@ test_expect_success 'set up unborn branch and content' ' echo bar > untracked-file ' -test_expect_failure 'will not clobber WT/index when merging into unborn' ' +test_expect_success 'will not clobber WT/index when merging into unborn' ' git merge master && grep foo tracked-file && git show :tracked-file >expect && diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh index 5a6a4b9b7a..478c860647 100755 --- a/t/t9010-svn-fe.sh +++ b/t/t9010-svn-fe.sh @@ -370,6 +370,110 @@ test_expect_failure 'change file mode but keep old content' ' test_cmp hello actual.target ' +test_expect_success 'NUL in property value' ' + reinit_git && + echo "commit message" >expect.message && + { + properties \ + unimportant "something with a NUL (Q)" \ + svn:log "commit message"&& + echo PROPS-END + } | + q_to_nul >props && + { + cat <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + EOF + echo Prop-content-length: $(wc -c <props) && + echo Content-length: $(wc -c <props) && + echo && + cat props + } >nulprop.dump && + test-svn-fe nulprop.dump >stream && + git fast-import <stream && + git diff-tree --always -s --format=%s HEAD >actual.message && + test_cmp expect.message actual.message +' + +test_expect_success 'NUL in log message, file content, and property name' ' + # Caveat: svnadmin 1.6.16 (r1073529) truncates at \0 in the + # svn:specialQnotreally example. + reinit_git && + cat >expect <<-\EOF && + OBJID + :100644 100644 OBJID OBJID M greeting + OBJID + :000000 100644 OBJID OBJID A greeting + EOF + printf "\n%s" "something with an ASCII NUL (Q)" >expect.message && + printf "%s\n" "helQo" >expect.hello1 && + printf "%s\n" "link hello" >expect.hello2 && + { + properties svn:log "something with an ASCII NUL (Q)" && + echo PROPS-END + } | + q_to_nul >props && + { + q_to_nul <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: add + Prop-content-length: 10 + Text-content-length: 6 + Content-length: 16 + + PROPS-END + helQo + + Revision-number: 2 + EOF + echo Prop-content-length: $(wc -c <props) && + echo Content-length: $(wc -c <props) && + echo && + cat props && + q_to_nul <<-\EOF + + Node-path: greeting + Node-kind: file + Node-action: change + Prop-content-length: 43 + Text-content-length: 11 + Content-length: 54 + + K 21 + svn:specialQnotreally + V 1 + * + PROPS-END + link hello + EOF + } >8bitclean.dump && + test-svn-fe 8bitclean.dump >stream && + git fast-import <stream && + { + git rev-list HEAD | + git diff-tree --root --stdin | + sed "s/$_x40/OBJID/g" + } >actual && + git cat-file commit HEAD | nul_to_q | sed -ne "/^\$/,\$ p" >actual.message && + git cat-file blob HEAD^:greeting | nul_to_q >actual.hello1 && + git cat-file blob HEAD:greeting | nul_to_q >actual.hello2 && + test_cmp expect actual && + test_cmp expect.message actual.message && + test_cmp expect.hello1 actual.hello1 && + test_cmp expect.hello2 actual.hello2 +' + test_expect_success 'change file mode and reiterate content' ' reinit_git && cat >expect <<-\EOF && diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh index ec0a106614..b324c491c5 100755 --- a/t/t9130-git-svn-authors-file.sh +++ b/t/t9130-git-svn-authors-file.sh @@ -96,7 +96,6 @@ test_expect_success 'fresh clone with svn.authors-file in config' ' rm -r "$GIT_DIR" && test x = x"$(git config svn.authorsfile)" && test_config="$HOME"/.gitconfig && - unset GIT_CONFIG_NOGLOBAL && unset GIT_DIR && unset GIT_CONFIG && git config --global \ diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh index abe7c64ba9..a523473954 100755 --- a/t/t9800-git-p4.sh +++ b/t/t9800-git-p4.sh @@ -61,6 +61,29 @@ test_expect_success 'git-p4 clone @all' ' rm -rf "$git" && mkdir "$git" ' +test_expect_success 'git-p4 sync uninitialized repo' ' + test_create_repo "$git" && + cd "$git" && + test_must_fail "$GITP4" sync && + rm -rf "$git" && mkdir "$git" +' + +# +# Create a git repo by hand. Add a commit so that HEAD is valid. +# Test imports a new p4 repository into a new git branch. +# +test_expect_success 'git-p4 sync new branch' ' + test_create_repo "$git" && + cd "$git" && + test_commit head && + "$GITP4" sync --branch=refs/remotes/p4/depot //depot@all && + git log --oneline p4/depot >lines && + cat lines && + test_line_count = 2 lines && + cd .. && + rm -rf "$git" && mkdir "$git" +' + test_expect_success 'exit when p4 fails to produce marshaled output' ' badp4dir="$TRASH_DIRECTORY/badp4dir" && mkdir -p "$badp4dir" && diff --git a/t/test-lib.sh b/t/test-lib.sh index f4c1e04e4f..7cc9a52cbf 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -43,36 +43,16 @@ TERM=dumb export LANG LC_ALL PAGER TERM TZ EDITOR=: unset VISUAL -unset GIT_EDITOR -unset AUTHOR_DATE -unset AUTHOR_EMAIL -unset AUTHOR_NAME -unset COMMIT_AUTHOR_EMAIL -unset COMMIT_AUTHOR_NAME unset EMAIL -unset GIT_ALTERNATE_OBJECT_DIRECTORIES -unset GIT_AUTHOR_DATE +unset $(perl -e ' + my @env = keys %ENV; + my @vars = grep(/^GIT_/ && !/^GIT_(TRACE|DEBUG|USE_LOOKUP)/, @env); + print join("\n", @vars); +') GIT_AUTHOR_EMAIL=author@example.com GIT_AUTHOR_NAME='A U Thor' -unset GIT_COMMITTER_DATE GIT_COMMITTER_EMAIL=committer@example.com GIT_COMMITTER_NAME='C O Mitter' -unset GIT_DIFF_OPTS -unset GIT_DIR -unset GIT_WORK_TREE -unset GIT_EXTERNAL_DIFF -unset GIT_INDEX_FILE -unset GIT_OBJECT_DIRECTORY -unset GIT_CEILING_DIRECTORIES -unset SHA1_FILE_DIRECTORIES -unset SHA1_FILE_DIRECTORY -unset GIT_NOTES_REF -unset GIT_NOTES_DISPLAY_REF -unset GIT_NOTES_REWRITE_REF -unset GIT_NOTES_REWRITE_MODE -unset GIT_REFLOG_ACTION -unset GIT_CHERRY_PICK_HELP -unset GIT_QUIET GIT_MERGE_VERBOSITY=5 export GIT_MERGE_VERBOSITY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME @@ -954,8 +934,8 @@ fi GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt unset GIT_CONFIG GIT_CONFIG_NOSYSTEM=1 -GIT_CONFIG_NOGLOBAL=1 -export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL +GIT_ATTR_NOSYSTEM=1 +export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS diff --git a/test-line-buffer.c b/test-line-buffer.c index 25b20b93fd..7ec9b13c9b 100644 --- a/test-line-buffer.c +++ b/test-line-buffer.c @@ -32,12 +32,6 @@ static void handle_command(const char *command, const char *arg, struct line_buf buffer_copy_bytes(buf, strtouint32(arg)); return; } - case 'r': - if (!prefixcmp(command, "read ")) { - const char *s = buffer_read_string(buf, strtouint32(arg)); - fputs(s, stdout); - return; - } case 's': if (!prefixcmp(command, "skip ")) { buffer_skip_bytes(buf, strtouint32(arg)); diff --git a/transport.c b/transport.c index f1c07816e0..a02f79aae3 100644 --- a/transport.c +++ b/transport.c @@ -1189,3 +1189,37 @@ char *transport_anonymize_url(const char *url) literal_copy: return xstrdup(url); } + +int refs_from_alternate_cb(struct alternate_object_database *e, void *cb) +{ + char *other; + size_t len; + struct remote *remote; + struct transport *transport; + const struct ref *extra; + alternate_ref_fn *ref_fn = cb; + + e->name[-1] = '\0'; + other = xstrdup(real_path(e->base)); + e->name[-1] = '/'; + len = strlen(other); + + while (other[len-1] == '/') + other[--len] = '\0'; + if (len < 8 || memcmp(other + len - 8, "/objects", 8)) + return 0; + /* Is this a git repository with refs? */ + memcpy(other + len - 8, "/refs", 6); + if (!is_directory(other)) + return 0; + other[len - 8] = '\0'; + remote = remote_get(other); + transport = transport_get(remote, other); + for (extra = transport_get_remote_refs(transport); + extra; + extra = extra->next) + ref_fn(extra, NULL); + transport_disconnect(transport); + free(other); + return 0; +} diff --git a/transport.h b/transport.h index e803c0e7ba..efb1968869 100644 --- a/transport.h +++ b/transport.h @@ -166,4 +166,7 @@ int transport_refs_pushed(struct ref *ref); void transport_print_push_status(const char *dest, struct ref *refs, int verbose, int porcelain, int *nonfastforward); +typedef void alternate_ref_fn(const struct ref *, void *); +extern int refs_from_alternate_cb(struct alternate_object_database *e, void *cb); + #endif diff --git a/upload-pack.c b/upload-pack.c index 0c87bc00f0..72aa661f8d 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -27,6 +27,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=< static unsigned long oldest_have; static int multi_ack, nr_our_refs; +static int no_done; static int use_thin_pack, use_ofs_delta, use_include_tag; static int no_progress, daemon_mode; static int shallow_nr; @@ -429,6 +430,9 @@ static int get_common_commits(void) static char line[1000]; unsigned char sha1[20]; char last_hex[41]; + int got_common = 0; + int got_other = 0; + int sent_ready = 0; save_commit_buffer = 0; @@ -437,25 +441,40 @@ static int get_common_commits(void) reset_timeout(); if (!len) { + if (multi_ack == 2 && got_common + && !got_other && ok_to_give_up()) { + sent_ready = 1; + packet_write(1, "ACK %s ready\n", last_hex); + } if (have_obj.nr == 0 || multi_ack) packet_write(1, "NAK\n"); + + if (no_done && sent_ready) { + packet_write(1, "ACK %s\n", last_hex); + return 0; + } if (stateless_rpc) exit(0); + got_common = 0; + got_other = 0; continue; } strip(line, len); if (!prefixcmp(line, "have ")) { switch (got_sha1(line+5, sha1)) { case -1: /* they have what we do not */ + got_other = 1; if (multi_ack && ok_to_give_up()) { const char *hex = sha1_to_hex(sha1); - if (multi_ack == 2) + if (multi_ack == 2) { + sent_ready = 1; packet_write(1, "ACK %s ready\n", hex); - else + } else packet_write(1, "ACK %s continue\n", hex); } break; default: + got_common = 1; memcpy(last_hex, sha1_to_hex(sha1), 41); if (multi_ack == 2) packet_write(1, "ACK %s common\n", last_hex); @@ -526,6 +545,8 @@ static void receive_needs(void) multi_ack = 2; else if (strstr(line+45, "multi_ack")) multi_ack = 1; + if (strstr(line+45, "no-done")) + no_done = 1; if (strstr(line+45, "thin-pack")) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) @@ -619,7 +640,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo { static const char *capabilities = "multi_ack thin-pack side-band" " side-band-64k ofs-delta shallow no-progress" - " include-tag multi_ack_detailed"; + " include-tag multi_ack_detailed no-done"; struct object *o = parse_object(sha1); if (!o) diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c index 260cf50e77..2e5bb67255 100644 --- a/vcs-svn/fast_export.c +++ b/vcs-svn/fast_export.c @@ -31,27 +31,29 @@ void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode, } static char gitsvnline[MAX_GITSVN_LINE_LEN]; -void fast_export_commit(uint32_t revision, uint32_t author, char *log, - uint32_t uuid, uint32_t url, +void fast_export_commit(uint32_t revision, const char *author, + const struct strbuf *log, + const char *uuid, const char *url, unsigned long timestamp) { + static const struct strbuf empty = STRBUF_INIT; if (!log) - log = ""; - if (~uuid && ~url) { + log = ∅ + if (*uuid && *url) { snprintf(gitsvnline, MAX_GITSVN_LINE_LEN, "\n\ngit-svn-id: %s@%"PRIu32" %s\n", - pool_fetch(url), revision, pool_fetch(uuid)); + url, revision, uuid); } else { *gitsvnline = '\0'; } printf("commit refs/heads/master\n"); printf("committer %s <%s@%s> %ld +0000\n", - ~author ? pool_fetch(author) : "nobody", - ~author ? pool_fetch(author) : "nobody", - ~uuid ? pool_fetch(uuid) : "local", timestamp); - printf("data %"PRIu32"\n%s%s\n", - (uint32_t) (strlen(log) + strlen(gitsvnline)), - log, gitsvnline); + *author ? author : "nobody", + *author ? author : "nobody", + *uuid ? uuid : "local", timestamp); + printf("data %"PRIuMAX"\n", log->len + strlen(gitsvnline)); + fwrite(log->buf, log->len, 1, stdout); + printf("%s\n", gitsvnline); if (!first_commit_done) { if (revision > 1) printf("from refs/heads/master^0\n"); @@ -63,14 +65,23 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log, printf("progress Imported commit %"PRIu32".\n\n", revision); } +static void die_short_read(struct line_buffer *input) +{ + if (buffer_ferror(input)) + die_errno("error reading dump file"); + die("invalid dump: unexpected end of file"); +} + void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input) { if (mode == REPO_MODE_LNK) { /* svn symlink blobs start with "link " */ - buffer_skip_bytes(input, 5); len -= 5; + if (buffer_skip_bytes(input, 5) != 5) + die_short_read(input); } printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len); - buffer_copy_bytes(input, len); + if (buffer_copy_bytes(input, len) != len) + die_short_read(input); fputc('\n', stdout); } diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h index 054e7d5eb1..33a8fe996f 100644 --- a/vcs-svn/fast_export.h +++ b/vcs-svn/fast_export.h @@ -2,12 +2,14 @@ #define FAST_EXPORT_H_ #include "line_buffer.h" +struct strbuf; void fast_export_delete(uint32_t depth, uint32_t *path); void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode, uint32_t mark); -void fast_export_commit(uint32_t revision, uint32_t author, char *log, - uint32_t uuid, uint32_t url, unsigned long timestamp); +void fast_export_commit(uint32_t revision, const char *author, + const struct strbuf *log, const char *uuid, + const char *url, unsigned long timestamp); void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input); diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c index aedf105b70..c39038723e 100644 --- a/vcs-svn/line_buffer.c +++ b/vcs-svn/line_buffer.c @@ -59,6 +59,11 @@ long buffer_tmpfile_prepare_to_read(struct line_buffer *buf) return pos; } +int buffer_ferror(struct line_buffer *buf) +{ + return ferror(buf->infile); +} + int buffer_read_char(struct line_buffer *buf) { return fgetc(buf->infile); @@ -86,47 +91,40 @@ char *buffer_read_line(struct line_buffer *buf) return buf->line_buffer; } -char *buffer_read_string(struct line_buffer *buf, uint32_t len) -{ - strbuf_reset(&buf->blob_buffer); - strbuf_fread(&buf->blob_buffer, len, buf->infile); - return ferror(buf->infile) ? NULL : buf->blob_buffer.buf; -} - void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t size) { strbuf_fread(sb, size, buf->infile); } -void buffer_copy_bytes(struct line_buffer *buf, uint32_t len) +off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes) { char byte_buffer[COPY_BUFFER_LEN]; - uint32_t in; - while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) { - in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN; + off_t done = 0; + while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) { + off_t len = nbytes - done; + size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN; in = fread(byte_buffer, 1, in, buf->infile); - len -= in; + done += in; fwrite(byte_buffer, 1, in, stdout); - if (ferror(stdout)) { - buffer_skip_bytes(buf, len); - return; - } + if (ferror(stdout)) + return done + buffer_skip_bytes(buf, nbytes - done); } + return done; } -void buffer_skip_bytes(struct line_buffer *buf, uint32_t len) +off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes) { char byte_buffer[COPY_BUFFER_LEN]; - uint32_t in; - while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) { - in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN; - in = fread(byte_buffer, 1, in, buf->infile); - len -= in; + off_t done = 0; + while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) { + off_t len = nbytes - done; + size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN; + done += fread(byte_buffer, 1, in, buf->infile); } + return done; } void buffer_reset(struct line_buffer *buf) { - strbuf_release(&buf->blob_buffer); } diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h index 96ce966a22..d0b22dda76 100644 --- a/vcs-svn/line_buffer.h +++ b/vcs-svn/line_buffer.h @@ -7,10 +7,9 @@ struct line_buffer { char line_buffer[LINE_BUFFER_LEN]; - struct strbuf blob_buffer; FILE *infile; }; -#define LINE_BUFFER_INIT {"", STRBUF_INIT, NULL} +#define LINE_BUFFER_INIT { "", NULL } int buffer_init(struct line_buffer *buf, const char *filename); int buffer_fdinit(struct line_buffer *buf, int fd); @@ -21,11 +20,12 @@ int buffer_tmpfile_init(struct line_buffer *buf); FILE *buffer_tmpfile_rewind(struct line_buffer *buf); /* prepare to write. */ long buffer_tmpfile_prepare_to_read(struct line_buffer *buf); +int buffer_ferror(struct line_buffer *buf); char *buffer_read_line(struct line_buffer *buf); -char *buffer_read_string(struct line_buffer *buf, uint32_t len); int buffer_read_char(struct line_buffer *buf); void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len); -void buffer_copy_bytes(struct line_buffer *buf, uint32_t len); -void buffer_skip_bytes(struct line_buffer *buf, uint32_t len); +/* Returns number of bytes read (not necessarily written). */ +off_t buffer_copy_bytes(struct line_buffer *buf, off_t len); +off_t buffer_skip_bytes(struct line_buffer *buf, off_t len); #endif diff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt index e89cc41d56..8e139eb22d 100644 --- a/vcs-svn/line_buffer.txt +++ b/vcs-svn/line_buffer.txt @@ -16,8 +16,8 @@ The calling program: - initializes a `struct line_buffer` to LINE_BUFFER_INIT - specifies a file to read with `buffer_init` - - processes input with `buffer_read_line`, `buffer_read_string`, - `buffer_skip_bytes`, and `buffer_copy_bytes` + - processes input with `buffer_read_line`, `buffer_skip_bytes`, + and `buffer_copy_bytes` - closes the file with `buffer_deinit`, perhaps to start over and read another file. @@ -37,7 +37,7 @@ the calling program. A program the temporary file - declares writing is over with `buffer_tmpfile_prepare_to_read` - can re-read what was written with `buffer_read_line`, - `buffer_read_string`, and so on + `buffer_copy_bytes`, and so on - can reuse the temporary file by calling `buffer_tmpfile_rewind` again - removes the temporary file with `buffer_deinit`, perhaps to @@ -64,19 +64,14 @@ Functions Read a line and strip off the trailing newline. On failure or end of file, returns NULL. -`buffer_read_string`:: - Read `len` characters of input or up to the end of the - file, whichever comes first. Returns NULL on error. - Returns whatever characters were read (possibly "") - for end of file. - `buffer_copy_bytes`:: Read `len` bytes of input and dump them to the standard output stream. Returns early for error or end of file. `buffer_skip_bytes`:: Discards `len` bytes from the input stream (stopping early - if necessary because of an error or eof). + if necessary because of an error or eof). Return value is + the number of bytes successfully read. `buffer_reset`:: Deallocates non-static buffers. diff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c index 207ffc3a83..a21d89de97 100644 --- a/vcs-svn/repo_tree.c +++ b/vcs-svn/repo_tree.c @@ -87,7 +87,8 @@ static struct repo_dir *repo_clone_dir(struct repo_dir *orig_dir) return dir_pointer(new_o); } -static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path) +static struct repo_dirent *repo_read_dirent(uint32_t revision, + const uint32_t *path) { uint32_t name = 0; struct repo_dirent *key = dent_pointer(dent_alloc(1)); @@ -105,7 +106,7 @@ static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path) return dent; } -static void repo_write_dirent(uint32_t *path, uint32_t mode, +static void repo_write_dirent(const uint32_t *path, uint32_t mode, uint32_t content_offset, uint32_t del) { uint32_t name, revision, dir_o = ~0, parent_dir_o = ~0; @@ -157,7 +158,24 @@ static void repo_write_dirent(uint32_t *path, uint32_t mode, dent_remove(&dir_pointer(parent_dir_o)->entries, dent); } -uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst) +uint32_t repo_read_path(const uint32_t *path) +{ + uint32_t content_offset = 0; + struct repo_dirent *dent = repo_read_dirent(active_commit, path); + if (dent != NULL) + content_offset = dent->content_offset; + return content_offset; +} + +uint32_t repo_read_mode(const uint32_t *path) +{ + struct repo_dirent *dent = repo_read_dirent(active_commit, path); + if (dent == NULL) + die("invalid dump: path to be modified is missing"); + return dent->mode; +} + +void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst) { uint32_t mode = 0, content_offset = 0; struct repo_dirent *src_dent; @@ -167,7 +185,6 @@ uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst) content_offset = src_dent->content_offset; repo_write_dirent(dst, mode, content_offset, 0); } - return mode; } void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark) @@ -175,20 +192,6 @@ void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark) repo_write_dirent(path, mode, blob_mark, 0); } -uint32_t repo_modify_path(uint32_t *path, uint32_t mode, uint32_t blob_mark) -{ - struct repo_dirent *src_dent; - src_dent = repo_read_dirent(active_commit, path); - if (!src_dent) - return 0; - if (!blob_mark) - blob_mark = src_dent->content_offset; - if (!mode) - mode = src_dent->mode; - repo_write_dirent(path, mode, blob_mark, 0); - return mode; -} - void repo_delete(uint32_t *path) { repo_write_dirent(path, 0, 0, 1); @@ -275,8 +278,9 @@ void repo_diff(uint32_t r1, uint32_t r2) repo_commit_root_dir(commit_pointer(r2))); } -void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid, - uint32_t url, unsigned long timestamp) +void repo_commit(uint32_t revision, const char *author, + const struct strbuf *log, const char *uuid, const char *url, + unsigned long timestamp) { fast_export_commit(revision, author, log, uuid, url, timestamp); dent_commit(); diff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h index 68baeb582f..37bde2e374 100644 --- a/vcs-svn/repo_tree.h +++ b/vcs-svn/repo_tree.h @@ -1,7 +1,7 @@ #ifndef REPO_TREE_H_ #define REPO_TREE_H_ -#include "git-compat-util.h" +struct strbuf; #define REPO_MODE_DIR 0040000 #define REPO_MODE_BLB 0100644 @@ -12,12 +12,14 @@ #define REPO_MAX_PATH_DEPTH 1000 uint32_t next_blob_mark(void); -uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst); +void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst); void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark); -uint32_t repo_modify_path(uint32_t *path, uint32_t mode, uint32_t blob_mark); +uint32_t repo_read_path(const uint32_t *path); +uint32_t repo_read_mode(const uint32_t *path); void repo_delete(uint32_t *path); -void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid, - uint32_t url, long unsigned timestamp); +void repo_commit(uint32_t revision, const char *author, + const struct strbuf *log, const char *uuid, const char *url, + long unsigned timestamp); void repo_diff(uint32_t r1, uint32_t r2); void repo_init(void); void repo_reset(void); diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c index ee7c0bb2ea..eef49ca192 100644 --- a/vcs-svn/svndump.c +++ b/vcs-svn/svndump.c @@ -11,8 +11,14 @@ #include "repo_tree.h" #include "fast_export.h" #include "line_buffer.h" -#include "obj_pool.h" #include "string_pool.h" +#include "strbuf.h" + +/* + * Compare start of string to literal of equal length; + * must be guarded by length test. + */ +#define constcmp(s, ref) memcmp(s, ref, sizeof(ref) - 1) #define NODEACT_REPLACE 4 #define NODEACT_DELETE 3 @@ -27,20 +33,8 @@ #define LENGTH_UNKNOWN (~0) #define DATE_RFC2822_LEN 31 -/* Create memory pool for log messages */ -obj_pool_gen(log, char, 4096) - static struct line_buffer input = LINE_BUFFER_INIT; -static char *log_copy(uint32_t length, const char *log) -{ - char *buffer; - log_free(log_pool.size); - buffer = log_pointer(log_alloc(length)); - strncpy(buffer, log, length); - return buffer; -} - static struct { uint32_t action, propLength, textLength, srcRev, type; uint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH]; @@ -48,24 +42,16 @@ static struct { } node_ctx; static struct { - uint32_t revision, author; + uint32_t revision; unsigned long timestamp; - char *log; + struct strbuf log, author; } rev_ctx; static struct { - uint32_t version, uuid, url; + uint32_t version; + struct strbuf uuid, url; } dump_ctx; -static struct { - uint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid, - revision_number, node_path, node_kind, node_action, - node_copyfrom_path, node_copyfrom_rev, text_content_length, - prop_content_length, content_length, svn_fs_dump_format_version, - /* version 3 format */ - text_delta, prop_delta; -} keys; - static void reset_node_ctx(char *fname) { node_ctx.type = 0; @@ -83,56 +69,58 @@ static void reset_rev_ctx(uint32_t revision) { rev_ctx.revision = revision; rev_ctx.timestamp = 0; - rev_ctx.log = NULL; - rev_ctx.author = ~0; + strbuf_reset(&rev_ctx.log); + strbuf_reset(&rev_ctx.author); } -static void reset_dump_ctx(uint32_t url) +static void reset_dump_ctx(const char *url) { - dump_ctx.url = url; + strbuf_reset(&dump_ctx.url); + if (url) + strbuf_addstr(&dump_ctx.url, url); dump_ctx.version = 1; - dump_ctx.uuid = ~0; + strbuf_reset(&dump_ctx.uuid); } -static void init_keys(void) -{ - keys.svn_log = pool_intern("svn:log"); - keys.svn_author = pool_intern("svn:author"); - keys.svn_date = pool_intern("svn:date"); - keys.svn_executable = pool_intern("svn:executable"); - keys.svn_special = pool_intern("svn:special"); - keys.uuid = pool_intern("UUID"); - keys.revision_number = pool_intern("Revision-number"); - keys.node_path = pool_intern("Node-path"); - keys.node_kind = pool_intern("Node-kind"); - keys.node_action = pool_intern("Node-action"); - keys.node_copyfrom_path = pool_intern("Node-copyfrom-path"); - keys.node_copyfrom_rev = pool_intern("Node-copyfrom-rev"); - keys.text_content_length = pool_intern("Text-content-length"); - keys.prop_content_length = pool_intern("Prop-content-length"); - keys.content_length = pool_intern("Content-length"); - keys.svn_fs_dump_format_version = pool_intern("SVN-fs-dump-format-version"); - /* version 3 format (Subversion 1.1.0) */ - keys.text_delta = pool_intern("Text-delta"); - keys.prop_delta = pool_intern("Prop-delta"); -} - -static void handle_property(uint32_t key, const char *val, uint32_t len, +static void handle_property(const struct strbuf *key_buf, + struct strbuf *val, uint32_t *type_set) { - if (key == keys.svn_log) { + const char *key = key_buf->buf; + size_t keylen = key_buf->len; + + switch (keylen + 1) { + case sizeof("svn:log"): + if (constcmp(key, "svn:log")) + break; if (!val) die("invalid dump: unsets svn:log"); - /* Value length excludes terminating nul. */ - rev_ctx.log = log_copy(len + 1, val); - } else if (key == keys.svn_author) { - rev_ctx.author = pool_intern(val); - } else if (key == keys.svn_date) { + strbuf_swap(&rev_ctx.log, val); + break; + case sizeof("svn:author"): + if (constcmp(key, "svn:author")) + break; + if (!val) + strbuf_reset(&rev_ctx.author); + else + strbuf_swap(&rev_ctx.author, val); + break; + case sizeof("svn:date"): + if (constcmp(key, "svn:date")) + break; if (!val) die("invalid dump: unsets svn:date"); - if (parse_date_basic(val, &rev_ctx.timestamp, NULL)) - warning("invalid timestamp: %s", val); - } else if (key == keys.svn_executable || key == keys.svn_special) { + if (parse_date_basic(val->buf, &rev_ctx.timestamp, NULL)) + warning("invalid timestamp: %s", val->buf); + break; + case sizeof("svn:executable"): + case sizeof("svn:special"): + if (keylen == strlen("svn:executable") && + constcmp(key, "svn:executable")) + break; + if (keylen == strlen("svn:special") && + constcmp(key, "svn:special")) + break; if (*type_set) { if (!val) return; @@ -143,15 +131,23 @@ static void handle_property(uint32_t key, const char *val, uint32_t len, return; } *type_set = 1; - node_ctx.type = key == keys.svn_executable ? + node_ctx.type = keylen == strlen("svn:executable") ? REPO_MODE_EXE : REPO_MODE_LNK; } } +static void die_short_read(void) +{ + if (buffer_ferror(&input)) + die_errno("error reading dump file"); + die("invalid dump: unexpected end of file"); +} + static void read_props(void) { - uint32_t key = ~0; + static struct strbuf key = STRBUF_INIT; + static struct strbuf val = STRBUF_INIT; const char *t; /* * NEEDSWORK: to support simple mode changes like @@ -168,27 +164,34 @@ static void read_props(void) uint32_t type_set = 0; while ((t = buffer_read_line(&input)) && strcmp(t, "PROPS-END")) { uint32_t len; - const char *val; const char type = t[0]; + int ch; if (!type || t[1] != ' ') die("invalid property line: %s\n", t); len = atoi(&t[2]); - val = buffer_read_string(&input, len); - buffer_skip_bytes(&input, 1); /* Discard trailing newline. */ + strbuf_reset(&val); + buffer_read_binary(&input, &val, len); + if (val.len < len) + die_short_read(); + + /* Discard trailing newline. */ + ch = buffer_read_char(&input); + if (ch == EOF) + die_short_read(); + if (ch != '\n') + die("invalid dump: expected newline after %s", val.buf); switch (type) { case 'K': - key = pool_intern(val); + strbuf_swap(&key, &val); continue; case 'D': - key = pool_intern(val); - val = NULL; - len = 0; - /* fall through */ + handle_property(&val, NULL, &type_set); + continue; case 'V': - handle_property(key, val, len, &type_set); - key = ~0; + handle_property(&key, &val, &type_set); + strbuf_reset(&key); continue; default: die("invalid property line: %s\n", t); @@ -201,13 +204,14 @@ static void handle_node(void) uint32_t mark = 0; const uint32_t type = node_ctx.type; const int have_props = node_ctx.propLength != LENGTH_UNKNOWN; + const int have_text = node_ctx.textLength != LENGTH_UNKNOWN; if (node_ctx.text_delta) die("text deltas not supported"); - if (node_ctx.textLength != LENGTH_UNKNOWN) + if (have_text) mark = next_blob_mark(); if (node_ctx.action == NODEACT_DELETE) { - if (mark || have_props || node_ctx.srcRev) + if (have_text || have_props || node_ctx.srcRev) die("invalid dump: deletion node has " "copyfrom info, text, or properties"); return repo_delete(node_ctx.dst); @@ -221,37 +225,47 @@ static void handle_node(void) if (node_ctx.action == NODEACT_ADD) node_ctx.action = NODEACT_CHANGE; } - if (mark && type == REPO_MODE_DIR) + if (have_text && type == REPO_MODE_DIR) die("invalid dump: directories cannot have text attached"); + + /* + * Decide on the new content (mark) and mode (node_ctx.type). + */ if (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) { if (type != REPO_MODE_DIR) die("invalid dump: root of tree is not a regular file"); } else if (node_ctx.action == NODEACT_CHANGE) { - uint32_t mode = repo_modify_path(node_ctx.dst, 0, mark); - if (!mode) - die("invalid dump: path to be modified is missing"); + uint32_t mode; + if (!have_text) + mark = repo_read_path(node_ctx.dst); + mode = repo_read_mode(node_ctx.dst); if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR) die("invalid dump: cannot modify a directory into a file"); if (mode != REPO_MODE_DIR && type == REPO_MODE_DIR) die("invalid dump: cannot modify a file into a directory"); node_ctx.type = mode; } else if (node_ctx.action == NODEACT_ADD) { - if (!mark && type != REPO_MODE_DIR) + if (!have_text && type != REPO_MODE_DIR) die("invalid dump: adds node without text"); - repo_add(node_ctx.dst, type, mark); } else { die("invalid dump: Node-path block lacks Node-action"); } + + /* + * Adjust mode to reflect properties. + */ if (have_props) { - const uint32_t old_mode = node_ctx.type; if (!node_ctx.prop_delta) node_ctx.type = type; if (node_ctx.propLength) read_props(); - if (node_ctx.type != old_mode) - repo_modify_path(node_ctx.dst, node_ctx.type, mark); } - if (mark) + + /* + * Save the result. + */ + repo_add(node_ctx.dst, node_ctx.type, mark); + if (have_text) fast_export_blob(node_ctx.type, mark, node_ctx.textLength, &input); } @@ -259,8 +273,9 @@ static void handle_node(void) static void handle_revision(void) { if (rev_ctx.revision) - repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log, - dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp); + repo_commit(rev_ctx.revision, rev_ctx.author.buf, + &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf, + rev_ctx.timestamp); } void svndump_read(const char *url) @@ -269,44 +284,65 @@ void svndump_read(const char *url) char *t; uint32_t active_ctx = DUMP_CTX; uint32_t len; - uint32_t key; - reset_dump_ctx(pool_intern(url)); + reset_dump_ctx(url); while ((t = buffer_read_line(&input))) { - val = strstr(t, ": "); + val = strchr(t, ':'); if (!val) continue; - *val++ = '\0'; - *val++ = '\0'; - key = pool_intern(t); + val++; + if (*val != ' ') + continue; + val++; - if (key == keys.svn_fs_dump_format_version) { + /* strlen(key) + 1 */ + switch (val - t - 1) { + case sizeof("SVN-fs-dump-format-version"): + if (constcmp(t, "SVN-fs-dump-format-version")) + continue; dump_ctx.version = atoi(val); if (dump_ctx.version > 3) die("expected svn dump format version <= 3, found %"PRIu32, dump_ctx.version); - } else if (key == keys.uuid) { - dump_ctx.uuid = pool_intern(val); - } else if (key == keys.revision_number) { + break; + case sizeof("UUID"): + if (constcmp(t, "UUID")) + continue; + strbuf_reset(&dump_ctx.uuid); + strbuf_addstr(&dump_ctx.uuid, val); + break; + case sizeof("Revision-number"): + if (constcmp(t, "Revision-number")) + continue; if (active_ctx == NODE_CTX) handle_node(); if (active_ctx != DUMP_CTX) handle_revision(); active_ctx = REV_CTX; reset_rev_ctx(atoi(val)); - } else if (key == keys.node_path) { - if (active_ctx == NODE_CTX) - handle_node(); - active_ctx = NODE_CTX; - reset_node_ctx(val); - } else if (key == keys.node_kind) { + break; + case sizeof("Node-path"): + if (prefixcmp(t, "Node-")) + continue; + if (!constcmp(t + strlen("Node-"), "path")) { + if (active_ctx == NODE_CTX) + handle_node(); + active_ctx = NODE_CTX; + reset_node_ctx(val); + break; + } + if (constcmp(t + strlen("Node-"), "kind")) + continue; if (!strcmp(val, "dir")) node_ctx.type = REPO_MODE_DIR; else if (!strcmp(val, "file")) node_ctx.type = REPO_MODE_BLB; else fprintf(stderr, "Unknown node-kind: %s\n", val); - } else if (key == keys.node_action) { + break; + case sizeof("Node-action"): + if (constcmp(t, "Node-action")) + continue; if (!strcmp(val, "delete")) { node_ctx.action = NODEACT_DELETE; } else if (!strcmp(val, "add")) { @@ -319,21 +355,44 @@ void svndump_read(const char *url) fprintf(stderr, "Unknown node-action: %s\n", val); node_ctx.action = NODEACT_UNKNOWN; } - } else if (key == keys.node_copyfrom_path) { + break; + case sizeof("Node-copyfrom-path"): + if (constcmp(t, "Node-copyfrom-path")) + continue; pool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.src, "/", val); - } else if (key == keys.node_copyfrom_rev) { + break; + case sizeof("Node-copyfrom-rev"): + if (constcmp(t, "Node-copyfrom-rev")) + continue; node_ctx.srcRev = atoi(val); - } else if (key == keys.text_content_length) { - node_ctx.textLength = atoi(val); - } else if (key == keys.prop_content_length) { + break; + case sizeof("Text-content-length"): + if (!constcmp(t, "Text-content-length")) { + node_ctx.textLength = atoi(val); + break; + } + if (constcmp(t, "Prop-content-length")) + continue; node_ctx.propLength = atoi(val); - } else if (key == keys.text_delta) { - node_ctx.text_delta = !strcmp(val, "true"); - } else if (key == keys.prop_delta) { + break; + case sizeof("Text-delta"): + if (!constcmp(t, "Text-delta")) { + node_ctx.text_delta = !strcmp(val, "true"); + break; + } + if (constcmp(t, "Prop-delta")) + continue; node_ctx.prop_delta = !strcmp(val, "true"); - } else if (key == keys.content_length) { + break; + case sizeof("Content-length"): + if (constcmp(t, "Content-length")) + continue; len = atoi(val); - buffer_read_line(&input); + t = buffer_read_line(&input); + if (!t) + die_short_read(); + if (*t) + die("invalid dump: expected blank line after content length header"); if (active_ctx == REV_CTX) { read_props(); } else if (active_ctx == NODE_CTX) { @@ -341,10 +400,13 @@ void svndump_read(const char *url) active_ctx = REV_CTX; } else { fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len); - buffer_skip_bytes(&input, len); + if (buffer_skip_bytes(&input, len) != len) + die_short_read(); } } } + if (buffer_ferror(&input)) + die_short_read(); if (active_ctx == NODE_CTX) handle_node(); if (active_ctx != DUMP_CTX) @@ -356,20 +418,23 @@ int svndump_init(const char *filename) if (buffer_init(&input, filename)) return error("cannot open %s: %s", filename, strerror(errno)); repo_init(); - reset_dump_ctx(~0); + strbuf_init(&dump_ctx.uuid, 4096); + strbuf_init(&dump_ctx.url, 4096); + strbuf_init(&rev_ctx.log, 4096); + strbuf_init(&rev_ctx.author, 4096); + reset_dump_ctx(NULL); reset_rev_ctx(0); reset_node_ctx(NULL); - init_keys(); return 0; } void svndump_deinit(void) { - log_reset(); repo_reset(); - reset_dump_ctx(~0); + reset_dump_ctx(NULL); reset_rev_ctx(0); reset_node_ctx(NULL); + strbuf_release(&rev_ctx.log); if (buffer_deinit(&input)) fprintf(stderr, "Input error\n"); if (ferror(stdout)) @@ -378,10 +443,10 @@ void svndump_deinit(void) void svndump_reset(void) { - log_reset(); buffer_reset(&input); repo_reset(); - reset_dump_ctx(~0); - reset_rev_ctx(0); - reset_node_ctx(NULL); + strbuf_release(&dump_ctx.uuid); + strbuf_release(&dump_ctx.url); + strbuf_release(&rev_ctx.log); + strbuf_release(&rev_ctx.author); } |
