diff options
103 files changed, 4914 insertions, 460 deletions
@@ -48,6 +48,7 @@ David Kågedal <davidk@lysator.liu.se> David Reiss <dreiss@facebook.com> <dreiss@dreiss-vmware.(none)> David S. Miller <davem@davemloft.net> David Turner <novalis@novalis.org> <dturner@twopensource.com> +David Turner <novalis@novalis.org> <dturner@twosigma.com> Deskin Miller <deskinm@umich.edu> Dirk Süsserott <newsletter@dirk.my1.cc> Eric Blake <eblake@redhat.com> <ebb9@byu.net> diff --git a/.travis.yml b/.travis.yml index 477c3d2efb..37a1e1fb6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,7 +78,7 @@ before_install: FORMULA=$1 SHA=$(brew fetch --force $FORMULA 2>&1 | grep ^SHA256: | cut -d ' ' -f 2) sed -E -i.bak "s/sha256 \"[0-9a-f]{64}\"/sha256 \"$SHA\"/g" \ - /usr/local/Library/Taps/homebrew/homebrew-binary/$FORMULA.rb + "$(brew --repository homebrew/homebrew-binary)/$FORMULA.rb" } brew update --quiet brew tap homebrew/binary --quiet diff --git a/Documentation/RelNotes/2.10.1.txt b/Documentation/RelNotes/2.10.1.txt index 75c07e199e..73f3b978cf 100644 --- a/Documentation/RelNotes/2.10.1.txt +++ b/Documentation/RelNotes/2.10.1.txt @@ -30,4 +30,91 @@ Fixes since v2.10 * Update a few tests that used to use GIT_CURL_VERBOSE to use the newer GIT_TRACE_CURL. + * Update Japanese translation for "git-gui". + + * "git fetch http::/site/path" did not die correctly and segfaulted + instead. + + * "git commit-tree" stopped reading commit.gpgsign configuration + variable that was meant for Porcelain "git commit" in Git 2.9; we + forgot to update "git gui" to look at the configuration to match + this change. + + * "git log --cherry-pick" used to include merge commits as candidates + to be matched up with other commits, resulting a lot of wasted time. + The patch-id generation logic has been updated to ignore merges to + avoid the wastage. + + * The http transport (with curl-multi option, which is the default + these days) failed to remove curl-easy handle from a curlm session, + which led to unnecessary API failures. + + * "git diff -W" output needs to extend the context backward to + include the header line of the current function and also forward to + include the body of the entire current function up to the header + line of the next one. This process may have to merge to adjacent + hunks, but the code forgot to do so in some cases. + + * Performance tests done via "t/perf" did not use the same set of + build configuration if the user relied on autoconf generated + configuration. + + * "git format-patch --base=..." feature that was recently added + showed the base commit information after "-- " e-mail signature + line, which turned out to be inconvenient. The base information + has been moved above the signature line. + + * Even when "git pull --rebase=preserve" (and the underlying "git + rebase --preserve") can complete without creating any new commit + (i.e. fast-forwards), it still insisted on having a usable ident + information (read: user.email is set correctly), which was less + than nice. As the underlying commands used inside "git rebase" + would fail with a more meaningful error message and advice text + when the bogus ident matters, this extra check was removed. + + * "git gc --aggressive" used to limit the delta-chain length to 250, + which is way too deep for gaining additional space savings and is + detrimental for runtime performance. The limit has been reduced to + 50. + + * Documentation for individual configuration variables to control use + of color (like `color.grep`) said that their default value is + 'false', instead of saying their default is taken from `color.ui`. + When we updated the default value for color.ui from 'false' to + 'auto' quite a while ago, all of them broke. This has been + corrected. + + * A shell script example in check-ref-format documentation has been + fixed. + + * "git checkout <word>" does not follow the usual disambiguation + rules when the <word> can be both a rev and a path, to allow + checking out a branch 'foo' in a project that happens to have a + file 'foo' in the working tree without having to disambiguate. + This was poorly documented and the check was incorrect when the + command was run from a subdirectory. + + * Some codepaths in "git diff" used regexec(3) on a buffer that was + mmap(2)ed, which may not have a terminating NUL, leading to a read + beyond the end of the mapped region. This was fixed by introducing + a regexec_buf() helper that takes a <ptr,len> pair with REG_STARTEND + extension. + + * The procedure to build Git on Mac OS X for Travis CI hardcoded the + internal directory structure we assumed HomeBrew uses, which was a + no-no. The procedure has been updated to ask HomeBrew things we + need to know to fix this. + + * When "git rebase -i" is given a broken instruction, it told the + user to fix it with "--edit-todo", but didn't say what the step + after that was (i.e. "--continue"). + + * "git add --chmod=+x" added recently lacked documentation, which has + been corrected. + + * "git add --chmod=+x <pathspec>" added recently only toggled the + executable bit for paths that are either new or modified. This has + been corrected to flip the executable bit for all paths that match + the given pathspec. + Also contains minor documentation updates and code clean-ups. diff --git a/Documentation/RelNotes/2.11.0.txt b/Documentation/RelNotes/2.11.0.txt index 8b29f7712d..cfe94b9918 100644 --- a/Documentation/RelNotes/2.11.0.txt +++ b/Documentation/RelNotes/2.11.0.txt @@ -38,6 +38,27 @@ UI, Workflows & Features lacked an equivalent mechanism to run the "Git-to-outside-world" conversion. The command learned the "--filters" option to do so. + * Output from "git diff" can be made easier to read by selecting + which lines are common and which lines are added/deleted + intelligently when the lines before and after the changed section + are the same. A command line option is added to help with the + experiment to find a good heuristics. + + * In some projects, it is common to use "[RFC PATCH]" as the subject + prefix for a patch meant for discussion rather than application. A + new option "--rfc" was a short-hand for "--subject-prefix=RFC PATCH" + to help the participants of such projects. + + * "git add --chmod=+x <pathspec>" added recently only toggled the + executable bit for paths that are either new or modified. This has + been corrected to flip the executable bit for all paths that match + the given pathspec. + + * When "git format-patch --stdout" output is placed as an in-body + header and it uses the RFC2822 header folding, "git am" failed to + put the header line back into a single logical line. The + underlying "git mailinfo" was taught to handle this properly. + Performance, Internal Implementation, Development Support etc. @@ -196,9 +217,82 @@ notes for details). 50. (merge 07e7dbf jk/reduce-gc-aggressive-depth later to maint). + * Documentation for individual configuration variables to control use + of color (like `color.grep`) said that their default value is + 'false', instead of saying their default is taken from `color.ui`. + When we updated the default value for color.ui from 'false' to + 'auto' quite a while ago, all of them broke. This has been + corrected. + (merge 14d16e2 mm/config-color-ui-default-to-auto later to maint). + + * The pretty-format specifier "%C(auto)" used by the "log" family of + commands to enable coloring of the output is taught to also issue a + color-reset sequence to the output. + (merge c99ad27 rs/c-auto-resets-attributes later to maint). + + * A shell script example in check-ref-format documentation has been + fixed. + (merge 92dece7 ep/doc-check-ref-format-example later to maint). + + * "git checkout <word>" does not follow the usual disambiguation + rules when the <word> can be both a rev and a path, to allow + checking out a branch 'foo' in a project that happens to have a + file 'foo' in the working tree without having to disambiguate. + This was poorly documented and the check was incorrect when the + command was run from a subdirectory. + (merge b829b94 nd/checkout-disambiguation later to maint). + + * Some codepaths in "git diff" used regexec(3) on a buffer that was + mmap(2)ed, which may not have a terminating NUL, leading to a read + beyond the end of the mapped region. This was fixed by introducing + a regexec_buf() helper that takes a <ptr,len> pair with REG_STARTEND + extension. + (merge b7d36ff js/regexec-buf later to maint). + + * The procedure to build Git on Mac OS X for Travis CI hardcoded the + internal directory structure we assumed HomeBrew uses, which was a + no-no. The procedure has been updated to ask HomeBrew things we + need to know to fix this. + (merge f86f49b ls/travis-homebrew-path-fix later to maint). + + * When "git rebase -i" is given a broken instruction, it told the + user to fix it with "--edit-todo", but didn't say what the step + after that was (i.e. "--continue"). + (merge 37875b4 rt/rebase-i-broken-insn-advise later to maint). + + * Documentation around tools to import from CVS was fairly outdated. + (merge 106b672 jk/doc-cvs-update later to maint). + + * "git clone --recurse-submodules" lost the progress eye-candy in + recent update, which has been corrected. + + * A low-level function verify_packfile() was meant to show errors + that were detected without dying itself, but under some conditions + it didn't and died instead, which has been fixed. + (merge a9445d859e jk/verify-packfile-gently later to maint). + + * When "git fetch" tries to find where the history of the repository + it runs in has diverged from what the other side has, it has a + mechanism to avoid digging too deep into irrelevant side branches. + This however did not work well over the "smart-http" transport due + to a design bug, which has been fixed. + (merge 06b3d386e0 jt/fetch-pack-in-vain-count-with-stateless later to maint). + + * In the codepath that comes up with the hostname to be used in an + e-mail when the user didn't tell us, we looked at ai_canonname + field in struct addrinfo without making sure it is not NULL first. + (merge c375a7efa3 jk/ident-ai-canonname-could-be-null later to maint). + + * "git worktree", even though it used the default_abbrev setting that + ought to be affected by core.abbrev configuration variable, ignored + the variable setting. The command has been taught to read the + default set of configuration variables to correct this. + (merge d49028e6e7 jc/worktree-config later to maint). + * Other minor doc, test and build updates and code cleanups. (merge e78d57e bw/pathspec-remove-unused-extern-decl later to maint). (merge ce25e4c rs/checkout-some-states-are-const later to maint). (merge a8342a4 rs/strbuf-remove-fix later to maint). (merge b56aa5b rs/unpack-trees-reduce-file-scope-global later to maint). (merge 5efc60c mr/vcs-svn-printf-ulong later to maint). + (merge a22ae75 rs/cocci later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index 6410d7cd98..e78293b6db 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -953,7 +953,8 @@ color.branch:: A boolean to enable/disable color in the output of linkgit:git-branch[1]. May be set to `always`, `false` (or `never`) or `auto` (or `true`), in which case colors are used - only when the output is to a terminal. Defaults to false. + only when the output is to a terminal. If unset, then the + value of `color.ui` is used (`auto` by default). color.branch.<slot>:: Use customized color for branch coloration. `<slot>` is one of @@ -968,7 +969,8 @@ color.diff:: linkgit:git-log[1], and linkgit:git-show[1] will use color for all patches. If it is set to `true` or `auto`, those commands will only use color when output is to the terminal. - Defaults to false. + If unset, then the value of `color.ui` is used (`auto` by + default). + This does not affect linkgit:git-format-patch[1] or the 'git-diff-{asterisk}' plumbing commands. Can be overridden on the @@ -991,7 +993,8 @@ color.decorate.<slot>:: color.grep:: When set to `always`, always highlight matches. When `false` (or `never`), never. When set to `true` or `auto`, use color only - when the output is written to the terminal. Defaults to `false`. + when the output is written to the terminal. If unset, then the + value of `color.ui` is used (`auto` by default). color.grep.<slot>:: Use customized color for grep colorization. `<slot>` specifies which @@ -1024,7 +1027,8 @@ color.interactive:: and displays (such as those used by "git-add --interactive" and "git-clean --interactive"). When false (or `never`), never. When set to `true` or `auto`, use colors only when the output is - to the terminal. Defaults to false. + to the terminal. If unset, then the value of `color.ui` is + used (`auto` by default). color.interactive.<slot>:: Use customized color for 'git add --interactive' and 'git clean @@ -1040,13 +1044,15 @@ color.showBranch:: A boolean to enable/disable color in the output of linkgit:git-show-branch[1]. May be set to `always`, `false` (or `never`) or `auto` (or `true`), in which case colors are used - only when the output is to a terminal. Defaults to false. + only when the output is to a terminal. If unset, then the + value of `color.ui` is used (`auto` by default). color.status:: A boolean to enable/disable color in the output of linkgit:git-status[1]. May be set to `always`, `false` (or `never`) or `auto` (or `true`), in which case colors are used - only when the output is to a terminal. Defaults to false. + only when the output is to a terminal. If unset, then the + value of `color.ui` is used (`auto` by default). color.status.<slot>:: Use customized color for status colorization. `<slot>` is diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt index 0eded24034..b27a38f896 100644 --- a/Documentation/diff-config.txt +++ b/Documentation/diff-config.txt @@ -171,10 +171,11 @@ diff.tool:: include::mergetools-diff.txt[] +diff.indentHeuristic:: diff.compactionHeuristic:: - Set this option to `true` to enable an experimental heuristic that - shifts the hunk boundary in an attempt to make the resulting - patch easier to read. + Set one of these options to `true` to enable one of two + experimental heuristics that shift diff hunk boundaries to + make patches easier to read. diff.algorithm:: Choose a diff algorithm. The variants are as follows: diff --git a/Documentation/diff-heuristic-options.txt b/Documentation/diff-heuristic-options.txt new file mode 100644 index 0000000000..36cb549df9 --- /dev/null +++ b/Documentation/diff-heuristic-options.txt @@ -0,0 +1,7 @@ +--indent-heuristic:: +--no-indent-heuristic:: +--compaction-heuristic:: +--no-compaction-heuristic:: + These are to help debugging and tuning experimental heuristics + (which are off by default) that shift diff hunk boundaries to + make patches easier to read. diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 7805a0ccad..2d77a19626 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -63,12 +63,7 @@ ifndef::git-format-patch[] Synonym for `-p --raw`. endif::git-format-patch[] ---compaction-heuristic:: ---no-compaction-heuristic:: - These are to help debugging and tuning an experimental - heuristic (which is off by default) that shifts the hunk - boundary in an attempt to make the resulting patch easier - to read. +include::diff-heuristic-options.txt[] --minimal:: Spend extra time to make sure the smallest possible diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.txt index 05fd482b74..94be4b85e0 100644 --- a/Documentation/git-annotate.txt +++ b/Documentation/git-annotate.txt @@ -23,6 +23,7 @@ familiar command name for people coming from other SCM systems. OPTIONS ------- include::blame-options.txt[] +include::diff-heuristic-options.txt[] SEE ALSO -------- diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt index ba5417567c..9dccb3319b 100644 --- a/Documentation/git-blame.txt +++ b/Documentation/git-blame.txt @@ -89,6 +89,8 @@ include::blame-options.txt[] abbreviated object name, use <n>+1 digits. Note that 1 column is used for a caret to mark the boundary commit. +include::diff-heuristic-options.txt[] + THE PORCELAIN FORMAT -------------------- diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 91a3622ee4..8611a99120 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -118,8 +118,8 @@ $ git check-ref-format --branch @{-1} * Determine the reference name to use for a new branch: + ------------ -$ ref=$(git check-ref-format --normalize "refs/heads/$newbranch") || -die "we do not like '$newbranch' as a branch name." +$ ref=$(git check-ref-format --normalize "refs/heads/$newbranch")|| +{ echo "we do not like '$newbranch' as a branch name." >&2 ; exit 1 ; } ------------ GIT diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 7a2201b051..8e2c0662dd 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -419,6 +419,18 @@ $ git reflog -2 HEAD # or $ git log -g -2 HEAD ------------ +ARGUMENT DISAMBIGUATION +----------------------- + +When there is only one argument given and it is not `--` (e.g. "git +checkout abc"), and when the argument is both a valid `<tree-ish>` +(e.g. a branch "abc" exists) and a valid `<pathspec>` (e.g. a file +or a directory whose name is "abc" exists), Git would usually ask +you to disambiguate. Because checking out a branch is so common an +operation, however, "git checkout abc" takes "abc" as a `<tree-ish>` +in such a situation. Use `git checkout -- <pathspec>` if you want +to checkout these paths out of the index. + EXAMPLES -------- diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index 41207a24b0..de1ebed67d 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -22,7 +22,7 @@ DESCRIPTION deprecated; it does not work with cvsps version 3 and later. If you are performing a one-shot import of a CVS repository consider using http://cvs2svn.tigris.org/cvs2git.html[cvs2git] or -https://github.com/BartMassey/parsecvs[parsecvs]. +http://www.catb.org/esr/cvs-fast-export/[cvs-fast-export]. Imports a CVS repository into Git. It will either create a new repository, or incrementally import into an existing one. diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 9624c84a65..9b200b379b 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -19,7 +19,8 @@ SYNOPSIS [--start-number <n>] [--numbered-files] [--in-reply-to=Message-Id] [--suffix=.<sfx>] [--ignore-if-in-upstream] - [--subject-prefix=Subject-Prefix] [(--reroll-count|-v) <n>] + [--rfc] [--subject-prefix=Subject-Prefix] + [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>] [--[no-]cover-letter] [--quiet] [--notes[=<ref>]] [<common diff options>] @@ -172,6 +173,11 @@ will want to ensure that threading is disabled for `git send-email`. allows for useful naming of a patch series, and can be combined with the `--numbered` option. +--rfc:: + Alias for `--subject-prefix="RFC PATCH"`. RFC means "Request For + Comments"; use this when sending an experimental patch for + discussion rather than application. + -v <n>:: --reroll-count=<n>:: Mark the series as the <n>-th iteration of the topic. The diff --git a/Documentation/gitcvs-migration.txt b/Documentation/gitcvs-migration.txt index b06e852a85..4c6143c511 100644 --- a/Documentation/gitcvs-migration.txt +++ b/Documentation/gitcvs-migration.txt @@ -116,8 +116,12 @@ they create are writable and searchable by other group members. Importing a CVS archive ----------------------- +NOTE: These instructions use the `git-cvsimport` script which ships with +git, but other importers may provide better results. See the note in +linkgit:git-cvsimport[1] for other options. + First, install version 2.1 or higher of cvsps from -http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make +https://github.com/andreyvit/cvsps[https://github.com/andreyvit/cvsps] and make sure it is in your path. Then cd to a checked out CVS working directory of the project you are interested in and run linkgit:git-cvsimport[1]: diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt index a79e350246..e6320891b1 100644 --- a/Documentation/gitweb.conf.txt +++ b/Documentation/gitweb.conf.txt @@ -246,13 +246,20 @@ $highlight_bin:: Note that 'highlight' feature must be set for gitweb to actually use syntax highlighting. + -*NOTE*: if you want to add support for new file type (supported by -"highlight" but not used by gitweb), you need to modify `%highlight_ext` -or `%highlight_basename`, depending on whether you detect type of file -based on extension (for example "sh") or on its basename (for example -"Makefile"). The keys of these hashes are extension and basename, -respectively, and value for given key is name of syntax to be passed via -`--syntax <syntax>` to highlighter. +*NOTE*: for a file to be highlighted, its syntax type must be detected +and that syntax must be supported by "highlight". The default syntax +detection is minimal, and there are many supported syntax types with no +detection by default. There are three options for adding syntax +detection. The first and second priority are `%highlight_basename` and +`%highlight_ext`, which detect based on basename (the full filename, for +example "Makefile") and extension (for example "sh"). The keys of these +hashes are the basename and extension, respectively, and the value for a +given key is the name of the syntax to be passed via `--syntax <syntax>` +to "highlight". The last priority is the "highlight" configuration of +`Shebang` regular expressions to detect the language based on the first +line in the file, (for example, matching the line "#!/bin/bash"). See +the highlight documentation and the default config at +/etc/highlight/filetypes.conf for more details. + For example if repositories you are hosting use "phtml" extension for PHP files, and you want to have correct syntax-highlighting for those @@ -301,7 +301,8 @@ all:: # crashes due to allocation and free working on different 'heaps'. # It's defined automatically if USE_NED_ALLOCATOR is set. # -# Define NO_REGEX if you have no or inferior regex support in your C library. +# Define NO_REGEX if your C library lacks regex support with REG_STARTEND +# feature. # # Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the # user. @@ -461,6 +462,7 @@ CURL_CONFIG = curl-config PTHREAD_LIBS = -lpthread PTHREAD_CFLAGS = GCOV = gcov +SPATCH = spatch export TCL_PATH TCLTK_PATH @@ -2308,6 +2310,18 @@ check: common-cmds.h exit 1; \ fi +C_SOURCES = $(patsubst %.o,%.c,$(C_OBJ)) +%.cocci.patch: %.cocci $(C_SOURCES) + @echo ' ' SPATCH $<; \ + for f in $(C_SOURCES); do \ + $(SPATCH) --sp-file $< $$f; \ + done >$@ 2>$@.log; \ + if test -s $@; \ + then \ + echo ' ' SPATCH result: $@; \ + fi +coccicheck: $(patsubst %.cocci,%.cocci.patch,$(wildcard contrib/coccinelle/*.cocci)) + ### Installation rules ifneq ($(filter /%,$(firstword $(template_dir))),) @@ -2499,6 +2513,7 @@ clean: profile-clean coverage-clean $(RM) -r $(GIT_TARNAME) .doc-tmp-dir $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz $(RM) $(htmldocs).tar.gz $(manpages).tar.gz + $(RM) contrib/coccinelle/*.cocci.patch* $(MAKE) -C Documentation/ clean ifndef NO_PERL $(MAKE) -C gitweb clean @@ -3334,10 +3334,8 @@ static void prepare_fn_table(struct apply_state *state, struct patch *patch) static int checkout_target(struct index_state *istate, struct cache_entry *ce, struct stat *st) { - struct checkout costate; + struct checkout costate = CHECKOUT_INIT; - memset(&costate, 0, sizeof(costate)); - costate.base_dir = ""; costate.refresh_cache = 1; costate.istate = istate; if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st)) diff --git a/builtin/add.c b/builtin/add.c index b1dddb4ac6..e8fb80b36e 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -26,10 +26,25 @@ static int patch_interactive, add_interactive, edit_interactive; static int take_worktree_changes; struct update_callback_data { - int flags, force_mode; + int flags; int add_errors; }; +static void chmod_pathspec(struct pathspec *pathspec, int force_mode) +{ + int i; + + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + + if (pathspec && !ce_path_match(ce, pathspec, NULL)) + continue; + + if (chmod_cache_entry(ce, force_mode) < 0) + fprintf(stderr, "cannot chmod '%s'", ce->name); + } +} + static int fix_unmerged_status(struct diff_filepair *p, struct update_callback_data *data) { @@ -65,8 +80,7 @@ static void update_callback(struct diff_queue_struct *q, die(_("unexpected diff status %c"), p->status); case DIFF_STATUS_MODIFIED: case DIFF_STATUS_TYPE_CHANGED: - if (add_file_to_index(&the_index, path, - data->flags, data->force_mode)) { + if (add_file_to_index(&the_index, path, data->flags)) { if (!(data->flags & ADD_CACHE_IGNORE_ERRORS)) die(_("updating files failed")); data->add_errors++; @@ -84,15 +98,14 @@ static void update_callback(struct diff_queue_struct *q, } } -int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, - int flags, int force_mode) +int add_files_to_cache(const char *prefix, + const struct pathspec *pathspec, int flags) { struct update_callback_data data; struct rev_info rev; memset(&data, 0, sizeof(data)); data.flags = flags; - data.force_mode = force_mode; init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); @@ -281,7 +294,7 @@ static int add_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } -static int add_files(struct dir_struct *dir, int flags, int force_mode) +static int add_files(struct dir_struct *dir, int flags) { int i, exit_status = 0; @@ -294,8 +307,7 @@ static int add_files(struct dir_struct *dir, int flags, int force_mode) } for (i = 0; i < dir->nr; i++) - if (add_file_to_index(&the_index, dir->entries[i]->name, - flags, force_mode)) { + if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) { if (!ignore_add_errors) die(_("adding files failed")); exit_status = 1; @@ -308,7 +320,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) int exit_status = 0; struct pathspec pathspec; struct dir_struct dir; - int flags, force_mode; + int flags; int add_new_files; int require_pathspec; char *seen = NULL; @@ -342,13 +354,8 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (!show_only && ignore_missing) die(_("Option --ignore-missing can only be used together with --dry-run")); - if (!chmod_arg) - force_mode = 0; - else if (!strcmp(chmod_arg, "-x")) - force_mode = 0666; - else if (!strcmp(chmod_arg, "+x")) - force_mode = 0777; - else + if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') || + chmod_arg[1] != 'x' || chmod_arg[2])) die(_("--chmod param '%s' must be either -x or +x"), chmod_arg); add_new_files = !take_worktree_changes && !refresh_only; @@ -441,11 +448,13 @@ int cmd_add(int argc, const char **argv, const char *prefix) plug_bulk_checkin(); - exit_status |= add_files_to_cache(prefix, &pathspec, flags, force_mode); + exit_status |= add_files_to_cache(prefix, &pathspec, flags); if (add_new_files) - exit_status |= add_files(&dir, flags, force_mode); + exit_status |= add_files(&dir, flags); + if (chmod_arg && pathspec.nr) + chmod_pathspec(&pathspec, chmod_arg[0]); unplug_bulk_checkin(); finish: diff --git a/builtin/blame.c b/builtin/blame.c index 2ff18b168e..a7bd7a6fd8 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -2220,6 +2220,8 @@ static int git_blame_config(const char *var, const char *value, void *cb) return 0; } + if (git_diff_heuristic_config(var, value, cb) < 0) + return -1; if (userdiff_config(var, value) < 0) return -1; @@ -2550,6 +2552,15 @@ int cmd_blame(int argc, const char **argv, const char *prefix) OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR), OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL), OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE), + + /* + * The following two options are parsed by parse_revision_opt() + * and are only included here to get included in the "-h" + * output: + */ + { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental indent-based heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, + { OPTION_LOWLEVEL_CALLBACK, 0, "compaction-heuristic", NULL, NULL, N_("Use an experimental blank-line-based heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, + OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL), OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")), OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")), @@ -2596,6 +2607,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) } parse_done: no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES); + xdl_opts |= revs.diffopt.xdl_opts & (XDF_COMPACTION_HEURISTIC | XDF_INDENT_HEURISTIC); DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES); argc = parse_options_end(&ctx); diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 92c69672e9..30a49d9f42 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -16,7 +16,7 @@ static int checkout_stage; /* default to checkout stage0 */ static int to_tempfile; static char topath[4][TEMPORARY_FILENAME_LENGTH + 1]; -static struct checkout state; +static struct checkout state = CHECKOUT_INIT; static void write_tempfile_record(const char *name, const char *prefix) { diff --git a/builtin/checkout.c b/builtin/checkout.c index 9941abc3ac..9b2a5b31d4 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -239,7 +239,7 @@ static int checkout_paths(const struct checkout_opts *opts, const char *revision) { int pos; - struct checkout state; + struct checkout state = CHECKOUT_INIT; static char *ps_matched; struct object_id rev; struct commit *head; @@ -352,7 +352,6 @@ static int checkout_paths(const struct checkout_opts *opts, return 1; /* Now we are committed to check them out */ - memset(&state, 0, sizeof(state)); state.force = 1; state.refresh_cache = 1; state.istate = &the_index; @@ -548,7 +547,7 @@ static int merge_working_tree(const struct checkout_opts *opts, * entries in the index. */ - add_files_to_cache(NULL, NULL, 0, 0); + add_files_to_cache(NULL, NULL, 0); /* * NEEDSWORK: carrying over local changes * when branches have different end-of-line @@ -985,7 +984,7 @@ static int parse_branchname_arg(int argc, const char **argv, int recover_with_dwim = dwim_new_local_branch_ok; if (!has_dash_dash && - (check_filename(NULL, arg) || !no_wildcard(arg))) + (check_filename(opts->prefix, arg) || !no_wildcard(arg))) recover_with_dwim = 0; /* * Accept "git checkout foo" and "git checkout foo --" @@ -1038,7 +1037,7 @@ static int parse_branchname_arg(int argc, const char **argv, if (!*source_tree) /* case (1): want a tree */ die(_("reference is not a tree: %s"), arg); - if (!has_dash_dash) {/* case (3).(d) -> (1) */ + if (!has_dash_dash) { /* case (3).(d) -> (1) */ /* * Do not complain the most common case * git checkout branch @@ -1046,7 +1045,7 @@ static int parse_branchname_arg(int argc, const char **argv, * it would be extremely annoying. */ if (argc) - verify_non_filename(NULL, arg); + verify_non_filename(opts->prefix, arg); } else { argcount++; argv++; diff --git a/builtin/clone.c b/builtin/clone.c index 404c5e8022..fb75f7ee64 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -670,7 +670,7 @@ static void update_head(const struct ref *our, const struct ref *remote, } } -static int checkout(void) +static int checkout(int submodule_progress) { unsigned char sha1[20]; char *head; @@ -734,6 +734,9 @@ static int checkout(void) if (max_jobs != -1) argv_array_pushf(&args, "--jobs=%d", max_jobs); + if (submodule_progress) + argv_array_push(&args, "--progress"); + err = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); } @@ -841,6 +844,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) const char *src_ref_prefix = "refs/heads/"; struct remote *remote; int err = 0, complete_refs_before_fetch = 1; + int submodule_progress; struct refspec *refspec; const char *fetch_pattern; @@ -931,16 +935,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) set_git_work_tree(work_tree); } - junk_git_dir = git_dir; + junk_git_dir = real_git_dir ? real_git_dir : git_dir; if (safe_create_leading_directories_const(git_dir) < 0) die(_("could not create leading directories of '%s'"), git_dir); - set_git_dir_init(git_dir, real_git_dir, 0); - if (real_git_dir) { - git_dir = real_git_dir; - junk_git_dir = real_git_dir; - } - if (0 <= option_verbosity) { if (option_bare) fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir); @@ -966,7 +964,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } } - init_db(option_template, INIT_DB_QUIET); + init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET); + + if (real_git_dir) + git_dir = real_git_dir; + write_config(&option_config); git_config(git_default_config, NULL); @@ -1099,6 +1101,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix) update_head(our_head_points_at, remote_head, reflog_msg.buf); + /* + * We want to show progress for recursive submodule clones iff + * we did so for the main clone. But only the transport knows + * the final decision for this flag, so we need to rescue the value + * before we free the transport. + */ + submodule_progress = transport->progress; + transport_unlock_pack(transport); transport_disconnect(transport); @@ -1108,7 +1118,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } junk_mode = JUNK_LEAVE_REPO; - err = checkout(); + err = checkout(submodule_progress); strbuf_release(&reflog_msg); strbuf_release(&branch_top); diff --git a/builtin/commit.c b/builtin/commit.c index bb9f79b6ef..1cba3b75c8 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -397,7 +397,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix */ if (all || (also && pathspec.nr)) { hold_locked_index(&index_lock, 1); - add_files_to_cache(also ? prefix : NULL, &pathspec, 0, 0); + add_files_to_cache(also ? prefix : NULL, &pathspec, 0); refresh_cache_or_die(refresh_flags); update_main_cache_tree(WRITE_TREE_SILENT); if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index ac84e99f3a..dc2e9e420d 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -395,7 +395,7 @@ static void shortlog(const char *name, for (i = 0; i < subjects.nr; i++) if (i >= limit) - strbuf_addf(out, " ...\n"); + strbuf_addstr(out, " ...\n"); else strbuf_addf(out, " %s\n", subjects.items[i].string); diff --git a/builtin/init-db.c b/builtin/init-db.c index 72e81447ae..2399b97d90 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -22,7 +22,6 @@ static int init_is_bare_repository = 0; static int init_shared_repository = -1; static const char *init_db_template_dir; -static const char *git_link; static void copy_templates_1(struct strbuf *path, struct strbuf *template, DIR *dir) @@ -138,7 +137,7 @@ static void copy_templates(const char *template_dir) goto close_free_return; } - strbuf_addstr(&path, get_git_dir()); + strbuf_addstr(&path, get_git_common_dir()); strbuf_complete(&path, '/'); copy_templates_1(&path, &template_path, dir); close_free_return: @@ -171,7 +170,8 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree) return 1; } -static int create_default_files(const char *template_path) +static int create_default_files(const char *template_path, + const char *original_git_dir) { struct stat st1; struct strbuf buf = STRBUF_INIT; @@ -264,7 +264,7 @@ static int create_default_files(const char *template_path) /* allow template config file to override the default */ if (log_all_ref_updates == -1) git_config_set("core.logallrefupdates", "true"); - if (needs_work_tree_config(get_git_dir(), work_tree)) + if (needs_work_tree_config(original_git_dir, work_tree)) git_config_set("core.worktree", work_tree); } @@ -312,34 +312,7 @@ static void create_object_directory(void) strbuf_release(&path); } -int set_git_dir_init(const char *git_dir, const char *real_git_dir, - int exist_ok) -{ - if (real_git_dir) { - struct stat st; - - if (!exist_ok && !stat(git_dir, &st)) - die(_("%s already exists"), git_dir); - - if (!exist_ok && !stat(real_git_dir, &st)) - die(_("%s already exists"), real_git_dir); - - /* - * make sure symlinks are resolved because we'll be - * moving the target repo later on in separate_git_dir() - */ - git_link = xstrdup(real_path(git_dir)); - set_git_dir(real_path(real_git_dir)); - } - else { - set_git_dir(real_path(git_dir)); - git_link = NULL; - } - startup_info->have_repository = 1; - return 0; -} - -static void separate_git_dir(const char *git_dir) +static void separate_git_dir(const char *git_dir, const char *git_link) { struct stat st; @@ -360,13 +333,31 @@ static void separate_git_dir(const char *git_dir) write_file(git_link, "gitdir: %s", git_dir); } -int init_db(const char *template_dir, unsigned int flags) +int init_db(const char *git_dir, const char *real_git_dir, + const char *template_dir, unsigned int flags) { int reinit; - const char *git_dir = get_git_dir(); + int exist_ok = flags & INIT_DB_EXIST_OK; + char *original_git_dir = xstrdup(real_path(git_dir)); + + if (real_git_dir) { + struct stat st; + + if (!exist_ok && !stat(git_dir, &st)) + die(_("%s already exists"), git_dir); + + if (!exist_ok && !stat(real_git_dir, &st)) + die(_("%s already exists"), real_git_dir); - if (git_link) - separate_git_dir(git_dir); + set_git_dir(real_path(real_git_dir)); + git_dir = get_git_dir(); + separate_git_dir(git_dir, original_git_dir); + } + else { + set_git_dir(real_path(git_dir)); + git_dir = get_git_dir(); + } + startup_info->have_repository = 1; safe_create_dir(git_dir, 0); @@ -379,7 +370,7 @@ int init_db(const char *template_dir, unsigned int flags) */ check_repository_format(); - reinit = create_default_files(template_dir); + reinit = create_default_files(template_dir, original_git_dir); create_object_directory(); @@ -419,6 +410,7 @@ int init_db(const char *template_dir, unsigned int flags) git_dir, len && git_dir[len-1] != '/' ? "/" : ""); } + free(original_git_dir); return 0; } @@ -586,7 +578,6 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) set_git_work_tree(work_tree); } - set_git_dir_init(git_dir, real_git_dir, 1); - - return init_db(template_dir, flags); + flags |= INIT_DB_EXIST_OK; + return init_db(git_dir, real_git_dir, template_dir, flags); } diff --git a/builtin/log.c b/builtin/log.c index b8cdf2b9d9..55d20cc2d8 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1111,6 +1111,11 @@ static int subject_prefix_callback(const struct option *opt, const char *arg, return 0; } +static int rfc_callback(const struct option *opt, const char *arg, int unset) +{ + return subject_prefix_callback(opt, "RFC PATCH", unset); +} + static int numbered_cmdline_opt = 0; static int numbered_callback(const struct option *opt, const char *arg, @@ -1418,6 +1423,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) N_("start numbering patches at <n> instead of 1")), OPT_INTEGER('v', "reroll-count", &reroll_count, N_("mark the series as Nth re-roll")), + { OPTION_CALLBACK, 0, "rfc", &rev, NULL, + N_("Use [RFC PATCH] instead of [PATCH]"), + PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback }, { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"), N_("Use [<prefix>] instead of [PATCH]"), PARSE_OPT_NONEG, subject_prefix_callback }, @@ -1556,7 +1564,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (numbered && keep_subject) die (_("-n and -k are mutually exclusive.")); if (keep_subject && subject_prefix) - die (_("--subject-prefix and -k are mutually exclusive.")); + die (_("--subject-prefix/--rfc and -k are mutually exclusive.")); rev.preserve_subject = keep_subject; argc = setup_revisions(argc, argv, &rev, &s_r_opt); diff --git a/builtin/merge.c b/builtin/merge.c index 0ae099f746..a8b57c7d98 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -940,7 +940,7 @@ static void write_merge_state(struct commit_list *remoteheads) strbuf_reset(&buf); if (fast_forward == FF_NO) - strbuf_addf(&buf, "no-ff"); + strbuf_addstr(&buf, "no-ff"); write_file_buf(git_path_merge_mode(), buf.buf, buf.len); } diff --git a/builtin/mv.c b/builtin/mv.c index 446a316738..2f43877bc9 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -26,7 +26,7 @@ static const char **internal_copy_pathspec(const char *prefix, int i; const char **result; ALLOC_ARRAY(result, count + 1); - memcpy(result, pathspec, count * sizeof(const char *)); + COPY_ARRAY(result, pathspec, count); result[count] = NULL; for (i = 0; i < count; i++) { int length = strlen(result[i]); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 7b8ddfe6cf..e3fdc0aa78 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -443,7 +443,8 @@ static int module_name(int argc, const char **argv, const char *prefix) } static int clone_submodule(const char *path, const char *gitdir, const char *url, - const char *depth, struct string_list *reference, int quiet) + const char *depth, struct string_list *reference, + int quiet, int progress) { struct child_process cp = CHILD_PROCESS_INIT; @@ -451,6 +452,8 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url argv_array_push(&cp.args, "--no-checkout"); if (quiet) argv_array_push(&cp.args, "--quiet"); + if (progress) + argv_array_push(&cp.args, "--progress"); if (depth && *depth) argv_array_pushl(&cp.args, "--depth", depth, NULL); if (reference->nr) { @@ -575,6 +578,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) { const char *name = NULL, *url = NULL, *depth = NULL; int quiet = 0; + int progress = 0; FILE *submodule_dot_git; char *p, *path = NULL, *sm_gitdir; struct strbuf rel_path = STRBUF_INIT; @@ -601,6 +605,8 @@ static int module_clone(int argc, const char **argv, const char *prefix) N_("string"), N_("depth for shallow clones")), OPT__QUIET(&quiet, "Suppress output for cloning a submodule"), + OPT_BOOL(0, "progress", &progress, + N_("force cloning progress")), OPT_END() }; @@ -634,7 +640,8 @@ static int module_clone(int argc, const char **argv, const char *prefix) prepare_possible_alternates(name, &reference); - if (clone_submodule(path, sm_gitdir, url, depth, &reference, quiet)) + if (clone_submodule(path, sm_gitdir, url, depth, &reference, + quiet, progress)) die(_("clone of '%s' into submodule path '%s' failed"), url, path); } else { @@ -684,6 +691,7 @@ struct submodule_update_clone { struct submodule_update_strategy update; /* configuration parameters which are passed on to the children */ + int progress; int quiet; int recommend_shallow; struct string_list references; @@ -702,7 +710,7 @@ struct submodule_update_clone { int failed_clones_nr, failed_clones_alloc; }; #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \ - SUBMODULE_UPDATE_STRATEGY_INIT, 0, -1, STRING_LIST_INIT_DUP, \ + SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, \ NULL, NULL, NULL, \ STRING_LIST_INIT_DUP, 0, NULL, 0, 0} @@ -804,6 +812,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, child->err = -1; argv_array_push(&child->args, "submodule--helper"); argv_array_push(&child->args, "clone"); + if (suc->progress) + argv_array_push(&child->args, "--progress"); if (suc->quiet) argv_array_push(&child->args, "--quiet"); if (suc->prefix) @@ -860,8 +870,9 @@ static int update_clone_get_next_task(struct child_process *child, ce = suc->failed_clones[index]; if (!prepare_to_clone_next_submodule(ce, child, suc, err)) { suc->current ++; - strbuf_addf(err, "BUG: submodule considered for cloning," - "doesn't need cloning any more?\n"); + strbuf_addstr(err, "BUG: submodule considered for " + "cloning, doesn't need cloning " + "any more?\n"); return 0; } p = xmalloc(sizeof(*p)); @@ -950,6 +961,8 @@ static int update_clone(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow, N_("whether the initial clone should follow the shallow recommendation")), OPT__QUIET(&suc.quiet, N_("don't print cloning progress")), + OPT_BOOL(0, "progress", &suc.progress, + N_("force cloning progress")), OPT_END() }; diff --git a/builtin/update-index.c b/builtin/update-index.c index 73f6b3e1be..f3f07e7f1c 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -419,30 +419,18 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid, return 0; } -static void chmod_path(int flip, const char *path) +static void chmod_path(char flip, const char *path) { int pos; struct cache_entry *ce; - unsigned int mode; pos = cache_name_pos(path, strlen(path)); if (pos < 0) goto fail; ce = active_cache[pos]; - mode = ce->ce_mode; - if (!S_ISREG(mode)) - goto fail; - switch (flip) { - case '+': - ce->ce_mode |= 0111; break; - case '-': - ce->ce_mode &= ~0111; break; - default: + if (chmod_cache_entry(ce, flip) < 0) goto fail; - } - cache_tree_invalidate_path(&the_index, path); - ce->ce_flags |= CE_UPDATE_IN_BASE; - active_cache_changed |= CE_ENTRY_CHANGED; + report("chmod %cx '%s'", flip, path); return; fail: diff --git a/builtin/worktree.c b/builtin/worktree.c index 6dcf7bd9d2..5c4854d3e4 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -528,6 +528,8 @@ int cmd_worktree(int ac, const char **av, const char *prefix) OPT_END() }; + git_config(git_default_config, NULL); + if (ac < 2) usage_with_options(worktree_usage, options); if (!prefix) @@ -367,8 +367,9 @@ extern void free_name_hash(struct index_state *istate); #define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name)) #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos)) #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path)) -#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags), 0) -#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags), 0) +#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags)) +#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags)) +#define chmod_cache_entry(ce, flip) chmod_index_entry(&the_index, (ce), (flip)) #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL) #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options)) #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options)) @@ -525,9 +526,10 @@ extern void verify_non_filename(const char *prefix, const char *name); extern int path_inside_repo(const char *prefix, const char *path); #define INIT_DB_QUIET 0x0001 +#define INIT_DB_EXIST_OK 0x0002 -extern int set_git_dir_init(const char *git_dir, const char *real_git_dir, int); -extern int init_db(const char *template_dir, unsigned int flags); +extern int init_db(const char *git_dir, const char *real_git_dir, + const char *template_dir, unsigned int flags); extern void sanitize_stdfds(void); extern int daemonize(void); @@ -587,9 +589,10 @@ extern int remove_file_from_index(struct index_state *, const char *path); #define ADD_CACHE_IGNORE_ERRORS 4 #define ADD_CACHE_IGNORE_REMOVAL 8 #define ADD_CACHE_INTENT 16 -extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags, int force_mode); -extern int add_file_to_index(struct index_state *, const char *path, int flags, int force_mode); +extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags); +extern int add_file_to_index(struct index_state *, const char *path, int flags); extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options); +extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip); extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b); extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce); extern int index_name_is_other(const struct index_state *, const char *, int); @@ -1354,6 +1357,7 @@ struct checkout { not_new:1, refresh_cache:1; }; +#define CHECKOUT_INIT { NULL, "" } #define TEMPORARY_FILENAME_LENGTH 25 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath); @@ -1858,7 +1862,7 @@ void packet_trace_identity(const char *prog); * return 0 if success, 1 - if addition of a file failed and * ADD_FILES_IGNORE_ERRORS was specified in flags */ -int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags, int force_mode); +int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags); /* diff.c */ extern int diff_auto_refresh_index; @@ -931,7 +931,7 @@ static int remove_redundant(struct commit **array, int cnt) } /* Now collect the result */ - memcpy(work, array, sizeof(*array) * cnt); + COPY_ARRAY(work, array, cnt); for (i = filled = 0; i < cnt; i++) if (!redundant[i]) array[filled++] = work[i]; @@ -1511,9 +1511,9 @@ static int verify_utf8(struct strbuf *buf) } static const char commit_utf8_warn[] = -"Warning: commit message did not conform to UTF-8.\n" -"You may want to amend it after fixing the message, or set the config\n" -"variable i18n.commitencoding to the encoding your project uses.\n"; +N_("Warning: commit message did not conform to UTF-8.\n" + "You may want to amend it after fixing the message, or set the config\n" + "variable i18n.commitencoding to the encoding your project uses.\n"); int commit_tree_extended(const char *msg, size_t msg_len, const unsigned char *tree, @@ -1566,7 +1566,7 @@ int commit_tree_extended(const char *msg, size_t msg_len, /* And check the encoding */ if (encoding_is_utf8 && !verify_utf8(&buffer)) - fprintf(stderr, commit_utf8_warn); + fprintf(stderr, _(commit_utf8_warn)); if (sign_commit && do_sign_commit(&buffer, sign_commit)) return -1; @@ -46,11 +46,11 @@ int check_ref_type(const struct ref *ref, int flags) static void die_initial_contact(int unexpected) { if (unexpected) - die("The remote end hung up upon initial contact"); + die(_("The remote end hung up upon initial contact")); else - die("Could not read from remote repository.\n\n" - "Please make sure you have the correct access rights\n" - "and the repository exists."); + die(_("Could not read from remote repository.\n\n" + "Please make sure you have the correct access rights\n" + "and the repository exists.")); } static void parse_one_symref_info(struct string_list *symref, const char *val, int len) diff --git a/contrib/coccinelle/array.cocci b/contrib/coccinelle/array.cocci new file mode 100644 index 0000000000..2d7f25d99f --- /dev/null +++ b/contrib/coccinelle/array.cocci @@ -0,0 +1,26 @@ +@@ +type T; +T *dst; +T *src; +expression n; +@@ +- memcpy(dst, src, n * sizeof(*dst)); ++ COPY_ARRAY(dst, src, n); + +@@ +type T; +T *dst; +T *src; +expression n; +@@ +- memcpy(dst, src, n * sizeof(*src)); ++ COPY_ARRAY(dst, src, n); + +@@ +type T; +T *dst; +T *src; +expression n; +@@ +- memcpy(dst, src, n * sizeof(T)); ++ COPY_ARRAY(dst, src, n); diff --git a/contrib/coccinelle/object_id.cocci b/contrib/coccinelle/object_id.cocci index 8ccdbb5666..0307624a03 100644 --- a/contrib/coccinelle/object_id.cocci +++ b/contrib/coccinelle/object_id.cocci @@ -23,16 +23,16 @@ expression E1; + oid_to_hex(E1) @@ -expression E1; +expression E1, E2; @@ -- sha1_to_hex_r(E1.hash) -+ oid_to_hex_r(&E1) +- sha1_to_hex_r(E1, E2.hash) ++ oid_to_hex_r(E1, &E2) @@ -expression E1; +expression E1, E2; @@ -- sha1_to_hex_r(E1->hash) -+ oid_to_hex_r(E1) +- sha1_to_hex_r(E1, E2->hash) ++ oid_to_hex_r(E1, E2) @@ expression E1; diff --git a/contrib/coccinelle/strbuf.cocci b/contrib/coccinelle/strbuf.cocci new file mode 100644 index 0000000000..7932d48cdf --- /dev/null +++ b/contrib/coccinelle/strbuf.cocci @@ -0,0 +1,5 @@ +@@ +expression E1, E2; +@@ +- strbuf_addf(E1, E2); ++ strbuf_addstr(E1, E2); @@ -27,6 +27,7 @@ #endif static int diff_detect_rename_default; +static int diff_indent_heuristic; /* experimental */ static int diff_compaction_heuristic; /* experimental */ static int diff_rename_limit_default = 400; static int diff_suppress_blank_empty; @@ -55,6 +56,11 @@ static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* FUNCINFO */ }; +static NORETURN void die_want_option(const char *option_name) +{ + die(_("option '%s' requires a value"), option_name); +} + static int parse_diff_color_slot(const char *var) { if (!strcasecmp(var, "context") || !strcasecmp(var, "plain")) @@ -177,6 +183,21 @@ void init_diff_ui_defaults(void) diff_detect_rename_default = 1; } +int git_diff_heuristic_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "diff.indentheuristic")) { + diff_indent_heuristic = git_config_bool(var, value); + if (diff_indent_heuristic) + diff_compaction_heuristic = 0; + } + if (!strcmp(var, "diff.compactionheuristic")) { + diff_compaction_heuristic = git_config_bool(var, value); + if (diff_compaction_heuristic) + diff_indent_heuristic = 0; + } + return 0; +} + int git_diff_ui_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { @@ -193,10 +214,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_detect_rename_default = git_config_rename(var, value); return 0; } - if (!strcmp(var, "diff.compactionheuristic")) { - diff_compaction_heuristic = git_config_bool(var, value); - return 0; - } if (!strcmp(var, "diff.autorefreshindex")) { diff_auto_refresh_index = git_config_bool(var, value); return 0; @@ -237,6 +254,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return 0; } + if (git_diff_heuristic_config(var, value, cb) < 0) + return -1; if (git_color_config(var, value, cb) < 0) return -1; @@ -952,7 +971,8 @@ static int find_word_boundaries(mmfile_t *buffer, regex_t *word_regex, { if (word_regex && *begin < buffer->size) { regmatch_t match[1]; - if (!regexec(word_regex, buffer->ptr + *begin, 1, match, 0)) { + if (!regexec_buf(word_regex, buffer->ptr + *begin, + buffer->size - *begin, 1, match, 0)) { char *p = memchr(buffer->ptr + *begin + match[0].rm_so, '\n', match[0].rm_eo - match[0].rm_so); *end = p ? p - buffer->ptr : match[0].rm_eo + *begin; @@ -3296,7 +3316,9 @@ void diff_setup(struct diff_options *options) options->use_color = diff_use_color_default; options->detect_rename = diff_detect_rename_default; options->xdl_opts |= diff_algorithm; - if (diff_compaction_heuristic) + if (diff_indent_heuristic) + DIFF_XDL_SET(options, INDENT_HEURISTIC); + else if (diff_compaction_heuristic) DIFF_XDL_SET(options, COMPACTION_HEURISTIC); options->orderfile = diff_order_file_cfg; @@ -3325,7 +3347,7 @@ void diff_setup_done(struct diff_options *options) if (options->output_format & DIFF_FORMAT_NO_OUTPUT) count++; if (count > 1) - die("--name-only, --name-status, --check and -s are mutually exclusive"); + die(_("--name-only, --name-status, --check and -s are mutually exclusive")); /* * Most of the time we can say "there are changes" @@ -3521,7 +3543,7 @@ static int stat_opt(struct diff_options *options, const char **av) if (*arg == '=') width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) - die("Option '--stat-width' requires a value"); + die_want_option("--stat-width"); else if (!*arg) { width = strtoul(av[1], &end, 10); argcount = 2; @@ -3530,7 +3552,7 @@ static int stat_opt(struct diff_options *options, const char **av) if (*arg == '=') name_width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) - die("Option '--stat-name-width' requires a value"); + die_want_option("--stat-name-width"); else if (!*arg) { name_width = strtoul(av[1], &end, 10); argcount = 2; @@ -3539,7 +3561,7 @@ static int stat_opt(struct diff_options *options, const char **av) if (*arg == '=') graph_width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) - die("Option '--stat-graph-width' requires a value"); + die_want_option("--stat-graph-width"); else if (!*arg) { graph_width = strtoul(av[1], &end, 10); argcount = 2; @@ -3548,7 +3570,7 @@ static int stat_opt(struct diff_options *options, const char **av) if (*arg == '=') count = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) - die("Option '--stat-count' requires a value"); + die_want_option("--stat-count"); else if (!*arg) { count = strtoul(av[1], &end, 10); argcount = 2; @@ -3818,9 +3840,15 @@ int diff_opt_parse(struct diff_options *options, DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL); else if (!strcmp(arg, "--ignore-blank-lines")) DIFF_XDL_SET(options, IGNORE_BLANK_LINES); - else if (!strcmp(arg, "--compaction-heuristic")) + else if (!strcmp(arg, "--indent-heuristic")) { + DIFF_XDL_SET(options, INDENT_HEURISTIC); + DIFF_XDL_CLR(options, COMPACTION_HEURISTIC); + } else if (!strcmp(arg, "--no-indent-heuristic")) + DIFF_XDL_CLR(options, INDENT_HEURISTIC); + else if (!strcmp(arg, "--compaction-heuristic")) { DIFF_XDL_SET(options, COMPACTION_HEURISTIC); - else if (!strcmp(arg, "--no-compaction-heuristic")) + DIFF_XDL_CLR(options, INDENT_HEURISTIC); + } else if (!strcmp(arg, "--no-compaction-heuristic")) DIFF_XDL_CLR(options, COMPACTION_HEURISTIC); else if (!strcmp(arg, "--patience")) options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); @@ -273,6 +273,7 @@ extern int parse_long_opt(const char *opt, const char **argv, const char **optarg); extern int git_diff_basic_config(const char *var, const char *value, void *cb); +extern int git_diff_heuristic_config(const char *var, const char *value, void *cb); extern void init_diff_ui_defaults(void); extern int git_diff_ui_config(const char *var, const char *value, void *cb); extern void diff_setup(struct diff_options *); diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index 55067cab6c..9795ca1c15 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -23,7 +23,6 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len) { struct diffgrep_cb *data = priv; regmatch_t regmatch; - int hold; if (line[0] != '+' && line[0] != '-') return; @@ -33,11 +32,8 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len) * caller early. */ return; - /* Yuck -- line ought to be "const char *"! */ - hold = line[len]; - line[len] = '\0'; - data->hit = !regexec(data->regexp, line + 1, 1, ®match, 0); - line[len] = hold; + data->hit = !regexec_buf(data->regexp, line + 1, len - 1, 1, + ®match, 0); } static int diff_grep(mmfile_t *one, mmfile_t *two, @@ -50,9 +46,11 @@ static int diff_grep(mmfile_t *one, mmfile_t *two, xdemitconf_t xecfg; if (!one) - return !regexec(regexp, two->ptr, 1, ®match, 0); + return !regexec_buf(regexp, two->ptr, two->size, + 1, ®match, 0); if (!two) - return !regexec(regexp, one->ptr, 1, ®match, 0); + return !regexec_buf(regexp, one->ptr, one->size, + 1, ®match, 0); /* * We have both sides; need to run textual diff and see if @@ -83,8 +81,8 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws) regmatch_t regmatch; int flags = 0; - assert(data[sz] == '\0'); - while (*data && !regexec(regexp, data, 1, ®match, flags)) { + while (*data && + !regexec_buf(regexp, data, sz, 1, ®match, flags)) { flags |= REG_NOTBOL; data += regmatch.rm_eo; if (*data && regmatch.rm_so == regmatch.rm_eo) diff --git a/fetch-pack.c b/fetch-pack.c index 85e77af61d..413937e740 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -428,10 +428,17 @@ static int find_common(struct fetch_pack_args *args, const char *hex = sha1_to_hex(result_sha1); packet_buf_write(&req_buf, "have %s\n", hex); state_len = req_buf.len; - } + /* + * Reset in_vain because an ack + * for this commit has not been + * seen. + */ + in_vain = 0; + } else if (!args->stateless_rpc + || ack != ACK_common) + in_vain = 0; mark_common(commit, 0, 1); retval = 0; - in_vain = 0; got_continue = 1; if (ack == ACK_ready) { clear_prio_queue(&rev_list); diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 642cce1ac6..ee3d812695 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -45,6 +45,7 @@ my ($diff_new_color) = my $normal_color = $repo->get_color("", "reset"); my $diff_algorithm = $repo->config('diff.algorithm'); +my $diff_indent_heuristic = $repo->config_bool('diff.indentheuristic'); my $diff_compaction_heuristic = $repo->config_bool('diff.compactionheuristic'); my $diff_filter = $repo->config('interactive.difffilter'); @@ -750,7 +751,9 @@ sub parse_diff { if (defined $diff_algorithm) { splice @diff_cmd, 1, 0, "--diff-algorithm=${diff_algorithm}"; } - if ($diff_compaction_heuristic) { + if ($diff_indent_heuristic) { + splice @diff_cmd, 1, 0, "--indent-heuristic"; + } elsif ($diff_compaction_heuristic) { splice @diff_cmd, 1, 0, "--compaction-heuristic"; } if (defined $patch_mode_revision) { diff --git a/git-compat-util.h b/git-compat-util.h index 37cce0746f..0ce2cdfb98 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -801,6 +801,14 @@ extern FILE *fopen_for_writing(const char *path); #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc))) #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc))) +#define COPY_ARRAY(dst, src, n) copy_array((dst), (src), (n), sizeof(*(dst)) + \ + BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src)))) +static inline void copy_array(void *dst, const void *src, size_t n, size_t size) +{ + if (n) + memcpy(dst, src, st_mult(size, n)); +} + /* * These functions help you allocate structs with flex arrays, and copy * the data directly into the array. For example, if you had: @@ -977,6 +985,19 @@ void git_qsort(void *base, size_t nmemb, size_t size, #define qsort git_qsort #endif +#ifndef REG_STARTEND +#error "Git requires REG_STARTEND support. Compile with NO_REGEX=NeedsStartEnd" +#endif + +static inline int regexec_buf(const regex_t *preg, const char *buf, size_t size, + size_t nmatch, regmatch_t pmatch[], int eflags) +{ + assert(nmatch > 0 && pmatch); + pmatch[0].rm_so = 0; + pmatch[0].rm_eo = size; + return regexec(preg, buf, nmatch, pmatch, eflags | REG_STARTEND); +} + #ifndef DIR_HAS_BSD_GROUP_SEMANTICS # define FORCE_DIR_SET_GID S_ISGID #else diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl index 74a81a7b42..3a3e534aef 100644 --- a/git-gui/lib/index.tcl +++ b/git-gui/lib/index.tcl @@ -291,7 +291,7 @@ proc do_unstage_selection {} { if {[array size selected_paths] > 0} { unstage_helper \ - {Unstaging selected files from commit} \ + [mc "Unstaging selected files from commit"] \ [array names selected_paths] } elseif {$current_diff_path ne {}} { unstage_helper \ @@ -343,7 +343,7 @@ proc do_add_selection {} { if {[array size selected_paths] > 0} { add_helper \ - {Adding selected files} \ + [mc "Adding selected files"] \ [array names selected_paths] } elseif {$current_diff_path ne {}} { add_helper \ @@ -385,7 +385,7 @@ proc do_add_all {} { set paths [concat $paths $untracked_paths] } } - add_helper {Adding all changed files} $paths + add_helper [mc "Adding all changed files"] $paths } proc revert_helper {txt paths} { diff --git a/git-gui/lib/merge.tcl b/git-gui/lib/merge.tcl index 460d32fa22..5ab6f8f102 100644 --- a/git-gui/lib/merge.tcl +++ b/git-gui/lib/merge.tcl @@ -112,12 +112,7 @@ method _start {} { close $fh set _last_merged_branch $branch - set cmd [list git] - lappend cmd merge - lappend cmd --strategy=recursive - lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]] - lappend cmd HEAD - lappend cmd $name + set cmd [list git merge --strategy=recursive FETCH_HEAD] ui_status [mc "Merging %s and %s..." $current_branch $stitle] set cons [console::new [mc "Merge"] "merge $stitle"] diff --git a/git-gui/po/glossary/pt_pt.po b/git-gui/po/glossary/pt_pt.po new file mode 100644 index 0000000000..adc3b542a6 --- /dev/null +++ b/git-gui/po/glossary/pt_pt.po @@ -0,0 +1,293 @@ +# Portuguese translations for git-gui glossary. +# Copyright (C) 2016 Shawn Pearce, et al. +# This file is distributed under the same license as the git package. +# Vasco Almeida <vascomalmeida@sapo.pt>, 2016. +msgid "" +msgstr "" +"Project-Id-Version: git-gui glossary\n" +"POT-Creation-Date: 2016-05-06 10:22+0000\n" +"PO-Revision-Date: 2016-05-06 12:32+0000\n" +"Last-Translator: Vasco Almeida <vascomalmeida@sapo.pt>\n" +"Language-Team: Portuguese\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Virtaal 0.7.1\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 "" +"Outro SCM em português:\n" +"http://svn.code.sf.net/p/tortoisesvn/code/trunk/Languages/pt/TortoiseUI.po e " +"\n" +"http://svn.code.sf.net/p/tortoisesvn/code/trunk/Languages/pt/TortoiseDoc.po\n" +" em html: https://tortoisesvn.net/docs/release/TortoiseSVN_pt/index.html\n" +"\n" +"https://translations.launchpad.net/tortoisehg (medíocre)" + +#. "" +msgid "amend" +msgstr "emendar" + +#. "" +msgid "annotate" +msgstr "anotar" + +#. "A 'branch' is an active line of development." +msgid "branch [noun]" +msgstr "ramo" + +#. "" +msgid "branch [verb]" +msgstr "criar ramo" + +#. "" +msgid "checkout [noun]" +msgstr "extração" + +#. "The action of updating the working tree to a revision which was stored in the object database." +msgid "checkout [verb]" +msgstr "extrair" + +#. "" +msgid "clone [verb]" +msgstr "clonar" + +#. "A single point in the git history." +msgid "commit [noun]" +msgstr "commit" + +#. "The action of storing a new snapshot of the project's state in the git history." +msgid "commit [verb]" +msgstr "submeter" + +#. "" +msgid "diff [noun]" +msgstr "diferenças" + +#. "" +msgid "diff [verb]" +msgstr "mostrar diferenças" + +#. "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 "integração por avanço rápido" + +#. "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 "obter" + +#. "One context of consecutive lines in a whole patch, which consists of many such hunks" +msgid "hunk" +msgstr "excerto" + +#. "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 "integração" + +#. "To bring the contents of another branch into the current branch." +msgid "merge [verb]" +msgstr "integrar" + +#. "" +msgid "message" +msgstr "mensagem" + +#. "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 "podar" + +#. "Pulling a branch means to fetch it and merge it." +msgid "pull" +msgstr "puxar" + +#. "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 "publicar" + +#. "" +msgid "redo" +msgstr "refazer" + +#. "An other repository ('remote'). One might have a set of remotes whose branches one tracks." +msgid "remote" +msgstr "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 "repor" + +#. "" +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 por baixo" + +#. "" +msgid "staging area" +msgstr "área de estágio" + +#. "" +msgid "status" +msgstr "estado" + +#. "A ref pointing to a tag or commit object" +msgid "tag [noun]" +msgstr "tag" + +#. "" +msgid "tag [verb]" +msgstr "criar tag" + +#. "A regular git branch that is used to follow changes from another repository." +msgid "tracking branch" +msgstr "ramo de monitorização" + +#. "" +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" + +#. "a commit that succeeds the current one in git's graph of commits (not necessarily directly)" +msgid "ancestor" +msgstr "antecessor" + +#. "prematurely stop and abandon an operation" +msgid "abort" +msgstr "abortar" + +#. "a repository with only .git directory, without working directory" +msgid "bare repository" +msgstr "repositório nu" + +#. "a parent version of the current file" +msgid "base" +msgstr "base" + +#. "get the authors responsible for each line in a file" +msgid "blame" +msgstr "culpar" + +#. "to select and apply a single commit without merging" +msgid "cherry-pick" +msgstr "efetuar cherry-pick (escolher-a-dedo?, selecionar?)" + +#. "a commit that directly succeeds the current one in git's graph of commits" +msgid "child" +msgstr "filho" + +#. "clean the state of the git repository, often after manually stopped operation" +msgid "cleanup" +msgstr "limpar" + +#. "a message that gets attached with any commit" +msgid "commit message" +msgstr "mensagem de commit" + +#. "a commit that precedes the current one in git's graph of commits (not necessarily directly)" +msgid "descendant" +msgstr "descendente" + +#. "checkout of a revision rather than a some head" +msgid "detached checkout" +msgstr "extração destacada" + +#. "any merge strategy that works on a file by file basis" +msgid "file level merging" +msgstr "integração ao nível de ficheiros" + +#. "the last revision in a branch" +msgid "head" +msgstr "cabeça" + +#. "script that gets executed automatically on some event" +msgid "hook" +msgstr "gancho" + +#. "the first checkout during a clone operation" +msgid "initial checkout" +msgstr "extração inicial" + +#. "a branch that resides in the local git repository" +msgid "local branch" +msgstr "ramo local" + +#. "a Git object that is not part of any pack" +msgid "loose object" +msgstr "objeto solto" + +#. "a branch called by convention 'master' that exists in a newly created git repository" +msgid "master branch" +msgstr "ramo mestre" + +#. "a remote called by convention 'origin' that the current git repository has been cloned from" +msgid "origin" +msgstr "origem" + +#. "a file containing many git objects packed together" +msgid "pack [noun]" +msgstr "pacote" + +#. "a Git object part of some pack" +msgid "packed object" +msgstr "objeto compactado" + +#. "a commit that directly precedes the current one in git's graph of commits" +msgid "parent" +msgstr "pai" + +#. "the log file containing all states of the HEAD reference (in other words past pristine states of the working copy)" +msgid "reflog" +msgstr "reflog" + +#. "decide which changes from alternative versions of a file should persist in Git" +msgid "resolve (a conflict)" +msgstr "resolver (um conflito)" + +#. "abandon changes and go to pristine version" +msgid "revert changes" +msgstr "reverter alterações" + +#. "expression that signifies a revision in git" +msgid "revision expression" +msgstr "expressão de revisão" + +#. "add some content of files and directories to the staging area in preparation for a commit" +msgid "stage/unstage" +msgstr "preparar/retirar" + +#. "temporarily save changes in a stack without committing" +msgid "stash" +msgstr "empilhar" + +#. "file whose content is tracked/not tracked by git" +msgid "tracked/untracked" +msgstr "controlado/não controlado" diff --git a/git-gui/po/pt_pt.po b/git-gui/po/pt_pt.po new file mode 100644 index 0000000000..0ef3c7927d --- /dev/null +++ b/git-gui/po/pt_pt.po @@ -0,0 +1,2716 @@ +# Portuguese translations for git-gui package. +# Copyright (C) 2016 Shawn Pearce, et al. +# This file is distributed under the same license as the git package. +# Vasco Almeida <vascomalmeida@sapo.pt>, 2016. +msgid "" +msgstr "" +"Project-Id-Version: git-gui\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-05-06 09:36+0000\n" +"PO-Revision-Date: 2016-05-06 13:09+0000\n" +"Last-Translator: Vasco Almeida <vascomalmeida@sapo.pt>\n" +"Language-Team: Portuguese\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Virtaal 0.7.1\n" + +#: git-gui.sh:861 +#, tcl-format +msgid "Invalid font specified in %s:" +msgstr "Tipo de letra inválido especificado em %s:" + +#: git-gui.sh:915 +msgid "Main Font" +msgstr "Tipo de letra principal" + +#: git-gui.sh:916 +msgid "Diff/Console Font" +msgstr "Tipo de letra Diferenças/Consola" + +#: git-gui.sh:931 git-gui.sh:945 git-gui.sh:958 git-gui.sh:1048 +#: git-gui.sh:1067 git-gui.sh:3125 +msgid "git-gui: fatal error" +msgstr "git-gui: erro fatal" + +#: git-gui.sh:932 +msgid "Cannot find git in PATH." +msgstr "Não é possível encontrar o git em PATH." + +#: git-gui.sh:959 +msgid "Cannot parse Git version string:" +msgstr "Não é possível analisar a versão do Git:" + +#: git-gui.sh:984 +#, 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 "" +"A versão do Git não pôde ser determinada.\n" +"\n" +"%s alega que está na versão '%s'.\n" +"\n" +"%s requer pelo menos Git 1.5.0 ou mais recente.\n" +"\n" +"Assumir que '%s' está na versão 1.5.0?\n" + +#: git-gui.sh:1281 +msgid "Git directory not found:" +msgstr "Diretório Git não encontrado:" + +#: git-gui.sh:1315 +msgid "Cannot move to top of working directory:" +msgstr "Não é possível mover para o topo do diretório de trabalho:" + +#: git-gui.sh:1323 +msgid "Cannot use bare repository:" +msgstr "Não é possível usar repositório nu:" + +#: git-gui.sh:1331 +msgid "No working directory" +msgstr "Nenhum diretório de trabalho" + +#: git-gui.sh:1503 lib/checkout_op.tcl:306 +msgid "Refreshing file status..." +msgstr "A atualizar estado do ficheiro..." + +#: git-gui.sh:1563 +msgid "Scanning for modified files ..." +msgstr "A procurar por ficheiros modificados..." + +#: git-gui.sh:1639 +msgid "Calling prepare-commit-msg hook..." +msgstr "" +"A invocar gancho preparar-mensagem-de-commit (prepare-commit-msg hook)..." + +#: git-gui.sh:1656 +msgid "Commit declined by prepare-commit-msg hook." +msgstr "" +"Commit recusado pelo gancho preparar-mensagem-de-commit (prepare-commit-msg " +"hook)." + +#: git-gui.sh:1814 lib/browser.tcl:252 +msgid "Ready." +msgstr "Pronto." + +#: git-gui.sh:1978 +#, tcl-format +msgid "" +"Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files." +msgstr "" +"Limite de visualização (gui.maxfilesdisplayed = %s) atingido, não são " +"mostrados todos os %s ficheiros." + +#: git-gui.sh:2101 +msgid "Unmodified" +msgstr "Não modificado" + +#: git-gui.sh:2103 +msgid "Modified, not staged" +msgstr "Modificado, não preparado" + +#: git-gui.sh:2104 git-gui.sh:2116 +msgid "Staged for commit" +msgstr "Preparado para commit" + +#: git-gui.sh:2105 git-gui.sh:2117 +msgid "Portions staged for commit" +msgstr "Porções preparadas para commit" + +#: git-gui.sh:2106 git-gui.sh:2118 +msgid "Staged for commit, missing" +msgstr "Preparado para commit, em falta" + +#: git-gui.sh:2108 +msgid "File type changed, not staged" +msgstr "Tipo de ficheiro modificado, não preparado" + +#: git-gui.sh:2109 git-gui.sh:2110 +msgid "File type changed, old type staged for commit" +msgstr "Tipo de ficheiro modificado, tipo antigo preparado para commit" + +#: git-gui.sh:2111 +msgid "File type changed, staged" +msgstr "Tipo de ficheiro modificado, preparado" + +#: git-gui.sh:2112 +msgid "File type change staged, modification not staged" +msgstr "Tipo de ficheiro modificado, modificação não preparada" + +#: git-gui.sh:2113 +msgid "File type change staged, file missing" +msgstr "Tipo de ficheiro modificado, ficheiro em falta" + +#: git-gui.sh:2115 +msgid "Untracked, not staged" +msgstr "Não controlado, não preparado" + +#: git-gui.sh:2120 +msgid "Missing" +msgstr "Em falta" + +#: git-gui.sh:2121 +msgid "Staged for removal" +msgstr "Preparado para remoção" + +#: git-gui.sh:2122 +msgid "Staged for removal, still present" +msgstr "Preparado para remoção, ainda presente" + +#: git-gui.sh:2124 git-gui.sh:2125 git-gui.sh:2126 git-gui.sh:2127 +#: git-gui.sh:2128 git-gui.sh:2129 +msgid "Requires merge resolution" +msgstr "Requer resolução de integração" + +#: git-gui.sh:2164 +msgid "Starting gitk... please wait..." +msgstr "A iniciar gitk... aguarde..." + +#: git-gui.sh:2176 +msgid "Couldn't find gitk in PATH" +msgstr "Não foi possível encontrar gitk em PATH" + +#: git-gui.sh:2235 +msgid "Couldn't find git gui in PATH" +msgstr "Não foi possível encontrar git gui em PATH" + +#: git-gui.sh:2654 lib/choose_repository.tcl:41 +msgid "Repository" +msgstr "Repositório" + +#: git-gui.sh:2655 +msgid "Edit" +msgstr "Editar" + +#: git-gui.sh:2657 lib/choose_rev.tcl:567 +msgid "Branch" +msgstr "Ramo" + +#: git-gui.sh:2660 lib/choose_rev.tcl:554 +msgid "Commit@@noun" +msgstr "Commit" + +#: git-gui.sh:2663 lib/merge.tcl:123 lib/merge.tcl:152 lib/merge.tcl:170 +msgid "Merge" +msgstr "Integrar" + +#: git-gui.sh:2664 lib/choose_rev.tcl:563 +msgid "Remote" +msgstr "Remoto" + +#: git-gui.sh:2667 +msgid "Tools" +msgstr "Ferramentas" + +#: git-gui.sh:2676 +msgid "Explore Working Copy" +msgstr "Explorar cópia de trabalho" + +#: git-gui.sh:2682 +msgid "Git Bash" +msgstr "Git Bash" + +#: git-gui.sh:2692 +msgid "Browse Current Branch's Files" +msgstr "Navegar pelos ficheiro do ramo atual" + +#: git-gui.sh:2696 +msgid "Browse Branch Files..." +msgstr "Navegar pelos ficheiros do ramo..." + +#: git-gui.sh:2701 +msgid "Visualize Current Branch's History" +msgstr "Visualizar histórico do ramo atual" + +#: git-gui.sh:2705 +msgid "Visualize All Branch History" +msgstr "Visualizar histórico de todos os ramos" + +#: git-gui.sh:2712 +#, tcl-format +msgid "Browse %s's Files" +msgstr "Navegar pelos ficheiro de %s" + +#: git-gui.sh:2714 +#, tcl-format +msgid "Visualize %s's History" +msgstr "Visualizar histórico de %s" + +#: git-gui.sh:2719 lib/database.tcl:40 lib/database.tcl:66 +msgid "Database Statistics" +msgstr "Estatísticas da base de dados" + +#: git-gui.sh:2722 lib/database.tcl:33 +msgid "Compress Database" +msgstr "Comprimir base de dados" + +#: git-gui.sh:2725 +msgid "Verify Database" +msgstr "Verificar base de dados" + +#: git-gui.sh:2732 git-gui.sh:2736 git-gui.sh:2740 lib/shortcut.tcl:8 +#: lib/shortcut.tcl:40 lib/shortcut.tcl:72 +msgid "Create Desktop Icon" +msgstr "Criar ícone no ambiente de trabalho" + +#: git-gui.sh:2748 lib/choose_repository.tcl:193 lib/choose_repository.tcl:201 +msgid "Quit" +msgstr "Sair" + +#: git-gui.sh:2756 +msgid "Undo" +msgstr "Desfazer" + +#: git-gui.sh:2759 +msgid "Redo" +msgstr "Refazer" + +#: git-gui.sh:2763 git-gui.sh:3368 +msgid "Cut" +msgstr "Cortar" + +#: git-gui.sh:2766 git-gui.sh:3371 git-gui.sh:3445 git-gui.sh:3530 +#: lib/console.tcl:69 +msgid "Copy" +msgstr "Copiar" + +#: git-gui.sh:2769 git-gui.sh:3374 +msgid "Paste" +msgstr "Colar" + +#: git-gui.sh:2772 git-gui.sh:3377 lib/remote_branch_delete.tcl:39 +#: lib/branch_delete.tcl:28 +msgid "Delete" +msgstr "Eliminar" + +#: git-gui.sh:2776 git-gui.sh:3381 git-gui.sh:3534 lib/console.tcl:71 +msgid "Select All" +msgstr "Selecionar tudo" + +#: git-gui.sh:2785 +msgid "Create..." +msgstr "Criar..." + +#: git-gui.sh:2791 +msgid "Checkout..." +msgstr "Extrair..." + +#: git-gui.sh:2797 +msgid "Rename..." +msgstr "Mudar nome..." + +#: git-gui.sh:2802 +msgid "Delete..." +msgstr "Eliminar..." + +#: git-gui.sh:2807 +msgid "Reset..." +msgstr "Repor..." + +#: git-gui.sh:2817 +msgid "Done" +msgstr "Concluído" + +#: git-gui.sh:2819 +msgid "Commit@@verb" +msgstr "Submeter" + +#: git-gui.sh:2828 git-gui.sh:3309 +msgid "New Commit" +msgstr "Novo commit" + +#: git-gui.sh:2836 git-gui.sh:3316 +msgid "Amend Last Commit" +msgstr "Emendar último commit" + +#: git-gui.sh:2846 git-gui.sh:3270 lib/remote_branch_delete.tcl:101 +msgid "Rescan" +msgstr "Reanalisar" + +#: git-gui.sh:2852 +msgid "Stage To Commit" +msgstr "Preparar para commit" + +#: git-gui.sh:2858 +msgid "Stage Changed Files To Commit" +msgstr "Preparar ficheiros modificados para commit" + +#: git-gui.sh:2864 +msgid "Unstage From Commit" +msgstr "Retirar do commit" + +#: git-gui.sh:2870 lib/index.tcl:442 +msgid "Revert Changes" +msgstr "Reverter alterações" + +#: git-gui.sh:2878 git-gui.sh:3581 git-gui.sh:3612 +msgid "Show Less Context" +msgstr "Mostrar menos contexto" + +#: git-gui.sh:2882 git-gui.sh:3585 git-gui.sh:3616 +msgid "Show More Context" +msgstr "Mostrar mais contexto" + +#: git-gui.sh:2889 git-gui.sh:3283 git-gui.sh:3392 +msgid "Sign Off" +msgstr "Assinar por baixo" + +#: git-gui.sh:2905 +msgid "Local Merge..." +msgstr "Integração local..." + +#: git-gui.sh:2910 +msgid "Abort Merge..." +msgstr "Abortar integração..." + +#: git-gui.sh:2922 git-gui.sh:2950 +msgid "Add..." +msgstr "Adicionar..." + +#: git-gui.sh:2926 +msgid "Push..." +msgstr "Publicar..." + +#: git-gui.sh:2930 +msgid "Delete Branch..." +msgstr "Eliminar ramo..." + +#: git-gui.sh:2940 git-gui.sh:3563 +msgid "Options..." +msgstr "Opções..." + +#: git-gui.sh:2951 +msgid "Remove..." +msgstr "Remover..." + +#: git-gui.sh:2960 lib/choose_repository.tcl:55 +msgid "Help" +msgstr "Ajuda" + +#: git-gui.sh:2964 git-gui.sh:2968 lib/choose_repository.tcl:49 +#: lib/choose_repository.tcl:58 lib/about.tcl:14 +#, tcl-format +msgid "About %s" +msgstr "Sobre %s" + +#: git-gui.sh:2992 +msgid "Online Documentation" +msgstr "Documentação online" + +#: git-gui.sh:2995 lib/choose_repository.tcl:52 lib/choose_repository.tcl:61 +msgid "Show SSH Key" +msgstr "Mostrar chave SSH" + +#: git-gui.sh:3014 git-gui.sh:3146 +msgid "Usage" +msgstr "Utilização" + +#: git-gui.sh:3095 lib/blame.tcl:573 +msgid "Error" +msgstr "Erro" + +#: git-gui.sh:3126 +#, tcl-format +msgid "fatal: cannot stat path %s: No such file or directory" +msgstr "" +"fatal: não é possível obter estado do caminho %s: Ficheiro ou diretório " +"inexistente" + +#: git-gui.sh:3159 +msgid "Current Branch:" +msgstr "Ramo atual:" + +#: git-gui.sh:3185 +msgid "Staged Changes (Will Commit)" +msgstr "Alterações preparadas (para commit)" + +#: git-gui.sh:3205 +msgid "Unstaged Changes" +msgstr "Alterações não preparadas" + +#: git-gui.sh:3276 +msgid "Stage Changed" +msgstr "Preparar modificados" + +#: git-gui.sh:3295 lib/transport.tcl:137 lib/transport.tcl:229 +msgid "Push" +msgstr "Publicar" + +#: git-gui.sh:3330 +msgid "Initial Commit Message:" +msgstr "Mensagem de commit inicial:" + +#: git-gui.sh:3331 +msgid "Amended Commit Message:" +msgstr "Mensagem de commit emendada:" + +#: git-gui.sh:3332 +msgid "Amended Initial Commit Message:" +msgstr "Mensagem de commit inicial emendada:" + +#: git-gui.sh:3333 +msgid "Amended Merge Commit Message:" +msgstr "Mensagem de commit de integração emendada:" + +#: git-gui.sh:3334 +msgid "Merge Commit Message:" +msgstr "Mensagem de commit de integração:" + +#: git-gui.sh:3335 +msgid "Commit Message:" +msgstr "Mensagem de commit:" + +#: git-gui.sh:3384 git-gui.sh:3538 lib/console.tcl:73 +msgid "Copy All" +msgstr "Copiar tudo" + +#: git-gui.sh:3408 lib/blame.tcl:105 +msgid "File:" +msgstr "Ficheiro:" + +#: git-gui.sh:3526 +msgid "Refresh" +msgstr "Atualizar" + +#: git-gui.sh:3547 +msgid "Decrease Font Size" +msgstr "Diminuir tamanho de letra" + +#: git-gui.sh:3551 +msgid "Increase Font Size" +msgstr "Aumentar tamanho de letra" + +#: git-gui.sh:3559 lib/blame.tcl:294 +msgid "Encoding" +msgstr "Codificação" + +#: git-gui.sh:3570 +msgid "Apply/Reverse Hunk" +msgstr "Aplicar/Reverter excerto" + +#: git-gui.sh:3575 +msgid "Apply/Reverse Line" +msgstr "Aplicar/Reverter linha" + +#: git-gui.sh:3594 +msgid "Run Merge Tool" +msgstr "Executar ferramenta de integração" + +#: git-gui.sh:3599 +msgid "Use Remote Version" +msgstr "Usar a versão remota" + +#: git-gui.sh:3603 +msgid "Use Local Version" +msgstr "Usar a versão local" + +#: git-gui.sh:3607 +msgid "Revert To Base" +msgstr "Reverter para a base" + +#: git-gui.sh:3625 +msgid "Visualize These Changes In The Submodule" +msgstr "Visualizar estas alterações no submódulo" + +#: git-gui.sh:3629 +msgid "Visualize Current Branch History In The Submodule" +msgstr "Visualizar histórico do ramo atual no submódulo" + +#: git-gui.sh:3633 +msgid "Visualize All Branch History In The Submodule" +msgstr "Visualizar histórico de todos os ramos no submódulo" + +#: git-gui.sh:3638 +msgid "Start git gui In The Submodule" +msgstr "Iniciar git gui no submódulo" + +#: git-gui.sh:3673 +msgid "Unstage Hunk From Commit" +msgstr "Retirar excerto do commit" + +#: git-gui.sh:3675 +msgid "Unstage Lines From Commit" +msgstr "Retirar linhas do commit" + +#: git-gui.sh:3677 +msgid "Unstage Line From Commit" +msgstr "Retirar linha do commit" + +#: git-gui.sh:3680 +msgid "Stage Hunk For Commit" +msgstr "Preparar excerto para commit" + +#: git-gui.sh:3682 +msgid "Stage Lines For Commit" +msgstr "Preparar linhas para commit" + +#: git-gui.sh:3684 +msgid "Stage Line For Commit" +msgstr "Preparar linha para commit" + +#: git-gui.sh:3709 +msgid "Initializing..." +msgstr "A inicializar..." + +#: git-gui.sh:3852 +#, 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 "" +"Existem possíveis erros de ambiente.\n" +"\n" +"As seguintes variáveis de ambiente serão provavelmente\n" +"ignoradas pelos subprocessos do Git executados\n" +"por %s:\n" +"\n" + +#: git-gui.sh:3881 +msgid "" +"\n" +"This is due to a known issue with the\n" +"Tcl binary distributed by Cygwin." +msgstr "" +"\n" +"Devido a um problema conhecido com o\n" +"binário Tcl distribuído pelo Cygwin." + +#: git-gui.sh:3886 +#, 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" +"Um bom substituto para %s\n" +"é colocar valores das definições user.name e\n" +"user.email no ficheiro pessoal ~/.gitconfig.\n" + +#: lib/line.tcl:17 +msgid "Goto Line:" +msgstr "Ir para a linha:" + +#: lib/line.tcl:23 +msgid "Go" +msgstr "Ir" + +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "A processar... aguarde..." + +#: lib/console.tcl:81 lib/checkout_op.tcl:146 lib/sshkey.tcl:55 +#: lib/database.tcl:30 +msgid "Close" +msgstr "Fechar" + +#: lib/console.tcl:186 +msgid "Success" +msgstr "Sucesso" + +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "Erro: falha ao executar comando" + +#: lib/checkout_op.tcl:85 +#, tcl-format +msgid "Fetching %s from %s" +msgstr "A obter %s de %s" + +#: lib/checkout_op.tcl:133 +#, tcl-format +msgid "fatal: Cannot resolve %s" +msgstr "fatal: Não é possível resolver %s" + +#: 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 "Falha ao configurar git-pull simplificado de '%s'." + +#: lib/checkout_op.tcl:202 lib/branch_rename.tcl:102 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "O ramo '%s' já existe." + +#: 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 pode ser avançado rapidamente para %s.\n" +"Integração necessária." + +#: lib/checkout_op.tcl:243 +#, tcl-format +msgid "Merge strategy '%s' not supported." +msgstr "A estratégia de integração '%s' não é suportada." + +#: lib/checkout_op.tcl:262 +#, tcl-format +msgid "Failed to update '%s'." +msgstr "Falha ao atualizar '%s'." + +#: lib/checkout_op.tcl:274 +msgid "Staging area (index) is already locked." +msgstr "A área de estágio (índice) 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 analisado não corresponde ao estado do repositório.\n" +"\n" +"Outro programa Git modificou este repositório deste a última análise. Deve-" +"se reanalisar antes do ramo atual poder ser alterado.\n" +"\n" +"Irá-se reanalisar automaticamente agora.\n" + +#: lib/checkout_op.tcl:345 +#, tcl-format +msgid "Updating working directory to '%s'..." +msgstr "A atualizar o diretório de trabalho para '%s'..." + +#: lib/checkout_op.tcl:346 +msgid "files checked out" +msgstr "ficheiros extraídos" + +#: lib/checkout_op.tcl:376 +#, tcl-format +msgid "Aborted checkout of '%s' (file level merging is required)." +msgstr "" +"Extração de '%s' abortada (é necessário integrar ao nível de ficheiros)." + +#: lib/checkout_op.tcl:377 +msgid "File level merge required." +msgstr "Integração ao nível de ficheiros necessária." + +#: lib/checkout_op.tcl:381 +#, tcl-format +msgid "Staying on branch '%s'." +msgstr "Permanecer 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 "" +"Já não se encontra num ramo local.\n" +"\n" +"Se queria estar sobre um ramo, crie um a partir de 'Esta extração destacada'." + +#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 +#, tcl-format +msgid "Checked out '%s'." +msgstr "'%s' extraído." + +#: lib/checkout_op.tcl:535 +#, tcl-format +msgid "Resetting '%s' to '%s' will lose the following commits:" +msgstr "Ao repor '%s' para '%s' perderá os seguintes commits:" + +#: lib/checkout_op.tcl:557 +msgid "Recovering lost commits may not be easy." +msgstr "Recuperar commits perdidos pode não ser fácil." + +#: lib/checkout_op.tcl:562 +#, tcl-format +msgid "Reset '%s'?" +msgstr "Repor '%s'?" + +#: lib/checkout_op.tcl:567 lib/tools_dlg.tcl:336 lib/merge.tcl:166 +msgid "Visualize" +msgstr "Visualizar" + +#: lib/checkout_op.tcl:571 lib/branch_create.tcl:85 +msgid "Reset" +msgstr "Repor" + +#: lib/checkout_op.tcl:579 lib/transport.tcl:141 lib/remote_add.tcl:34 +#: lib/browser.tcl:292 lib/branch_checkout.tcl:30 lib/choose_font.tcl:45 +#: lib/option.tcl:127 lib/tools_dlg.tcl:41 lib/tools_dlg.tcl:202 +#: lib/tools_dlg.tcl:345 lib/branch_rename.tcl:32 +#: lib/remote_branch_delete.tcl:43 lib/branch_create.tcl:37 +#: lib/branch_delete.tcl:34 lib/merge.tcl:174 +msgid "Cancel" +msgstr "Cancelar" + +#: 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 "" +"Falha ao definir ramo atual.\n" +"\n" +"Apenas se mudou o diretório de trabalho parcialmente. Os ficheiros foram " +"atualizados com sucesso, mas não foi possível atualizar o ficheiro Git " +"interno.\n" +"\n" +"Não devia ter ocorrido. %s irá terminar e desistir." + +#: lib/transport.tcl:6 lib/remote_add.tcl:132 +#, tcl-format +msgid "fetch %s" +msgstr "obter %s" + +#: lib/transport.tcl:7 +#, tcl-format +msgid "Fetching new changes from %s" +msgstr "Obter novas alterações de %s" + +#: lib/transport.tcl:18 +#, tcl-format +msgid "remote prune %s" +msgstr "poda remota de %s" + +#: lib/transport.tcl:19 +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "A podar ramos de monitorização eliminados de %s" + +#: lib/transport.tcl:25 +msgid "fetch all remotes" +msgstr "obter de todos os remotos" + +#: lib/transport.tcl:26 +msgid "Fetching new changes from all remotes" +msgstr "A obter novas alterações de todos os remotos" + +#: lib/transport.tcl:40 +msgid "remote prune all remotes" +msgstr "poda remota de todos os remotos" + +#: lib/transport.tcl:41 +msgid "Pruning tracking branches deleted from all remotes" +msgstr "A podar ramos de monitorização eliminados de todos os remotos" + +#: lib/transport.tcl:54 lib/transport.tcl:92 lib/transport.tcl:110 +#: lib/remote_add.tcl:162 +#, tcl-format +msgid "push %s" +msgstr "publicar %s" + +#: lib/transport.tcl:55 +#, tcl-format +msgid "Pushing changes to %s" +msgstr "A publicar alterações em %s" + +#: lib/transport.tcl:93 +#, tcl-format +msgid "Mirroring to %s" +msgstr "A espelhar em %s" + +#: lib/transport.tcl:111 +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "A publicar %s %s em %s" + +#: lib/transport.tcl:132 +msgid "Push Branches" +msgstr "Publicar ramos" + +#: lib/transport.tcl:147 +msgid "Source Branches" +msgstr "Ramos de origem" + +#: lib/transport.tcl:162 +msgid "Destination Repository" +msgstr "Repositório de destino" + +#: lib/transport.tcl:165 lib/remote_branch_delete.tcl:51 +msgid "Remote:" +msgstr "Remoto:" + +#: lib/transport.tcl:187 lib/remote_branch_delete.tcl:72 +msgid "Arbitrary Location:" +msgstr "Localização arbitrária:" + +#: lib/transport.tcl:205 +msgid "Transfer Options" +msgstr "Opções de transferência" + +#: lib/transport.tcl:207 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "Forçar substituição de ramos existente (pode descartar alterações)" + +#: lib/transport.tcl:211 +msgid "Use thin pack (for slow network connections)" +msgstr "Usar pacote fino (para conexões de rede lentas)" + +#: lib/transport.tcl:215 +msgid "Include tags" +msgstr "Incluir tags" + +#: lib/remote_add.tcl:20 +msgid "Add Remote" +msgstr "Adicionar remoto" + +#: lib/remote_add.tcl:25 +msgid "Add New Remote" +msgstr "Adicionar novo remoto" + +#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 +msgid "Add" +msgstr "Adicionar" + +#: lib/remote_add.tcl:39 +msgid "Remote Details" +msgstr "Detalhes do remoto" + +#: lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 lib/branch_create.tcl:44 +msgid "Name:" +msgstr "Nome:" + +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Localização:" + +#: lib/remote_add.tcl:60 +msgid "Further Action" +msgstr "Ação adicional" + +#: lib/remote_add.tcl:63 +msgid "Fetch Immediately" +msgstr "Obter imediatamente" + +#: lib/remote_add.tcl:69 +msgid "Initialize Remote Repository and Push" +msgstr "Inicializar repositório remoto e publicar" + +#: lib/remote_add.tcl:75 +msgid "Do Nothing Else Now" +msgstr "Não fazer mais nada agora" + +#: lib/remote_add.tcl:100 +msgid "Please supply a remote name." +msgstr "Forneça um nome para o remoto." + +#: lib/remote_add.tcl:113 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "'%s' não pode ser aceite como nome de remoto." + +#: lib/remote_add.tcl:124 +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Falha ao adicionar remoto '%s' localizado em '%s'." + +#: lib/remote_add.tcl:133 +#, tcl-format +msgid "Fetching the %s" +msgstr "A obter de %s" + +#: lib/remote_add.tcl:156 +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Não se sabe como inicializar o repositório localizado em '%s'." + +#: lib/remote_add.tcl:163 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "A configurar %s (em %s)" + +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "A iniciar..." + +#: lib/browser.tcl:27 +msgid "File Browser" +msgstr "Navegador de ficheiros" + +#: lib/browser.tcl:132 lib/browser.tcl:149 +#, tcl-format +msgid "Loading %s..." +msgstr "A carregar %s..." + +#: lib/browser.tcl:193 +msgid "[Up To Parent]" +msgstr "[Subir]" + +#: lib/browser.tcl:275 lib/browser.tcl:282 +msgid "Browse Branch Files" +msgstr "Navegar pelos ficheiros do ramo" + +#: lib/browser.tcl:288 lib/choose_repository.tcl:422 +#: lib/choose_repository.tcl:509 lib/choose_repository.tcl:518 +#: lib/choose_repository.tcl:1074 +msgid "Browse" +msgstr "Navegar" + +#: lib/browser.tcl:297 lib/branch_checkout.tcl:35 lib/tools_dlg.tcl:321 +msgid "Revision" +msgstr "Revisão" + +#: lib/tools.tcl:75 +#, tcl-format +msgid "Running %s requires a selected file." +msgstr "Deve selecionar um ficheiro para executar %s." + +#: lib/tools.tcl:91 +#, tcl-format +msgid "Are you sure you want to run %1$s on file \"%2$s\"?" +msgstr "Tem a certeza que pretende executar %1$s sobre o ficheiro \"%2$s\"?" + +#: lib/tools.tcl:95 +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Tem a certeza que pretende executar %s?" + +#: lib/tools.tcl:116 +#, tcl-format +msgid "Tool: %s" +msgstr "Ferramenta: %s" + +#: lib/tools.tcl:117 +#, tcl-format +msgid "Running: %s" +msgstr "A executar: %s" + +#: lib/tools.tcl:155 +#, tcl-format +msgid "Tool completed successfully: %s" +msgstr "A ferramenta concluí com sucesso: %s" + +#: lib/tools.tcl:157 +#, tcl-format +msgid "Tool failed: %s" +msgstr "A ferramenta falhou: %s" + +#: lib/branch_checkout.tcl:16 lib/branch_checkout.tcl:21 +msgid "Checkout Branch" +msgstr "Extrair ramo" + +#: lib/branch_checkout.tcl:26 +msgid "Checkout" +msgstr "Extrair" + +#: lib/branch_checkout.tcl:39 lib/option.tcl:310 lib/branch_create.tcl:69 +msgid "Options" +msgstr "Opções" + +#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "Obter ramo de monitorização" + +#: lib/branch_checkout.tcl:47 +msgid "Detach From Local Branch" +msgstr "Destacar do ramo local" + +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "Corretor ortográfico não suportado" + +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "Correção ortográfica indisponível" + +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "Configuração inválida do corretor ortográfico" + +#: lib/spellcheck.tcl:70 +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "A reverter dicionário para %s." + +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" +msgstr "O corretor ortográfico falhou silenciosamente ao iniciar" + +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" +msgstr "Corretor 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 "EOF (fim de ficheiro) inesperado do corretor ortográfico" + +#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "Corretor ortográfico falhou" + +#: lib/status_bar.tcl:87 +#, tcl-format +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s ... %*i de %*i %s (%3i%%)" + +#: lib/diff.tcl:77 +#, 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 "" +"Nenhum diferença detetada.\n" +"\n" +"%s não tem alterações.\n" +"\n" +"A data de modificação deste ficheiro foi atualizada por outra aplicação, mas " +"o conteúdo no interior do ficheiro não foi alterado.\n" +"\n" +"Irá-se reanalisar automaticamente para encontrar outros ficheiros que " +"estejam no mesmo estado." + +#: lib/diff.tcl:117 +#, tcl-format +msgid "Loading diff of %s..." +msgstr "A carregar diferenças de %s..." + +#: lib/diff.tcl:140 +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"LOCAL: eliminado\n" +"REMOTO:\n" + +#: lib/diff.tcl:145 +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"REMOTO: eliminado\n" +"LOCAL:\n" + +#: lib/diff.tcl:152 +msgid "LOCAL:\n" +msgstr "LOCAL:\n" + +#: lib/diff.tcl:155 +msgid "REMOTE:\n" +msgstr "REMOTO:\n" + +#: lib/diff.tcl:217 lib/diff.tcl:355 +#, tcl-format +msgid "Unable to display %s" +msgstr "Não é possível mostrar %s" + +#: lib/diff.tcl:218 +msgid "Error loading file:" +msgstr "Erro ao carregar ficheiro:" + +#: lib/diff.tcl:225 +msgid "Git Repository (subproject)" +msgstr "Repositório Git (subprojeto)" + +#: lib/diff.tcl:237 +msgid "* Binary file (not showing content)." +msgstr "* Ficheiro binário (conteúdo não exibido)." + +#: lib/diff.tcl:242 +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" +"* O ficheiro não controlado tem %d bytes.\n" +"* Exibido apenas os primeiros %d bytes.\n" + +#: lib/diff.tcl:248 +#, tcl-format +msgid "" +"\n" +"* Untracked file clipped here by %s.\n" +"* To see the entire file, use an external editor.\n" +msgstr "" +"\n" +"* Ficheiro não controlado recortado aqui por %s.\n" +"* Para ver o ficheiro inteiro, use um editor externo.\n" + +#: lib/diff.tcl:356 lib/blame.tcl:1128 +msgid "Error loading diff:" +msgstr "Erro ao carregar diferenças:" + +#: lib/diff.tcl:578 +msgid "Failed to unstage selected hunk." +msgstr "Falha ao retirar excerto selecionado do índice." + +#: lib/diff.tcl:585 +msgid "Failed to stage selected hunk." +msgstr "Falha ao preparar excerto selecionado." + +#: lib/diff.tcl:664 +msgid "Failed to unstage selected line." +msgstr "Falha ao retirar linha selecionada do índice." + +#: lib/diff.tcl:672 +msgid "Failed to stage selected line." +msgstr "Falha ao preparar linha selecionada." + +#: lib/remote.tcl:200 +msgid "Push to" +msgstr "Publicar em" + +#: lib/remote.tcl:218 +msgid "Remove Remote" +msgstr "Remover remoto" + +#: lib/remote.tcl:223 +msgid "Prune from" +msgstr "Podar de" + +#: lib/remote.tcl:228 +msgid "Fetch from" +msgstr "Obter de" + +#: lib/choose_font.tcl:41 +msgid "Select" +msgstr "Selecionar" + +#: lib/choose_font.tcl:55 +msgid "Font Family" +msgstr "Família de tipo de letra" + +#: lib/choose_font.tcl:76 +msgid "Font Size" +msgstr "Tamanho de letra" + +#: lib/choose_font.tcl:93 +msgid "Font Example" +msgstr "Exemplo do tipo de letra" + +#: lib/choose_font.tcl:105 +msgid "" +"This is example text.\n" +"If you like this text, it can be your font." +msgstr "" +"Este texto é um exemplo.\n" +"Se gostar deste texto, pode defini-lo como tipo de letra." + +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Codificação global '%s' inválida" + +#: lib/option.tcl:19 +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Codificação do repositório '%s' inválida" + +#: lib/option.tcl:119 +msgid "Restore Defaults" +msgstr "Restaurar predefinições" + +#: lib/option.tcl:123 +msgid "Save" +msgstr "Guardar" + +#: lib/option.tcl:133 +#, tcl-format +msgid "%s Repository" +msgstr "Repositório %s" + +#: lib/option.tcl:134 +msgid "Global (All Repositories)" +msgstr "Global (todos os repositórios)" + +#: lib/option.tcl:140 +msgid "User Name" +msgstr "Nome de utilizador" + +#: lib/option.tcl:141 +msgid "Email Address" +msgstr "Endereço de e-mail" + +#: lib/option.tcl:143 +msgid "Summarize Merge Commits" +msgstr "Resumir commits de integração" + +#: lib/option.tcl:144 +msgid "Merge Verbosity" +msgstr "Verbosidade de integração" + +#: lib/option.tcl:145 +msgid "Show Diffstat After Merge" +msgstr "Mostrar estatísticas de diferenças depois de integrar" + +#: lib/option.tcl:146 +msgid "Use Merge Tool" +msgstr "Usar ferramenta de integração" + +#: lib/option.tcl:148 +msgid "Trust File Modification Timestamps" +msgstr "Confiar na data de modificação dos ficheiros" + +#: lib/option.tcl:149 +msgid "Prune Tracking Branches During Fetch" +msgstr "Podar ramos de monitorização ao obter" + +#: lib/option.tcl:150 +msgid "Match Tracking Branches" +msgstr "Corresponder ramos de monitorização" + +#: lib/option.tcl:151 +msgid "Use Textconv For Diffs and Blames" +msgstr "Usar textconv para mostrar diferenças e culpar" + +#: lib/option.tcl:152 +msgid "Blame Copy Only On Changed Files" +msgstr "Detetar cópia apenas em ficheiros modificados" + +#: lib/option.tcl:153 +msgid "Maximum Length of Recent Repositories List" +msgstr "Comprimento máximo da lista de repositórios recentes" + +#: lib/option.tcl:154 +msgid "Minimum Letters To Blame Copy On" +msgstr "Número mínimo de letras para detetar cópia" + +#: lib/option.tcl:155 +msgid "Blame History Context Radius (days)" +msgstr "Raio de contexto histórico para culpar (dias)" + +#: lib/option.tcl:156 +msgid "Number of Diff Context Lines" +msgstr "Número de linhas de contexto ao mostrar diferenças" + +#: lib/option.tcl:157 +msgid "Additional Diff Parameters" +msgstr "Parâmetros de diff adicionais" + +#: lib/option.tcl:158 +msgid "Commit Message Text Width" +msgstr "Largura do texto da mensagem de commit" + +#: lib/option.tcl:159 +msgid "New Branch Name Template" +msgstr "Modelo para nome de novo ramo" + +#: lib/option.tcl:160 +msgid "Default File Contents Encoding" +msgstr "Codificação predefinida dos conteúdos de ficheiros" + +#: lib/option.tcl:161 +msgid "Warn before committing to a detached head" +msgstr "Avisar antes de submeter numa cabeça destacada" + +#: lib/option.tcl:162 +msgid "Staging of untracked files" +msgstr "Preparar ficheiros não controlados" + +#: lib/option.tcl:163 +msgid "Show untracked files" +msgstr "Mostrar ficheiros não controlados" + +#: lib/option.tcl:164 +msgid "Tab spacing" +msgstr "Espaçamento da tabulação" + +#: lib/option.tcl:210 +msgid "Change" +msgstr "Alterar" + +#: lib/option.tcl:254 +msgid "Spelling Dictionary:" +msgstr "Dicionário ortográfico:" + +#: lib/option.tcl:284 +msgid "Change Font" +msgstr "Alterar tipo de letra" + +#: lib/option.tcl:288 +#, tcl-format +msgid "Choose %s" +msgstr "Escolher %s" + +#: lib/option.tcl:294 +msgid "pt." +msgstr "pt." + +#: lib/option.tcl:308 +msgid "Preferences" +msgstr "Preferências" + +#: lib/option.tcl:345 +msgid "Failed to completely save options:" +msgstr "Falha ao guardar todas as opções:" + +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Forçar 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 as diferenças mostram apenas alterações em conflito.\n" +"\n" +"%s será substituído.\n" +"\n" +"Esta operação só pode ser anulada reiniciando a integração." + +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "" +"O ficheiro %s parece ter conflitos não resolvidos, prepará-lo mesmo assim?" + +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "A adicionar resolução de %s" + +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "" +"Não é possível resolver conflitos de exclusão ou ligação usando uma " +"ferramenta" + +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "O ficheiro em conflito não existe" + +#: lib/mergetool.tcl:246 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "Não é uma ferramenta GUI de integração: '%s'" + +#: lib/mergetool.tcl:275 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Ferramenta de integração '%s' não suportada" + +#: lib/mergetool.tcl:310 +msgid "Merge tool is already running, terminate it?" +msgstr "A ferramenta de integração já está a executar, terminá-la?" + +#: lib/mergetool.tcl:330 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Erro ao obter versões:\n" +"%s" + +#: lib/mergetool.tcl:350 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Não foi possível iniciar a ferramenta de integração:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:354 +msgid "Running merge tool..." +msgstr "A executar a ferramenta de integração..." + +#: lib/mergetool.tcl:382 lib/mergetool.tcl:390 +msgid "Merge tool failed." +msgstr "A ferramenta de integração falhou." + +#: 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:34 +msgid "Add globally" +msgstr "Adicionar globalmente" + +#: lib/tools_dlg.tcl:46 +msgid "Tool Details" +msgstr "Detalhes da ferramenta" + +#: lib/tools_dlg.tcl:49 +msgid "Use '/' separators to create a submenu tree:" +msgstr "Use separadores '/' para criar uma árvore de submenus:" + +#: lib/tools_dlg.tcl:60 +msgid "Command:" +msgstr "Comando:" + +#: lib/tools_dlg.tcl:71 +msgid "Show a dialog before running" +msgstr "Mostrar um diálogo antes de executar" + +#: lib/tools_dlg.tcl:77 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Pedir ao utilizador para selecionar uma revisão (define $REVISION)" + +#: lib/tools_dlg.tcl:82 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Pedir ao utilizador argumentos adicionais (define $ARGS)" + +#: lib/tools_dlg.tcl:89 +msgid "Don't show the command output window" +msgstr "Não mostrar a janela com a saída do comando" + +#: lib/tools_dlg.tcl:94 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Executar só se for selecionada um diferença ($FILENAME não vazio)" + +#: lib/tools_dlg.tcl:118 +msgid "Please supply a name for the tool." +msgstr "Forneça um nome para a ferramenta." + +#: lib/tools_dlg.tcl:126 +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "A ferramenta '%s' já existe." + +#: lib/tools_dlg.tcl:148 +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Não foi possível adicionar ferramenta:\n" +"%s" + +#: lib/tools_dlg.tcl:187 +msgid "Remove Tool" +msgstr "Remover ferramenta" + +#: lib/tools_dlg.tcl:193 +msgid "Remove Tool Commands" +msgstr "Remover comandos de ferramenta" + +#: lib/tools_dlg.tcl:198 +msgid "Remove" +msgstr "Remover" + +#: lib/tools_dlg.tcl:231 +msgid "(Blue denotes repository-local tools)" +msgstr "(Azul denota ferramentas locais do repositório)" + +#: lib/tools_dlg.tcl:292 +#, tcl-format +msgid "Run Command: %s" +msgstr "Executar comando: %s" + +#: lib/tools_dlg.tcl:306 +msgid "Arguments" +msgstr "Argumentos" + +#: lib/tools_dlg.tcl:341 +msgid "OK" +msgstr "OK" + +#: lib/search.tcl:48 +msgid "Find:" +msgstr "Procurar:" + +#: lib/search.tcl:50 +msgid "Next" +msgstr "Seguinte" + +#: lib/search.tcl:51 +msgid "Prev" +msgstr "Anterior" + +#: lib/search.tcl:52 +msgid "RegExp" +msgstr "ExpReg" + +#: lib/search.tcl:54 +msgid "Case" +msgstr "Maiúsculas" + +#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 +msgid "Cannot write shortcut:" +msgstr "Não é possível escrever atalho:" + +#: lib/shortcut.tcl:137 +msgid "Cannot write icon:" +msgstr "Não é possível escrever ícone:" + +#: lib/branch_rename.tcl:15 lib/branch_rename.tcl:23 +msgid "Rename Branch" +msgstr "Mudar nome de ramo" + +#: lib/branch_rename.tcl:28 +msgid "Rename" +msgstr "Mudar nome" + +#: lib/branch_rename.tcl:38 +msgid "Branch:" +msgstr "Ramo:" + +#: lib/branch_rename.tcl:46 +msgid "New Name:" +msgstr "Novo nome:" + +#: lib/branch_rename.tcl:81 +msgid "Please select a branch to rename." +msgstr "Selecione um ramo para mudar de nome." + +#: lib/branch_rename.tcl:92 lib/branch_create.tcl:154 +msgid "Please supply a branch name." +msgstr "Indique um nome para o ramo." + +#: lib/branch_rename.tcl:112 lib/branch_create.tcl:165 +#, tcl-format +msgid "'%s' is not an acceptable branch name." +msgstr "'%s' não pode ser aceite como nome de ramo." + +#: lib/branch_rename.tcl:123 +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "Falha ao mudar o nome de '%s'." + +#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 +msgid "Delete Branch Remotely" +msgstr "Remover ramo remotamente" + +#: lib/remote_branch_delete.tcl:48 +msgid "From Repository" +msgstr "Do repositório" + +#: lib/remote_branch_delete.tcl:88 +msgid "Branches" +msgstr "Ramos" + +#: lib/remote_branch_delete.tcl:110 +msgid "Delete Only If" +msgstr "Eliminar só se" + +#: lib/remote_branch_delete.tcl:112 +msgid "Merged Into:" +msgstr "Integrar em:" + +#: lib/remote_branch_delete.tcl:120 lib/branch_delete.tcl:53 +msgid "Always (Do not perform merge checks)" +msgstr "Sempre (não realizar verificação de integração)" + +#: lib/remote_branch_delete.tcl:153 +msgid "A branch is required for 'Merged Into'." +msgstr "É necessário um ramo em 'Integrar em'." + +#: lib/remote_branch_delete.tcl:185 +#, tcl-format +msgid "" +"The following branches are not completely merged into %s:\n" +"\n" +" - %s" +msgstr "" +"Os seguintes ramos não foram completamente integrados em %s:\n" +"\n" +" - %s" + +#: lib/remote_branch_delete.tcl:190 +#, tcl-format +msgid "" +"One or more of the merge tests failed because you have not fetched the " +"necessary commits. Try fetching from %s first." +msgstr "" +"Um ou mais testes de integração falharam porque não obteve os commits " +"necessários. Tente primeiro obter de %s." + +#: lib/remote_branch_delete.tcl:208 +msgid "Please select one or more branches to delete." +msgstr "Selecione um ou mais ramos para eliminar." + +#: lib/remote_branch_delete.tcl:218 lib/branch_delete.tcl:115 +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" +"Recuperar ramos eliminados é difícil.\n" +"\n" +"Eliminar os ramos selecionado?" + +#: lib/remote_branch_delete.tcl:227 +#, tcl-format +msgid "Deleting branches from %s" +msgstr "A eliminar ramos de %s" + +#: lib/remote_branch_delete.tcl:300 +msgid "No repository selected." +msgstr "Nenhum repositório selecionado." + +#: lib/remote_branch_delete.tcl:305 +#, tcl-format +msgid "Scanning %s..." +msgstr "A analisar %s..." + +#: lib/choose_repository.tcl:33 +msgid "Git Gui" +msgstr "Git Gui" + +#: lib/choose_repository.tcl:92 lib/choose_repository.tcl:412 +msgid "Create New Repository" +msgstr "Criar novo repositório" + +#: lib/choose_repository.tcl:98 +msgid "New..." +msgstr "Novo..." + +#: lib/choose_repository.tcl:105 lib/choose_repository.tcl:496 +msgid "Clone Existing Repository" +msgstr "Clonar repositório existente" + +#: lib/choose_repository.tcl:116 +msgid "Clone..." +msgstr "Clonar..." + +#: lib/choose_repository.tcl:123 lib/choose_repository.tcl:1064 +msgid "Open Existing Repository" +msgstr "Abrir repositório existente" + +#: lib/choose_repository.tcl:129 +msgid "Open..." +msgstr "Abrir..." + +#: lib/choose_repository.tcl:142 +msgid "Recent Repositories" +msgstr "Repositórios recentes" + +#: lib/choose_repository.tcl:148 +msgid "Open Recent Repository:" +msgstr "Abrir repositório recente:" + +#: lib/choose_repository.tcl:316 lib/choose_repository.tcl:323 +#: lib/choose_repository.tcl:330 +#, tcl-format +msgid "Failed to create repository %s:" +msgstr "Falha ao criar o repositório %s:" + +#: lib/choose_repository.tcl:407 lib/branch_create.tcl:33 +msgid "Create" +msgstr "Criar" + +#: lib/choose_repository.tcl:417 +msgid "Directory:" +msgstr "Diretório:" + +#: lib/choose_repository.tcl:447 lib/choose_repository.tcl:573 +#: lib/choose_repository.tcl:1098 +msgid "Git Repository" +msgstr "Repositório Git" + +#: lib/choose_repository.tcl:472 +#, tcl-format +msgid "Directory %s already exists." +msgstr "O diretório %s já existe." + +#: lib/choose_repository.tcl:476 +#, tcl-format +msgid "File %s already exists." +msgstr "O ficheiro %s já existe." + +#: lib/choose_repository.tcl:491 +msgid "Clone" +msgstr "Clonar" + +#: lib/choose_repository.tcl:504 +msgid "Source Location:" +msgstr "Localização de origem:" + +#: lib/choose_repository.tcl:513 +msgid "Target Directory:" +msgstr "Diretório de destino:" + +#: lib/choose_repository.tcl:523 +msgid "Clone Type:" +msgstr "Tipo de clone:" + +#: lib/choose_repository.tcl:528 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "Padrão (rápido, semi-redundante, ligações fixas)" + +#: lib/choose_repository.tcl:533 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "Cópia Total (lento, cópia de segurança redundante)" + +#: lib/choose_repository.tcl:538 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "Partilhado (mais rápido, não recomendado, sem cópia)" + +#: lib/choose_repository.tcl:545 +msgid "Recursively clone submodules too" +msgstr "Clonar recursivamente submódulos também" + +#: lib/choose_repository.tcl:579 lib/choose_repository.tcl:626 +#: lib/choose_repository.tcl:772 lib/choose_repository.tcl:842 +#: lib/choose_repository.tcl:1104 lib/choose_repository.tcl:1112 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "Não é um repositório Git: %s" + +#: lib/choose_repository.tcl:615 +msgid "Standard only available for local repository." +msgstr "Padrão só disponível em repositórios locais." + +#: lib/choose_repository.tcl:619 +msgid "Shared only available for local repository." +msgstr "Partilhado só disponível em repositórios locais." + +#: lib/choose_repository.tcl:640 +#, tcl-format +msgid "Location %s already exists." +msgstr "A localização %s já existe." + +#: lib/choose_repository.tcl:651 +msgid "Failed to configure origin" +msgstr "Falha ao configurar origem" + +#: lib/choose_repository.tcl:663 +msgid "Counting objects" +msgstr "A contar objetos" + +#: lib/choose_repository.tcl:664 +msgid "buckets" +msgstr "baldes" + +#: lib/choose_repository.tcl:688 +#, tcl-format +msgid "Unable to copy objects/info/alternates: %s" +msgstr "Não é possível copiar objects/info/alternates: %s" + +#: lib/choose_repository.tcl:724 +#, tcl-format +msgid "Nothing to clone from %s." +msgstr "Nada para clonar de %s." + +#: lib/choose_repository.tcl:726 lib/choose_repository.tcl:940 +#: lib/choose_repository.tcl:952 +msgid "The 'master' branch has not been initialized." +msgstr "O ramo 'master' não foi inicializado." + +#: lib/choose_repository.tcl:739 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "Ligações fixas indisponíveis. A recorrer a cópia." + +#: lib/choose_repository.tcl:751 +#, tcl-format +msgid "Cloning from %s" +msgstr "A clonar de %s" + +#: lib/choose_repository.tcl:782 +msgid "Copying objects" +msgstr "A copiar objetos" + +#: lib/choose_repository.tcl:783 +msgid "KiB" +msgstr "KiB" + +#: lib/choose_repository.tcl:807 +#, tcl-format +msgid "Unable to copy object: %s" +msgstr "Não é possível copiar objeto: %s" + +#: lib/choose_repository.tcl:817 +msgid "Linking objects" +msgstr "A ligar objetos" + +#: lib/choose_repository.tcl:818 +msgid "objects" +msgstr "objetos" + +#: lib/choose_repository.tcl:826 +#, tcl-format +msgid "Unable to hardlink object: %s" +msgstr "Não é possível criar ligação fixa de objeto: %s" + +#: lib/choose_repository.tcl:881 +msgid "Cannot fetch branches and objects. See console output for details." +msgstr "" +"Não é possível obter ramos e objetos. Ver saída na consola para detalhes." + +#: lib/choose_repository.tcl:892 +msgid "Cannot fetch tags. See console output for details." +msgstr "Não é possível obter tags. Ver saída na consola para detalhes." + +#: lib/choose_repository.tcl:916 +msgid "Cannot determine HEAD. See console output for details." +msgstr "Não é possível determinar HEAD. Ver saída na consola para detalhes." + +#: lib/choose_repository.tcl:925 +#, tcl-format +msgid "Unable to cleanup %s" +msgstr "Não foi possível limpar %s" + +#: lib/choose_repository.tcl:931 +msgid "Clone failed." +msgstr "Falha ao clonar." + +#: lib/choose_repository.tcl:938 +msgid "No default branch obtained." +msgstr "Não foi obtido nenhum ramo predefinido." + +#: lib/choose_repository.tcl:949 +#, tcl-format +msgid "Cannot resolve %s as a commit." +msgstr "Não é possível resolver %s como um commit." + +#: lib/choose_repository.tcl:961 +msgid "Creating working directory" +msgstr "A criar diretório de trabalho" + +#: lib/choose_repository.tcl:962 lib/index.tcl:70 lib/index.tcl:136 +#: lib/index.tcl:207 +msgid "files" +msgstr "ficheiros" + +#: lib/choose_repository.tcl:981 +msgid "Cannot clone submodules." +msgstr "Não é possível clonar submódulos." + +#: lib/choose_repository.tcl:990 +msgid "Cloning submodules" +msgstr "A clonar submódulos" + +#: lib/choose_repository.tcl:1015 +msgid "Initial file checkout failed." +msgstr "Falha de extração inicial de ficheiro." + +#: lib/choose_repository.tcl:1059 +msgid "Open" +msgstr "Abrir" + +#: lib/choose_repository.tcl:1069 +msgid "Repository:" +msgstr "Repositório:" + +#: lib/choose_repository.tcl:1118 +#, tcl-format +msgid "Failed to open repository %s:" +msgstr "Falha ao abrir o repositório %s:" + +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui - uma interface gráfica do Git." + +#: lib/blame.tcl:73 +msgid "File Viewer" +msgstr "Visualizador de ficheiros" + +#: lib/blame.tcl:79 +msgid "Commit:" +msgstr "Commit:" + +#: lib/blame.tcl:280 +msgid "Copy Commit" +msgstr "Copiar commit" + +#: lib/blame.tcl:284 +msgid "Find Text..." +msgstr "Procurar texto..." + +#: lib/blame.tcl:288 +msgid "Goto Line..." +msgstr "Ir para a linha..." + +#: lib/blame.tcl:297 +msgid "Do Full Copy Detection" +msgstr "Efetuar deteção de cópia integral" + +#: lib/blame.tcl:301 +msgid "Show History Context" +msgstr "Mostrar contexto histórico" + +#: lib/blame.tcl:304 +msgid "Blame Parent Commit" +msgstr "Culpar commit pai" + +#: lib/blame.tcl:466 +#, tcl-format +msgid "Reading %s..." +msgstr "A ler %s..." + +#: lib/blame.tcl:594 +msgid "Loading copy/move tracking annotations..." +msgstr "A carregar anotações de cópia/movimento..." + +#: lib/blame.tcl:614 +msgid "lines annotated" +msgstr "linhas anotadas" + +#: lib/blame.tcl:806 +msgid "Loading original location annotations..." +msgstr "A carregar anotações da localização original..." + +#: lib/blame.tcl:809 +msgid "Annotation complete." +msgstr "Anotação concluída." + +#: lib/blame.tcl:839 +msgid "Busy" +msgstr "A processar" + +#: lib/blame.tcl:840 +msgid "Annotation process is already running." +msgstr "O processo de anotação já está em execução." + +#: lib/blame.tcl:879 +msgid "Running thorough copy detection..." +msgstr "A executar deteção de cópia integral..." + +#: lib/blame.tcl:947 +msgid "Loading annotation..." +msgstr "A carregar anotação..." + +#: lib/blame.tcl:1000 +msgid "Author:" +msgstr "Autor:" + +#: lib/blame.tcl:1004 +msgid "Committer:" +msgstr "Committer:" + +#: lib/blame.tcl:1009 +msgid "Original File:" +msgstr "Ficheiro original:" + +#: lib/blame.tcl:1057 +msgid "Cannot find HEAD commit:" +msgstr "Não é possível encontrar commit HEAD:" + +#: lib/blame.tcl:1112 +msgid "Cannot find parent commit:" +msgstr "Não é possível encontrar commit pai:" + +#: lib/blame.tcl:1127 +msgid "Unable to display parent" +msgstr "Não é possível mostrar pai" + +#: lib/blame.tcl:1269 +msgid "Originally By:" +msgstr "Originalmente por:" + +#: lib/blame.tcl:1275 +msgid "In File:" +msgstr "No ficheiro:" + +#: lib/blame.tcl:1280 +msgid "Copied Or Moved Here By:" +msgstr "Copiado ou Movido para aqui por:" + +#: lib/sshkey.tcl:31 +msgid "No keys found." +msgstr "Nenhum 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:58 +msgid "Copy To Clipboard" +msgstr "Copiar para a área de transferência" + +#: lib/sshkey.tcl:72 +msgid "Your OpenSSH Public Key" +msgstr "A sua chave OpenSSH pública" + +#: lib/sshkey.tcl:80 +msgid "Generating..." +msgstr "A gerar..." + +#: lib/sshkey.tcl:86 +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Não foi possível iniciar ssh-keygen:\n" +"\n" +"%s" + +#: lib/sshkey.tcl:113 +msgid "Generation failed." +msgstr "Falha ao gerar." + +#: lib/sshkey.tcl:120 +msgid "Generation succeeded, but no keys found." +msgstr "Gerada com sucesso, mas não foi encontrada nenhum chave." + +#: lib/sshkey.tcl:123 +#, tcl-format +msgid "Your key is in: %s" +msgstr "A sua chave encontra-se em: %s" + +#: lib/branch_create.tcl:23 +msgid "Create Branch" +msgstr "Criar ramo" + +#: lib/branch_create.tcl:28 +msgid "Create New Branch" +msgstr "Cria novo ramo" + +#: lib/branch_create.tcl:42 +msgid "Branch Name" +msgstr "Nome do ramo" + +#: lib/branch_create.tcl:57 +msgid "Match Tracking Branch Name" +msgstr "Corresponder ao nome do ramo de monitorização" + +#: 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 "Apenas avanço rápido (fast-forward)" + +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "Extrair depois de criar" + +#: lib/branch_create.tcl:132 +msgid "Please select a tracking branch." +msgstr "Selecione um ramo de monitorização." + +#: lib/branch_create.tcl:141 +#, tcl-format +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "O ramo de monitorização %s não é um ramo no repositório remoto." + +#: 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 emendar.\n" +"\n" +"Está prestes a criar o commit inicial. Não há nenhum commit antes deste para " +"emendar.\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 emendar ao mesmo tempo que se integra.\n" +"\n" +"Há uma integração em curso que não foi concluída. Não pode emendar o commit " +"anterior a não ser que primeiro aborte a atividade da integração atual.\n" + +#: lib/commit.tcl:48 +msgid "Error loading commit data for amend:" +msgstr "Erro ao carregar dados do commit para emendar:" + +#: lib/commit.tcl:75 +msgid "Unable to obtain your identity:" +msgstr "Não é possível obter a sua identidade:" + +#: lib/commit.tcl:80 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "GIT_COMMITTER_IDENT inválido:" + +#: lib/commit.tcl:129 +#, tcl-format +msgid "warning: Tcl does not support encoding '%s'." +msgstr "aviso: 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 analisado não corresponde ao estado do repositório.\n" +"\n" +"Outro programa Git modificou este repositório deste a última análise. Deve-" +"se reanalisar antes que se possa criar outro commit.\n" +"\n" +"Irá-se reanalisar automaticamente agora.\n" + +#: lib/commit.tcl:173 +#, tcl-format +msgid "" +"Unmerged files cannot be committed.\n" +"\n" +"File %s has merge conflicts. You must resolve them and stage the file " +"before committing.\n" +msgstr "" +"Não pode fazer commit de ficheiros não integrados.\n" +"\n" +"O ficheiro %s tem conflitos de integração. Deve resolvê-los e preparar o " +"ficheiro antes de submeter.\n" + +#: lib/commit.tcl:181 +#, tcl-format +msgid "" +"Unknown file state %s detected.\n" +"\n" +"File %s cannot be committed by this program.\n" +msgstr "" +"Detetado estado de ficheiro %s desconhecido.\n" +"\n" +"Este programa não pode submeter o ficheiro %s.\n" + +#: lib/commit.tcl:189 +msgid "" +"No changes to commit.\n" +"\n" +"You must stage at least 1 file before you can commit.\n" +msgstr "" +"Nenhum alteração para submeter.\n" +"\n" +"Deve preparar pelo menos 1 ficheiro antes de submeter.\n" + +#: lib/commit.tcl:204 +msgid "" +"Please supply a commit message.\n" +"\n" +"A good commit message has the following format:\n" +"\n" +"- First line: Describe in one sentence what you did.\n" +"- Second line: Blank\n" +"- Remaining lines: Describe why this change is good.\n" +msgstr "" +"Forneça uma mensagem de commit.\n" +"\n" +"Um boa mensagem de commit tem o seguinte formato:\n" +"\n" +"- Primeira linha: descreve numa frase o que fez.\n" +"- Segunda linha: em branco.\n" +"- Linhas restantes: descreve porque esta alteração é vantajosa.\n" + +#: lib/commit.tcl:235 +msgid "Calling pre-commit hook..." +msgstr "A invocar gancho de pré-commit (pre-commit hook)..." + +#: lib/commit.tcl:250 +msgid "Commit declined by pre-commit hook." +msgstr "Commit recusado pela retina de pré-commit (pre-commit hook)." + +#: lib/commit.tcl:269 +msgid "" +"You are about to commit on a detached head. This is a potentially dangerous " +"thing to do because if you switch to another branch you will lose your " +"changes and it can be difficult to retrieve them later from the reflog. You " +"should probably cancel this commit and create a new branch to continue.\n" +" \n" +" Do you really want to proceed with your Commit?" +msgstr "" +"Está prestes a submeter numa cabeça destacada. Fazê-lo é potencialmente " +"perigoso, porque, se mudar para outro ramo, perderá as suas alterações e " +"pode ser difícil recuperá-las do reflog posteriormente. Provavelmente deve " +"cancelar este commit e criar um novo ramo para continuar.\n" +"\n" +"Pretende mesmo continuar com o commit?" + +#: lib/commit.tcl:290 +msgid "Calling commit-msg hook..." +msgstr "A invocar gancho de mensagem-de-commit (commit-msg hook)..." + +#: lib/commit.tcl:305 +msgid "Commit declined by commit-msg hook." +msgstr "Commit recusado pelo gancho de mensagem-de-commit (commit-msg hook)." + +#: lib/commit.tcl:318 +msgid "Committing changes..." +msgstr "A submeter alterações..." + +#: lib/commit.tcl:334 +msgid "write-tree failed:" +msgstr "write-tree falhou:" + +#: lib/commit.tcl:335 lib/commit.tcl:379 lib/commit.tcl:400 +msgid "Commit failed." +msgstr "Falha ao submeter." + +#: lib/commit.tcl:352 +#, tcl-format +msgid "Commit %s appears to be corrupt" +msgstr "O commit %s parece estar corrompido" + +#: lib/commit.tcl:357 +msgid "" +"No changes to commit.\n" +"\n" +"No files were modified by this commit and it was not a merge commit.\n" +"\n" +"A rescan will be automatically started now.\n" +msgstr "" +"Não há alterações para submeter.\n" +"\n" +"Nenhum ficheiro foi modificado por este commit e não era um commit de " +"integração.\n" +"\n" +"Irá-se reanalisar agora automaticamente.\n" + +#: lib/commit.tcl:364 +msgid "No changes to commit." +msgstr "Não há alterações para submeter." + +#: lib/commit.tcl:378 +msgid "commit-tree failed:" +msgstr "commit-tree falhou:" + +#: lib/commit.tcl:399 +msgid "update-ref failed:" +msgstr "update-ref falhou:" + +#: lib/commit.tcl:492 +#, tcl-format +msgid "Created commit %s: %s" +msgstr "Commit %s criado: %s" + +#: lib/branch_delete.tcl:16 +msgid "Delete Branch" +msgstr "Eliminar ramo" + +#: lib/branch_delete.tcl:21 +msgid "Delete Local Branch" +msgstr "Eliminar ramo local" + +#: lib/branch_delete.tcl:39 +msgid "Local Branches" +msgstr "Ramos locais" + +#: lib/branch_delete.tcl:51 +msgid "Delete Only If Merged Into" +msgstr "Eliminar só se foi integrado" + +#: lib/branch_delete.tcl:103 +#, tcl-format +msgid "The following branches are not completely merged into %s:" +msgstr "Os seguintes ramos não foram completamente integrados em %s:" + +#: lib/branch_delete.tcl:141 +#, tcl-format +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" +"Falha ao eliminar ramos:\n" +"%s" + +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "Não é possível desbloquear o índice." + +#: lib/index.tcl:17 +msgid "Index Error" +msgstr "Erro de Índice" + +#: lib/index.tcl:19 +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" +"Falha ao atualizar o índice do Git. Irá-se reanalisar automaticamente para " +"ressincronizar o git-gui." + +#: lib/index.tcl:30 +msgid "Continue" +msgstr "Continuar" + +#: lib/index.tcl:33 +msgid "Unlock Index" +msgstr "Desbloquear índice" + +#: lib/index.tcl:294 +msgid "Unstaging selected files from commit" +msgstr "A retirar ficheiros selecionados do commit" + +#: lib/index.tcl:298 +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "A retirar %s do commit" + +#: lib/index.tcl:337 +msgid "Ready to commit." +msgstr "Pronto para submeter." + +#: lib/index.tcl:346 +msgid "Adding selected files" +msgstr "A adicionar ficheiros selecionados" + +#: lib/index.tcl:350 +#, tcl-format +msgid "Adding %s" +msgstr "A adicionar %s" + +#: lib/index.tcl:380 +#, tcl-format +msgid "Stage %d untracked files?" +msgstr "Preparar %d ficheiros não controlados?" + +#: lib/index.tcl:388 +msgid "Adding all changed files" +msgstr "A adicionar todos os ficheiros controlados" + +#: lib/index.tcl:428 +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "Reverter alterações no ficheiro %s?" + +#: lib/index.tcl:430 +#, tcl-format +msgid "Revert changes in these %i files?" +msgstr "Reverter alterações nestes %i ficheiros?" + +#: lib/index.tcl:438 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Qualquer alteração não preparada será permanentemente perdida ao reverter." + +#: lib/index.tcl:441 +msgid "Do Nothing" +msgstr "Não fazer nada" + +#: lib/index.tcl:459 +msgid "Reverting selected files" +msgstr "A reverter ficheiros selecionados" + +#: lib/index.tcl:463 +#, tcl-format +msgid "Reverting %s" +msgstr "A reverter %s" + +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "Predefiniçã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/date.tcl:25 +#, tcl-format +msgid "Invalid date from Git: %s" +msgstr "Data do Git inválida: %s" + +#: lib/choose_rev.tcl:52 +msgid "This Detached Checkout" +msgstr "Esta extração destacada" + +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "Expressão de revisão:" + +#: lib/choose_rev.tcl:72 +msgid "Local Branch" +msgstr "Ramo local" + +#: lib/choose_rev.tcl:77 +msgid "Tracking Branch" +msgstr "Ramo de monitorização" + +#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544 +msgid "Tag" +msgstr "Tag" + +#: lib/choose_rev.tcl:321 +#, tcl-format +msgid "Invalid revision: %s" +msgstr "Revisão inválida: %s" + +#: lib/choose_rev.tcl:342 +msgid "No revision selected." +msgstr "Nenhum revisão selecionada." + +#: lib/choose_rev.tcl:350 +msgid "Revision expression is empty." +msgstr "A expressão de revisão está vazia." + +#: lib/choose_rev.tcl:537 +msgid "Updated" +msgstr "Atualizado" + +#: lib/choose_rev.tcl:565 +msgid "URL" +msgstr "URL" + +#: lib/database.tcl:42 +msgid "Number of loose objects" +msgstr "Número de objetos soltos" + +#: lib/database.tcl:43 +msgid "Disk space used by loose objects" +msgstr "Espaço em disco usados por objetos soltos" + +#: lib/database.tcl:44 +msgid "Number of packed objects" +msgstr "Número de objetos compactados" + +#: lib/database.tcl:45 +msgid "Number of packs" +msgstr "Números de pacotes" + +#: lib/database.tcl:46 +msgid "Disk space used by packed objects" +msgstr "Espaço em disco usado por objetos compactados" + +#: lib/database.tcl:47 +msgid "Packed objects waiting for pruning" +msgstr "Objetos compactados à espera de poda" + +#: lib/database.tcl:48 +msgid "Garbage files" +msgstr "Ficheiros de lixo" + +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "A comprimir a base de dados de objetos" + +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "A verificar a base 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 tem aproximadamente %i objetos soltos.\n" +"\n" +"Para manter o desempenho ótimo é veemente recomendado que comprima a base de " +"dados.\n" +"\n" +"Comprimir a base de dados agora?" + +#: lib/error.tcl:20 lib/error.tcl:116 +msgid "error" +msgstr "erro" + +#: lib/error.tcl:36 +msgid "warning" +msgstr "aviso" + +#: lib/error.tcl:96 +msgid "You must correct the above errors before committing." +msgstr "Deve corrigir os erros acima antes de submeter." + +#: 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 integrar ao mesmo tempo que se emenda.\n" +"\n" +"Deve acabar de emendar este commit antes de iniciar qualquer tipo de " +"integração.\n" + +#: lib/merge.tcl:27 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before a merge can be performed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"O último estado analisado não corresponde ao estado do repositório.\n" +"\n" +"Outro programa Git modificou este repositório deste a última análise. Deve-" +"se reanalisar antes de se poder integrar.\n" +"\n" +"Irá-se reanalisar agora automaticamente.\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 "" +"Integração com conflitos em curso.\n" +"\n" +"O ficheiro %s tem conflitos de integração.\n" +"\n" +"Deve resolvê-los, preparar o ficheiro e submeter para concluir a integração " +"atual. Só então pode iniciar outra integração.\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 "" +"Tem alterações presentes.\n" +"\n" +"O ficheiro %s foi modificado.\n" +"\n" +"Deve concluir o commit atual antes de iniciar uma integração. Assim, ajuda-o " +"a abortar uma integração falhada, caso necessário.\n" + +#: lib/merge.tcl:108 +#, tcl-format +msgid "%s of %s" +msgstr "%s de %s" + +#: lib/merge.tcl:122 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "A integrar %s e %s..." + +#: lib/merge.tcl:133 +msgid "Merge completed successfully." +msgstr "Integração concluída com sucesso." + +#: lib/merge.tcl:135 +msgid "Merge failed. Conflict resolution is required." +msgstr "Integração falhada. É necessário resolver conflitos." + +#: lib/merge.tcl:160 +#, tcl-format +msgid "Merge Into %s" +msgstr "Integrar em %s" + +#: lib/merge.tcl:179 +msgid "Revision To Merge" +msgstr "Revisão a integrar" + +#: lib/merge.tcl:214 +msgid "" +"Cannot abort while amending.\n" +"\n" +"You must finish amending this commit.\n" +msgstr "" +"Não é possível abortar enquanto se emenda.\n" +"\n" +"Deve acabar de emendar este commit.\n" + +#: lib/merge.tcl:224 +msgid "" +"Abort merge?\n" +"\n" +"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with aborting the current merge?" +msgstr "" +"Abortar integração?\n" +"\n" +"Ao abortar a integração atual perderá *TODAS* as alteração que não foram " +"submetidas.\n" +"\n" +"Continuar a abortar a integração atual?" + +#: lib/merge.tcl:230 +msgid "" +"Reset changes?\n" +"\n" +"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with resetting the current changes?" +msgstr "" +"Repor alterações?\n" +"\n" +"Ao repor as alterações perderá *TODAS* as alterações não submetidas.\n" +"\n" +"Continuar a repor as alterações atuais?" + +#: lib/merge.tcl:241 +msgid "Aborting" +msgstr "A abortar" + +#: lib/merge.tcl:241 +msgid "files reset" +msgstr "ficheiros repostos" + +#: lib/merge.tcl:269 +msgid "Abort failed." +msgstr "Falha ao abortar." + +#: lib/merge.tcl:271 +msgid "Abort completed. Ready." +msgstr "Aborto concluído. Pronto." + +#~ msgid "Displaying only %s of %s files." +#~ msgstr "A mostrar apenas %s de %s ficheiros." + +#~ msgid "Case-Sensitive" +#~ msgstr "Distinguir Maiúsculas" diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5e474e4a85..ca994c5c54 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -1041,7 +1041,7 @@ The possible behaviours are: ignore, warn, error.")" # placed before the commit of the next action checkout_onto - warn "$(gettext "You can fix this with 'git rebase --edit-todo'.")" + warn "$(gettext "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.")" die "$(gettext "Or you can abort the rebase with 'git rebase --abort'.")" fi } diff --git a/git-stash.sh b/git-stash.sh index 826af183d4..90d63f293e 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -100,7 +100,7 @@ create_stash () { u_tree=$(git write-tree) && printf 'untracked files on %s\n' "$msg" | git commit-tree $u_tree && rm -f "$TMPindex" - ) ) || die "Cannot save the untracked files" + ) ) || die "$(gettext "Cannot save the untracked files")" untracked_commit_option="-p $u_commit"; else @@ -248,7 +248,7 @@ save_stash () { if test -n "$patch_mode" && test -n "$untracked" then - die "Can't use --patch and --include-untracked or --all at the same time" + die "$(gettext "Can't use --patch and --include-untracked or --all at the same time")" fi stash_msg="$*" @@ -494,7 +494,7 @@ apply_stash () { GIT_INDEX_FILE="$TMPindex" git-read-tree "$u_tree" && GIT_INDEX_FILE="$TMPindex" git checkout-index --all && rm -f "$TMPindex" || - die 'Could not restore untracked files from stash' + die "$(gettext "Could not restore untracked files from stash")" fi eval " diff --git a/git-submodule.sh b/git-submodule.sh index a1cc71b521..a024a135d6 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -44,6 +44,7 @@ update= prefix= custom_name= depth= +progress= die_if_unmatched () { @@ -498,6 +499,9 @@ cmd_update() -q|--quiet) GIT_QUIET=1 ;; + --progress) + progress="--progress" + ;; -i|--init) init=1 ;; @@ -573,6 +577,7 @@ cmd_update() { git submodule--helper update-clone ${GIT_QUIET:+--quiet} \ + ${progress:+"$progress"} \ ${wt_prefix:+--prefix "$wt_prefix"} \ ${prefix:+--recursive-prefix "$prefix"} \ ${update:+--update "$update"} \ diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 33d701d852..44094f41d5 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3913,7 +3913,7 @@ sub blob_contenttype { # guess file syntax for syntax highlighting; return undef if no highlighting # the name of syntax can (in the future) depend on syntax highlighter used sub guess_file_syntax { - my ($highlight, $mimetype, $file_name) = @_; + my ($highlight, $file_name) = @_; return undef unless ($highlight && defined $file_name); my $basename = basename($file_name, '.in'); return $highlight_basename{$basename} @@ -3931,15 +3931,16 @@ sub guess_file_syntax { # or return original FD if no highlighting sub run_highlighter { my ($fd, $highlight, $syntax) = @_; - return $fd unless ($highlight && defined $syntax); + return $fd unless ($highlight); close $fd; + my $syntax_arg = (defined $syntax) ? "--syntax $syntax" : "--force"; open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ". quote_command($^X, '-CO', '-MEncode=decode,FB_DEFAULT', '-pse', '$_ = decode($fe, $_, FB_DEFAULT) if !utf8::decode($_);', '--', "-fe=$fallback_encoding")." | ". quote_command($highlight_bin). - " --replace-tabs=8 --fragment --syntax $syntax |" + " --replace-tabs=8 --fragment $syntax_arg |" or die_error(500, "Couldn't open file or run syntax highlighter"); return $fd; } @@ -7062,9 +7063,8 @@ sub git_blob { $have_blame &&= ($mimetype =~ m!^text/!); my $highlight = gitweb_check_feature('highlight'); - my $syntax = guess_file_syntax($highlight, $mimetype, $file_name); - $fd = run_highlighter($fd, $highlight, $syntax) - if $syntax; + my $syntax = guess_file_syntax($highlight, $file_name); + $fd = run_highlighter($fd, $highlight, $syntax); git_header_html(undef, $expires); my $formats_nav = ''; @@ -7117,7 +7117,7 @@ sub git_blob { $line = untabify($line); printf qq!<div class="pre"><a id="l%i" href="%s#l%i" class="linenr">%4i</a> %s</div>\n!, $nr, esc_attr(href(-replay => 1)), $nr, $nr, - $syntax ? sanitize($line) : esc_html($line, -nbsp=>1); + $highlight ? sanitize($line) : esc_html($line, -nbsp=>1); } } close $fd @@ -898,17 +898,6 @@ static int fixmatch(struct grep_pat *p, char *line, char *eol, } } -static int regmatch(const regex_t *preg, char *line, char *eol, - regmatch_t *match, int eflags) -{ -#ifdef REG_STARTEND - match->rm_so = 0; - match->rm_eo = eol - line; - eflags |= REG_STARTEND; -#endif - return regexec(preg, line, 1, match, eflags); -} - static int patmatch(struct grep_pat *p, char *line, char *eol, regmatch_t *match, int eflags) { @@ -919,7 +908,8 @@ static int patmatch(struct grep_pat *p, char *line, char *eol, else if (p->pcre_regexp) hit = !pcrematch(p, line, eol, match, eflags); else - hit = !regmatch(&p->regexp, line, eol, match, eflags); + hit = !regexec_buf(&p->regexp, line, eol - line, 1, match, + eflags); return hit; } @@ -101,7 +101,7 @@ static int canonical_name(const char *host, struct strbuf *out) memset (&hints, '\0', sizeof (hints)); hints.ai_flags = AI_CANONNAME; if (!getaddrinfo(host, NULL, &hints, &ai)) { - if (ai && strchr(ai->ai_canonname, '.')) { + if (ai && ai->ai_canonname && strchr(ai->ai_canonname, '.')) { strbuf_addstr(out, ai->ai_canonname); status = 0; } @@ -331,17 +331,17 @@ person_only: } static const char *env_hint = -"\n" -"*** Please tell me who you are.\n" -"\n" -"Run\n" -"\n" -" git config --global user.email \"you@example.com\"\n" -" git config --global user.name \"Your Name\"\n" -"\n" -"to set your account\'s default identity.\n" -"Omit --global to set the identity only in this repository.\n" -"\n"; +N_("\n" + "*** Please tell me who you are.\n" + "\n" + "Run\n" + "\n" + " git config --global user.email \"you@example.com\"\n" + " git config --global user.name \"Your Name\"\n" + "\n" + "to set your account\'s default identity.\n" + "Omit --global to set the identity only in this repository.\n" + "\n"); const char *fmt_ident(const char *name, const char *email, const char *date_str, int flag) @@ -356,13 +356,13 @@ const char *fmt_ident(const char *name, const char *email, if (!name) { if (strict && ident_use_config_only && !(ident_config_given & IDENT_NAME_GIVEN)) { - fputs(env_hint, stderr); + fputs(_(env_hint), stderr); die("no name was given and auto-detection is disabled"); } name = ident_default_name(); using_default = 1; if (strict && default_name_is_bogus) { - fputs(env_hint, stderr); + fputs(_(env_hint), stderr); die("unable to auto-detect name (got '%s')", name); } } @@ -370,7 +370,7 @@ const char *fmt_ident(const char *name, const char *email, struct passwd *pw; if (strict) { if (using_default) - fputs(env_hint, stderr); + fputs(_(env_hint), stderr); die("empty ident name (for <%s>) not allowed", email); } pw = xgetpwuid_self(NULL); @@ -381,12 +381,12 @@ const char *fmt_ident(const char *name, const char *email, if (!email) { if (strict && ident_use_config_only && !(ident_config_given & IDENT_MAIL_GIVEN)) { - fputs(env_hint, stderr); + fputs(_(env_hint), stderr); die("no email was given and auto-detection is disabled"); } email = ident_default_email(); if (strict && default_email_is_bogus) { - fputs(env_hint, stderr); + fputs(_(env_hint), stderr); die("unable to auto-detect email address (got '%s')", email); } } diff --git a/mailinfo.c b/mailinfo.c index e19abe3cb9..2fb3877ee4 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -54,6 +54,86 @@ static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line) get_sane_name(&mi->name, &mi->name, &mi->email); } +static const char *unquote_comment(struct strbuf *outbuf, const char *in) +{ + int c; + int take_next_litterally = 0; + + strbuf_addch(outbuf, '('); + + while ((c = *in++) != 0) { + if (take_next_litterally == 1) { + take_next_litterally = 0; + } else { + switch (c) { + case '\\': + take_next_litterally = 1; + continue; + case '(': + in = unquote_comment(outbuf, in); + continue; + case ')': + strbuf_addch(outbuf, ')'); + return in; + } + } + + strbuf_addch(outbuf, c); + } + + return in; +} + +static const char *unquote_quoted_string(struct strbuf *outbuf, const char *in) +{ + int c; + int take_next_litterally = 0; + + while ((c = *in++) != 0) { + if (take_next_litterally == 1) { + take_next_litterally = 0; + } else { + switch (c) { + case '\\': + take_next_litterally = 1; + continue; + case '"': + return in; + } + } + + strbuf_addch(outbuf, c); + } + + return in; +} + +static void unquote_quoted_pair(struct strbuf *line) +{ + struct strbuf outbuf; + const char *in = line->buf; + int c; + + strbuf_init(&outbuf, line->len); + + while ((c = *in++) != 0) { + switch (c) { + case '"': + in = unquote_quoted_string(&outbuf, in); + continue; + case '(': + in = unquote_comment(&outbuf, in); + continue; + } + + strbuf_addch(&outbuf, c); + } + + strbuf_swap(&outbuf, line); + strbuf_release(&outbuf); + +} + static void handle_from(struct mailinfo *mi, const struct strbuf *from) { char *at; @@ -63,6 +143,8 @@ static void handle_from(struct mailinfo *mi, const struct strbuf *from) strbuf_init(&f, from->len); strbuf_addbuf(&f, from); + unquote_quoted_pair(&f); + at = strchr(f.buf, '@'); if (!at) { parse_bogus_from(mi, from); @@ -495,26 +577,26 @@ static int check_header(struct mailinfo *mi, goto check_header_out; } - /* for inbody stuff */ - if (starts_with(line->buf, ">From") && isspace(line->buf[5])) { - ret = is_format_patch_separator(line->buf + 1, line->len - 1); - goto check_header_out; - } - if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) { - for (i = 0; header[i]; i++) { - if (!strcmp("Subject", header[i])) { - handle_header(&hdr_data[i], line); - ret = 1; - goto check_header_out; - } - } - } - check_header_out: strbuf_release(&sb); return ret; } +/* + * Returns 1 if the given line or any line beginning with the given line is an + * in-body header (that is, check_header will succeed when passed + * mi->s_hdr_data). + */ +static int is_inbody_header(const struct mailinfo *mi, + const struct strbuf *line) +{ + int i; + for (i = 0; header[i]; i++) + if (!mi->s_hdr_data[i] && cmp_header(line, header[i])) + return 1; + return 0; +} + static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line) { struct strbuf *ret; @@ -572,37 +654,35 @@ static inline int patchbreak(const struct strbuf *line) return 0; } -static int is_scissors_line(const struct strbuf *line) +static int is_scissors_line(const char *line) { - size_t i, len = line->len; + const char *c; int scissors = 0, gap = 0; - int first_nonblank = -1; - int last_nonblank = 0, visible, perforation = 0, in_perforation = 0; - const char *buf = line->buf; + const char *first_nonblank = NULL, *last_nonblank = NULL; + int visible, perforation = 0, in_perforation = 0; - for (i = 0; i < len; i++) { - if (isspace(buf[i])) { + for (c = line; *c; c++) { + if (isspace(*c)) { if (in_perforation) { perforation++; gap++; } continue; } - last_nonblank = i; - if (first_nonblank < 0) - first_nonblank = i; - if (buf[i] == '-') { + last_nonblank = c; + if (first_nonblank == NULL) + first_nonblank = c; + if (*c == '-') { in_perforation = 1; perforation++; continue; } - if (i + 1 < len && - (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2) || - !memcmp(buf + i, ">%", 2) || !memcmp(buf + i, "%<", 2))) { + if ((!memcmp(c, ">8", 2) || !memcmp(c, "8<", 2) || + !memcmp(c, ">%", 2) || !memcmp(c, "%<", 2))) { in_perforation = 1; perforation += 2; scissors += 2; - i++; + c++; continue; } in_perforation = 0; @@ -617,12 +697,60 @@ static int is_scissors_line(const struct strbuf *line) * than half of the perforation. */ - visible = last_nonblank - first_nonblank + 1; + if (first_nonblank && last_nonblank) + visible = last_nonblank - first_nonblank + 1; + else + visible = 0; return (scissors && 8 <= visible && visible < perforation * 3 && gap * 2 < perforation); } +static void flush_inbody_header_accum(struct mailinfo *mi) +{ + if (!mi->inbody_header_accum.len) + return; + assert(check_header(mi, &mi->inbody_header_accum, mi->s_hdr_data, 0)); + strbuf_reset(&mi->inbody_header_accum); +} + +static int check_inbody_header(struct mailinfo *mi, const struct strbuf *line) +{ + if (mi->inbody_header_accum.len && + (line->buf[0] == ' ' || line->buf[0] == '\t')) { + if (mi->use_scissors && is_scissors_line(line->buf)) { + /* + * This is a scissors line; do not consider this line + * as a header continuation line. + */ + flush_inbody_header_accum(mi); + return 0; + } + strbuf_strip_suffix(&mi->inbody_header_accum, "\n"); + strbuf_addbuf(&mi->inbody_header_accum, line); + return 1; + } + + flush_inbody_header_accum(mi); + + if (starts_with(line->buf, ">From") && isspace(line->buf[5])) + return is_format_patch_separator(line->buf + 1, line->len - 1); + if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) { + int i; + for (i = 0; header[i]; i++) + if (!strcmp("Subject", header[i])) { + handle_header(&mi->s_hdr_data[i], line); + return 1; + } + return 0; + } + if (is_inbody_header(mi, line)) { + strbuf_addbuf(&mi->inbody_header_accum, line); + return 1; + } + return 0; +} + static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line) { assert(!mi->filter_stage); @@ -633,7 +761,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line) } if (mi->use_inbody_headers && mi->header_stage) { - mi->header_stage = check_header(mi, line, mi->s_hdr_data, 0); + mi->header_stage = check_inbody_header(mi, line); if (mi->header_stage) return 0; } else @@ -646,7 +774,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line) if (convert_to_utf8(mi, line, mi->charset.buf)) return 0; /* mi->input_error already set */ - if (mi->use_scissors && is_scissors_line(line)) { + if (mi->use_scissors && is_scissors_line(line->buf)) { int i; strbuf_setlen(&mi->log_message, 0); @@ -886,6 +1014,8 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line) break; } while (!strbuf_getwholeline(line, mi->input, '\n')); + flush_inbody_header_accum(mi); + handle_body_out: strbuf_release(&prev); } @@ -1001,6 +1131,7 @@ void setup_mailinfo(struct mailinfo *mi) strbuf_init(&mi->email, 0); strbuf_init(&mi->charset, 0); strbuf_init(&mi->log_message, 0); + strbuf_init(&mi->inbody_header_accum, 0); mi->header_stage = 1; mi->use_inbody_headers = 1; mi->content_top = mi->content; @@ -1014,6 +1145,7 @@ void clear_mailinfo(struct mailinfo *mi) strbuf_release(&mi->name); strbuf_release(&mi->email); strbuf_release(&mi->charset); + strbuf_release(&mi->inbody_header_accum); free(mi->message_id); for (i = 0; mi->p_hdr_data[i]; i++) diff --git a/mailinfo.h b/mailinfo.h index 93776a7e05..04a25351d6 100644 --- a/mailinfo.h +++ b/mailinfo.h @@ -27,6 +27,7 @@ struct mailinfo { int patch_lines; int filter_stage; /* still reading log or are we copying patch? */ int header_stage; /* still checking in-body headers? */ + struct strbuf inbody_header_accum; struct strbuf **p_hdr_data; struct strbuf **s_hdr_data; diff --git a/merge-recursive.c b/merge-recursive.c index 3750d2534f..5200d5ccf8 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -206,7 +206,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit) find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV)); if (parse_commit(commit) != 0) - strbuf_addf(&o->obuf, _("(bad commit)\n")); + strbuf_addstr(&o->obuf, _("(bad commit)\n")); else { const char *title; const char *msg = get_commit_buffer(commit, NULL); diff --git a/notes-merge.c b/notes-merge.c index b3536284c4..5998605acc 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -270,15 +270,15 @@ static void check_notes_merge_worktree(struct notes_merge_options *o) if (file_exists(git_path(NOTES_MERGE_WORKTREE)) && !is_empty_dir(git_path(NOTES_MERGE_WORKTREE))) { if (advice_resolve_conflict) - die("You have not concluded your previous " + die(_("You have not concluded your previous " "notes merge (%s exists).\nPlease, use " "'git notes merge --commit' or 'git notes " "merge --abort' to commit/abort the " "previous merge before you start a new " - "notes merge.", git_path("NOTES_MERGE_*")); + "notes merge."), git_path("NOTES_MERGE_*")); else - die("You have not concluded your notes merge " - "(%s exists).", git_path("NOTES_MERGE_*")); + die(_("You have not concluded your notes merge " + "(%s exists)."), git_path("NOTES_MERGE_*")); } if (safe_create_leading_directories_const(git_path( diff --git a/pack-check.c b/pack-check.c index d123846ea2..c5c7763323 100644 --- a/pack-check.c +++ b/pack-check.c @@ -57,11 +57,8 @@ static int verify_packfile(struct packed_git *p, int err = 0; struct idx_entry *entries; - /* Note that the pack header checks are actually performed by - * use_pack when it first opens the pack file. If anything - * goes wrong during those checks then the call will die out - * immediately. - */ + if (!is_pack_valid(p)) + return error("packfile %s cannot be accessed", p->pack_name); git_SHA1_Init(&ctx); do { diff --git a/pack-revindex.c b/pack-revindex.c index 96d51c3467..6bc7c94033 100644 --- a/pack-revindex.c +++ b/pack-revindex.c @@ -107,7 +107,7 @@ static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max) * we have to move it back from the temporary storage. */ if (from != entries) - memcpy(entries, tmp, n * sizeof(*entries)); + COPY_ARRAY(entries, tmp, n); free(tmp); free(pos); diff --git a/parse-options-cb.c b/parse-options-cb.c index 9667bc75a0..b5d920914e 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -159,6 +159,18 @@ int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset) } /** + * Report that the option is unknown, so that other code can handle + * it. This can be used as a callback together with + * OPTION_LOWLEVEL_CALLBACK to allow an option to be documented in the + * "-h" output even if it's not being handled directly by + * parse_options(). + */ +int parse_opt_unknown_cb(const struct option *opt, const char *arg, int unset) +{ + return -2; +} + +/** * Recreates the command-line option in the strbuf. */ static int recreate_opt(struct strbuf *sb, const struct option *opt, diff --git a/parse-options.h b/parse-options.h index 78f8384c56..dcd8a0926c 100644 --- a/parse-options.h +++ b/parse-options.h @@ -228,6 +228,7 @@ extern int parse_opt_commits(const struct option *, const char *, int); extern int parse_opt_tertiary(const struct option *, const char *, int); extern int parse_opt_string_list(const struct option *, const char *, int); extern int parse_opt_noop_cb(const struct option *, const char *, int); +extern int parse_opt_unknown_cb(const struct option *, const char *, int); extern int parse_opt_passthru(const struct option *, const char *, int); extern int parse_opt_passthru_argv(const struct option *, const char *, int); diff --git a/pathspec.c b/pathspec.c index 24e0dd5232..49a53607bb 100644 --- a/pathspec.c +++ b/pathspec.c @@ -485,8 +485,7 @@ void copy_pathspec(struct pathspec *dst, const struct pathspec *src) { *dst = *src; ALLOC_ARRAY(dst->items, dst->nr); - memcpy(dst->items, src->items, - sizeof(struct pathspec_item) * dst->nr); + COPY_ARRAY(dst->items, src->items, dst->nr); } void clear_pathspec(struct pathspec *pathspec) @@ -1072,6 +1072,8 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ case 'C': if (starts_with(placeholder + 1, "(auto)")) { c->auto_color = want_color(c->pretty_ctx->color); + if (c->auto_color) + strbuf_addstr(sb, GIT_COLOR_RESET); return 7; /* consumed 7 bytes, "C(auto)" */ } else { int ret = parse_color(sb, placeholder, c); diff --git a/read-cache.c b/read-cache.c index 31eddec5f7..38d67faf70 100644 --- a/read-cache.c +++ b/read-cache.c @@ -627,7 +627,7 @@ void set_object_name_for_intent_to_add_entry(struct cache_entry *ce) hashcpy(ce->oid.hash, sha1); } -int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags, int force_mode) +int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags) { int size, namelen, was_same; mode_t st_mode = st->st_mode; @@ -656,11 +656,10 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, else ce->ce_flags |= CE_INTENT_TO_ADD; - if (S_ISREG(st_mode) && force_mode) - ce->ce_mode = create_ce_mode(force_mode); - else if (trust_executable_bit && has_symlinks) + + if (trust_executable_bit && has_symlinks) { ce->ce_mode = create_ce_mode(st_mode); - else { + } else { /* If there is an existing entry, pick the mode bits and type * from it, otherwise assume unexecutable regular file. */ @@ -719,13 +718,12 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, return 0; } -int add_file_to_index(struct index_state *istate, const char *path, - int flags, int force_mode) +int add_file_to_index(struct index_state *istate, const char *path, int flags) { struct stat st; if (lstat(path, &st)) die_errno("unable to stat '%s'", path); - return add_to_index(istate, path, &st, flags, force_mode); + return add_to_index(istate, path, &st, flags); } struct cache_entry *make_cache_entry(unsigned int mode, @@ -756,6 +754,35 @@ struct cache_entry *make_cache_entry(unsigned int mode, return ret; } +/* + * Chmod an index entry with either +x or -x. + * + * Returns -1 if the chmod for the particular cache entry failed (if it's + * not a regular file), -2 if an invalid flip argument is passed in, 0 + * otherwise. + */ +int chmod_index_entry(struct index_state *istate, struct cache_entry *ce, + char flip) +{ + if (!S_ISREG(ce->ce_mode)) + return -1; + switch (flip) { + case '+': + ce->ce_mode |= 0111; + break; + case '-': + ce->ce_mode &= ~0111; + break; + default: + return -2; + } + cache_tree_invalidate_path(istate, ce->name); + ce->ce_flags |= CE_UPDATE_IN_BASE; + istate->cache_changed |= CE_ENTRY_CHANGED; + + return 0; +} + int ce_same_name(const struct cache_entry *a, const struct cache_entry *b) { int len = ce_namelen(a); @@ -2073,7 +2073,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) _("Your branch is based on '%s', but the upstream is gone.\n"), base); if (advice_status_hints) - strbuf_addf(sb, + strbuf_addstr(sb, _(" (use \"git branch --unset-upstream\" to fixup)\n")); } else if (!ours && !theirs) { strbuf_addf(sb, @@ -2086,7 +2086,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) ours), base, ours); if (advice_status_hints) - strbuf_addf(sb, + strbuf_addstr(sb, _(" (use \"git push\" to publish your local commits)\n")); } else if (!ours) { strbuf_addf(sb, @@ -2097,7 +2097,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) theirs), base, theirs); if (advice_status_hints) - strbuf_addf(sb, + strbuf_addstr(sb, _(" (use \"git pull\" to update your local branch)\n")); } else { strbuf_addf(sb, @@ -2110,7 +2110,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) ours + theirs), base, ours, theirs); if (advice_status_hints) - strbuf_addf(sb, + strbuf_addstr(sb, _(" (use \"git pull\" to merge the remote branch into yours)\n")); } free(base); diff --git a/sha1_file.c b/sha1_file.c index b9c1fa3f1a..94daf31ec6 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1646,7 +1646,9 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf, return used; } -int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz) +static int unpack_sha1_short_header(git_zstream *stream, + unsigned char *map, unsigned long mapsize, + void *buffer, unsigned long bufsiz) { /* Get the data stream */ memset(stream, 0, sizeof(*stream)); @@ -1659,13 +1661,31 @@ int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long ma return git_inflate(stream, 0); } +int unpack_sha1_header(git_zstream *stream, + unsigned char *map, unsigned long mapsize, + void *buffer, unsigned long bufsiz) +{ + int status = unpack_sha1_short_header(stream, map, mapsize, + buffer, bufsiz); + + if (status < Z_OK) + return status; + + /* Make sure we have the terminating NUL */ + if (!memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer)) + return -1; + return 0; +} + static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz, struct strbuf *header) { int status; - status = unpack_sha1_header(stream, map, mapsize, buffer, bufsiz); + status = unpack_sha1_short_header(stream, map, mapsize, buffer, bufsiz); + if (status < Z_OK) + return -1; /* * Check if entire header is unpacked in the first iteration. @@ -1756,6 +1776,8 @@ static int parse_sha1_header_extended(const char *hdr, struct object_info *oi, */ for (;;) { char c = *hdr++; + if (!c) + return -1; if (c == ' ') break; type_len++; diff --git a/split-index.c b/split-index.c index 3c75d4b9ce..35da553655 100644 --- a/split-index.c +++ b/split-index.c @@ -83,8 +83,7 @@ void move_cache_to_base_index(struct index_state *istate) si->base->timestamp = istate->timestamp; ALLOC_GROW(si->base->cache, istate->cache_nr, si->base->cache_alloc); si->base->cache_nr = istate->cache_nr; - memcpy(si->base->cache, istate->cache, - sizeof(*istate->cache) * istate->cache_nr); + COPY_ARRAY(si->base->cache, istate->cache, istate->cache_nr); mark_base_index_entries(si->base); for (i = 0; i < si->base->cache_nr; i++) si->base->cache[i]->ce_flags &= ~CE_UPDATE_IN_BASE; @@ -141,8 +140,7 @@ void merge_base_index(struct index_state *istate) istate->cache = NULL; istate->cache_alloc = 0; ALLOC_GROW(istate->cache, istate->cache_nr, istate->cache_alloc); - memcpy(istate->cache, si->base->cache, - sizeof(*istate->cache) * istate->cache_nr); + COPY_ARRAY(istate->cache, si->base->cache, istate->cache_nr); si->nr_deletions = 0; si->nr_replacements = 0; diff --git a/streaming.c b/streaming.c index 3c48f049d3..3f017a1c05 100644 --- a/streaming.c +++ b/streaming.c @@ -337,17 +337,17 @@ static open_method_decl(loose) st->u.loose.mapped = map_sha1_file(sha1, &st->u.loose.mapsize); if (!st->u.loose.mapped) return -1; - if (unpack_sha1_header(&st->z, - st->u.loose.mapped, - st->u.loose.mapsize, - st->u.loose.hdr, - sizeof(st->u.loose.hdr)) < 0) { + if ((unpack_sha1_header(&st->z, + st->u.loose.mapped, + st->u.loose.mapsize, + st->u.loose.hdr, + sizeof(st->u.loose.hdr)) < 0) || + (parse_sha1_header(st->u.loose.hdr, &st->size) < 0)) { git_inflate_end(&st->z); munmap(st->u.loose.mapped, st->u.loose.mapsize); return -1; } - parse_sha1_header(st->u.loose.hdr, &st->size); st->u.loose.hdr_used = strlen(st->u.loose.hdr) + 1; st->u.loose.hdr_avail = st->z.total_out; st->z_state = z_used; diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 8ffbbea4d6..b8fc588b19 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -393,4 +393,21 @@ test_expect_success 'remote init from does not use config from cwd' ' test_cmp expect actual ' +test_expect_success 're-init from a linked worktree' ' + git init main-worktree && + ( + cd main-worktree && + test_commit first && + git worktree add ../linked-worktree && + mv .git/info/exclude expected-exclude && + cp .git/config expected-config && + find .git/worktrees -print | sort >expected && + git -C ../linked-worktree init && + test_cmp expected-exclude .git/info/exclude && + test_cmp expected-config .git/config && + find .git/worktrees -print | sort >actual && + test_cmp expected actual + ) +' + test_done diff --git a/t/t2010-checkout-ambiguous.sh b/t/t2010-checkout-ambiguous.sh index e76e84afbb..2e47fe01cf 100755 --- a/t/t2010-checkout-ambiguous.sh +++ b/t/t2010-checkout-ambiguous.sh @@ -41,6 +41,15 @@ test_expect_success 'check ambiguity' ' test_must_fail git checkout world all ' +test_expect_success 'check ambiguity in subdir' ' + mkdir sub && + # not ambiguous because sub/world does not exist + git -C sub checkout world ../all && + echo hello >sub/world && + # ambiguous because sub/world does exist + test_must_fail git -C sub checkout world ../all +' + test_expect_success 'disambiguate checking out from a tree-ish' ' echo bye > world && git checkout world -- world && diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh index 468a000e4b..3e5ac81bd2 100755 --- a/t/t2024-checkout-dwim.sh +++ b/t/t2024-checkout-dwim.sh @@ -174,6 +174,18 @@ test_expect_success 'checkout of branch with a file having the same name fails' test_branch master ' +test_expect_success 'checkout of branch with a file in subdir having the same name fails' ' + git checkout -B master && + test_might_fail git branch -D spam && + + >spam && + mkdir sub && + mv spam sub/spam && + test_must_fail git -C sub checkout spam && + test_must_fail git rev-parse --verify refs/heads/spam && + test_branch master +' + test_expect_success 'checkout <branch> -- succeeds, even if a file with the same name exists' ' git checkout -B master && test_might_fail git branch -D spam && diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh index dfe02f4818..32ac6e09bd 100755 --- a/t/t2107-update-index-basic.sh +++ b/t/t2107-update-index-basic.sh @@ -80,4 +80,17 @@ test_expect_success '.lock files cleaned up' ' ) ' +test_expect_success '--chmod=+x and chmod=-x in the same argument list' ' + >A && + >B && + git add A B && + git update-index --chmod=+x A --chmod=-x B && + cat >expect <<-\EOF && + 100755 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 A + 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 B + EOF + git ls-files --stage A B >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh index 6967436327..baef2d6924 100755 --- a/t/t3310-notes-merge-manual-resolve.sh +++ b/t/t3310-notes-merge-manual-resolve.sh @@ -225,7 +225,7 @@ test_expect_success 'cannot do merge w/conflicts when previous merge is unfinish test -d .git/NOTES_MERGE_WORKTREE && test_must_fail git notes merge z >output 2>&1 && # Output should indicate what is wrong - grep -q "\\.git/NOTES_MERGE_\\* exists" output + test_i18ngrep -q "\\.git/NOTES_MERGE_\\* exists" output ' # Setup non-conflicting merge between x and new notes ref w diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 597e94e294..e38e296388 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -1195,7 +1195,7 @@ To avoid this message, use "drop" to explicitly remove a commit. Use 'git config rebase.missingCommitsCheck' to change the level of warnings. The possible behaviours are: ignore, warn, error. -You can fix this with 'git rebase --edit-todo'. +You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'. Or you can abort the rebase with 'git rebase --abort'. EOF @@ -1219,7 +1219,7 @@ cat >expect <<EOF Warning: the command isn't recognized in the following line: - badcmd $(git rev-list --oneline -1 master~1) -You can fix this with 'git rebase --edit-todo'. +You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'. Or you can abort the rebase with 'git rebase --abort'. EOF @@ -1254,7 +1254,7 @@ cat >expect <<EOF Warning: the SHA-1 is missing or isn't a commit in the following line: - edit XXXXXXX False commit -You can fix this with 'git rebase --edit-todo'. +You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'. Or you can abort the rebase with 'git rebase --abort'. EOF diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 2978cb9d64..924a266126 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -349,4 +349,52 @@ test_expect_success POSIXPERM,SYMLINKS 'git add --chmod=+x with symlinks' ' test_mode_in_index 100755 foo2 ' +test_expect_success 'git add --chmod=[+-]x changes index with already added file' ' + echo foo >foo3 && + git add foo3 && + git add --chmod=+x foo3 && + test_mode_in_index 100755 foo3 && + echo foo >xfoo3 && + chmod 755 xfoo3 && + git add xfoo3 && + git add --chmod=-x xfoo3 && + test_mode_in_index 100644 xfoo3 +' + +test_expect_success POSIXPERM 'git add --chmod=[+-]x does not change the working tree' ' + echo foo >foo4 && + git add foo4 && + git add --chmod=+x foo4 && + ! test -x foo4 +' + +test_expect_success 'no file status change if no pathspec is given' ' + >foo5 && + >foo6 && + git add foo5 foo6 && + git add --chmod=+x && + test_mode_in_index 100644 foo5 && + test_mode_in_index 100644 foo6 +' + +test_expect_success 'no file status change if no pathspec is given in subdir' ' + mkdir -p sub && + ( + cd sub && + >sub-foo1 && + >sub-foo2 && + git add . && + git add --chmod=+x && + test_mode_in_index 100644 sub-foo1 && + test_mode_in_index 100644 sub-foo2 + ) +' + +test_expect_success 'all statuses changed in folder if . is given' ' + git add --chmod=+x . && + test $(git ls-files --stage | grep ^100644 | wc -l) -eq 0 && + git add --chmod=-x . && + test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0 +' + test_done diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 4bf1dbe9c9..3b94283e35 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -45,7 +45,7 @@ test_expect_success 'UTF-8 invalid characters refused' ' printf "Commit message\n\nInvalid surrogate:\355\240\200\n" \ >"$HOME/invalid" && git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr && - grep "did not conform" "$HOME"/stderr + test_i18ngrep "did not conform" "$HOME"/stderr ' test_expect_success 'UTF-8 overlong sequences rejected' ' @@ -55,7 +55,7 @@ test_expect_success 'UTF-8 overlong sequences rejected' ' printf "\340\202\251ommit message\n\nThis is not a space:\300\240\n" \ >"$HOME/invalid" && git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr && - grep "did not conform" "$HOME"/stderr + test_i18ngrep "did not conform" "$HOME"/stderr ' test_expect_success 'UTF-8 non-characters refused' ' @@ -64,7 +64,7 @@ test_expect_success 'UTF-8 non-characters refused' ' printf "Commit message\n\nNon-character:\364\217\277\276\n" \ >"$HOME/invalid" && git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr && - grep "did not conform" "$HOME"/stderr + test_i18ngrep "did not conform" "$HOME"/stderr ' test_expect_success 'UTF-8 non-characters refused' ' @@ -73,7 +73,7 @@ test_expect_success 'UTF-8 non-characters refused' ' printf "Commit message\n\nNon-character:\357\267\220\n" \ >"$HOME/invalid" && git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr && - grep "did not conform" "$HOME"/stderr + test_i18ngrep "did not conform" "$HOME"/stderr ' for H in ISO8859-1 eucJP ISO-2022-JP diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index 509084e1a7..f663d567c8 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -295,7 +295,7 @@ test_expect_success 'am --no-utf8 (U/L)' ' # commit-tree will warn that the commit message does not contain valid UTF-8 # as mailinfo did not convert it - grep "did not conform" err && + test_i18ngrep "did not conform" err && check_encoding 2 ' diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 8d90a6e500..ba4902df2b 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -1086,6 +1086,15 @@ test_expect_success 'empty subject prefix does not have extra space' ' test_cmp expect actual ' +test_expect_success '--rfc' ' + cat >expect <<-\EOF && + Subject: [RFC PATCH 1/1] header with . in it + EOF + git format-patch -n -1 --stdout --rfc >patch && + grep ^Subject: patch >actual && + test_cmp expect actual +' + test_expect_success '--from=ident notices bogus ident' ' test_must_fail git format-patch -1 --stdout --from=foo >patch ' diff --git a/t/t4061-diff-indent.sh b/t/t4061-diff-indent.sh new file mode 100755 index 0000000000..556450609b --- /dev/null +++ b/t/t4061-diff-indent.sh @@ -0,0 +1,216 @@ +#!/bin/sh + +test_description='Test diff indent heuristic. + +' +. ./test-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh + +# Compare two diff outputs. Ignore "index" lines, because we don't +# care about SHA-1s or file modes. +compare_diff () { + sed -e "/^index /d" <"$1" >.tmp-1 + sed -e "/^index /d" <"$2" >.tmp-2 + test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 +} + +# Compare blame output using the expectation for a diff as reference. +# Only look for the lines coming from non-boundary commits. +compare_blame () { + sed -n -e "1,4d" -e "s/^\+//p" <"$1" >.tmp-1 + sed -ne "s/^[^^][^)]*) *//p" <"$2" >.tmp-2 + test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 +} + +test_expect_success 'prepare' ' + cat <<-\EOF >spaces.txt && + 1 + 2 + a + + b + 3 + 4 + EOF + + cat <<-\EOF >functions.c && + 1 + 2 + /* function */ + foo() { + foo + } + + 3 + 4 + EOF + + git add spaces.txt functions.c && + test_tick && + git commit -m initial && + git branch old && + + cat <<-\EOF >spaces.txt && + 1 + 2 + a + + b + a + + b + 3 + 4 + EOF + + cat <<-\EOF >functions.c && + 1 + 2 + /* function */ + bar() { + foo + } + + /* function */ + foo() { + foo + } + + 3 + 4 + EOF + + git add spaces.txt functions.c && + test_tick && + git commit -m initial && + git branch new && + + tr "_" " " <<-\EOF >spaces-expect && + diff --git a/spaces.txt b/spaces.txt + --- a/spaces.txt + +++ b/spaces.txt + @@ -3,5 +3,8 @@ + a + _ + b + +a + + + +b + 3 + 4 + EOF + + tr "_" " " <<-\EOF >spaces-compacted-expect && + diff --git a/spaces.txt b/spaces.txt + --- a/spaces.txt + +++ b/spaces.txt + @@ -2,6 +2,9 @@ + 2 + a + _ + +b + +a + + + b + 3 + 4 + EOF + + tr "_" " " <<-\EOF >functions-expect && + diff --git a/functions.c b/functions.c + --- a/functions.c + +++ b/functions.c + @@ -1,6 +1,11 @@ + 1 + 2 + /* function */ + +bar() { + + foo + +} + + + +/* function */ + foo() { + foo + } + EOF + + tr "_" " " <<-\EOF >functions-compacted-expect + diff --git a/functions.c b/functions.c + --- a/functions.c + +++ b/functions.c + @@ -1,5 +1,10 @@ + 1 + 2 + +/* function */ + +bar() { + + foo + +} + + + /* function */ + foo() { + foo + EOF +' + +test_expect_success 'diff: ugly spaces' ' + git diff old new -- spaces.txt >out && + compare_diff spaces-expect out +' + +test_expect_success 'diff: nice spaces with --indent-heuristic' ' + git diff --indent-heuristic old new -- spaces.txt >out-compacted && + compare_diff spaces-compacted-expect out-compacted +' + +test_expect_success 'diff: nice spaces with diff.indentHeuristic' ' + git -c diff.indentHeuristic=true diff old new -- spaces.txt >out-compacted2 && + compare_diff spaces-compacted-expect out-compacted2 +' + +test_expect_success 'diff: --no-indent-heuristic overrides config' ' + git -c diff.indentHeuristic=true diff --no-indent-heuristic old new -- spaces.txt >out2 && + compare_diff spaces-expect out2 +' + +test_expect_success 'diff: --indent-heuristic with --patience' ' + git diff --indent-heuristic --patience old new -- spaces.txt >out-compacted3 && + compare_diff spaces-compacted-expect out-compacted3 +' + +test_expect_success 'diff: --indent-heuristic with --histogram' ' + git diff --indent-heuristic --histogram old new -- spaces.txt >out-compacted4 && + compare_diff spaces-compacted-expect out-compacted4 +' + +test_expect_success 'diff: ugly functions' ' + git diff old new -- functions.c >out && + compare_diff functions-expect out +' + +test_expect_success 'diff: nice functions with --indent-heuristic' ' + git diff --indent-heuristic old new -- functions.c >out-compacted && + compare_diff functions-compacted-expect out-compacted +' + +test_expect_success 'blame: ugly spaces' ' + git blame old..new -- spaces.txt >out-blame && + compare_blame spaces-expect out-blame +' + +test_expect_success 'blame: nice spaces with --indent-heuristic' ' + git blame --indent-heuristic old..new -- spaces.txt >out-blame-compacted && + compare_blame spaces-compacted-expect out-blame-compacted +' + +test_expect_success 'blame: nice spaces with diff.indentHeuristic' ' + git -c diff.indentHeuristic=true blame old..new -- spaces.txt >out-blame-compacted2 && + compare_blame spaces-compacted-expect out-blame-compacted2 +' + +test_expect_success 'blame: --no-indent-heuristic overrides config' ' + git -c diff.indentHeuristic=true blame --no-indent-heuristic old..new -- spaces.txt >out-blame2 && + git blame old..new -- spaces.txt >out-blame && + compare_blame spaces-expect out-blame2 +' + +test_done diff --git a/t/t4062-diff-pickaxe.sh b/t/t4062-diff-pickaxe.sh new file mode 100755 index 0000000000..f0bf50bda7 --- /dev/null +++ b/t/t4062-diff-pickaxe.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Copyright (c) 2016 Johannes Schindelin +# + +test_description='Pickaxe options' + +. ./test-lib.sh + +test_expect_success setup ' + test_commit initial && + printf "%04096d" 0 >4096-zeroes.txt && + git add 4096-zeroes.txt && + test_tick && + git commit -m "A 4k file" +' +test_expect_success '-G matches' ' + git diff --name-only -G "^0{4096}$" HEAD^ >out && + test 4096-zeroes.txt = "$(cat out)" +' + +test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 9ce9424d15..89a5bacac5 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -977,4 +977,27 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' ' test_cmp msg out ' +test_expect_success 'am works with multi-line in-body headers' ' + FORTY="String that has a length of more than forty characters" && + LONG="$FORTY $FORTY" && + rm -fr .git/rebase-apply && + git checkout -f first && + echo one >> file && + git commit -am "$LONG" --author="$LONG <long@example.com>" && + git format-patch --stdout -1 >patch && + # bump from, date, and subject down to in-body header + perl -lpe " + if (/^From:/) { + print \"From: x <x\@example.com>\"; + print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\"; + print \"Subject: x\n\"; + } + " patch >msg && + git checkout HEAD^ && + git am msg && + # Ensure that the author and full message are present + git cat-file commit HEAD | grep "^author.*long@example.com" && + git cat-file commit HEAD | grep "^$LONG" +' + test_done diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 1a5a546230..e6b995161e 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -7,37 +7,39 @@ test_description='git mailinfo and git mailsplit test' . ./test-lib.sh +DATA="$TEST_DIRECTORY/t5100" + test_expect_success 'split sample box' \ - 'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last && + 'git mailsplit -o. "$DATA/sample.mbox" >last && last=$(cat last) && echo total is $last && - test $(cat last) = 17' + test $(cat last) = 18' check_mailinfo () { mail=$1 opt=$2 mo="$mail$opt" - git mailinfo -u $opt msg$mo patch$mo <$mail >info$mo && - test_cmp "$TEST_DIRECTORY"/t5100/msg$mo msg$mo && - test_cmp "$TEST_DIRECTORY"/t5100/patch$mo patch$mo && - test_cmp "$TEST_DIRECTORY"/t5100/info$mo info$mo + git mailinfo -u $opt "msg$mo" "patch$mo" <"$mail" >"info$mo" && + test_cmp "$DATA/msg$mo" "msg$mo" && + test_cmp "$DATA/patch$mo" "patch$mo" && + test_cmp "$DATA/info$mo" "info$mo" } for mail in 00* do test_expect_success "mailinfo $mail" ' - check_mailinfo $mail "" && - if test -f "$TEST_DIRECTORY"/t5100/msg$mail--scissors + check_mailinfo "$mail" "" && + if test -f "$DATA/msg$mail--scissors" then - check_mailinfo $mail --scissors + check_mailinfo "$mail" --scissors fi && - if test -f "$TEST_DIRECTORY"/t5100/msg$mail--no-inbody-headers + if test -f "$DATA/msg$mail--no-inbody-headers" then - check_mailinfo $mail --no-inbody-headers + check_mailinfo "$mail" --no-inbody-headers fi && - if test -f "$TEST_DIRECTORY"/t5100/msg$mail--message-id + if test -f "$DATA/msg$mail--message-id" then - check_mailinfo $mail --message-id + check_mailinfo "$mail" --message-id fi ' done @@ -45,7 +47,7 @@ done test_expect_success 'split box with rfc2047 samples' \ 'mkdir rfc2047 && - git mailsplit -orfc2047 "$TEST_DIRECTORY"/t5100/rfc2047-samples.mbox \ + git mailsplit -orfc2047 "$DATA/rfc2047-samples.mbox" \ >rfc2047/last && last=$(cat rfc2047/last) && echo total is $last && @@ -54,20 +56,20 @@ test_expect_success 'split box with rfc2047 samples' \ for mail in rfc2047/00* do test_expect_success "mailinfo $mail" ' - git mailinfo -u $mail-msg $mail-patch <$mail >$mail-info && + git mailinfo -u "$mail-msg" "$mail-patch" <"$mail" >"$mail-info" && echo msg && - test_cmp "$TEST_DIRECTORY"/t5100/empty $mail-msg && + test_cmp "$DATA/empty" "$mail-msg" && echo patch && - test_cmp "$TEST_DIRECTORY"/t5100/empty $mail-patch && + test_cmp "$DATA/empty" "$mail-patch" && echo info && - test_cmp "$TEST_DIRECTORY"/t5100/rfc2047-info-$(basename $mail) $mail-info + test_cmp "$DATA/rfc2047-info-$(basename $mail)" "$mail-info" ' done test_expect_success 'respect NULs' ' - git mailsplit -d3 -o. "$TEST_DIRECTORY"/t5100/nul-plain && - test_cmp "$TEST_DIRECTORY"/t5100/nul-plain 001 && + git mailsplit -d3 -o. "$DATA/nul-plain" && + test_cmp "$DATA/nul-plain" 001 && (cat 001 | git mailinfo msg patch) && test_line_count = 4 patch @@ -75,52 +77,52 @@ test_expect_success 'respect NULs' ' test_expect_success 'Preserve NULs out of MIME encoded message' ' - git mailsplit -d5 -o. "$TEST_DIRECTORY"/t5100/nul-b64.in && - test_cmp "$TEST_DIRECTORY"/t5100/nul-b64.in 00001 && + git mailsplit -d5 -o. "$DATA/nul-b64.in" && + test_cmp "$DATA/nul-b64.in" 00001 && git mailinfo msg patch <00001 && - test_cmp "$TEST_DIRECTORY"/t5100/nul-b64.expect patch + test_cmp "$DATA/nul-b64.expect" patch ' test_expect_success 'mailinfo on from header without name works' ' mkdir info-from && - git mailsplit -oinfo-from "$TEST_DIRECTORY"/t5100/info-from.in && - test_cmp "$TEST_DIRECTORY"/t5100/info-from.in info-from/0001 && + git mailsplit -oinfo-from "$DATA/info-from.in" && + test_cmp "$DATA/info-from.in" info-from/0001 && git mailinfo info-from/msg info-from/patch \ <info-from/0001 >info-from/out && - test_cmp "$TEST_DIRECTORY"/t5100/info-from.expect info-from/out + test_cmp "$DATA/info-from.expect" info-from/out ' test_expect_success 'mailinfo finds headers after embedded From line' ' mkdir embed-from && - git mailsplit -oembed-from "$TEST_DIRECTORY"/t5100/embed-from.in && - test_cmp "$TEST_DIRECTORY"/t5100/embed-from.in embed-from/0001 && + git mailsplit -oembed-from "$DATA/embed-from.in" && + test_cmp "$DATA/embed-from.in" embed-from/0001 && git mailinfo embed-from/msg embed-from/patch \ <embed-from/0001 >embed-from/out && - test_cmp "$TEST_DIRECTORY"/t5100/embed-from.expect embed-from/out + test_cmp "$DATA/embed-from.expect" embed-from/out ' test_expect_success 'mailinfo on message with quoted >From' ' mkdir quoted-from && - git mailsplit -oquoted-from "$TEST_DIRECTORY"/t5100/quoted-from.in && - test_cmp "$TEST_DIRECTORY"/t5100/quoted-from.in quoted-from/0001 && + git mailsplit -oquoted-from "$DATA/quoted-from.in" && + test_cmp "$DATA/quoted-from.in" quoted-from/0001 && git mailinfo quoted-from/msg quoted-from/patch \ <quoted-from/0001 >quoted-from/out && - test_cmp "$TEST_DIRECTORY"/t5100/quoted-from.expect quoted-from/msg + test_cmp "$DATA/quoted-from.expect" quoted-from/msg ' test_expect_success 'mailinfo unescapes with --mboxrd' ' mkdir mboxrd && git mailsplit -omboxrd --mboxrd \ - "$TEST_DIRECTORY"/t5100/sample.mboxrd >last && + "$DATA/sample.mboxrd" >last && test x"$(cat last)" = x2 && for i in 0001 0002 do git mailinfo mboxrd/msg mboxrd/patch \ <mboxrd/$i >mboxrd/out && - test_cmp "$TEST_DIRECTORY"/t5100/${i}mboxrd mboxrd/msg + test_cmp "$DATA/${i}mboxrd" mboxrd/msg done && sp=" " && echo "From " >expect && @@ -142,4 +144,18 @@ test_expect_success 'mailinfo unescapes with --mboxrd' ' test_cmp expect mboxrd/msg ' +test_expect_success 'mailinfo handles rfc2822 quoted-string' ' + mkdir quoted-string && + git mailinfo /dev/null /dev/null <"$DATA/quoted-string.in" \ + >quoted-string/info && + test_cmp "$DATA/quoted-string.expect" quoted-string/info +' + +test_expect_success 'mailinfo handles rfc2822 comment' ' + mkdir comment && + git mailinfo /dev/null /dev/null <"$DATA/comment.in" \ + >comment/info && + test_cmp "$DATA/comment.expect" comment/info +' + test_done diff --git a/t/t5100/comment.expect b/t/t5100/comment.expect new file mode 100644 index 0000000000..7228177984 --- /dev/null +++ b/t/t5100/comment.expect @@ -0,0 +1,5 @@ +Author: A U Thor (this is (really) a comment (honestly)) +Email: somebody@example.com +Subject: testing comments +Date: Sun, 25 May 2008 00:38:18 -0700 + diff --git a/t/t5100/comment.in b/t/t5100/comment.in new file mode 100644 index 0000000000..c53a192dfe --- /dev/null +++ b/t/t5100/comment.in @@ -0,0 +1,9 @@ +From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001 +From: "A U Thor" <somebody@example.com> (this is \(really\) a comment (honestly)) +Date: Sun, 25 May 2008 00:38:18 -0700 +Subject: [PATCH] testing comments + + + +--- +patch diff --git a/t/t5100/info0018 b/t/t5100/info0018 new file mode 100644 index 0000000000..d53e7491c7 --- /dev/null +++ b/t/t5100/info0018 @@ -0,0 +1,5 @@ +Author: Another Thor +Email: a.thor@example.com +Subject: This one contains a tab and a space +Date: Fri, 9 Jun 2006 00:44:16 -0700 + diff --git a/t/t5100/info0018--no-inbody-headers b/t/t5100/info0018--no-inbody-headers new file mode 100644 index 0000000000..30b17bd913 --- /dev/null +++ b/t/t5100/info0018--no-inbody-headers @@ -0,0 +1,5 @@ +Author: A U Thor +Email: a.u.thor@example.com +Subject: check multiline inbody headers +Date: Fri, 9 Jun 2006 00:44:16 -0700 + diff --git a/t/t5100/msg0015 b/t/t5100/msg0015 index 4abb3d5c6c..e69de29bb2 100644 --- a/t/t5100/msg0015 +++ b/t/t5100/msg0015 @@ -1,2 +0,0 @@ - - a list - - of stuff diff --git a/t/t5100/msg0018 b/t/t5100/msg0018 new file mode 100644 index 0000000000..56de83d7fc --- /dev/null +++ b/t/t5100/msg0018 @@ -0,0 +1,2 @@ +a commit message + diff --git a/t/t5100/msg0018--no-inbody-headers b/t/t5100/msg0018--no-inbody-headers new file mode 100644 index 0000000000..b1e05d3862 --- /dev/null +++ b/t/t5100/msg0018--no-inbody-headers @@ -0,0 +1,8 @@ +From: Another Thor + <a.thor@example.com> +Subject: This one contains + a tab + and a space + +a commit message + diff --git a/t/t5100/patch0018 b/t/t5100/patch0018 new file mode 100644 index 0000000000..789df6d030 --- /dev/null +++ b/t/t5100/patch0018 @@ -0,0 +1,6 @@ +diff --git a/foo b/foo +index e69de29..d95f3ad 100644 +--- a/foo ++++ b/foo +@@ -0,0 +1 @@ ++content diff --git a/t/t5100/patch0018--no-inbody-headers b/t/t5100/patch0018--no-inbody-headers new file mode 100644 index 0000000000..789df6d030 --- /dev/null +++ b/t/t5100/patch0018--no-inbody-headers @@ -0,0 +1,6 @@ +diff --git a/foo b/foo +index e69de29..d95f3ad 100644 +--- a/foo ++++ b/foo +@@ -0,0 +1 @@ ++content diff --git a/t/t5100/quoted-string.expect b/t/t5100/quoted-string.expect new file mode 100644 index 0000000000..cab1bcebf9 --- /dev/null +++ b/t/t5100/quoted-string.expect @@ -0,0 +1,5 @@ +Author: Author "The Author" Name +Email: somebody@example.com +Subject: testing quoted-pair +Date: Sun, 25 May 2008 00:38:18 -0700 + diff --git a/t/t5100/quoted-string.in b/t/t5100/quoted-string.in new file mode 100644 index 0000000000..e2e627ae23 --- /dev/null +++ b/t/t5100/quoted-string.in @@ -0,0 +1,9 @@ +From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001 +From: "Author \"The Author\" Name" <somebody@example.com> +Date: Sun, 25 May 2008 00:38:18 -0700 +Subject: [PATCH] testing quoted-pair + + + +--- +patch diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox index 8b2ae064c3..6d4d0e4474 100644 --- a/t/t5100/sample.mbox +++ b/t/t5100/sample.mbox @@ -699,3 +699,22 @@ index e69de29..d95f3ad 100644 +++ b/foo @@ -0,0 +1 @@ +New content +From nobody Mon Sep 17 00:00:00 2001 +From: A U Thor <a.u.thor@example.com> +Subject: check multiline inbody headers +Date: Fri, 9 Jun 2006 00:44:16 -0700 + +From: Another Thor + <a.thor@example.com> +Subject: This one contains + a tab + and a space + +a commit message + +diff --git a/foo b/foo +index e69de29..d95f3ad 100644 +--- a/foo ++++ b/foo +@@ -0,0 +1 @@ ++content diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index befdfeefc6..55fc83fc06 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -99,7 +99,7 @@ test_expect_success 'confuses pattern as remote when no remote specified' ' # We could just as easily have used "master"; the "*" emphasizes its # role as a pattern. test_must_fail git ls-remote refs*master >actual 2>&1 && - test_cmp exp actual + test_i18ncmp exp actual ' test_expect_success 'die with non-2 for wrong repository even with --exit-code' ' diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index a1dcdb81d7..f6020cd2aa 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -225,7 +225,7 @@ test_expect_success '%C(auto,...) respects --color=auto (stdout not tty)' ' test_expect_success '%C(auto) respects --color' ' git log --color --format="%C(auto)%H" -1 >actual && - printf "\\033[33m%s\\033[m\\n" $(git rev-parse HEAD) >expect && + printf "\\033[m\\033[33m%s\\033[m\\n" $(git rev-parse HEAD) >expect && test_cmp expect actual ' diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index e94b2f147a..6d06ed96cb 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -709,6 +709,14 @@ test_expect_success HIGHLIGHT \ git commit -m "Add test.sh" && gitweb_run "p=.git;a=blob;f=test.sh"' +test_expect_success HIGHLIGHT \ + 'syntax highlighting (highlighter language autodetection)' \ + 'git config gitweb.highlight yes && + echo "#!/usr/bin/perl" > test && + git add test && + git commit -m "Add test" && + gitweb_run "p=.git;a=blob;f=test"' + # ---------------------------------------------------------------------- # forks of projects diff --git a/unpack-trees.c b/unpack-trees.c index 3db3f02577..ea6bdd20e0 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1094,12 +1094,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options int i, ret; static struct cache_entry *dfc; struct exclude_list el; - struct checkout state; + struct checkout state = CHECKOUT_INIT; if (len > MAX_UNPACK_TREES) die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES); - memset(&state, 0, sizeof(state)); - state.base_dir = ""; state.force = 1; state.quiet = 1; state.refresh_cache = 1; diff --git a/wt-status.c b/wt-status.c index 9a14658e7e..9628c1d5d7 100644 --- a/wt-status.c +++ b/wt-status.c @@ -367,11 +367,11 @@ static void wt_longstatus_print_change_data(struct wt_status *s, if (d->new_submodule_commits || d->dirty_submodule) { strbuf_addstr(&extra, " ("); if (d->new_submodule_commits) - strbuf_addf(&extra, _("new commits, ")); + strbuf_addstr(&extra, _("new commits, ")); if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED) - strbuf_addf(&extra, _("modified content, ")); + strbuf_addstr(&extra, _("modified content, ")); if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) - strbuf_addf(&extra, _("untracked content, ")); + strbuf_addstr(&extra, _("untracked content, ")); strbuf_setlen(&extra, extra.len - 2); strbuf_addch(&extra, ')'); } diff --git a/xdiff-interface.c b/xdiff-interface.c index 3bfc69cade..060038c2d6 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -214,11 +214,10 @@ struct ff_regs { static long ff_regexp(const char *line, long len, char *buffer, long buffer_size, void *priv) { - char *line_buffer; struct ff_regs *regs = priv; regmatch_t pmatch[2]; int i; - int result = -1; + int result; /* Exclude terminating newline (and cr) from matching */ if (len > 0 && line[len-1] == '\n') { @@ -228,18 +227,16 @@ static long ff_regexp(const char *line, long len, len--; } - line_buffer = xstrndup(line, len); /* make NUL terminated */ - for (i = 0; i < regs->nr; i++) { struct ff_reg *reg = regs->array + i; - if (!regexec(®->re, line_buffer, 2, pmatch, 0)) { + if (!regexec_buf(®->re, line, len, 2, pmatch, 0)) { if (reg->negate) - goto fail; + return -1; break; } } if (regs->nr <= i) - goto fail; + return -1; i = pmatch[1].rm_so >= 0 ? 1 : 0; line += pmatch[i].rm_so; result = pmatch[i].rm_eo - pmatch[i].rm_so; @@ -248,8 +245,6 @@ static long ff_regexp(const char *line, long len, while (result > 0 && (isspace(line[result - 1]))) result--; memcpy(buffer, line, result); - fail: - free(line_buffer); return result; } diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 7423f77fc8..8db16d4ae6 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -42,6 +42,7 @@ extern "C" { #define XDF_IGNORE_BLANK_LINES (1 << 7) #define XDF_COMPACTION_HEURISTIC (1 << 8) +#define XDF_INDENT_HEURISTIC (1 << 9) #define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_FUNCCONTEXT (1 << 2) diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index b3c6848875..760fbb6db7 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -400,138 +400,577 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, } -static int is_blank_line(xrecord_t **recs, long ix, long flags) +static int is_blank_line(xrecord_t *rec, long flags) { - return xdl_blankline(recs[ix]->ptr, recs[ix]->size, flags); + return xdl_blankline(rec->ptr, rec->size, flags); } -static int recs_match(xrecord_t **recs, long ixs, long ix, long flags) +static int recs_match(xrecord_t *rec1, xrecord_t *rec2, long flags) { - return (recs[ixs]->ha == recs[ix]->ha && - xdl_recmatch(recs[ixs]->ptr, recs[ixs]->size, - recs[ix]->ptr, recs[ix]->size, + return (rec1->ha == rec2->ha && + xdl_recmatch(rec1->ptr, rec1->size, + rec2->ptr, rec2->size, flags)); } -int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { - long ix, ixo, ixs, ixref, grpsiz, nrec = xdf->nrec; - char *rchg = xdf->rchg, *rchgo = xdfo->rchg; - unsigned int blank_lines; - xrecord_t **recs = xdf->recs; +/* + * If a line is indented more than this, get_indent() just returns this value. + * This avoids having to do absurd amounts of work for data that are not + * human-readable text, and also ensures that the output of get_indent fits within + * an int. + */ +#define MAX_INDENT 200 +/* + * Return the amount of indentation of the specified line, treating TAB as 8 + * columns. Return -1 if line is empty or contains only whitespace. Clamp the + * output value at MAX_INDENT. + */ +static int get_indent(xrecord_t *rec) +{ + long i; + int ret = 0; + + for (i = 0; i < rec->size; i++) { + char c = rec->ptr[i]; + + if (!XDL_ISSPACE(c)) + return ret; + else if (c == ' ') + ret += 1; + else if (c == '\t') + ret += 8 - ret % 8; + /* ignore other whitespace characters */ + + if (ret >= MAX_INDENT) + return MAX_INDENT; + } + + /* The line contains only whitespace. */ + return -1; +} + +/* + * If more than this number of consecutive blank rows are found, just return this + * value. This avoids requiring O(N^2) work for pathological cases, and also + * ensures that the output of score_split fits in an int. + */ +#define MAX_BLANKS 20 + +/* Characteristics measured about a hypothetical split position. */ +struct split_measurement { /* - * This is the same of what GNU diff does. Move back and forward - * change groups for a consistent and pretty diff output. This also - * helps in finding joinable change groups and reduce the diff size. + * Is the split at the end of the file (aside from any blank lines)? */ - for (ix = ixo = 0;;) { - /* - * Find the first changed line in the to-be-compacted file. - * We need to keep track of both indexes, so if we find a - * changed lines group on the other file, while scanning the - * to-be-compacted file, we need to skip it properly. Note - * that loops that are testing for changed lines on rchg* do - * not need index bounding since the array is prepared with - * a zero at position -1 and N. - */ - for (; ix < nrec && !rchg[ix]; ix++) - while (rchgo[ixo++]); - if (ix == nrec) + int end_of_file; + + /* + * How much is the line immediately following the split indented (or -1 if + * the line is blank): + */ + int indent; + + /* + * How many consecutive lines above the split are blank? + */ + int pre_blank; + + /* + * How much is the nearest non-blank line above the split indented (or -1 + * if there is no such line)? + */ + int pre_indent; + + /* + * How many lines after the line following the split are blank? + */ + int post_blank; + + /* + * How much is the nearest non-blank line after the line following the + * split indented (or -1 if there is no such line)? + */ + int post_indent; +}; + +struct split_score { + /* The effective indent of this split (smaller is preferred). */ + int effective_indent; + + /* Penalty for this split (smaller is preferred). */ + int penalty; +}; + +/* + * Fill m with information about a hypothetical split of xdf above line split. + */ +static void measure_split(const xdfile_t *xdf, long split, + struct split_measurement *m) +{ + long i; + + if (split >= xdf->nrec) { + m->end_of_file = 1; + m->indent = -1; + } else { + m->end_of_file = 0; + m->indent = get_indent(xdf->recs[split]); + } + + m->pre_blank = 0; + m->pre_indent = -1; + for (i = split - 1; i >= 0; i--) { + m->pre_indent = get_indent(xdf->recs[i]); + if (m->pre_indent != -1) + break; + m->pre_blank += 1; + if (m->pre_blank == MAX_BLANKS) { + m->pre_indent = 0; + break; + } + } + + m->post_blank = 0; + m->post_indent = -1; + for (i = split + 1; i < xdf->nrec; i++) { + m->post_indent = get_indent(xdf->recs[i]); + if (m->post_indent != -1) break; + m->post_blank += 1; + if (m->post_blank == MAX_BLANKS) { + m->post_indent = 0; + break; + } + } +} + +/* + * The empirically-determined weight factors used by score_split() below. + * Larger values means that the position is a less favorable place to split. + * + * Note that scores are only ever compared against each other, so multiplying + * all of these weight/penalty values by the same factor wouldn't change the + * heuristic's behavior. Still, we need to set that arbitrary scale *somehow*. + * In practice, these numbers are chosen to be large enough that they can be + * adjusted relative to each other with sufficient precision despite using + * integer math. + */ + +/* Penalty if there are no non-blank lines before the split */ +#define START_OF_FILE_PENALTY 1 + +/* Penalty if there are no non-blank lines after the split */ +#define END_OF_FILE_PENALTY 21 +/* Multiplier for the number of blank lines around the split */ +#define TOTAL_BLANK_WEIGHT (-30) + +/* Multiplier for the number of blank lines after the split */ +#define POST_BLANK_WEIGHT 6 + +/* + * Penalties applied if the line is indented more than its predecessor + */ +#define RELATIVE_INDENT_PENALTY (-4) +#define RELATIVE_INDENT_WITH_BLANK_PENALTY 10 + +/* + * Penalties applied if the line is indented less than both its predecessor and + * its successor + */ +#define RELATIVE_OUTDENT_PENALTY 24 +#define RELATIVE_OUTDENT_WITH_BLANK_PENALTY 17 + +/* + * Penalties applied if the line is indented less than its predecessor but not + * less than its successor + */ +#define RELATIVE_DEDENT_PENALTY 23 +#define RELATIVE_DEDENT_WITH_BLANK_PENALTY 17 + +/* + * We only consider whether the sum of the effective indents for splits are + * less than (-1), equal to (0), or greater than (+1) each other. The resulting + * value is multiplied by the following weight and combined with the penalty to + * determine the better of two scores. + */ +#define INDENT_WEIGHT 60 + +/* + * Compute a badness score for the hypothetical split whose measurements are + * stored in m. The weight factors were determined empirically using the tools and + * corpus described in + * + * https://github.com/mhagger/diff-slider-tools + * + * Also see that project if you want to improve the weights based on, for example, + * a larger or more diverse corpus. + */ +static void score_add_split(const struct split_measurement *m, struct split_score *s) +{ + /* + * A place to accumulate penalty factors (positive makes this index more + * favored): + */ + int post_blank, total_blank, indent, any_blanks; + + if (m->pre_indent == -1 && m->pre_blank == 0) + s->penalty += START_OF_FILE_PENALTY; + + if (m->end_of_file) + s->penalty += END_OF_FILE_PENALTY; + + /* + * Set post_blank to the number of blank lines following the split, + * including the line immediately after the split: + */ + post_blank = (m->indent == -1) ? 1 + m->post_blank : 0; + total_blank = m->pre_blank + post_blank; + + /* Penalties based on nearby blank lines: */ + s->penalty += TOTAL_BLANK_WEIGHT * total_blank; + s->penalty += POST_BLANK_WEIGHT * post_blank; + + if (m->indent != -1) + indent = m->indent; + else + indent = m->post_indent; + + any_blanks = (total_blank != 0); + + /* Note that the effective indent is -1 at the end of the file: */ + s->effective_indent += indent; + + if (indent == -1) { + /* No additional adjustments needed. */ + } else if (m->pre_indent == -1) { + /* No additional adjustments needed. */ + } else if (indent > m->pre_indent) { + /* + * The line is indented more than its predecessor. + */ + s->penalty += any_blanks ? + RELATIVE_INDENT_WITH_BLANK_PENALTY : + RELATIVE_INDENT_PENALTY; + } else if (indent == m->pre_indent) { + /* + * The line has the same indentation level as its predecessor. + * No additional adjustments needed. + */ + } else { /* - * Record the start of a changed-group in the to-be-compacted file - * and find the end of it, on both to-be-compacted and other file - * indexes (ix and ixo). + * The line is indented less than its predecessor. It could be + * the block terminator of the previous block, but it could + * also be the start of a new block (e.g., an "else" block, or + * maybe the previous block didn't have a block terminator). + * Try to distinguish those cases based on what comes next: */ - ixs = ix; - for (ix++; rchg[ix]; ix++); - for (; rchgo[ixo]; ixo++); + if (m->post_indent != -1 && m->post_indent > indent) { + /* + * The following line is indented more. So it is likely + * that this line is the start of a block. + */ + s->penalty += any_blanks ? + RELATIVE_OUTDENT_WITH_BLANK_PENALTY : + RELATIVE_OUTDENT_PENALTY; + } else { + /* + * That was probably the end of a block. + */ + s->penalty += any_blanks ? + RELATIVE_DEDENT_WITH_BLANK_PENALTY : + RELATIVE_DEDENT_PENALTY; + } + } +} + +static int score_cmp(struct split_score *s1, struct split_score *s2) +{ + /* -1 if s1.effective_indent < s2->effective_indent, etc. */ + int cmp_indents = ((s1->effective_indent > s2->effective_indent) - + (s1->effective_indent < s2->effective_indent)); + + return INDENT_WEIGHT * cmp_indents + (s1->penalty - s2->penalty); +} + +/* + * Represent a group of changed lines in an xdfile_t (i.e., a contiguous group + * of lines that was inserted or deleted from the corresponding version of the + * file). We consider there to be such a group at the beginning of the file, at + * the end of the file, and between any two unchanged lines, though most such + * groups will usually be empty. + * + * If the first line in a group is equal to the line following the group, then + * the group can be slid down. Similarly, if the last line in a group is equal + * to the line preceding the group, then the group can be slid up. See + * group_slide_down() and group_slide_up(). + * + * Note that loops that are testing for changed lines in xdf->rchg do not need + * index bounding since the array is prepared with a zero at position -1 and N. + */ +struct xdlgroup { + /* + * The index of the first changed line in the group, or the index of + * the unchanged line above which the (empty) group is located. + */ + long start; + + /* + * The index of the first unchanged line after the group. For an empty + * group, end is equal to start. + */ + long end; +}; + +/* + * Initialize g to point at the first group in xdf. + */ +static void group_init(xdfile_t *xdf, struct xdlgroup *g) +{ + g->start = g->end = 0; + while (xdf->rchg[g->end]) + g->end++; +} + +/* + * Move g to describe the next (possibly empty) group in xdf and return 0. If g + * is already at the end of the file, do nothing and return -1. + */ +static inline int group_next(xdfile_t *xdf, struct xdlgroup *g) +{ + if (g->end == xdf->nrec) + return -1; + g->start = g->end + 1; + for (g->end = g->start; xdf->rchg[g->end]; g->end++) + ; + + return 0; +} + +/* + * Move g to describe the previous (possibly empty) group in xdf and return 0. + * If g is already at the beginning of the file, do nothing and return -1. + */ +static inline int group_previous(xdfile_t *xdf, struct xdlgroup *g) +{ + if (g->start == 0) + return -1; + + g->end = g->start - 1; + for (g->start = g->end; xdf->rchg[g->start - 1]; g->start--) + ; + + return 0; +} + +/* + * If g can be slid toward the end of the file, do so, and if it bumps into a + * following group, expand this group to include it. Return 0 on success or -1 + * if g cannot be slid down. + */ +static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g, long flags) +{ + if (g->end < xdf->nrec && + recs_match(xdf->recs[g->start], xdf->recs[g->end], flags)) { + xdf->rchg[g->start++] = 0; + xdf->rchg[g->end++] = 1; + + while (xdf->rchg[g->end]) + g->end++; + + return 0; + } else { + return -1; + } +} + +/* + * If g can be slid toward the beginning of the file, do so, and if it bumps + * into a previous group, expand this group to include it. Return 0 on success + * or -1 if g cannot be slid up. + */ +static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g, long flags) +{ + if (g->start > 0 && + recs_match(xdf->recs[g->start - 1], xdf->recs[g->end - 1], flags)) { + xdf->rchg[--g->start] = 1; + xdf->rchg[--g->end] = 0; + + while (xdf->rchg[g->start - 1]) + g->start--; + + return 0; + } else { + return -1; + } +} + +static void xdl_bug(const char *msg) +{ + fprintf(stderr, "BUG: %s\n", msg); + exit(1); +} + +/* + * Move back and forward change groups for a consistent and pretty diff output. + * This also helps in finding joinable change groups and reducing the diff + * size. + */ +int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { + struct xdlgroup g, go; + long earliest_end, end_matching_other; + long groupsize; + unsigned int blank_lines; + + group_init(xdf, &g); + group_init(xdfo, &go); + + while (1) { + /* If the group is empty in the to-be-compacted file, skip it: */ + if (g.end == g.start) + goto next; + + /* + * Now shift the change up and then down as far as possible in + * each direction. If it bumps into any other changes, merge them. + */ do { - grpsiz = ix - ixs; - blank_lines = 0; + groupsize = g.end - g.start; /* - * If the line before the current change group, is equal to - * the last line of the current change group, shift backward - * the group. + * Keep track of the last "end" index that causes this + * group to align with a group of changed lines in the + * other file. -1 indicates that we haven't found such + * a match yet: */ - while (ixs > 0 && recs_match(recs, ixs - 1, ix - 1, flags)) { - rchg[--ixs] = 1; - rchg[--ix] = 0; - - /* - * This change might have joined two change groups, - * so we try to take this scenario in account by moving - * the start index accordingly (and so the other-file - * end-of-group index). - */ - for (; rchg[ixs - 1]; ixs--); - while (rchgo[--ixo]); - } + end_matching_other = -1; /* - * Record the end-of-group position in case we are matched - * with a group of changes in the other file (that is, the - * change record before the end-of-group index in the other - * file is set). + * Boolean value that records whether there are any blank + * lines that could be made to be the last line of this + * group. */ - ixref = rchgo[ixo - 1] ? ix: nrec; + blank_lines = 0; + + /* Shift the group backward as much as possible: */ + while (!group_slide_up(xdf, &g, flags)) + if (group_previous(xdfo, &go)) + xdl_bug("group sync broken sliding up"); /* - * If the first line of the current change group, is equal to - * the line next of the current change group, shift forward - * the group. + * This is this highest that this group can be shifted. + * Record its end index: */ - while (ix < nrec && recs_match(recs, ixs, ix, flags)) { - blank_lines += is_blank_line(recs, ix, flags); - - rchg[ixs++] = 0; - rchg[ix++] = 1; - - /* - * This change might have joined two change groups, - * so we try to take this scenario in account by moving - * the start index accordingly (and so the other-file - * end-of-group index). Keep tracking the reference - * index in case we are shifting together with a - * corresponding group of changes in the other file. - */ - for (; rchg[ix]; ix++); - while (rchgo[++ixo]) - ixref = ix; - } - } while (grpsiz != ix - ixs); + earliest_end = g.end; - /* - * Try to move back the possibly merged group of changes, to match - * the recorded position in the other file. - */ - while (ixref < ix) { - rchg[--ixs] = 1; - rchg[--ix] = 0; - while (rchgo[--ixo]); - } + if (go.end > go.start) + end_matching_other = g.end; + + /* Now shift the group forward as far as possible: */ + while (1) { + if (!blank_lines) + blank_lines = is_blank_line( + xdf->recs[g.end - 1], + flags); + + if (group_slide_down(xdf, &g, flags)) + break; + if (group_next(xdfo, &go)) + xdl_bug("group sync broken sliding down"); + + if (go.end > go.start) + end_matching_other = g.end; + } + } while (groupsize != g.end - g.start); /* - * If a group can be moved back and forth, see if there is a - * blank line in the moving space. If there is a blank line, - * make sure the last blank line is the end of the group. + * If the group can be shifted, then we can possibly use this + * freedom to produce a more intuitive diff. * - * As we already shifted the group forward as far as possible - * in the earlier loop, we need to shift it back only if at all. + * The group is currently shifted as far down as possible, so the + * heuristics below only have to handle upwards shifts. */ - if ((flags & XDF_COMPACTION_HEURISTIC) && blank_lines) { - while (ixs > 0 && - !is_blank_line(recs, ix - 1, flags) && - recs_match(recs, ixs - 1, ix - 1, flags)) { - rchg[--ixs] = 1; - rchg[--ix] = 0; + + if (g.end == earliest_end) { + /* no shifting was possible */ + } else if (end_matching_other != -1) { + /* + * Move the possibly merged group of changes back to line + * up with the last group of changes from the other file + * that it can align with. + */ + while (go.end == go.start) { + if (group_slide_up(xdf, &g, flags)) + xdl_bug("match disappeared"); + if (group_previous(xdfo, &go)) + xdl_bug("group sync broken sliding to match"); + } + } else if ((flags & XDF_COMPACTION_HEURISTIC) && blank_lines) { + /* + * Compaction heuristic: if it is possible to shift the + * group to make its bottom line a blank line, do so. + * + * As we already shifted the group forward as far as + * possible in the earlier loop, we only need to handle + * backward shifts, not forward ones. + */ + while (!is_blank_line(xdf->recs[g.end - 1], flags)) { + if (group_slide_up(xdf, &g, flags)) + xdl_bug("blank line disappeared"); + if (group_previous(xdfo, &go)) + xdl_bug("group sync broken sliding to blank line"); + } + } else if (flags & XDF_INDENT_HEURISTIC) { + /* + * Indent heuristic: a group of pure add/delete lines + * implies two splits, one between the end of the "before" + * context and the start of the group, and another between + * the end of the group and the beginning of the "after" + * context. Some splits are aesthetically better and some + * are worse. We compute a badness "score" for each split, + * and add the scores for the two splits to define a + * "score" for each position that the group can be shifted + * to. Then we pick the shift with the lowest score. + */ + long shift, best_shift = -1; + struct split_score best_score; + + for (shift = earliest_end; shift <= g.end; shift++) { + struct split_measurement m; + struct split_score score = {0, 0}; + + measure_split(xdf, shift, &m); + score_add_split(&m, &score); + measure_split(xdf, shift - groupsize, &m); + score_add_split(&m, &score); + if (best_shift == -1 || + score_cmp(&score, &best_score) <= 0) { + best_score.effective_indent = score.effective_indent; + best_score.penalty = score.penalty; + best_shift = shift; + } + } + + while (g.end > best_shift) { + if (group_slide_up(xdf, &g, flags)) + xdl_bug("best shift unreached"); + if (group_previous(xdfo, &go)) + xdl_bug("group sync broken sliding to blank line"); } } + + next: + /* Move past the just-processed group: */ + if (group_next(xdf, &g)) + break; + if (group_next(xdfo, &go)) + xdl_bug("group sync broken moving to next group"); } + if (!group_next(xdfo, &go)) + xdl_bug("group sync broken at end of file"); + return 0; } |