diff options
237 files changed, 7002 insertions, 2750 deletions
diff --git a/.gitignore b/.gitignore index 1c57d4c958..41c0b20a76 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ git-apply git-archimport git-archive git-bisect +git-bisect--helper git-blame git-branch git-bundle @@ -35,6 +36,8 @@ git-diff git-diff-files git-diff-index git-diff-tree +git-difftool +git-difftool--helper git-describe git-fast-export git-fast-import @@ -78,6 +81,7 @@ git-merge-recursive git-merge-resolve git-merge-subtree git-mergetool +git-mergetool--lib git-mktag git-mktree git-name-rev diff --git a/Documentation/Makefile b/Documentation/Makefile index e18242a6d4..7a8037f586 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -240,7 +240,7 @@ $(MAN_HTML): %.html : %.txt mv $@+ $@ user-manual.xml: user-manual.txt user-manual.conf - $(QUIET_ASCIIDOC)$(ASCIIDOC) -b docbook -d book $< + $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book $< technical/api-index.txt: technical/api-index-skel.txt \ technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS)) @@ -293,13 +293,13 @@ howto-index.txt: howto-index.sh $(wildcard howto/*.txt) mv $@+ $@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt - $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt + $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 $*.txt WEBDOC_DEST = /pub/software/scm/git/docs $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ - sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \ + sed -e '1,/^$$/d' $< | $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 - >$@+ && \ mv $@+ $@ install-webdoc : html diff --git a/Documentation/RelNotes-1.6.1.4.txt b/Documentation/RelNotes-1.6.1.4.txt index a9f1a6b8b5..0ce6316d75 100644 --- a/Documentation/RelNotes-1.6.1.4.txt +++ b/Documentation/RelNotes-1.6.1.4.txt @@ -4,15 +4,40 @@ GIT v1.6.1.4 Release Notes Fixes since v1.6.1.3 -------------------- +* .gitignore learned to handle backslash as a quoting mechanism for + comment introduction character "#". + This fix was first merged to 1.6.2.1. + * "git fast-export" produced wrong output with some parents missing from commits, when the history is clock-skewed. * "git fast-import" sometimes failed to read back objects it just wrote out and aborted, because it failed to flush stale cached data. +* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when + deciding to descend into a subdirectory but they did not match the + individual paths correctly. This caused pathspecs "abc/d ab" to match + "abc/0" ("abc/d" made them decide to descend into the directory "abc/", + and then "ab" incorrectly matched "abc/0" when it shouldn't). + This fix was first merged to 1.6.2.3. + +* import-zips script (in contrib) did not compute the common directory + prefix correctly. + This fix was first merged to 1.6.2.2. + +* "git init" segfaulted when given an overlong template location via + the --template= option. + This fix was first merged to 1.6.2.4. + * "git repack" did not error out when necessary object was missing in the repository. +* git-repack (invoked from git-gc) did not work as nicely as it should in + a repository that borrows objects from neighbours via alternates + mechanism especially when some packs are marked with the ".keep" flag + to prevent them from being repacked. + This fix was first merged to 1.6.2.3. + Also includes minor documentation fixes and updates. -- diff --git a/Documentation/RelNotes-1.6.2.3.txt b/Documentation/RelNotes-1.6.2.3.txt index 6560593fd5..4d3c1ac91c 100644 --- a/Documentation/RelNotes-1.6.2.3.txt +++ b/Documentation/RelNotes-1.6.2.3.txt @@ -20,9 +20,3 @@ Fixes since v1.6.2.2 to prevent them from being repacked. Many small documentation updates are included as well. - ---- -exec >/var/tmp/1 -echo O=$(git describe maint) -O=v1.6.2.2-41-gbff82d0 -git shortlog --no-merges $O..maint diff --git a/Documentation/RelNotes-1.6.2.4.txt b/Documentation/RelNotes-1.6.2.4.txt new file mode 100644 index 0000000000..f4bf1d0986 --- /dev/null +++ b/Documentation/RelNotes-1.6.2.4.txt @@ -0,0 +1,39 @@ +GIT v1.6.2.4 Release Notes +========================== + +Fixes since v1.6.2.3 +-------------------- + +* The configuration parser had a buffer overflow while parsing an overlong + value. + +* pruning reflog entries that are unreachable from the tip of the ref + during "git reflog prune" (hence "git gc") was very inefficient. + +* "git-add -p" lacked a way to say "q"uit to refuse staging any hunks for + the remaining paths. You had to say "d" and then ^C. + +* "git-checkout <tree-ish> <submodule>" did not update the index entry at + the named path; it now does. + +* "git-fast-export" choked when seeing a tag that does not point at commit. + +* "git init" segfaulted when given an overlong template location via + the --template= option. + +* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when + deciding to descend into a subdirectory but they did not match the + individual paths correctly. This caused pathspecs "abc/d ab" to match + "abc/0" ("abc/d" made them decide to descend into the directory "abc/", + and then "ab" incorrectly matched "abc/0" when it shouldn't). + +* "git-merge-recursive" was broken when a submodule entry was involved in + a criss-cross merge situation. + +Many small documentation updates are included as well. + +--- +exec >/var/tmp/1 +echo O=$(git describe maint) +O=v1.6.2.3-38-g318b847 +git shortlog --no-merges $O..maint diff --git a/Documentation/RelNotes-1.6.2.5.txt b/Documentation/RelNotes-1.6.2.5.txt new file mode 100644 index 0000000000..b23f9e95d1 --- /dev/null +++ b/Documentation/RelNotes-1.6.2.5.txt @@ -0,0 +1,21 @@ +GIT v1.6.2.5 Release Notes +========================== + +Fixes since v1.6.2.4 +-------------------- + +* "git apply" mishandled if you fed a git generated patch that renames + file A to B and file B to A at the same time. + +* "git diff -c -p" (and "diff --cc") did not expect to see submodule + differences and instead refused to work. + +* "git grep -e '('" segfaulted, instead of diagnosing a mismatched + parentheses error. + +* "git fetch" generated packs with offset-delta encoding when both ends of + the connection are capable of producing one; this cannot be read by + ancient git and the user should be able to disable this by setting + repack.usedeltabaseoffset configuration to false. + + diff --git a/Documentation/RelNotes-1.6.3.1.txt b/Documentation/RelNotes-1.6.3.1.txt new file mode 100644 index 0000000000..2400b72ef7 --- /dev/null +++ b/Documentation/RelNotes-1.6.3.1.txt @@ -0,0 +1,10 @@ +GIT v1.6.3.1 Release Notes +========================== + +Fixes since v1.6.3 +------------------ + +* "git checkout -b new-branch" with a staged change in the index + incorrectly primed the in-index cache-tree, resulting a wrong tree + object to be written out of the index. This is a grave regression + since the last 1.6.2.X maintenance release. diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt index 9aa143b199..418c685cf8 100644 --- a/Documentation/RelNotes-1.6.3.txt +++ b/Documentation/RelNotes-1.6.3.txt @@ -35,16 +35,23 @@ Updates since v1.6.2 (subsystems) +* various git-svn updates. + +* git-gui updates, including an update to Russian translation, and a + fix to an infinite loop when showing an empty diff. + +* gitk updates, including an update to Russian translation and improved Windows + support. + (performance) * many uses of lstat(2) in the codepath for "git checkout" have been optimized out. -* pruning reflog entries that are unreachable from the tip of the ref - during "git reflog prune" (hence "git gc") was very inefficient. - (usability, bells and whistles) +* Boolean configuration variable yes/no can be written as on/off. + * rsync:/path/to/repo can be used to run git over rsync for local repositories. It may not be useful in practice; meant primarily for testing. @@ -61,34 +68,45 @@ Updates since v1.6.2 * "--oneline" is a synonym for "--pretty=oneline --abbrev-commit". +* "--graph" to the "git log" family can draw the commit ancestry graph + in colors. + * If you realize that you botched the patch when you are editing hunks with the 'edit' action in git-add -i/-p, you can abort the editor to tell git not to apply it. -* The number of commits shown in "you are ahead/behind your upstream" - messages given by "git checkout" and "git status" used to count merge - commits; now it doesn't. - * @{-1} is a new way to refer to the last branch you were on introduced in 1.6.2, but the initial implementation did not teach this to a few commands. Now the syntax works with "branch -m @{-1} newname". * git-archive learned --output=<file> option. +* git-archive takes attributes from the tree being archived; strictly + speaking, this is an incompatible behaviour change, but is a good one. + Use --worktree-attributes option to allow it to read attributes from + the work tree as before (deprecated git-tar tree command always reads + attributes from the work tree). + * git-bisect shows not just the number of remaining commits whose goodness is unknown, but also shows the estimated number of remaining rounds. * You can give --date=<format> option to git-blame. -* git-branch -r shows HEAD symref that points at a remote branch in +* "git-branch -r" shows HEAD symref that points at a remote branch in interest of each tracked remote repository. +* "git-branch -v -v" is a new way to get list of names for branches and the + "upstream" branch for them. + * git-config learned -e option to open an editor to edit the config file directly. * git-clone runs post-checkout hook when run without --no-checkout. -* git-fast-export choked when seeing a tag that does not point at commit. +* git-difftool is now part of the officially supported command, primarily + maintained by David Aguilar. + +* git-for-each-ref learned a new "upstream" token. * git-format-patch can be told to use attachment with a new configuration, format.attach. @@ -118,6 +136,9 @@ Updates since v1.6.2 * Output from git-remote command has been vastly improved. +* "git remote update --prune $remote" updates from the named remote and + then prunes stale tracking branches. + * git-send-email learned --confirm option to review the Cc: list before sending the messages out. @@ -137,6 +158,10 @@ Updates since v1.6.2 knobs you can tweak to work around issues with various versions of the docbook-xsl package. See comments in Documentation/Makefile for details. +* Support for building and testing a subset of git on a system without a + working perl has been improved. + + Fixes since v1.6.2 ------------------ @@ -146,26 +171,12 @@ release, unless otherwise noted. Here are fixes that this release has, but have not been backported to v1.6.2.X series. +* "git-apply" rejected a patch that swaps two files (i.e. renames A to B + and B to A at the same time). May need to be backported by cherry + picking d8c81df and then 7fac0ee). + * The initial checkout did not read the attributes from the .gitattribute file that is being checked out. -* "git-checkout <tree-ish> <submodule>" did not update the index entry at - the named path; it now does. - * git-gc spent excessive amount of time to decide if an object appears in a locally existing pack (if needed, backport by merging 69e020a). - -* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when - deciding to descend into a subdirectory but they did not match the - individual paths correctly. This caused pathspecs "abc/d ab" to match - "abc/0" ("abc/d" made them decide to descend into the directory "abc/", - and then "ab" incorrectly matched "abc/0" when it shouldn't). - -* "git-merge-recursive" was broken when a submodule entry was involved in - a criss-cross merge situation. - ---- -exec >/var/tmp/1 -O=v1.6.2.2-484-g796b137 -echo O=$(git describe master) -git shortlog --no-merges $O..master ^maint diff --git a/Documentation/RelNotes-1.6.4.txt b/Documentation/RelNotes-1.6.4.txt new file mode 100644 index 0000000000..b70ec11c26 --- /dev/null +++ b/Documentation/RelNotes-1.6.4.txt @@ -0,0 +1,59 @@ +GIT v1.6.4 Release Notes +======================== + +With the next major release, "git push" into a branch that is +currently checked out will be refused by default. You can choose +what should happen upon such a push by setting the configuration +variable receive.denyCurrentBranch in the receiving repository. + +To ease the transition plan, the receiving repository of such a +push running this release will issue a big warning when the +configuration variable is missing. Please refer to: + + http://git.or.cz/gitwiki/GitFaq#non-bare + http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007 + +for more details on the reason why this change is needed and the +transition plan. + +For a similar reason, "git push $there :$killed" to delete the branch +$killed in a remote repository $there, if $killed branch is the current +branch pointed at by its HEAD, gets a large warning. You can choose what +should happen upon such a push by setting the configuration variable +receive.denyDeleteCurrent in the receiving repository. + +When the user does not tell "git push" what to push, it has always +pushed matching refs. For some people it is unexpected, and a new +configuration variable push.default has been introduced to allow +changing a different default behaviour. To advertise the new feature, +a big warning is issued if this is not configured and a git push without +arguments is attempted. + + +Updates since v1.6.3 +-------------------- + +(subsystems) + +(performance) + +(usability, bells and whistles) + +(developers) + + +Fixes since v1.6.3 +------------------ + +All of the fixes in v1.6.3.X maintenance series are included in this +release, unless otherwise noted. + +Here are fixes that this release has, but have not been backported to +v1.6.3.X series. + + +--- +exec >/var/tmp/1 +echo O=$(git describe master) +O=v1.6.3 +git shortlog --no-merges $O..master ^maint diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 8d818a2160..76fc84d878 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -6,9 +6,13 @@ Checklist (and a short version for the impatient): - check for unnecessary whitespace with "git diff --check" before committing - do not check in commented out code or unneeded files - - provide a meaningful commit message - the first line of the commit message should be a short description and should skip the full stop + - the body should provide a meaningful commit message, which: + - uses the imperative, present tense: "change", + not "changed" or "changes". + - includes motivation for the change, and contrasts + its implementation with previous behaviour - if you want your work included in git.git, add a "Signed-off-by: Your Name <you@example.com>" line to the commit message (or just use the option "-s" when @@ -62,6 +66,14 @@ Describe the technical detail of the change(s). If your description starts to get too long, that's a sign that you probably need to split up your commit to finer grained pieces. +That being said, patches which plainly describe the things that +help reviewers check the patch, and future maintainers understand +the code, are the most beautiful patches. Descriptions that summarise +the point in the subject well, and describe the motivation for the +change, the approach taken by the change, and if relevant how this +differs substantially from the prior version, can be found on Usenet +archives back into the late 80's. Consider it like good Netiquette, +but for code. Oh, another thing. I am picky about whitespaces. Make sure your changes do not trigger errors with the sample pre-commit hook shipped diff --git a/Documentation/config.txt b/Documentation/config.txt index 3afd124749..2c031620c5 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -2,15 +2,15 @@ CONFIGURATION FILE ------------------ The git configuration file contains a number of variables that affect -the git command's behavior. `.git/config` file for each repository -is used to store the information for that repository, and -`$HOME/.gitconfig` is used to store per user information to give -fallback values for `.git/config` file. The file `/etc/gitconfig` -can be used to store system-wide defaults. - -They can be used by both the git plumbing -and the porcelains. The variables are divided into sections, where -in the fully qualified variable name the variable itself is the last +the git command's behavior. The `.git/config` file in each repository +is used to store the configuration for that repository, and +`$HOME/.gitconfig` is used to store a per-user configuration as +fallback values for the `.git/config` file. The file `/etc/gitconfig` +can be used to store a system-wide default configuration. + +The configuration variables are used by both the git plumbing +and the porcelains. The variables are divided into sections, wherein +the fully qualified variable name of the variable itself is the last dot-separated segment and the section name is everything before the last dot. The variable names are case-insensitive and only alphanumeric characters are allowed. Some variables may appear multiple times. @@ -26,28 +26,28 @@ The file consists of sections and variables. A section begins with the name of the section in square brackets and continues until the next section begins. Section names are not case sensitive. Only alphanumeric characters, `-` and `.` are allowed in section names. Each variable -must belong to some section, which means that there must be section -header before first setting of a variable. +must belong to some section, which means that there must be a section +header before the first setting of a variable. Sections can be further divided into subsections. To begin a subsection put its name in double quotes, separated by space from the section name, -in the section header, like in example below: +in the section header, like in the example below: -------- [section "subsection"] -------- -Subsection names can contain any characters except newline (doublequote -`"` and backslash have to be escaped as `\"` and `\\`, -respectively) and are case sensitive. Section header cannot span multiple +Subsection names are case sensitive and can contain any characters except +newline (doublequote `"` and backslash have to be escaped as `\"` and `\\`, +respectively). Section headers cannot span multiple lines. Variables may belong directly to a section or to a given subsection. You can have `[section]` if you have `[section "subsection"]`, but you don't need to. -There is also (case insensitive) alternative `[section.subsection]` syntax. -In this syntax subsection names follow the same restrictions as for section -name. +There is also a case insensitive alternative `[section.subsection]` syntax. +In this syntax, subsection names follow the same restrictions as for section +names. All the other lines are recognized as setting variables, in the form 'name = value'. If there is no equal sign on the line, the entire line @@ -61,15 +61,15 @@ Internal whitespace within a variable value is retained verbatim. The values following the equals sign in variable assign are all either a string, an integer, or a boolean. Boolean values may be given as yes/no, -0/1 or true/false. Case is not significant in boolean values, when +0/1, true/false or on/off. Case is not significant in boolean values, when converting value to the canonical form using '--bool' type specifier; 'git-config' will ensure that the output is "true" or "false". String values may be entirely or partially enclosed in double quotes. -You need to enclose variable value in double quotes if you want to -preserve leading or trailing whitespace, or if variable value contains -beginning of comment characters (if it contains '#' or ';'). -Double quote `"` and backslash `\` characters in variable value must +You need to enclose variable values in double quotes if you want to +preserve leading or trailing whitespace, or if the variable value contains +comment characters (i.e. it contains '#' or ';'). +Double quote `"` and backslash `\` characters in variable values must be escaped: use `\"` for `"` and `\\` for `\`. The following escape sequences (beside `\"` and `\\`) are recognized: @@ -77,10 +77,10 @@ The following escape sequences (beside `\"` and `\\`) are recognized: and `\b` for backspace (BS). No other char escape sequence, nor octal char sequences are valid. -Variable value ending in a `\` is continued on the next line in the +Variable values ending in a `\` are continued on the next line in the customary UNIX fashion. -Some variables may require special value format. +Some variables may require a special value format. Example ~~~~~~~ @@ -295,8 +295,10 @@ core.sharedRepository:: group-shareable. When 'umask' (or 'false'), git will use permissions reported by umask(2). When '0xxx', where '0xxx' is an octal number, files in the repository will have this mode value. '0xxx' will override - user's umask value, and thus, users with a safe umask (0077) can use - this option. Examples: '0660' is equivalent to 'group'. '0640' is a + user's umask value (whereas the other options will only override + requested parts of the user's umask value). Examples: '0660' will make + the repo read/write-able for the owner and group, but inaccessible to + others (equivalent to 'group' unless umask is e.g. '0022'). '0640' is a repository that is group-readable but not group-writable. See linkgit:git-init[1]. False by default. @@ -427,6 +429,15 @@ relatively high IO latencies. With this set to 'true', git will do the index comparison to the filesystem data in parallel, allowing overlapping IO's. +core.createObject:: + You can set this to 'link', in which case a hardlink followed by + a delete of the source are used to make sure that object creation + will not overwrite existing objects. ++ +On some file system/operating system combinations, this is unreliable. +Set this config setting to 'rename' there; However, This will remove the +check that makes sure that existing object files will not get overwritten. + alias.*:: Command aliases for the linkgit:git[1] command wrapper - e.g. after defining "alias.last = cat-file commit HEAD", the invocation @@ -593,6 +604,12 @@ color.pager:: A boolean to enable/disable colored output when the pager is in use (default is true). +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. + color.status:: A boolean to enable/disable color in the output of linkgit:git-status[1]. May be set to `always`, @@ -667,6 +684,27 @@ diff.suppressBlankEmpty:: A boolean to inhibit the standard behavior of printing a space before each empty output line. Defaults to false. +diff.tool:: + Controls which diff tool is used. `diff.tool` overrides + `merge.tool` when used by linkgit:git-difftool[1] and has + the same valid values as `merge.tool` minus "tortoisemerge" + and plus "kompare". + +difftool.<tool>.path:: + Override the path for the given tool. This is useful in case + your tool is not in the PATH. + +difftool.<tool>.cmd:: + Specify the command to invoke the specified diff tool. + The specified command is evaluated in shell with the following + variables available: 'LOCAL' is set to the name of the temporary + file containing the contents of the diff pre-image and 'REMOTE' + is set to the name of the temporary file containing the contents + of the diff post-image. + +difftool.prompt:: + Prompt before each invocation of the diff tool. + diff.wordRegex:: A POSIX Extended Regular Expression used to determine what is a "word" when performing word-by-word difference calculations. Character @@ -684,6 +722,13 @@ fetch.unpackLimit:: especially on slow filesystems. If not set, the value of `transfer.unpackLimit` is used instead. +format.attach:: + Enable multipart/mixed attachments as the default for + 'format-patch'. The value can also be a double quoted string + which will enable attachments as the default and set the + value as the boundary. See the --attach option in + linkgit:git-format-patch[1]. + format.numbered:: A boolean which can enable or disable sequence numbers in patch subjects. It defaults to "auto" which enables it only if there @@ -695,6 +740,14 @@ format.headers:: Additional email headers to include in a patch to be submitted by mail. See linkgit:git-format-patch[1]. +format.cc:: + Additional "Cc:" headers to include in a patch to be submitted + by mail. See the --cc option in linkgit:git-format-patch[1]. + +format.subjectprefix:: + The default for format-patch is to output files with the '[PATCH]' + subject prefix. Use this variable to change that prefix. + format.suffix:: The default for format-patch is to output files with the suffix `.patch`. Use this variable to change that suffix (make sure to @@ -707,11 +760,11 @@ format.pretty:: format.thread:: The default threading style for 'git-format-patch'. Can be - either a boolean value, `shallow` or `deep`. 'Shallow' + either a boolean value, `shallow` or `deep`. `shallow` threading makes every mail a reply to the head of the series, where the head is chosen from the cover letter, the `\--in-reply-to`, and the first patch mail, in this order. - 'Deep' threading makes every mail a reply to the previous one. + `deep` threading makes every mail a reply to the previous one. A true boolean value is the same as `shallow`, and a false value disables threading. @@ -1215,7 +1268,7 @@ push.default:: * `matching` push all matching branches. All branches having the same name in both ends are considered to be matching. This is the default. -* `tracking` push the current branch to the branch it is tracking. +* `tracking` push the current branch to its upstream branch. * `current` push the current branch to a branch of the same name. rebase.stat:: diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index 25e6667736..ab1943c712 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -254,8 +254,11 @@ patch:: y - stage this hunk n - do not stage this hunk + q - quit, do not stage this hunk nor any of the remaining ones a - stage this and all the remaining hunks in the file d - do not stage this hunk nor any of the remaining hunks in the file + g - select a hunk to go to + / - search for a hunk matching the given regex j - leave this hunk undecided, see next undecided hunk J - leave this hunk undecided, see next hunk k - leave this hunk undecided, see previous undecided hunk diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 1e71dd536b..6d92cbee64 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -32,7 +32,7 @@ OPTIONS -s:: --signoff:: - Add `Signed-off-by:` line to the commit message, using + Add a `Signed-off-by:` line to the commit message, using the committer identity of yourself. -k:: @@ -79,14 +79,14 @@ default. You can use `--no-utf8` to override this. message as the commit author date, and uses the time of commit creation as the committer date. This allows the user to lie about the committer date by using the same - timestamp as the author date. + value as the author date. --ignore-date:: By default the command records the date from the e-mail message as the commit author date, and uses the time of commit creation as the committer date. This allows the - user to lie about author timestamp by using the same - timestamp as the committer date. + user to lie about the author date by using the same + value as the committer date. --skip:: Skip the current patch. This is only meaningful when @@ -115,21 +115,21 @@ DISCUSSION ---------- The commit author name is taken from the "From: " line of the -message, and commit author time is taken from the "Date: " line +message, and commit author date is taken from the "Date: " line of the message. The "Subject: " line is used as the title of the commit, after stripping common prefix "[PATCH <anything>]". -It is supposed to describe what the commit is about concisely as -a one line text. +The "Subject: " line is supposed to concisely describe what the +commit is about in one line of text. -The body of the message (the rest of the message after the blank line -that terminates the RFC2822 headers) can begin with "Subject: " and -"From: " lines that are different from those of the mail header, -to override the values of these fields. +"From: " and "Subject: " lines starting the body (the rest of the +message after the blank line terminating the RFC2822 headers) +override the respective commit author name and title values taken +from the headers. The commit message is formed by the title taken from the "Subject: ", a blank line and the body of the message up to -where the patch begins. Excess whitespace characters at the end of the -lines are automatically stripped. +where the patch begins. Excess whitespace at the end of each +line is automatically stripped. The patch is expected to be inline, directly following the message. Any line that is of the form: @@ -141,7 +141,7 @@ message. Any line that is of the form: is taken as the beginning of a patch, and the commit log message is terminated before the first occurrence of such a line. -When initially invoking it, you give it the names of the mailboxes +When initially invoking `git am`, you give it the names of the mailboxes to process. Upon seeing the first patch that does not apply, it aborts in the middle. You can recover from this in one of two ways: diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index c1adf59497..bc132c87e1 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>] - [--output=<file>] + [--output=<file>] [--worktree-attributes] [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish> [path...] @@ -51,6 +51,9 @@ OPTIONS --output=<file>:: Write the archive to <file> instead of stdout. +--worktree-attributes:: + Look for attributes in .gitattributes in working directory too. + <extra>:: This can be any options that the archiver backend understands. See next section. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 31ba7f2ade..ae201deb7a 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -100,7 +100,9 @@ OPTIONS -v:: --verbose:: - Show sha1 and commit subject line for each head. + Show sha1 and commit subject line for each head, along with + relationship to upstream branch (if any). If given twice, print + the name of the upstream branch, as well. --abbrev=<length>:: Alter the sha1's minimum display length in the output listing. @@ -109,20 +111,24 @@ OPTIONS --no-abbrev:: Display the full sha1s in the output listing rather than abbreviating them. +-t:: --track:: - When creating a new branch, set up the configuration so that 'git-pull' - will automatically retrieve data from the start point, which must be - a branch. Use this if you always pull from the same upstream branch - into the new branch, and if you do not want to use "git pull - <repository> <refspec>" explicitly. This behavior is the default - when the start point is a remote branch. Set the - branch.autosetupmerge configuration variable to `false` if you want - 'git-checkout' and 'git-branch' to always behave as if '--no-track' were - given. Set it to `always` if you want this behavior when the - start-point is either a local or remote branch. + When creating a new branch, set up configuration to mark the + start-point branch as "upstream" from the new branch. This + configuration will tell git to show the relationship between the + two branches in `git status` and `git branch -v`. Furthermore, + it directs `git pull` without arguments to pull from the + upstream when the new branch is checked out. ++ +This behavior is the default when the start point is a remote branch. +Set the branch.autosetupmerge configuration variable to `false` if you +want `git checkout` and `git branch` to always behave as if '--no-track' +were given. Set it to `always` if you want this behavior when the +start-point is either a local or remote branch. --no-track:: - Ignore the branch.autosetupmerge configuration variable. + Do not set up "upstream" configuration, even if the + branch.autosetupmerge configuration variable is true. --contains <commit>:: Only list branches which contain the specified commit. diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index c1ce26884e..0873e60f7f 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -25,6 +25,10 @@ imposes the following rules on how references are named: grouping, but no slash-separated component can begin with a dot `.`. +. They must contain at least one `/`. This enforces the presence of a + category like `heads/`, `tags/` etc. but the actual names are not + restricted. + . They cannot have two consecutive dots `..` anywhere. . They cannot have ASCII control characters (i.e. bytes whose diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 223ea9caef..ad4b31e892 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -8,22 +8,22 @@ git-checkout - Checkout a branch or paths to the working tree SYNOPSIS -------- [verse] -'git checkout' [-q] [-f] [-t | --track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>] +'git checkout' [-q] [-f] [-m] [<branch>] +'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>] 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... DESCRIPTION ----------- When <paths> are not given, this command switches branches by -updating the index and working tree to reflect the specified -branch, <branch>, and updating HEAD to be <branch> or, if -specified, <new_branch>. Using -b will cause <new_branch> to -be created; in this case you can use the --track or --no-track -options, which will be passed to `git branch`. +updating the index, working tree, and HEAD to reflect the specified +branch. -As a convenience, --track will default to creating a branch whose -name is constructed from the specified branch name by stripping -the first namespace level. +If `-b` is given, a new branch is created and checked out, as if +linkgit:git-branch[1] were called; in this case you can +use the --track or --no-track options, which will be passed to `git +branch`. As a convenience, --track without `-b` implies branch +creation; see the description of --track below. When <paths> are given, this command does *not* switch branches. It updates the named paths in the working tree from @@ -62,22 +62,12 @@ entries; instead, unmerged entries are ignored. -b:: Create a new branch named <new_branch> and start it at - <branch>. The new branch name must pass all checks defined - by linkgit:git-check-ref-format[1]. Some of these checks - may restrict the characters allowed in a branch name. + <start_point>; see linkgit:git-branch[1] for details. -t:: --track:: - When creating a new branch, set up configuration so that 'git-pull' - will automatically retrieve data from the start point, which must be - a branch. Use this if you always pull from the same upstream branch - into the new branch, and if you don't want to use "git pull - <repository> <refspec>" explicitly. This behavior is the default - when the start point is a remote branch. Set the - branch.autosetupmerge configuration variable to `false` if you want - 'git checkout' and 'git branch' to always behave as if '--no-track' were - given. Set it to `always` if you want this behavior when the - start point is either a local or remote branch. + When creating a new branch, set up "upstream" configuration. See + "--track" in linkgit:git-branch[1] for details. + If no '-b' option is given, the name of the new branch will be derived from the remote branch. If "remotes/" or "refs/remotes/" @@ -90,12 +80,12 @@ guessing results in an empty name, the guessing is aborted. You can explicitly give a name with '-b' in such a case. --no-track:: - Ignore the branch.autosetupmerge configuration variable. + Do not set up "upstream" configuration, even if the + branch.autosetupmerge configuration variable is true. -l:: - Create the new branch's reflog. This activates recording of - all changes made to the branch ref, enabling use of date - based sha1 expressions such as "<branchname>@\{yesterday}". + Create the new branch's reflog; see linkgit:git-branch[1] for + details. -m:: --merge:: @@ -123,23 +113,28 @@ the conflicted merge in the specified paths. "merge" (default) and "diff3" (in addition to what is shown by "merge" style, shows the original contents). +<branch>:: + Branch to checkout; if it refers to a branch (i.e., a name that, + when prepended with "refs/heads/", is a valid ref), then that + branch is checked out. Otherwise, if it refers to a valid + commit, your HEAD becomes "detached" and you are no longer on + any branch (see below for details). ++ +As a special case, the `"@\{-N\}"` syntax for the N-th last branch +checks out the branch (instead of detaching). You may also specify +`-` which is synonymous with `"@\{-1\}"`. + <new_branch>:: Name for the new branch. +<start_point>:: + The name of a commit at which to start the new branch; see + linkgit:git-branch[1] for details. Defaults to HEAD. + <tree-ish>:: Tree to checkout from (when paths are given). If not specified, the index will be used. -<branch>:: - Branch to checkout (when no paths are given); may be any object - ID that resolves to a commit. Defaults to HEAD. -+ -When this parameter names a non-branch (but still a valid commit object), -your HEAD becomes 'detached'. -+ -As a special case, the `"@\{-N\}"` syntax for the N-th last branch -checks out the branch (instead of detaching). You may also specify -`-` which is synonymous with `"@\{-1\}"`. Detached HEAD diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index 8a114509f4..be894af39f 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -12,14 +12,17 @@ SYNOPSIS DESCRIPTION ----------- -Removes files unknown to git. This allows to clean the working tree -from files that are not under version control. If the '-x' option is -specified, ignored files are also removed, allowing to remove all -build products. + +Cleans the working tree by recursively removing files that are not +under version control, starting from the current directory. + +Normally, only files unknown to git are removed, but if the '-x' +option is specified, ignored files are also removed. This can, for +example, be useful to remove all build products. + If any optional `<path>...` arguments are given, only those paths are affected. - OPTIONS ------- -d:: diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 4072f40d7a..b14de6c407 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -149,7 +149,7 @@ then the cloned repository will become corrupt. part of the source repository is used if no directory is explicitly given ("repo" for "/path/to/repo.git" and "foo" for "host.xz:foo/.git"). Cloning into an existing directory - is not allowed. + is only allowed if the directory is empty. :git-clone: 1 include::urls.txt[] diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 7131ee3c66..f68b198205 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -69,7 +69,8 @@ OPTIONS --add:: Adds a new line to the option without altering any existing - values. This is the same as providing '^$' as the value_regex. + values. This is the same as providing '^$' as the value_regex + in `--replace-all`. --get:: Get the value for a given key (optionally filtered by a regex @@ -155,7 +156,7 @@ See also <<FILES>>. When the color setting for `name` is undefined, the command uses `color.ui` as fallback. ---get-color name default:: +--get-color name [default]:: Find the color configured for `name` (e.g. `color.diff.new`) and output it as the ANSI color escape sequence to the standard diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index d7bab13f6c..614e769f4e 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -196,7 +196,7 @@ Problems related to tags: If you suspect that any of these issues may apply to the repository you want to import consider using these alternative tools which proved to be -more stable in practise: +more stable in practice: * cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org` * parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs` diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt index 36f00aed67..a85121c689 100644 --- a/Documentation/git-daemon.txt +++ b/Documentation/git-daemon.txt @@ -48,7 +48,7 @@ OPTIONS 'git-daemon' will refuse to start when this option is enabled and no whitelist is specified. ---base-path:: +--base-path=path:: Remap all the path requests as relative to the given path. This is sort of "GIT root" - if you run 'git-daemon' with '--base-path=/srv/git' on example.com, then if you later try to pull @@ -81,8 +81,8 @@ OPTIONS Incompatible with --port, --listen, --user and --group options. --listen=host_or_ipaddr:: - Listen on an a specific IP address or hostname. IP addresses can - be either an IPv4 address or an IPV6 address if supported. If IPv6 + Listen on a specific IP address or hostname. IP addresses can + be either an IPv4 address or an IPv6 address if supported. If IPv6 is not supported, then --listen=hostname is also not supported and --listen must be given an IPv4 address. Incompatible with '--inetd' option. @@ -90,17 +90,17 @@ OPTIONS --port=n:: Listen on an alternative port. Incompatible with '--inetd' option. ---init-timeout:: +--init-timeout=n:: Timeout between the moment the connection is established and the client request is received (typically a rather low value, since that should be basically immediate). ---timeout:: +--timeout=n:: Timeout for specific client sub-requests. This includes the time - it takes for the server to process the sub-request and time spent - waiting for next client's request. + it takes for the server to process the sub-request and the time spent + waiting for the next client's request. ---max-connections:: +--max-connections=n:: Maximum number of concurrent clients, defaults to 32. Set it to zero for no limit. @@ -150,7 +150,7 @@ the facility of inet daemon to achieve the same before spawning Enable/disable the service site-wide per default. Note that a service disabled site-wide can still be enabled per repository if it is marked overridable and the - repository enables the service with an configuration + repository enables the service with a configuration item. --allow-override=service:: diff --git a/contrib/difftool/git-difftool.txt b/Documentation/git-difftool.txt index 2b7bc03ec3..15b247bab4 100644 --- a/contrib/difftool/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -3,35 +3,37 @@ git-difftool(1) NAME ---- -git-difftool - compare changes using common merge tools +git-difftool - Show changes using common diff tools SYNOPSIS -------- -'git difftool' [--tool=<tool>] [--no-prompt] ['git diff' options] +'git difftool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<'git diff' options>] DESCRIPTION ----------- 'git-difftool' is a git command that allows you to compare and edit files -between revisions using common merge tools. At its most basic level, -'git-difftool' does what 'git-mergetool' does but its use is for non-merge -situations such as when preparing commits or comparing changes against -the index. - -'git difftool' is a frontend to 'git diff' and accepts the same -arguments and options. - -See linkgit:git-diff[1] for the full list of supported options. +between revisions using common diff tools. 'git difftool' is a frontend +to 'git-diff' and accepts the same options and arguments. OPTIONS ------- +-y:: +--no-prompt:: + Do not prompt before launching a diff tool. + +--prompt:: + Prompt before each invocation of the diff tool. + This is the default behaviour; the option is provided to + override any configuration settings. + -t <tool>:: --tool=<tool>:: - Use the merge resolution program specified by <tool>. + Use the diff tool specified by <tool>. Valid merge tools are: - kdiff3, kompare, tkdiff, meld, xxdiff, emerge, - vimdiff, gvimdiff, ecmerge, and opendiff + kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, + ecmerge, diffuse and opendiff + -If a merge resolution program is not specified, 'git-difftool' +If a diff tool is not specified, 'git-difftool' will use the configuration variable `diff.tool`. If the configuration variable `diff.tool` is not set, 'git-difftool' will pick a suitable default. @@ -42,7 +44,7 @@ can configure the absolute path to kdiff3 by setting `difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the tool is available in PATH. + -Instead of running one of the known merge tool programs, +Instead of running one of the known diff tools, 'git-difftool' can be customized to run an alternative program by specifying the command line to invoke in a configuration variable `difftool.<tool>.cmd`. @@ -56,8 +58,7 @@ is set to the name of the temporary file containing the contents of the diff post-image. `$BASE` is provided for compatibility with custom merge tool commands and has the same value as `$LOCAL`. ---no-prompt:: - Do not prompt before launching a diff tool. +See linkgit:git-diff[1] for the full list of supported options. CONFIG VARIABLES ---------------- @@ -65,20 +66,19 @@ CONFIG VARIABLES difftool equivalents have not been defined. diff.tool:: - The default merge tool to use. + The default diff tool to use. difftool.<tool>.path:: Override the path for the given tool. This is useful in case your tool is not in the PATH. difftool.<tool>.cmd:: - Specify the command to invoke the specified merge tool. + Specify the command to invoke the specified diff tool. + See the `--tool=<tool>` option above for more details. -merge.keepBackup:: - The original, unedited file content can be saved to a file with - a `.orig` extension. Defaults to `true` (i.e. keep the backup files). +difftool.prompt:: + Prompt before each invocation of the diff tool. SEE ALSO -------- diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index 237f85e767..ab527b5b31 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -31,6 +31,9 @@ changes, which would normally have no effect. Nevertheless, this may be useful in the future for compensating for some git bugs or such, therefore such a usage is permitted. +*NOTE*: This command honors `.git/info/grafts`. If you have any grafts +defined, running this command will make them permanent. + *WARNING*! The rewritten history will have different object names for all the objects and will not converge with the original branch. You will not be able to easily push and distribute the rewritten branch on top of the diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index 5061d3e4e7..8dc873fd44 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -75,6 +75,8 @@ For all objects, the following names can be used: refname:: The name of the ref (the part after $GIT_DIR/). For a non-ambiguous short name of the ref append `:short`. + The option core.warnAmbiguousRefs is used to select the strict + abbreviation mode. objecttype:: The type of the object (`blob`, `tree`, `commit`, `tag`). @@ -85,6 +87,11 @@ objectsize:: objectname:: The object name (aka SHA-1). +upstream:: + The name of a local ref which can be considered ``upstream'' + from the displayed ref. Respects `:short` in the same way as + `refname` above. + In addition to the above, for commit and tag objects, the header field names (`tree`, `parent`, `object`, `type`, and `tag`) can be used to specify the value in the header field. diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index eb2fbcff1a..6f1fc80119 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -9,10 +9,10 @@ git-format-patch - Prepare patches for e-mail submission SYNOPSIS -------- [verse] -'git format-patch' [-k] [-o <dir> | --stdout] [--thread] - [--attach[=<boundary>] | --inline[=<boundary>] | - [--no-attach]] - [-s | --signoff] [<common diff options>] +'git format-patch' [-k] [(-o|--output-directory) <dir> | --stdout] + [--thread[=<style>]] + [(--attach|--inline)[=<boundary>] | --no-attach] + [-s | --signoff] [-n | --numbered | -N | --no-numbered] [--start-number <n>] [--numbered-files] [--in-reply-to=Message-Id] [--suffix=.<sfx>] @@ -20,6 +20,7 @@ SYNOPSIS [--subject-prefix=Subject-Prefix] [--cc=<email>] [--cover-letter] + [<common diff options>] [ <since> | <revision range> ] DESCRIPTION @@ -128,9 +129,9 @@ include::diff-options.txt[] the Message-Id header to reference. + The optional <style> argument can be either `shallow` or `deep`. -'Shallow' threading makes every mail a reply to the head of the +'shallow' threading makes every mail a reply to the head of the series, where the head is chosen from the cover letter, the -`\--in-reply-to`, and the first patch mail, in this order. 'Deep' +`\--in-reply-to`, and the first patch mail, in this order. 'deep' threading makes every mail a reply to the previous one. If not specified, defaults to the 'format.thread' configuration, or `shallow` if that is not set. @@ -170,18 +171,17 @@ if that is not set. --suffix=.<sfx>:: Instead of using `.patch` as the suffix for generated filenames, use specified suffix. A common alternative is - `--suffix=.txt`. + `--suffix=.txt`. Leaving this empty will remove the `.patch` + suffix. + -Note that you would need to include the leading dot `.` if you -want a filename like `0001-description-of-my-change.patch`, and -the first letter does not have to be a dot. Leaving it empty would -not add any suffix. +Note that the leading character does not have to be a dot; for example, +you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`. --no-binary:: - Don't output contents of changes in binary files, just take note - that they differ. Note that this disable the patch to be properly - applied. By default the contents of changes in those files are - encoded in the patch. + Do not output contents of changes in binary files, instead + display a notice that those files changed. Patches generated + using this option cannot be applied properly, but they are + still useful for code review. --root:: Treat the revision argument as a <revision range>, even if it @@ -192,10 +192,10 @@ not add any suffix. CONFIGURATION ------------- -You can specify extra mail header lines to be added to each message -in the repository configuration, new defaults for the subject prefix -and file suffix, control attachements, and number patches when outputting -more than one. +You can specify extra mail header lines to be added to each message, +defaults for the subject prefix and file suffix, number patches when +outputting more than one patch, add "Cc:" headers, configure attachments, +and sign off patches with configuration variables. ------------ [format] @@ -243,8 +243,8 @@ $ git format-patch -M -B origin + Additionally, it detects and handles renames and complete rewrites intelligently to produce a renaming patch. A renaming patch reduces -the amount of text output, and generally makes it easier to review it. -Note that the "patch" program does not understand renaming patches, so +the amount of text output, and generally makes it easier to review. +Note that non-git "patch" programs won't understand renaming patches, so use it only when you know the recipient uses git to apply your patch. * Extract three topmost commits from the current branch and format them diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt index 024084b8b7..d016dafd49 100644 --- a/Documentation/git-imap-send.txt +++ b/Documentation/git-imap-send.txt @@ -51,7 +51,7 @@ imap.host:: imap.user:: The username to use when logging in to the server. -imap.password:: +imap.pass:: The password to use when logging in to the server. imap.port:: diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt index 71749c09d3..7151d12f34 100644 --- a/Documentation/git-init.txt +++ b/Documentation/git-init.txt @@ -54,15 +54,21 @@ is given: - 'group' (or 'true'): Make the repository group-writable, (and g+sx, since the git group may be not the primary group of all users). + This is used to loosen the permissions of an otherwise safe umask(2) value. + Note that the umask still applies to the other permission bits (e.g. if + umask is '0022', using 'group' will not remove read privileges from other + (non-group) users). See '0xxx' for how to exactly specify the repository + permissions. - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository readable by all users. - - '0xxx': '0xxx' is an octal number and each file will have mode '0xxx' - Any option except 'umask' can be set using this option. '0xxx' will - override users umask(2) value, and thus, users with a safe umask (0077) - can use this option. '0640' will create a repository which is group-readable - but not writable. '0660' is equivalent to 'group'. + - '0xxx': '0xxx' is an octal number and each file will have mode '0xxx'. + '0xxx' will override users' umask(2) value (and not only loosen permissions + as 'group' and 'all' does). '0640' will create a repository which is + group-readable, but not group-writable or accessible to others. '0660' will + create a repo that is readable and writable to the current user and group, + but inaccessible to others. By default, the configuration flag receive.denyNonFastForwards is enabled in shared repositories, so that you cannot force a non fast-forwarding push diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt index f68e5c5c1a..c3fdccb4c2 100644 --- a/Documentation/git-ls-tree.txt +++ b/Documentation/git-ls-tree.txt @@ -82,8 +82,10 @@ Output Format ------------- <mode> SP <type> SP <object> TAB <file> -When the `-z` option is not used, TAB, LF, and backslash characters +Unless the `-z` option is used, TAB, LF, and backslash characters in pathnames are represented as `\t`, `\n`, and `\\`, respectively. +This output format is compatible with what '--index-info --stdin' of +'git update-index' expects. When the `-l` option is used, format changes to diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt new file mode 100644 index 0000000000..78eb03f0ae --- /dev/null +++ b/Documentation/git-mergetool--lib.txt @@ -0,0 +1,54 @@ +git-mergetool--lib(1) +===================== + +NAME +---- +git-mergetool--lib - Common git merge tool shell scriptlets + +SYNOPSIS +-------- +'TOOL_MODE=(diff|merge) . "$(git --exec-path)/git-mergetool--lib"' + +DESCRIPTION +----------- + +This is not a command the end user would want to run. Ever. +This documentation is meant for people who are studying the +Porcelain-ish scripts and/or are writing new ones. + +The 'git-mergetool--lib' scriptlet is designed to be sourced (using +`.`) by other shell scripts to set up functions for working +with git merge tools. + +Before sourcing 'git-mergetool--lib', your script must set `TOOL_MODE` +to define the operation mode for the functions listed below. +'diff' and 'merge' are valid values. + +FUNCTIONS +--------- +get_merge_tool:: + returns a merge tool. + +get_merge_tool_cmd:: + returns the custom command for a merge tool. + +get_merge_tool_path:: + returns the custom path for a merge tool. + +run_merge_tool:: + launches a merge tool given the tool name and a true/false + flag to indicate whether a merge base is present. + '$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined + for use by the merge tool. + +Author +------ +Written by David Aguilar <davvid@gmail.com> + +Documentation +-------------- +Documentation by David Aguilar and the git-list <git@vger.kernel.org>. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 5d3c632872..ff9700d17a 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -26,7 +26,8 @@ OPTIONS --tool=<tool>:: Use the merge resolution program specified by <tool>. Valid merge tools are: - kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff + kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, + diffuse, tortoisemerge and opendiff + If a merge resolution program is not specified, 'git-mergetool' will use the configuration variable `merge.tool`. If the diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index c9c0e6f932..9e2b4eaa38 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -16,7 +16,7 @@ SYNOPSIS 'git remote set-head' <name> [-a | -d | <branch>] 'git remote show' [-n] <name> 'git remote prune' [-n | --dry-run] <name> -'git remote update' [group] +'git remote update' [-p | --prune] [group | remote]... DESCRIPTION ----------- @@ -125,6 +125,8 @@ the configuration parameter remotes.default will get used; if remotes.default is not defined, all remotes which do not have the configuration parameter remote.<name>.skipDefaultUpdate set to true will be updated. (See linkgit:git-config[1]). ++ +With `--prune` option, prune all the remotes that are updated. DISCUSSION diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 5ed2bc840f..52c353e674 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -26,7 +26,7 @@ OPTIONS --parseopt:: Use 'git-rev-parse' in option parsing mode (see PARSEOPT section below). ---keep-dash-dash:: +--keep-dashdash:: Only meaningful in `--parseopt` mode. Tells the option parser to echo out the first `--` met instead of skipping it. @@ -84,6 +84,11 @@ OPTIONS unfortunately named tag "master"), and show them as full refnames (e.g. "refs/heads/master"). +--abbrev-ref[={strict|loose}]:: + A non-ambiguous short name of the objects name. + The option core.warnAmbiguousRefs is used to select the strict + abbreviation mode. + --all:: Show all refs found in `$GIT_DIR/refs`. diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 0b1f183ce8..794224b1b3 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -262,7 +262,7 @@ sendemail.aliasesfile:: sendemail.aliasfiletype:: Format of the file(s) specified in sendemail.aliasesfile. Must be - one of 'mutt', 'mailrc', 'pine', or 'gnus'. + one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus'. sendemail.multiedit:: If true (default), a single editor instance will be spawned to edit diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt index 3f8d973af1..0f3ad811cf 100644 --- a/Documentation/git-shell.txt +++ b/Documentation/git-shell.txt @@ -18,9 +18,9 @@ of server-side GIT commands implementing the pull/push functionality. The commands can be executed only by the '-c' option; the shell is not interactive. -Currently, only three commands are permitted to be called, 'git-receive-pack' -'git-upload-pack' with a single required argument or 'cvs server' (to invoke -'git-cvsserver'). +Currently, only four commands are permitted to be called, 'git-receive-pack' +'git-upload-pack' and 'git-upload-archive' with a single required argument, or +'cvs server' (to invoke 'git-cvsserver'). Author ------ diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt index 7e9ff3762b..edd8f6463e 100644 --- a/Documentation/git-show-branch.txt +++ b/Documentation/git-show-branch.txt @@ -10,6 +10,7 @@ SYNOPSIS [verse] 'git show-branch' [--all] [--remotes] [--topo-order] [--current] [--more=<n> | --list | --independent | --merge-base] + [--color | --no-color] [--no-name | --sha1-name] [--topics] [<rev> | <glob>]... 'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>] @@ -107,6 +108,14 @@ OPTIONS When no explicit <ref> parameter is given, it defaults to the current branch (or `HEAD` if it is detached). +--color:: + Color the status sign (one of these: `*` `!` `+` `-`) of each commit + corresponding to the branch it's in. + +--no-color:: + Turn off colored output, even when the configuration file gives the + default to color output. + Note that --more, --list, --independent and --merge-base options are mutually exclusive. @@ -148,9 +157,10 @@ $ git show-branch master fixes mhf ------------------------------------------------ These three branches all forked from a common commit, [master], -whose commit message is "Add 'git show-branch'. "fixes" branch -adds one commit 'Introduce "reset type"'. "mhf" branch has many -other commits. The current branch is "master". +whose commit message is "Add \'git show-branch\'". The "fixes" +branch adds one commit "Introduce "reset type" flag to "git reset"". +The "mhf" branch adds many other commits. The current branch +is "master". EXAMPLE diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 9229d45ad9..1c40894669 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -693,9 +693,9 @@ listed below are allowed: tags = tags/*/project-a:refs/remotes/project-a/tags/* ------------------------------------------------------------------------ -Keep in mind that the '*' (asterisk) wildcard of the local ref +Keep in mind that the '\*' (asterisk) wildcard of the local ref (right of the ':') *must* be the farthest right path component; -however the remote wildcard may be anywhere as long as it's own +however the remote wildcard may be anywhere as long as it's an independent path component (surrounded by '/' or EOL). This type of configuration is not automatically created by 'init' and should be manually entered with a text-editor or using 'git-config'. diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt index 35d27b0c7f..035cc3018f 100644 --- a/Documentation/git-update-server-info.txt +++ b/Documentation/git-update-server-info.txt @@ -39,12 +39,6 @@ what they are for: * info/refs -BUGS ----- -When you remove an existing ref, the command fails to update -info/refs file unless `--force` flag is given. - - Author ------ Written by Junio C Hamano <gitster@pobox.com> diff --git a/Documentation/git.txt b/Documentation/git.txt index 2ce5e6b451..9d8f236fe8 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,13 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.2.1/git.html[documentation for release 1.6.2.1] +* link:v1.6.3/git.html[documentation for release 1.6.3] * release notes for + link:RelNotes-1.6.2.5.txt[1.6.2.5], + link:RelNotes-1.6.2.4.txt[1.6.2.4], + link:RelNotes-1.6.2.3.txt[1.6.2.3], + link:RelNotes-1.6.2.2.txt[1.6.2.2], link:RelNotes-1.6.2.1.txt[1.6.2.1], link:RelNotes-1.6.2.txt[1.6.2]. diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index b762bba759..aaa073efc8 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -297,7 +297,8 @@ for paths. Then, you would define a "diff.tex.xfuncname" configuration to specify a regular expression that matches a line that you would -want to appear as the hunk header "TEXT", like this: +want to appear as the hunk header "TEXT". Add a section to your +`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this: ------------------------ [diff "tex"] @@ -345,7 +346,8 @@ split words in a line, by specifying an appropriate regular expression in the "diff.*.wordRegex" configuration variable. For example, in TeX a backslash followed by a sequence of letters forms a command, but several such commands can be run together without intervening -whitespace. To separate them, use a regular expression such as +whitespace. To separate them, use a regular expression in your +`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this: ------------------------ [diff "tex"] @@ -373,7 +375,8 @@ resulting text on stdout. For example, to show the diff of the exif information of a file instead of the binary information (assuming you have the -exif tool installed): +exif tool installed), add the following section to your +`$GIT_DIR/config` file (or `$HOME/.gitconfig` file): ------------------------ [diff "jpg"] diff --git a/Documentation/gitcvs-migration.txt b/Documentation/gitcvs-migration.txt index aaa7ef737a..0e49c1c037 100644 --- a/Documentation/gitcvs-migration.txt +++ b/Documentation/gitcvs-migration.txt @@ -118,7 +118,7 @@ Importing a CVS archive First, install version 2.1 or higher of cvsps from link:http://www.cobite.com/cvsps/[http://www.cobite.com/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 'git-cvsimport': +of the project you are interested in and run linkgit:git-cvsimport[1]: ------------------------------------------- $ git cvsimport -C <destination> <module> diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 4fc1cf1184..572374f7a6 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -449,6 +449,12 @@ This commit is referred to as a "merge commit", or sometimes just a An <<def_object,object>> which is not <<def_reachable,reachable>> from a <<def_branch,branch>>, <<def_tag,tag>>, or any other reference. +[[def_upstream_branch]]upstream branch:: + The default <<def_branch,branch>> that is merged into the branch in + question (or the branch in question is rebased onto). It is configured + via branch.<name>.remote and branch.<name>.merge. If the upstream branch + of 'A' is 'origin/B' sometimes we say "'A' is tracking 'origin/B'". + [[def_working_tree]]working tree:: The tree of actual checked out files. The working tree is normally equal to the <<def_HEAD,HEAD>> plus any local changes diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 1ff08ff2cc..4832bc75e2 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -22,7 +22,8 @@ merge.stat:: merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", - "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and + "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", + "diffuse", "ecmerge", "tortoisemerge", and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool.<tool>.cmd option. diff --git a/Documentation/technical/api-builtin.txt b/Documentation/technical/api-builtin.txt index 7ede1e64e5..5cb2b0590a 100644 --- a/Documentation/technical/api-builtin.txt +++ b/Documentation/technical/api-builtin.txt @@ -37,7 +37,7 @@ where options is the bitwise-or of: Make sure there is a work tree, i.e. the command cannot act on bare repositories. - This makes only sense when `RUN_SETUP` is also set. + This only makes sense when `RUN_SETUP` is also set. . Add `builtin-foo.o` to `BUILTIN_OBJS` in `Makefile`. diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index e66ca9f70c..e30c602f47 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -198,7 +198,7 @@ The function must be defined in this form: The callback mechanism is as follows: -* Inside `funct`, the only interesting member of the structure +* Inside `func`, the only interesting member of the structure given by `opt` is the void pointer `opt->value`. `\*opt->value` will be the value that is saved into `var`, if you use `OPT_CALLBACK()`. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 97fc1e0519..39cde784c9 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.2.GIT +DEF_VER=v1.6.3.GIT LF=' ' @@ -145,6 +145,8 @@ all:: # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's # MakeMaker (e.g. using ActiveState under Cygwin). # +# Define NO_PERL if you do not want Perl scripts or libraries at all. +# # Define NO_TCLTK if you do not want Tcl/Tk GUI. # # The TCL_PATH variable governs the location of the Tcl interpreter @@ -165,6 +167,14 @@ all:: # Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call # your external grep (e.g., if your system lacks grep, if its grep is # broken, or spawning external process is slower than built-in grep git has). +# +# Define UNRELIABLE_FSTAT if your system's fstat does not return the same +# information on a not yet closed file that lstat would return for the same +# file after it was closed. +# +# Define OBJECT_CREATION_USES_RENAMES if your operating systems has problems +# when hardlinking a file to another name and unlinking the original file right +# away (some NTFS drivers seem to zero the contents in that scenario). GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -277,12 +287,14 @@ TEST_PROGRAMS = SCRIPT_SH += git-am.sh SCRIPT_SH += git-bisect.sh +SCRIPT_SH += git-difftool--helper.sh SCRIPT_SH += git-filter-branch.sh SCRIPT_SH += git-lost-found.sh SCRIPT_SH += git-merge-octopus.sh SCRIPT_SH += git-merge-one-file.sh SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh +SCRIPT_SH += git-mergetool--lib.sh SCRIPT_SH += git-parse-remote.sh SCRIPT_SH += git-pull.sh SCRIPT_SH += git-quiltimport.sh @@ -296,6 +308,7 @@ SCRIPT_SH += git-submodule.sh SCRIPT_SH += git-web--browse.sh SCRIPT_PERL += git-add--interactive.perl +SCRIPT_PERL += git-difftool.perl SCRIPT_PERL += git-archimport.perl SCRIPT_PERL += git-cvsexportcommit.perl SCRIPT_PERL += git-cvsimport.perl @@ -314,7 +327,6 @@ EXTRA_PROGRAMS = # ... and all the rest that could be moved out of bindir to gitexecdir PROGRAMS += $(EXTRA_PROGRAMS) PROGRAMS += git-fast-import$X -PROGRAMS += git-fetch-pack$X PROGRAMS += git-hash-object$X PROGRAMS += git-index-pack$X PROGRAMS += git-merge-index$X @@ -323,7 +335,6 @@ PROGRAMS += git-mktag$X PROGRAMS += git-mktree$X PROGRAMS += git-pack-redundant$X PROGRAMS += git-patch-id$X -PROGRAMS += git-send-pack$X PROGRAMS += git-shell$X PROGRAMS += git-show-index$X PROGRAMS += git-unpack-file$X @@ -353,7 +364,7 @@ BUILT_INS += git-whatchanged$X ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) # what 'all' will build but not install in gitexecdir -OTHER_PROGRAMS = git$X gitweb/gitweb.cgi +OTHER_PROGRAMS = git$X # Set paths to tools early so that they can be used for version tests. ifndef SHELL_PATH @@ -432,6 +443,7 @@ LIB_OBJS += archive-tar.o LIB_OBJS += archive-zip.o LIB_OBJS += attr.o LIB_OBJS += base85.o +LIB_OBJS += bisect.o LIB_OBJS += blob.o LIB_OBJS += branch.o LIB_OBJS += bundle.o @@ -532,6 +544,7 @@ BUILTIN_OBJS += builtin-add.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-apply.o BUILTIN_OBJS += builtin-archive.o +BUILTIN_OBJS += builtin-bisect--helper.o BUILTIN_OBJS += builtin-blame.o BUILTIN_OBJS += builtin-branch.o BUILTIN_OBJS += builtin-bundle.o @@ -736,6 +749,7 @@ endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease NO_MEMMEM = YesPlease + USE_ST_TIMESPEC = YesPlease NEEDS_LIBICONV = YesPlease BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib @@ -748,6 +762,7 @@ ifeq ($(uname_S),NetBSD) BASIC_CFLAGS += -I/usr/pkg/include BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib THREADED_DELTA_SEARCH = YesPlease + USE_ST_TIMESPEC = YesPlease endif ifeq ($(uname_S),AIX) NO_STRCASESTR=YesPlease @@ -795,6 +810,7 @@ ifeq ($(uname_S),HP-UX) endif ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o + UNRELIABLE_FSTAT = UnfortunatelyYes endif ifneq (,$(findstring MINGW,$(uname_S))) NO_PREAD = YesPlease @@ -821,6 +837,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_NSEC = YesPlease USE_WIN32_MMAP = YesPlease + UNRELIABLE_FSTAT = UnfortunatelyYes + OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -1004,6 +1022,9 @@ else COMPAT_OBJS += compat/win32mmap.o endif endif +ifdef OBJECT_CREATION_USES_RENAMES + COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1 +endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD COMPAT_OBJS += compat/pread.o @@ -1099,11 +1120,18 @@ endif ifdef NO_EXTERNAL_GREP BASIC_CFLAGS += -DNO_EXTERNAL_GREP endif +ifdef UNRELIABLE_FSTAT + BASIC_CFLAGS += -DUNRELIABLE_FSTAT +endif ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif +ifeq ($(PERL_PATH),) +NO_PERL=NoThanks +endif + QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir QUIET_SUBDIR1 = @@ -1178,7 +1206,9 @@ ifndef NO_TCLTK $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) gitexecdir='$(gitexec_instdir_SQ)' all $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all endif +ifndef NO_PERL $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all +endif $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) please_set_SHELL_PATH_to_a_more_modern_shell: @@ -1226,6 +1256,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh chmod +x $@+ && \ mv $@+ $@ +ifndef NO_PERL $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL @@ -1247,6 +1278,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl chmod +x $@+ && \ mv $@+ $@ +OTHER_PROGRAMS += gitweb/gitweb.cgi gitweb/gitweb.cgi: gitweb/gitweb.perl $(QUIET_GEN)$(RM) $@ $@+ && \ sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \ @@ -1285,6 +1317,15 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css $@.sh > $@+ && \ chmod +x $@+ && \ mv $@+ $@ +else # NO_PERL +$(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh + $(QUIET_GEN)$(RM) $@ $@+ && \ + sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ + -e 's|@@REASON@@|NO_PERL=$(NO_PERL)|g' \ + unimplemented.sh >$@+ && \ + chmod +x $@+ && \ + mv $@+ $@ +endif # NO_PERL configure: configure.ac $(QUIET_GEN)$(RM) $@ $<+ && \ @@ -1401,6 +1442,7 @@ GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ + @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK @@ -1495,13 +1537,15 @@ install: all $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install +ifndef NO_PERL $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install +endif ifndef NO_TCLTK $(MAKE) -C gitk-git install $(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install endif ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';) endif bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \ execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \ @@ -1513,7 +1557,7 @@ endif ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \ ln -s "git-add$X" "$$execdir/$$p" 2>/dev/null || \ cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \ - done } && \ + done; } && \ ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" install-doc: @@ -1603,9 +1647,11 @@ 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) gitweb/gitweb.cgi $(MAKE) -C Documentation/ clean +ifndef NO_PERL + $(RM) gitweb/gitweb.cgi $(MAKE) -C perl clean +endif $(MAKE) -C templates/ clean $(MAKE) -C t/ clean ifndef NO_TCLTK @@ -1 +1 @@ -Documentation/RelNotes-1.6.3.txt
\ No newline at end of file +Documentation/RelNotes-1.6.4.txt
\ No newline at end of file @@ -27,7 +27,7 @@ int split_cmdline(char *cmdline, const char ***argv) int src, dst, count = 0, size = 16; char quoted = 0; - *argv = xmalloc(sizeof(char*) * size); + *argv = xmalloc(sizeof(char *) * size); /* split alias_string */ (*argv)[count++] = cmdline; @@ -40,7 +40,7 @@ int split_cmdline(char *cmdline, const char ***argv) ; /* skip */ if (count >= size) { size += 16; - *argv = xrealloc(*argv, sizeof(char*) * size); + *argv = xrealloc(*argv, sizeof(char *) * size); } (*argv)[count++] = cmdline + dst; } else if (!quoted && (c == '\'' || c == '"')) { @@ -57,7 +57,7 @@ DEFINE_ALLOCATOR(object, union any_object) #define SZ_FMT "%zu" #endif -static void report(const char* name, unsigned int count, size_t size) +static void report(const char *name, unsigned int count, size_t size) { fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size); } diff --git a/archive-tar.c b/archive-tar.c index ba890ebdec..cee06ce3cb 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -180,7 +180,7 @@ static int write_tar_entry(struct archiver_args *args, sprintf(header.mode, "%07o", mode & 07777); sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0); - sprintf(header.mtime, "%011lo", args->time); + sprintf(header.mtime, "%011lo", (unsigned long) args->time); sprintf(header.uid, "%07o", 0); sprintf(header.gid, "%07o", 0); @@ -4,6 +4,7 @@ #include "attr.h" #include "archive.h" #include "parse-options.h" +#include "unpack-trees.h" static char const * const archive_usage[] = { "git archive [options] <tree-ish> [path...]", @@ -150,6 +151,8 @@ int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry) { struct archiver_context context; + struct unpack_trees_options opts; + struct tree_desc t; int err; if (args->baselen > 0 && args->base[args->baselen - 1] == '/') { @@ -168,6 +171,22 @@ int write_archive_entries(struct archiver_args *args, context.args = args; context.write_entry = write_entry; + /* + * Setup index and instruct attr to read index only + */ + if (!args->worktree_attributes) { + memset(&opts, 0, sizeof(opts)); + opts.index_only = 1; + opts.head_idx = -1; + opts.src_index = &the_index; + opts.dst_index = &the_index; + opts.fn = oneway_merge; + init_tree_desc(&t, args->tree->buffer, args->tree->size); + if (unpack_trees(1, &t, &opts)) + return -1; + git_attr_set_direction(GIT_ATTR_INDEX, &the_index); + } + err = read_tree_recursive(args->tree, args->base, args->baselen, 0, args->pathspec, write_archive_entry, &context); if (err == READ_TREE_RECURSIVE) @@ -258,6 +277,7 @@ static int parse_archive_args(int argc, const char **argv, int verbose = 0; int i; int list = 0; + int worktree_attributes = 0; struct option opts[] = { OPT_GROUP(""), OPT_STRING(0, "format", &format, "fmt", "archive format"), @@ -265,6 +285,8 @@ static int parse_archive_args(int argc, const char **argv, "prepend prefix to each pathname in the archive"), OPT_STRING(0, "output", &output, "file", "write the archive to this file"), + OPT_BOOLEAN(0, "worktree-attributes", &worktree_attributes, + "read .gitattributes in working directory"), OPT__VERBOSE(&verbose), OPT__COMPR('0', &compression_level, "store only", 0), OPT__COMPR('1', &compression_level, "compress faster", 1), @@ -324,6 +346,7 @@ static int parse_archive_args(int argc, const char **argv, args->verbose = verbose; args->base = base; args->baselen = strlen(base); + args->worktree_attributes = worktree_attributes; return argc; } @@ -10,6 +10,7 @@ struct archiver_args { time_t time; const char **pathspec; unsigned int verbose : 1; + unsigned int worktree_attributes : 1; int compression_level; }; @@ -224,7 +224,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, if (is_macro) res->u.attr = git_attr(name, namelen); else { - res->u.pattern = (char*)&(res->state[num_attr]); + res->u.pattern = (char *)&(res->state[num_attr]); memcpy(res->u.pattern, name, namelen); res->u.pattern[namelen] = 0; } @@ -275,7 +275,7 @@ static void free_attr_elem(struct attr_stack *e) setto == ATTR__UNKNOWN) ; else - free((char*) setto); + free((char *) setto); } free(a); } @@ -405,7 +405,7 @@ static struct attr_stack *read_attr(const char *path, int macro_ok) if (!res) res = read_attr_from_file(path, macro_ok); } - else { + else if (direction == GIT_ATTR_CHECKIN) { res = read_attr_from_file(path, macro_ok); if (!res) /* @@ -415,6 +415,8 @@ static struct attr_stack *read_attr(const char *path, int macro_ok) */ res = read_attr_from_index(path, macro_ok); } + else + res = read_attr_from_index(path, macro_ok); if (!res) res = xcalloc(1, sizeof(*res)); return res; @@ -466,7 +468,7 @@ static void bootstrap_attr_stack(void) elem->prev = attr_stack; attr_stack = elem; - if (!is_bare_repository()) { + if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { elem = read_attr(GITATTRIBUTES_FILE, 1); elem->origin = strdup(""); elem->prev = attr_stack; @@ -533,7 +535,7 @@ static void prepare_attr_stack(const char *path, int dirlen) /* * Read from parent directories and push them down */ - if (!is_bare_repository()) { + if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { while (1) { char *cp; @@ -674,6 +676,10 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check) void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate) { enum git_attr_direction old = direction; + + if (is_bare_repository() && new != GIT_ATTR_INDEX) + die("BUG: non-INDEX attr direction in a bare repo"); + direction = new; if (new != old) drop_attr_stack(); @@ -33,7 +33,8 @@ int git_checkattr(const char *path, int, struct git_attr_check *); enum git_attr_direction { GIT_ATTR_CHECKIN, - GIT_ATTR_CHECKOUT + GIT_ATTR_CHECKOUT, + GIT_ATTR_INDEX, }; void git_attr_set_direction(enum git_attr_direction, struct index_state *); diff --git a/bisect.c b/bisect.c new file mode 100644 index 0000000000..58f7e6f773 --- /dev/null +++ b/bisect.c @@ -0,0 +1,556 @@ +#include "cache.h" +#include "commit.h" +#include "diff.h" +#include "revision.h" +#include "refs.h" +#include "list-objects.h" +#include "quote.h" +#include "sha1-lookup.h" +#include "bisect.h" + +static unsigned char (*skipped_sha1)[20]; +static int skipped_sha1_nr; +static int skipped_sha1_alloc; + +static const char **rev_argv; +static int rev_argv_nr; +static int rev_argv_alloc; + +/* bits #0-15 in revision.h */ + +#define COUNTED (1u<<16) + +/* + * This is a truly stupid algorithm, but it's only + * used for bisection, and we just don't care enough. + * + * We care just barely enough to avoid recursing for + * non-merge entries. + */ +static int count_distance(struct commit_list *entry) +{ + int nr = 0; + + while (entry) { + struct commit *commit = entry->item; + struct commit_list *p; + + if (commit->object.flags & (UNINTERESTING | COUNTED)) + break; + if (!(commit->object.flags & TREESAME)) + nr++; + commit->object.flags |= COUNTED; + p = commit->parents; + entry = p; + if (p) { + p = p->next; + while (p) { + nr += count_distance(p); + p = p->next; + } + } + } + + return nr; +} + +static void clear_distance(struct commit_list *list) +{ + while (list) { + struct commit *commit = list->item; + commit->object.flags &= ~COUNTED; + list = list->next; + } +} + +#define DEBUG_BISECT 0 + +static inline int weight(struct commit_list *elem) +{ + return *((int*)(elem->item->util)); +} + +static inline void weight_set(struct commit_list *elem, int weight) +{ + *((int*)(elem->item->util)) = weight; +} + +static int count_interesting_parents(struct commit *commit) +{ + struct commit_list *p; + int count; + + for (count = 0, p = commit->parents; p; p = p->next) { + if (p->item->object.flags & UNINTERESTING) + continue; + count++; + } + return count; +} + +static inline int halfway(struct commit_list *p, int nr) +{ + /* + * Don't short-cut something we are not going to return! + */ + if (p->item->object.flags & TREESAME) + return 0; + if (DEBUG_BISECT) + return 0; + /* + * 2 and 3 are halfway of 5. + * 3 is halfway of 6 but 2 and 4 are not. + */ + switch (2 * weight(p) - nr) { + case -1: case 0: case 1: + return 1; + default: + return 0; + } +} + +#if !DEBUG_BISECT +#define show_list(a,b,c,d) do { ; } while (0) +#else +static void show_list(const char *debug, int counted, int nr, + struct commit_list *list) +{ + struct commit_list *p; + + fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr); + + for (p = list; p; p = p->next) { + struct commit_list *pp; + struct commit *commit = p->item; + unsigned flags = commit->object.flags; + enum object_type type; + unsigned long size; + char *buf = read_sha1_file(commit->object.sha1, &type, &size); + char *ep, *sp; + + fprintf(stderr, "%c%c%c ", + (flags & TREESAME) ? ' ' : 'T', + (flags & UNINTERESTING) ? 'U' : ' ', + (flags & COUNTED) ? 'C' : ' '); + if (commit->util) + fprintf(stderr, "%3d", weight(p)); + else + fprintf(stderr, "---"); + fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1)); + for (pp = commit->parents; pp; pp = pp->next) + fprintf(stderr, " %.*s", 8, + sha1_to_hex(pp->item->object.sha1)); + + sp = strstr(buf, "\n\n"); + if (sp) { + sp += 2; + for (ep = sp; *ep && *ep != '\n'; ep++) + ; + fprintf(stderr, " %.*s", (int)(ep - sp), sp); + } + fprintf(stderr, "\n"); + } +} +#endif /* DEBUG_BISECT */ + +static struct commit_list *best_bisection(struct commit_list *list, int nr) +{ + struct commit_list *p, *best; + int best_distance = -1; + + best = list; + for (p = list; p; p = p->next) { + int distance; + unsigned flags = p->item->object.flags; + + if (flags & TREESAME) + continue; + distance = weight(p); + if (nr - distance < distance) + distance = nr - distance; + if (distance > best_distance) { + best = p; + best_distance = distance; + } + } + + return best; +} + +struct commit_dist { + struct commit *commit; + int distance; +}; + +static int compare_commit_dist(const void *a_, const void *b_) +{ + struct commit_dist *a, *b; + + a = (struct commit_dist *)a_; + b = (struct commit_dist *)b_; + if (a->distance != b->distance) + return b->distance - a->distance; /* desc sort */ + return hashcmp(a->commit->object.sha1, b->commit->object.sha1); +} + +static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr) +{ + struct commit_list *p; + struct commit_dist *array = xcalloc(nr, sizeof(*array)); + int cnt, i; + + for (p = list, cnt = 0; p; p = p->next) { + int distance; + unsigned flags = p->item->object.flags; + + if (flags & TREESAME) + continue; + distance = weight(p); + if (nr - distance < distance) + distance = nr - distance; + array[cnt].commit = p->item; + array[cnt].distance = distance; + cnt++; + } + qsort(array, cnt, sizeof(*array), compare_commit_dist); + for (p = list, i = 0; i < cnt; i++) { + struct name_decoration *r = xmalloc(sizeof(*r) + 100); + struct object *obj = &(array[i].commit->object); + + sprintf(r->name, "dist=%d", array[i].distance); + r->next = add_decoration(&name_decoration, obj, r); + p->item = array[i].commit; + p = p->next; + } + if (p) + p->next = NULL; + free(array); + return list; +} + +/* + * zero or positive weight is the number of interesting commits it can + * reach, including itself. Especially, weight = 0 means it does not + * reach any tree-changing commits (e.g. just above uninteresting one + * but traversal is with pathspec). + * + * weight = -1 means it has one parent and its distance is yet to + * be computed. + * + * weight = -2 means it has more than one parent and its distance is + * unknown. After running count_distance() first, they will get zero + * or positive distance. + */ +static struct commit_list *do_find_bisection(struct commit_list *list, + int nr, int *weights, + int find_all) +{ + int n, counted; + struct commit_list *p; + + counted = 0; + + for (n = 0, p = list; p; p = p->next) { + struct commit *commit = p->item; + unsigned flags = commit->object.flags; + + p->item->util = &weights[n++]; + switch (count_interesting_parents(commit)) { + case 0: + if (!(flags & TREESAME)) { + weight_set(p, 1); + counted++; + show_list("bisection 2 count one", + counted, nr, list); + } + /* + * otherwise, it is known not to reach any + * tree-changing commit and gets weight 0. + */ + break; + case 1: + weight_set(p, -1); + break; + default: + weight_set(p, -2); + break; + } + } + + show_list("bisection 2 initialize", counted, nr, list); + + /* + * If you have only one parent in the resulting set + * then you can reach one commit more than that parent + * can reach. So we do not have to run the expensive + * count_distance() for single strand of pearls. + * + * However, if you have more than one parents, you cannot + * just add their distance and one for yourself, since + * they usually reach the same ancestor and you would + * end up counting them twice that way. + * + * So we will first count distance of merges the usual + * way, and then fill the blanks using cheaper algorithm. + */ + for (p = list; p; p = p->next) { + if (p->item->object.flags & UNINTERESTING) + continue; + if (weight(p) != -2) + continue; + weight_set(p, count_distance(p)); + clear_distance(list); + + /* Does it happen to be at exactly half-way? */ + if (!find_all && halfway(p, nr)) + return p; + counted++; + } + + show_list("bisection 2 count_distance", counted, nr, list); + + while (counted < nr) { + for (p = list; p; p = p->next) { + struct commit_list *q; + unsigned flags = p->item->object.flags; + + if (0 <= weight(p)) + continue; + for (q = p->item->parents; q; q = q->next) { + if (q->item->object.flags & UNINTERESTING) + continue; + if (0 <= weight(q)) + break; + } + if (!q) + continue; + + /* + * weight for p is unknown but q is known. + * add one for p itself if p is to be counted, + * otherwise inherit it from q directly. + */ + if (!(flags & TREESAME)) { + weight_set(p, weight(q)+1); + counted++; + show_list("bisection 2 count one", + counted, nr, list); + } + else + weight_set(p, weight(q)); + + /* Does it happen to be at exactly half-way? */ + if (!find_all && halfway(p, nr)) + return p; + } + } + + show_list("bisection 2 counted all", counted, nr, list); + + if (!find_all) + return best_bisection(list, nr); + else + return best_bisection_sorted(list, nr); +} + +struct commit_list *find_bisection(struct commit_list *list, + int *reaches, int *all, + int find_all) +{ + int nr, on_list; + struct commit_list *p, *best, *next, *last; + int *weights; + + show_list("bisection 2 entry", 0, 0, list); + + /* + * Count the number of total and tree-changing items on the + * list, while reversing the list. + */ + for (nr = on_list = 0, last = NULL, p = list; + p; + p = next) { + unsigned flags = p->item->object.flags; + + next = p->next; + if (flags & UNINTERESTING) + continue; + p->next = last; + last = p; + if (!(flags & TREESAME)) + nr++; + on_list++; + } + list = last; + show_list("bisection 2 sorted", 0, nr, list); + + *all = nr; + weights = xcalloc(on_list, sizeof(*weights)); + + /* Do the real work of finding bisection commit. */ + best = do_find_bisection(list, nr, weights, find_all); + if (best) { + if (!find_all) + best->next = NULL; + *reaches = weight(best); + } + free(weights); + return best; +} + +static int register_ref(const char *refname, const unsigned char *sha1, + int flags, void *cb_data) +{ + if (!strcmp(refname, "bad")) { + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = xstrdup(sha1_to_hex(sha1)); + } else if (!prefixcmp(refname, "good-")) { + const char *hex = sha1_to_hex(sha1); + char *good = xmalloc(strlen(hex) + 2); + *good = '^'; + memcpy(good + 1, hex, strlen(hex) + 1); + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = good; + } else if (!prefixcmp(refname, "skip-")) { + ALLOC_GROW(skipped_sha1, skipped_sha1_nr + 1, + skipped_sha1_alloc); + hashcpy(skipped_sha1[skipped_sha1_nr++], sha1); + } + + return 0; +} + +static int read_bisect_refs(void) +{ + return for_each_ref_in("refs/bisect/", register_ref, NULL); +} + +void read_bisect_paths(void) +{ + struct strbuf str = STRBUF_INIT; + const char *filename = git_path("BISECT_NAMES"); + FILE *fp = fopen(filename, "r"); + + if (!fp) + die("Could not open file '%s': %s", filename, strerror(errno)); + + while (strbuf_getline(&str, fp, '\n') != EOF) { + char *quoted; + int res; + + strbuf_trim(&str); + quoted = strbuf_detach(&str, NULL); + res = sq_dequote_to_argv(quoted, &rev_argv, + &rev_argv_nr, &rev_argv_alloc); + if (res) + die("Badly quoted content in file '%s': %s", + filename, quoted); + } + + strbuf_release(&str); + fclose(fp); +} + +static int skipcmp(const void *a, const void *b) +{ + return hashcmp(a, b); +} + +static void prepare_skipped(void) +{ + qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp); +} + +static const unsigned char *skipped_sha1_access(size_t index, void *table) +{ + unsigned char (*skipped)[20] = table; + return skipped[index]; +} + +static int lookup_skipped(unsigned char *sha1) +{ + return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr, + skipped_sha1_access); +} + +struct commit_list *filter_skipped(struct commit_list *list, + struct commit_list **tried, + int show_all) +{ + struct commit_list *filtered = NULL, **f = &filtered; + + *tried = NULL; + + if (!skipped_sha1_nr) + return list; + + prepare_skipped(); + + while (list) { + struct commit_list *next = list->next; + list->next = NULL; + if (0 <= lookup_skipped(list->item->object.sha1)) { + /* Move current to tried list */ + *tried = list; + tried = &list->next; + } else { + if (!show_all) + return list; + /* Move current to filtered list */ + *f = list; + f = &list->next; + } + list = next; + } + + return filtered; +} + +static void bisect_rev_setup(struct rev_info *revs, const char *prefix) +{ + init_revisions(revs, prefix); + revs->abbrev = 0; + revs->commit_format = CMIT_FMT_UNSPECIFIED; + + /* argv[0] will be ignored by setup_revisions */ + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = xstrdup("bisect_rev_setup"); + + if (read_bisect_refs()) + die("reading bisect refs failed"); + + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = xstrdup("--"); + + read_bisect_paths(); + + ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc); + rev_argv[rev_argv_nr++] = NULL; + + setup_revisions(rev_argv_nr, rev_argv, revs, NULL); + + revs->limited = 1; +} + +int bisect_next_vars(const char *prefix) +{ + struct rev_info revs; + struct rev_list_info info; + int reaches = 0, all = 0; + + memset(&info, 0, sizeof(info)); + info.revs = &revs; + info.bisect_show_flags = BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED; + + bisect_rev_setup(&revs, prefix); + + if (prepare_revision_walk(&revs)) + die("revision walk setup failed"); + if (revs.tree_objects) + mark_edges_uninteresting(revs.commits, &revs, NULL); + + revs.commits = find_bisection(revs.commits, &reaches, &all, + !!skipped_sha1_nr); + + return show_bisect_vars(&info, reaches, all); +} diff --git a/bisect.h b/bisect.h new file mode 100644 index 0000000000..fdba913877 --- /dev/null +++ b/bisect.h @@ -0,0 +1,29 @@ +#ifndef BISECT_H +#define BISECT_H + +extern struct commit_list *find_bisection(struct commit_list *list, + int *reaches, int *all, + int find_all); + +extern struct commit_list *filter_skipped(struct commit_list *list, + struct commit_list **tried, + int show_all); + +/* bisect_show_flags flags in struct rev_list_info */ +#define BISECT_SHOW_ALL (1<<0) +#define BISECT_SHOW_TRIED (1<<1) +#define BISECT_SHOW_STRINGED (1<<2) + +struct rev_list_info { + struct rev_info *revs; + int bisect_show_flags; + int show_timestamp; + int hdr_termination; + const char *header_prefix; +}; + +extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all); + +extern int bisect_next_vars(const char *prefix); + +#endif diff --git a/builtin-apply.c b/builtin-apply.c index 1926cd8055..7b404ef660 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2271,6 +2271,25 @@ static struct patch *in_fn_table(const char *name) return NULL; } +/* + * item->util in the filename table records the status of the path. + * Usually it points at a patch (whose result records the contents + * of it after applying it), but it could be PATH_WAS_DELETED for a + * path that a previously applied patch has already removed. + */ + #define PATH_TO_BE_DELETED ((struct patch *) -2) +#define PATH_WAS_DELETED ((struct patch *) -1) + +static int to_be_deleted(struct patch *patch) +{ + return patch == PATH_TO_BE_DELETED; +} + +static int was_deleted(struct patch *patch) +{ + return patch == PATH_WAS_DELETED; +} + static void add_to_fn_table(struct patch *patch) { struct string_list_item *item; @@ -2291,7 +2310,22 @@ static void add_to_fn_table(struct patch *patch) */ if ((patch->new_name == NULL) || (patch->is_rename)) { item = string_list_insert(patch->old_name, &fn_table); - item->util = (struct patch *) -1; + item->util = PATH_WAS_DELETED; + } +} + +static void prepare_fn_table(struct patch *patch) +{ + /* + * store information about incoming file deletion + */ + while (patch) { + if ((patch->new_name == NULL) || (patch->is_rename)) { + struct string_list_item *item; + item = string_list_insert(patch->old_name, &fn_table); + item->util = PATH_TO_BE_DELETED; + } + patch = patch->next; } } @@ -2304,8 +2338,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * struct patch *tpatch; if (!(patch->is_copy || patch->is_rename) && - ((tpatch = in_fn_table(patch->old_name)) != NULL)) { - if (tpatch == (struct patch *) -1) { + (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) { + if (was_deleted(tpatch)) { return error("patch %s has been renamed/deleted", patch->old_name); } @@ -2399,10 +2433,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s assert(patch->is_new <= 0); if (!(patch->is_copy || patch->is_rename) && - (tpatch = in_fn_table(old_name)) != NULL) { - if (tpatch == (struct patch *) -1) { + (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) { + if (was_deleted(tpatch)) return error("%s: has been deleted/renamed", old_name); - } st_mode = tpatch->new_mode; } else if (!cached) { stat_ret = lstat(old_name, st); @@ -2410,6 +2443,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s return error("%s: %s", old_name, strerror(errno)); } + if (to_be_deleted(tpatch)) + tpatch = NULL; + if (check_index && !tpatch) { int pos = cache_name_pos(old_name, strlen(old_name)); if (pos < 0) { @@ -2471,6 +2507,7 @@ static int check_patch(struct patch *patch) const char *new_name = patch->new_name; const char *name = old_name ? old_name : new_name; struct cache_entry *ce = NULL; + struct patch *tpatch; int ok_if_exists; int status; @@ -2481,7 +2518,8 @@ static int check_patch(struct patch *patch) return status; old_name = patch->old_name; - if (in_fn_table(new_name) == (struct patch *) -1) + if ((tpatch = in_fn_table(new_name)) && + (was_deleted(tpatch) || to_be_deleted(tpatch))) /* * A type-change diff is always split into a patch to * delete old, immediately followed by a patch to @@ -2533,6 +2571,7 @@ static int check_patch_list(struct patch *patch) { int err = 0; + prepare_fn_table(patch); while (patch) { if (apply_verbosely) say_patch_name(stderr, diff --git a/builtin-bisect--helper.c b/builtin-bisect--helper.c new file mode 100644 index 0000000000..8fe778766a --- /dev/null +++ b/builtin-bisect--helper.c @@ -0,0 +1,27 @@ +#include "builtin.h" +#include "cache.h" +#include "parse-options.h" +#include "bisect.h" + +static const char * const git_bisect_helper_usage[] = { + "git bisect--helper --next-vars", + NULL +}; + +int cmd_bisect__helper(int argc, const char **argv, const char *prefix) +{ + int next_vars = 0; + struct option options[] = { + OPT_BOOLEAN(0, "next-vars", &next_vars, + "output next bisect step variables"), + OPT_END() + }; + + argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0); + + if (!next_vars) + usage_with_options(git_bisect_helper_usage, options); + + /* next-vars */ + return bisect_next_vars(prefix); +} diff --git a/builtin-blame.c b/builtin-blame.c index 83141fc84e..cf74a92614 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -873,7 +873,7 @@ static void find_copy_in_blob(struct scoreboard *sb, * Prepare mmfile that contains only the lines in ent. */ cp = nth_line(sb, ent->lno); - file_o.ptr = (char*) cp; + file_o.ptr = (char *) cp; cnt = ent->num_lines; while (cnt && cp < sb->final_buf + sb->final_buf_size) { @@ -1704,7 +1704,7 @@ static int prepare_lines(struct scoreboard *sb) while (len--) { if (bol) { sb->lineno = xrealloc(sb->lineno, - sizeof(int* ) * (num + 1)); + sizeof(int *) * (num + 1)); sb->lineno[num] = buf - sb->final_buf; bol = 0; } @@ -1714,7 +1714,7 @@ static int prepare_lines(struct scoreboard *sb) } } sb->lineno = xrealloc(sb->lineno, - sizeof(int* ) * (num + incomplete + 1)); + sizeof(int *) * (num + incomplete + 1)); sb->lineno[num + incomplete] = buf - sb->final_buf; sb->num_lines = num + incomplete; return sb->num_lines; @@ -1889,7 +1889,7 @@ static const char *parse_loc(const char *spec, return spec; /* it could be a regexp of form /.../ */ - for (term = (char*) spec + 1; *term && *term != '/'; term++) { + for (term = (char *) spec + 1; *term && *term != '/'; term++) { if (*term == '\\') term++; } diff --git a/builtin-branch.c b/builtin-branch.c index ca81d725cb..6aaa708473 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -301,19 +301,30 @@ static int ref_cmp(const void *r1, const void *r2) return strcmp(c1->name, c2->name); } -static void fill_tracking_info(struct strbuf *stat, const char *branch_name) +static void fill_tracking_info(struct strbuf *stat, const char *branch_name, + int show_upstream_ref) { int ours, theirs; struct branch *branch = branch_get(branch_name); - if (!stat_tracking_info(branch, &ours, &theirs) || (!ours && !theirs)) + if (!stat_tracking_info(branch, &ours, &theirs)) { + if (branch && branch->merge && branch->merge[0]->dst && + show_upstream_ref) + strbuf_addf(stat, "[%s] ", + shorten_unambiguous_ref(branch->merge[0]->dst, 0)); return; + } + + strbuf_addch(stat, '['); + if (show_upstream_ref) + strbuf_addf(stat, "%s: ", + shorten_unambiguous_ref(branch->merge[0]->dst, 0)); if (!ours) - strbuf_addf(stat, "[behind %d] ", theirs); + strbuf_addf(stat, "behind %d] ", theirs); else if (!theirs) - strbuf_addf(stat, "[ahead %d] ", ours); + strbuf_addf(stat, "ahead %d] ", ours); else - strbuf_addf(stat, "[ahead %d, behind %d] ", ours, theirs); + strbuf_addf(stat, "ahead %d, behind %d] ", ours, theirs); } static int matches_merge_filter(struct commit *commit) @@ -379,7 +390,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, } if (item->kind == REF_LOCAL_BRANCH) - fill_tracking_info(&stat, item->name); + fill_tracking_info(&stat, item->name, verbose > 1); strbuf_addf(&out, " %s %s%s", find_unique_abbrev(item->commit->object.sha1, abbrev), @@ -536,7 +547,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_GROUP("Generic options"), OPT__VERBOSE(&verbose), - OPT_SET_INT( 0 , "track", &track, "set up tracking mode (see git-pull(1))", + OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))", BRANCH_TRACK_EXPLICIT), OPT_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"), OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches", diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 0d534bc023..afe35e246c 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -124,7 +124,7 @@ static int checkout_file(const char *name, int prefix_length) static void checkout_all(const char *prefix, int prefix_length) { int i, errs = 0; - struct cache_entry* last_ce = NULL; + struct cache_entry *last_ce = NULL; for (i = 0; i < active_nr ; i++) { struct cache_entry *ce = active_cache[i]; @@ -278,7 +278,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) p = prefix_path(prefix, prefix_length, arg); checkout_file(p, prefix_length); if (p < arg || p > arg + strlen(arg)) - free((char*)p); + free((char *)p); } if (read_from_stdin) { diff --git a/builtin-checkout.c b/builtin-checkout.c index ee1edd406f..f2d7ef01b0 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -5,6 +5,7 @@ #include "commit.h" #include "tree.h" #include "tree-walk.h" +#include "cache-tree.h" #include "unpack-trees.h" #include "dir.h" #include "run-command.h" @@ -178,7 +179,7 @@ static int checkout_merged(int pos, struct checkout *state) /* * NEEDSWORK: * There is absolutely no reason to write this as a blob object - * and create a phoney cache entry just to leak. This hack is + * and create a phony cache entry just to leak. This hack is * primarily to get to the write_entry() machinery that massages * the contents to work-tree format and writes out which only * allows it for a cache entry. The code in write_entry() needs @@ -540,14 +541,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) parse_commit(new->commit); } - /* - * If we were on a detached HEAD, but we are now moving to - * a new commit, we want to mention the old commit once more - * to remind the user that it might be lost. - */ - if (!opts->quiet && !old.path && old.commit && new->commit != old.commit) - describe_detached_head("Previous HEAD position was", old.commit); - if (!old.commit && !opts->force) { if (!opts->quiet) { warning("You appear to be on a branch yet to be born."); @@ -560,6 +553,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) if (ret) return ret; + /* + * If we were on a detached HEAD, but have now moved to + * a new commit, we want to mention the old commit once more + * to remind the user that it might be lost. + */ + if (!opts->quiet && !old.path && old.commit && new->commit != old.commit) + describe_detached_head("Previous HEAD position was", old.commit); + update_refs_for_switch(opts, &old, new); ret = post_checkout_hook(old.commit, new->commit, 1); diff --git a/builtin-clone.c b/builtin-clone.c index 880373f279..d068b7e0d8 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -104,11 +104,12 @@ static char *get_repo_path(const char *repo, int *is_bundle) static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) { const char *end = repo + strlen(repo), *start; + char *dir; /* - * Strip trailing slashes and /.git + * Strip trailing spaces, slashes and /.git */ - while (repo < end && is_dir_sep(end[-1])) + while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1]))) end--; if (end - repo > 5 && is_dir_sep(end[-5]) && !strncmp(end - 4, ".git", 4)) { @@ -140,10 +141,33 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) if (is_bare) { struct strbuf result = STRBUF_INIT; strbuf_addf(&result, "%.*s.git", (int)(end - start), start); - return strbuf_detach(&result, 0); + dir = strbuf_detach(&result, 0); + } else + dir = xstrndup(start, end - start); + /* + * Replace sequences of 'control' characters and whitespace + * with one ascii space, remove leading and trailing spaces. + */ + if (*dir) { + char *out = dir; + int prev_space = 1 /* strip leading whitespace */; + for (end = dir; *end; ++end) { + char ch = *end; + if ((unsigned char)ch < '\x20') + ch = '\x20'; + if (isspace(ch)) { + if (prev_space) + continue; + prev_space = 1; + } else + prev_space = 0; + *out++ = ch; + } + *out = '\0'; + if (out > dir && prev_space) + out[-1] = '\0'; } - - return xstrndup(start, end - start); + return dir; } static void strip_trailing_slashes(char *dir) diff --git a/builtin-config.c b/builtin-config.c index d8da72cf20..a81bc8bbf0 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -390,6 +390,8 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } else if (actions == ACTION_EDIT) { check_argc(argc, 0, 0); + if (!config_exclusive_filename && nongit) + die("not in a git directory"); git_config(git_default_config, NULL); launch_editor(config_exclusive_filename ? config_exclusive_filename : git_path("config"), diff --git a/builtin-describe.c b/builtin-describe.c index 3a007ed1ca..63c6a19da5 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -334,7 +334,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) die("--long is incompatible with --abbrev=0"); if (contains) { - const char **args = xmalloc((7 + argc) * sizeof(char*)); + const char **args = xmalloc((7 + argc) * sizeof(char *)); int i = 0; args[i++] = "name-rev"; args[i++] = "--name-only"; @@ -349,7 +349,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) args[i++] = s; } } - memcpy(args + i, argv, argc * sizeof(char*)); + memcpy(args + i, argv, argc * sizeof(char *)); args[i + argc] = NULL; return cmd_name_rev(i + argc, args, prefix); } diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 5d134be47c..87f46c6d07 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -13,6 +13,7 @@ static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; static int unpack_limit = 100; +static int prefer_ofs_delta = 1; static struct fetch_pack_args args = { /* .uploadpack = */ "git-upload-pack", }; @@ -111,7 +112,7 @@ static void mark_common(struct commit *commit, Get the next rev to send, ignoring the common. */ -static const unsigned char* get_rev(void) +static const unsigned char *get_rev(void) { struct commit *commit = NULL; @@ -200,7 +201,7 @@ static int find_common(int fd[2], unsigned char *result_sha1, (args.use_thin_pack ? " thin-pack" : ""), (args.no_progress ? " no-progress" : ""), (args.include_tag ? " include-tag" : ""), - " ofs-delta"); + (prefer_ofs_delta ? " ofs-delta" : "")); else packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); fetching++; @@ -596,6 +597,11 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports side-band\n"); use_sideband = 1; } + if (server_supports("ofs-delta")) { + if (args.verbose) + fprintf(stderr, "Server supports ofs-delta\n"); + } else + prefer_ofs_delta = 0; if (everything_local(&ref, nr_match, match)) { packet_flush(fd[1]); goto all_done; @@ -648,6 +654,11 @@ static int fetch_pack_config(const char *var, const char *value, void *cb) return 0; } + if (strcmp(var, "repack.usedeltabaseoffset") == 0) { + prefer_ofs_delta = git_config_bool(var, value); + return 0; + } + return git_default_config(var, value, cb); } diff --git a/builtin-fetch.c b/builtin-fetch.c index 3c998ea740..b944cac6e6 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -289,7 +289,7 @@ static int update_local_ref(struct ref *ref, } } -static int store_updated_refs(const char *url, const char *remote_name, +static int store_updated_refs(const char *raw_url, const char *remote_name, struct ref *ref_map) { FILE *fp; @@ -298,11 +298,13 @@ static int store_updated_refs(const char *url, const char *remote_name, char note[1024]; const char *what, *kind; struct ref *rm; - char *filename = git_path("FETCH_HEAD"); + char *url, *filename = git_path("FETCH_HEAD"); fp = fopen(filename, "a"); if (!fp) return error("cannot open %s: %s\n", filename, strerror(errno)); + + url = transport_anonymize_url(raw_url); for (rm = ref_map; rm; rm = rm->next) { struct ref *ref = NULL; @@ -353,12 +355,18 @@ static int store_updated_refs(const char *url, const char *remote_name, kind); note_len += sprintf(note + note_len, "'%s' of ", what); } - note_len += sprintf(note + note_len, "%.*s", url_len, url); - fprintf(fp, "%s\t%s\t%s\n", + note[note_len] = '\0'; + fprintf(fp, "%s\t%s\t%s", sha1_to_hex(commit ? commit->object.sha1 : rm->old_sha1), rm->merge ? "" : "not-for-merge", note); + for (i = 0; i < url_len; ++i) + if ('\n' == url[i]) + fputs("\\n", fp); + else + fputc(url[i], fp); + fputc('\n', fp); if (ref) rc |= update_local_ref(ref, what, note); @@ -376,6 +384,7 @@ static int store_updated_refs(const char *url, const char *remote_name, fprintf(stderr, " %s\n", note); } } + free(url); fclose(fp); if (rc & 2) error("some local refs could not be updated; try running\n" diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 5cbb4b081d..91e8f95fd2 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -8,6 +8,7 @@ #include "blob.h" #include "quote.h" #include "parse-options.h" +#include "remote.h" /* Quoting styles */ #define QUOTE_NONE 0 @@ -66,6 +67,7 @@ static struct { { "subject" }, { "body" }, { "contents" }, + { "upstream" }, }; /* @@ -544,109 +546,6 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v } /* - * generate a format suitable for scanf from a ref_rev_parse_rules - * rule, that is replace the "%.*s" spec with a "%s" spec - */ -static void gen_scanf_fmt(char *scanf_fmt, const char *rule) -{ - char *spec; - - spec = strstr(rule, "%.*s"); - if (!spec || strstr(spec + 4, "%.*s")) - die("invalid rule in ref_rev_parse_rules: %s", rule); - - /* copy all until spec */ - strncpy(scanf_fmt, rule, spec - rule); - scanf_fmt[spec - rule] = '\0'; - /* copy new spec */ - strcat(scanf_fmt, "%s"); - /* copy remaining rule */ - strcat(scanf_fmt, spec + 4); - - return; -} - -/* - * Shorten the refname to an non-ambiguous form - */ -static char *get_short_ref(struct refinfo *ref) -{ - int i; - static char **scanf_fmts; - static int nr_rules; - char *short_name; - - /* pre generate scanf formats from ref_rev_parse_rules[] */ - if (!nr_rules) { - size_t total_len = 0; - - /* the rule list is NULL terminated, count them first */ - for (; ref_rev_parse_rules[nr_rules]; nr_rules++) - /* no +1 because strlen("%s") < strlen("%.*s") */ - total_len += strlen(ref_rev_parse_rules[nr_rules]); - - scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len); - - total_len = 0; - for (i = 0; i < nr_rules; i++) { - scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] - + total_len; - gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]); - total_len += strlen(ref_rev_parse_rules[i]); - } - } - - /* bail out if there are no rules */ - if (!nr_rules) - return ref->refname; - - /* buffer for scanf result, at most ref->refname must fit */ - short_name = xstrdup(ref->refname); - - /* skip first rule, it will always match */ - for (i = nr_rules - 1; i > 0 ; --i) { - int j; - int short_name_len; - - if (1 != sscanf(ref->refname, scanf_fmts[i], short_name)) - continue; - - short_name_len = strlen(short_name); - - /* - * check if the short name resolves to a valid ref, - * but use only rules prior to the matched one - */ - for (j = 0; j < i; j++) { - const char *rule = ref_rev_parse_rules[j]; - unsigned char short_objectname[20]; - char refname[PATH_MAX]; - - /* - * the short name is ambiguous, if it resolves - * (with this previous rule) to a valid ref - * read_ref() returns 0 on success - */ - mksnpath(refname, sizeof(refname), - rule, short_name_len, short_name); - if (!read_ref(refname, short_objectname)) - break; - } - - /* - * short name is non-ambiguous if all previous rules - * haven't resolved to a valid ref - */ - if (j == i) - return short_name; - } - - free(short_name); - return ref->refname; -} - - -/* * Parse the object referred by ref, and grab needed value. */ static void populate_value(struct refinfo *ref) @@ -672,32 +571,50 @@ static void populate_value(struct refinfo *ref) const char *name = used_atom[i]; struct atom_value *v = &ref->value[i]; int deref = 0; + const char *refname; + const char *formatp; + if (*name == '*') { deref = 1; name++; } - if (!prefixcmp(name, "refname")) { - const char *formatp = strchr(name, ':'); - const char *refname = ref->refname; - - /* look for "short" refname format */ - if (formatp) { - formatp++; - if (!strcmp(formatp, "short")) - refname = get_short_ref(ref); - else - die("unknown refname format %s", - formatp); - } - if (!deref) - v->s = refname; - else { - int len = strlen(refname); - char *s = xmalloc(len + 4); - sprintf(s, "%s^{}", refname); - v->s = s; - } + if (!prefixcmp(name, "refname")) + refname = ref->refname; + else if(!prefixcmp(name, "upstream")) { + struct branch *branch; + /* only local branches may have an upstream */ + if (prefixcmp(ref->refname, "refs/heads/")) + continue; + branch = branch_get(ref->refname + 11); + + if (!branch || !branch->merge || !branch->merge[0] || + !branch->merge[0]->dst) + continue; + refname = branch->merge[0]->dst; + } + else + continue; + + formatp = strchr(name, ':'); + /* look for "short" refname format */ + if (formatp) { + formatp++; + if (!strcmp(formatp, "short")) + refname = shorten_unambiguous_ref(refname, + warn_ambiguous_refs); + else + die("unknown %.*s format %s", + (int)(formatp - name), name, formatp); + } + + if (!deref) + v->s = refname; + else { + int len = strlen(refname); + char *s = xmalloc(len + 4); + sprintf(s, "%s^{}", refname); + v->s = s; } } @@ -1001,6 +918,9 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) sort = default_sort(); sort_atom_limit = used_atom_cnt; + /* for warn_ambiguous_refs */ + git_config(git_default_config, NULL); + memset(&cbdata, 0, sizeof(cbdata)); cbdata.grab_pattern = argv; for_each_ref(grab_single_ref, &cbdata); diff --git a/builtin-grep.c b/builtin-grep.c index 89489ddcf8..f88a912ace 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -26,16 +26,13 @@ static int grep_config(const char *var, const char *value, void *cb) { struct grep_opt *opt = cb; - if (!strcmp(var, "grep.color") || !strcmp(var, "color.grep")) { + if (!strcmp(var, "color.grep")) { opt->color = git_config_colorbool(var, value, -1); return 0; } - if (!strcmp(var, "grep.color.external") || - !strcmp(var, "color.grep.external")) { + if (!strcmp(var, "color.grep.external")) return git_config_string(&(opt->color_external), var, value); - } - if (!strcmp(var, "grep.color.match") || - !strcmp(var, "color.grep.match")) { + if (!strcmp(var, "color.grep.match")) { if (!value) return config_error_nonbool(var); color_parse(value, var, opt->color_match); diff --git a/builtin-help.c b/builtin-help.c index 9b57a74618..67dda3e6e6 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -114,7 +114,7 @@ static int check_emacsclient_version(void) return 0; } -static void exec_woman_emacs(const char* path, const char *page) +static void exec_woman_emacs(const char *path, const char *page) { if (!check_emacsclient_version()) { /* This works only with emacsclient version >= 22. */ @@ -128,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page) } } -static void exec_man_konqueror(const char* path, const char *page) +static void exec_man_konqueror(const char *path, const char *page) { const char *display = getenv("DISPLAY"); if (display && *display) { @@ -156,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page) } } -static void exec_man_man(const char* path, const char *page) +static void exec_man_man(const char *path, const char *page) { if (!path) path = "man"; @@ -236,7 +236,7 @@ static int add_man_viewer_info(const char *var, const char *value) const char *subkey = strrchr(name, '.'); if (!subkey) - return error("Config with no key for man viewer: %s", name); + return 0; if (!strcmp(subkey, ".path")) { if (!value) @@ -249,7 +249,6 @@ static int add_man_viewer_info(const char *var, const char *value) return add_man_viewer_cmd(name, subkey - name, value); } - warning("'%s': unsupported man viewer sub key.", subkey); return 0; } diff --git a/builtin-init-db.c b/builtin-init-db.c index 4e02b33bb7..d1fa12a59e 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -122,8 +122,10 @@ static void copy_templates(const char *template_dir) template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR); if (!template_dir[0]) return; + template_len = strlen(template_dir); + if (PATH_MAX <= (template_len+strlen("/config"))) + die("insanely long template path %s", template_dir); strcpy(template_path, template_dir); - template_len = strlen(template_path); if (template_path[template_len-1] != '/') { template_path[template_len++] = '/'; template_path[template_len] = 0; diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 88e2697aeb..da2daf45ac 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -512,7 +512,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) pathspec = get_pathspec(prefix, argv); - /* be nice with submodule patsh ending in a slash */ + /* be nice with submodule paths ending in a slash */ read_cache(); if (pathspec) strip_trailing_slash_from_submodules(); diff --git a/builtin-merge.c b/builtin-merge.c index 6a51823a55..0b58e5eda1 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -764,7 +764,7 @@ static int suggest_conflicts(void) fp = fopen(git_path("MERGE_MSG"), "a"); if (!fp) - die("Could open %s for writing", git_path("MERGE_MSG")); + die("Could not open %s for writing", git_path("MERGE_MSG")); fprintf(fp, "\nConflicts:\n"); for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 99181fd7ee..9742b45c4d 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -293,7 +293,7 @@ static unsigned long write_object(struct sha1file *f, die("unable to read %s", sha1_to_hex(entry->idx.sha1)); /* * make sure no cached delta data remains from a - * previous attempt before a pack split occured. + * previous attempt before a pack split occurred. */ free(entry->delta_data); entry->delta_data = NULL; @@ -1901,17 +1901,25 @@ static void read_object_list_from_stdin(void) #define OBJECT_ADDED (1u<<20) -static void show_commit(struct commit *commit) +static void show_commit(struct commit *commit, void *data) { add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0); commit->object.flags |= OBJECT_ADDED; } -static void show_object(struct object_array_entry *p) +static void show_object(struct object *obj, const struct name_path *path, const char *last) { - add_preferred_base_object(p->name); - add_object_entry(p->item->sha1, p->item->type, p->name, 0); - p->item->flags |= OBJECT_ADDED; + char *name = path_name(path, last); + + add_preferred_base_object(name); + add_object_entry(obj->sha1, obj->type, name, 0); + obj->flags |= OBJECT_ADDED; + + /* + * We will have generated the hash from the name, + * but not saved a pointer to it - we can free it + */ + free((char *)name); } static void show_edge(struct commit *commit) @@ -2071,7 +2079,7 @@ static void get_object_list(int ac, const char **av) if (prepare_revision_walk(&revs)) die("revision walk setup failed"); mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, show_object); + traverse_commit_list(&revs, show_commit, show_object, NULL); if (keep_unreachable) add_objects_in_unpacked_packs(&revs); diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 2d5b2cd353..4942892e9f 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -55,6 +55,7 @@ void prune_packed_objects(int opts) for (i = 0; i < 256; i++) { DIR *d; + display_progress(progress, i + 1); sprintf(pathname + len, "%02x/", i); d = opendir(pathname); if (!d) diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 8e0273864d..82e25eaa07 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -29,41 +29,6 @@ static int list_tree(unsigned char *sha1) return 0; } -static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) -{ - struct tree_desc desc; - struct name_entry entry; - int cnt; - - hashcpy(it->sha1, tree->object.sha1); - init_tree_desc(&desc, tree->buffer, tree->size); - cnt = 0; - while (tree_entry(&desc, &entry)) { - if (!S_ISDIR(entry.mode)) - cnt++; - else { - struct cache_tree_sub *sub; - struct tree *subtree = lookup_tree(entry.sha1); - if (!subtree->object.parsed) - parse_tree(subtree); - sub = cache_tree_sub(it, entry.path); - sub->cache_tree = cache_tree(); - prime_cache_tree_rec(sub->cache_tree, subtree); - cnt += sub->cache_tree->entry_count; - } - } - it->entry_count = cnt; -} - -static void prime_cache_tree(void) -{ - if (!nr_trees) - return; - active_cache_tree = cache_tree(); - prime_cache_tree_rec(active_cache_tree, trees[0]); - -} - static const char read_tree_usage[] = "git read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])"; static struct lock_file lock_file; @@ -211,7 +176,6 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) case 3: default: opts.fn = threeway_merge; - cache_tree_free(&active_cache_tree); break; } @@ -221,6 +185,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) opts.head_idx = 1; } + cache_tree_free(&active_cache_tree); for (i = 0; i < nr_trees; i++) { struct tree *tree = trees[i]; parse_tree(tree); @@ -234,11 +199,14 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) * "-m ent" or "--reset ent" form), we can obtain a fully * valid cache-tree because the index must match exactly * what came from the tree. + * + * The same holds true if we are switching between two trees + * using read-tree -m A B. The index must match B after that. */ - if (nr_trees && !opts.prefix && (!opts.merge || (stage == 2))) { - cache_tree_free(&active_cache_tree); - prime_cache_tree(); - } + if (nr_trees == 1 && !opts.prefix) + prime_cache_tree(&active_cache_tree, trees[0]); + else if (nr_trees == 2 && opts.merge) + prime_cache_tree(&active_cache_tree, trees[1]); if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) diff --git a/builtin-reflog.c b/builtin-reflog.c index 249ad2a311..ddfdf5a3cb 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -240,10 +240,10 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig static void mark_reachable(struct commit *commit, unsigned long expire_limit) { /* - * We need to compute if commit on either side of an reflog + * We need to compute whether the commit on either side of a reflog * entry is reachable from the tip of the ref for all entries. * Mark commits that are reachable from the tip down to the - * time threashold first; we know a commit marked thusly is + * time threshold first; we know a commit marked thusly is * reachable from the tip without running in_merge_bases() * at all. */ diff --git a/builtin-remote.c b/builtin-remote.c index 9ef846f6a4..2ed752cbf1 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -15,7 +15,7 @@ static const char * const builtin_remote_usage[] = { "git remote set-head <name> [-a | -d | <branch>]", "git remote show [-n] <name>", "git remote prune [-n | --dry-run] <name>", - "git remote [-v | --verbose] update [group]", + "git remote [-v | --verbose] update [-p | --prune] [group]", NULL }; @@ -26,6 +26,7 @@ static const char * const builtin_remote_usage[] = { static int verbose; static int show_all(void); +static int prune_remote(const char *remote, int dry_run); static inline int postfixcmp(const char *string, const char *postfix) { @@ -1128,46 +1129,49 @@ static int prune(int argc, const char **argv) OPT__DRY_RUN(&dry_run), OPT_END() }; - struct ref_states states; - const char *dangling_msg; argc = parse_options(argc, argv, options, builtin_remote_usage, 0); if (argc < 1) usage_with_options(builtin_remote_usage, options); - dangling_msg = (dry_run - ? " %s will become dangling!\n" - : " %s has become dangling!\n"); - - memset(&states, 0, sizeof(states)); - for (; argc; argc--, argv++) { - int i; + for (; argc; argc--, argv++) + result |= prune_remote(*argv, dry_run); - get_remote_ref_states(*argv, &states, GET_REF_STATES); + return result; +} - if (states.stale.nr) { - printf("Pruning %s\n", *argv); - printf("URL: %s\n", - states.remote->url_nr - ? states.remote->url[0] - : "(no URL)"); - } +static int prune_remote(const char *remote, int dry_run) +{ + int result = 0, i; + struct ref_states states; + const char *dangling_msg = dry_run + ? " %s will become dangling!\n" + : " %s has become dangling!\n"; - for (i = 0; i < states.stale.nr; i++) { - const char *refname = states.stale.items[i].util; + memset(&states, 0, sizeof(states)); + get_remote_ref_states(remote, &states, GET_REF_STATES); + + if (states.stale.nr) { + printf("Pruning %s\n", remote); + printf("URL: %s\n", + states.remote->url_nr + ? states.remote->url[0] + : "(no URL)"); + } - if (!dry_run) - result |= delete_ref(refname, NULL, 0); + for (i = 0; i < states.stale.nr; i++) { + const char *refname = states.stale.items[i].util; - printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned", - abbrev_ref(refname, "refs/remotes/")); - warn_dangling_symref(dangling_msg, refname); - } + if (!dry_run) + result |= delete_ref(refname, NULL, 0); - free_remote_ref_states(&states); + printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned", + abbrev_ref(refname, "refs/remotes/")); + warn_dangling_symref(dangling_msg, refname); } + free_remote_ref_states(&states); return result; } @@ -1184,16 +1188,18 @@ struct remote_group { struct string_list *list; } remote_group; -static int get_remote_group(const char *key, const char *value, void *cb) +static int get_remote_group(const char *key, const char *value, void *num_hits) { if (!prefixcmp(key, "remotes.") && !strcmp(key + 8, remote_group.name)) { /* split list by white space */ int space = strcspn(value, " \t\n"); while (*value) { - if (space > 1) + if (space > 1) { string_list_append(xstrndup(value, space), remote_group.list); + ++*((int *)num_hits); + } value += space + (value[space] != '\0'); space = strcspn(value, " \t\n"); } @@ -1204,10 +1210,18 @@ static int get_remote_group(const char *key, const char *value, void *cb) static int update(int argc, const char **argv) { - int i, result = 0; + int i, result = 0, prune = 0; struct string_list list = { NULL, 0, 0, 0 }; static const char *default_argv[] = { NULL, "default", NULL }; + struct option options[] = { + OPT_GROUP("update specific options"), + OPT_BOOLEAN('p', "prune", &prune, + "prune remotes after fetching"), + OPT_END() + }; + argc = parse_options(argc, argv, options, builtin_remote_usage, + PARSE_OPT_KEEP_ARGV0); if (argc < 2) { argc = 2; argv = default_argv; @@ -1215,15 +1229,28 @@ static int update(int argc, const char **argv) remote_group.list = &list; for (i = 1; i < argc; i++) { + int groups_found = 0; remote_group.name = argv[i]; - result = git_config(get_remote_group, NULL); + result = git_config(get_remote_group, &groups_found); + if (!groups_found && (i != 1 || strcmp(argv[1], "default"))) { + struct remote *remote; + if (!remote_is_configured(argv[i])) + die("No such remote or remote group: %s", + argv[i]); + remote = remote_get(argv[i]); + string_list_append(remote->name, remote_group.list); + } } if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default")) result = for_each_remote(get_one_remote_for_update, &list); - for (i = 0; i < list.nr; i++) - result |= fetch_remote(list.items[i].string); + for (i = 0; i < list.nr; i++) { + int err = fetch_remote(list.items[i].string); + result |= err; + if (!err && prune) + result |= prune_remote(list.items[i].string, 0); + } /* all names were strdup()ed or strndup()ed */ list.strdup_strings = 1; diff --git a/builtin-reset.c b/builtin-reset.c index c0cb915c26..7e7ebabaa8 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -228,7 +228,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) } /* * Otherwise, argv[i] could be either <rev> or <paths> and - * has to be unambigous. + * has to be unambiguous. */ else if (!get_sha1(argv[i], sha1)) { /* diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 40d5fcb6b0..38a8f234de 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -1,20 +1,12 @@ #include "cache.h" -#include "refs.h" -#include "tag.h" #include "commit.h" -#include "tree.h" -#include "blob.h" -#include "tree-walk.h" #include "diff.h" #include "revision.h" #include "list-objects.h" #include "builtin.h" #include "log-tree.h" #include "graph.h" - -/* bits #0-15 in revision.h */ - -#define COUNTED (1u<<16) +#include "bisect.h" static const char rev_list_usage[] = "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n" @@ -50,73 +42,69 @@ static const char rev_list_usage[] = " --bisect-all" ; -static struct rev_info revs; - -static int bisect_list; -static int show_timestamp; -static int hdr_termination; -static const char *header_prefix; - -static void finish_commit(struct commit *commit); -static void show_commit(struct commit *commit) +static void finish_commit(struct commit *commit, void *data); +static void show_commit(struct commit *commit, void *data) { - graph_show_commit(revs.graph); + struct rev_list_info *info = data; + struct rev_info *revs = info->revs; + + graph_show_commit(revs->graph); - if (show_timestamp) + if (info->show_timestamp) printf("%lu ", commit->date); - if (header_prefix) - fputs(header_prefix, stdout); + if (info->header_prefix) + fputs(info->header_prefix, stdout); - if (!revs.graph) { + if (!revs->graph) { if (commit->object.flags & BOUNDARY) putchar('-'); else if (commit->object.flags & UNINTERESTING) putchar('^'); - else if (revs.left_right) { + else if (revs->left_right) { if (commit->object.flags & SYMMETRIC_LEFT) putchar('<'); else putchar('>'); } } - if (revs.abbrev_commit && revs.abbrev) - fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev), + if (revs->abbrev_commit && revs->abbrev) + fputs(find_unique_abbrev(commit->object.sha1, revs->abbrev), stdout); else fputs(sha1_to_hex(commit->object.sha1), stdout); - if (revs.print_parents) { + if (revs->print_parents) { struct commit_list *parents = commit->parents; while (parents) { printf(" %s", sha1_to_hex(parents->item->object.sha1)); parents = parents->next; } } - if (revs.children.name) { + if (revs->children.name) { struct commit_list *children; - children = lookup_decoration(&revs.children, &commit->object); + children = lookup_decoration(&revs->children, &commit->object); while (children) { printf(" %s", sha1_to_hex(children->item->object.sha1)); children = children->next; } } - show_decorations(&revs, commit); - if (revs.commit_format == CMIT_FMT_ONELINE) + show_decorations(revs, commit); + if (revs->commit_format == CMIT_FMT_ONELINE) putchar(' '); else putchar('\n'); - if (revs.verbose_header && commit->buffer) { + if (revs->verbose_header && commit->buffer) { struct strbuf buf = STRBUF_INIT; - pretty_print_commit(revs.commit_format, commit, - &buf, revs.abbrev, NULL, NULL, - revs.date_mode, 0); - if (revs.graph) { + pretty_print_commit(revs->commit_format, commit, + &buf, revs->abbrev, NULL, NULL, + revs->date_mode, 0); + if (revs->graph) { if (buf.len) { - if (revs.commit_format != CMIT_FMT_ONELINE) - graph_show_oneline(revs.graph); + if (revs->commit_format != CMIT_FMT_ONELINE) + graph_show_oneline(revs->graph); - graph_show_commit_msg(revs.graph, &buf); + graph_show_commit_msg(revs->graph, &buf); /* * Add a newline after the commit message. @@ -134,7 +122,7 @@ static void show_commit(struct commit *commit) * format doesn't explicitly end in a newline.) */ if (buf.len && buf.buf[buf.len - 1] == '\n') - graph_show_padding(revs.graph); + graph_show_padding(revs->graph); putchar('\n'); } else { /* @@ -142,23 +130,23 @@ static void show_commit(struct commit *commit) * the rest of the graph output for this * commit. */ - if (graph_show_remainder(revs.graph)) + if (graph_show_remainder(revs->graph)) putchar('\n'); } } else { if (buf.len) - printf("%s%c", buf.buf, hdr_termination); + printf("%s%c", buf.buf, info->hdr_termination); } strbuf_release(&buf); } else { - if (graph_show_remainder(revs.graph)) + if (graph_show_remainder(revs->graph)) putchar('\n'); } maybe_flush_or_die(stdout, "stdout"); - finish_commit(commit); + finish_commit(commit, data); } -static void finish_commit(struct commit *commit) +static void finish_commit(struct commit *commit, void *data) { if (commit->parents) { free_commit_list(commit->parents); @@ -168,27 +156,29 @@ static void finish_commit(struct commit *commit) commit->buffer = NULL; } -static void finish_object(struct object_array_entry *p) +static void finish_object(struct object *obj, const struct name_path *path, const char *name) { - if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1)) - die("missing blob object '%s'", sha1_to_hex(p->item->sha1)); + if (obj->type == OBJ_BLOB && !has_sha1_file(obj->sha1)) + die("missing blob object '%s'", sha1_to_hex(obj->sha1)); } -static void show_object(struct object_array_entry *p) +static void show_object(struct object *obj, const struct name_path *path, const char *component) { + char *name = path_name(path, component); /* An object with name "foo\n0000000..." can be used to * confuse downstream "git pack-objects" very badly. */ - const char *ep = strchr(p->name, '\n'); + const char *ep = strchr(name, '\n'); - finish_object(p); + finish_object(obj, path, name); if (ep) { - printf("%s %.*s\n", sha1_to_hex(p->item->sha1), - (int) (ep - p->name), - p->name); + printf("%s %.*s\n", sha1_to_hex(obj->sha1), + (int) (ep - name), + name); } else - printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name); + printf("%s %s\n", sha1_to_hex(obj->sha1), name); + free(name); } static void show_edge(struct commit *commit) @@ -196,384 +186,6 @@ static void show_edge(struct commit *commit) printf("-%s\n", sha1_to_hex(commit->object.sha1)); } -/* - * This is a truly stupid algorithm, but it's only - * used for bisection, and we just don't care enough. - * - * We care just barely enough to avoid recursing for - * non-merge entries. - */ -static int count_distance(struct commit_list *entry) -{ - int nr = 0; - - while (entry) { - struct commit *commit = entry->item; - struct commit_list *p; - - if (commit->object.flags & (UNINTERESTING | COUNTED)) - break; - if (!(commit->object.flags & TREESAME)) - nr++; - commit->object.flags |= COUNTED; - p = commit->parents; - entry = p; - if (p) { - p = p->next; - while (p) { - nr += count_distance(p); - p = p->next; - } - } - } - - return nr; -} - -static void clear_distance(struct commit_list *list) -{ - while (list) { - struct commit *commit = list->item; - commit->object.flags &= ~COUNTED; - list = list->next; - } -} - -#define DEBUG_BISECT 0 - -static inline int weight(struct commit_list *elem) -{ - return *((int*)(elem->item->util)); -} - -static inline void weight_set(struct commit_list *elem, int weight) -{ - *((int*)(elem->item->util)) = weight; -} - -static int count_interesting_parents(struct commit *commit) -{ - struct commit_list *p; - int count; - - for (count = 0, p = commit->parents; p; p = p->next) { - if (p->item->object.flags & UNINTERESTING) - continue; - count++; - } - return count; -} - -static inline int halfway(struct commit_list *p, int nr) -{ - /* - * Don't short-cut something we are not going to return! - */ - if (p->item->object.flags & TREESAME) - return 0; - if (DEBUG_BISECT) - return 0; - /* - * 2 and 3 are halfway of 5. - * 3 is halfway of 6 but 2 and 4 are not. - */ - switch (2 * weight(p) - nr) { - case -1: case 0: case 1: - return 1; - default: - return 0; - } -} - -#if !DEBUG_BISECT -#define show_list(a,b,c,d) do { ; } while (0) -#else -static void show_list(const char *debug, int counted, int nr, - struct commit_list *list) -{ - struct commit_list *p; - - fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr); - - for (p = list; p; p = p->next) { - struct commit_list *pp; - struct commit *commit = p->item; - unsigned flags = commit->object.flags; - enum object_type type; - unsigned long size; - char *buf = read_sha1_file(commit->object.sha1, &type, &size); - char *ep, *sp; - - fprintf(stderr, "%c%c%c ", - (flags & TREESAME) ? ' ' : 'T', - (flags & UNINTERESTING) ? 'U' : ' ', - (flags & COUNTED) ? 'C' : ' '); - if (commit->util) - fprintf(stderr, "%3d", weight(p)); - else - fprintf(stderr, "---"); - fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1)); - for (pp = commit->parents; pp; pp = pp->next) - fprintf(stderr, " %.*s", 8, - sha1_to_hex(pp->item->object.sha1)); - - sp = strstr(buf, "\n\n"); - if (sp) { - sp += 2; - for (ep = sp; *ep && *ep != '\n'; ep++) - ; - fprintf(stderr, " %.*s", (int)(ep - sp), sp); - } - fprintf(stderr, "\n"); - } -} -#endif /* DEBUG_BISECT */ - -static struct commit_list *best_bisection(struct commit_list *list, int nr) -{ - struct commit_list *p, *best; - int best_distance = -1; - - best = list; - for (p = list; p; p = p->next) { - int distance; - unsigned flags = p->item->object.flags; - - if (flags & TREESAME) - continue; - distance = weight(p); - if (nr - distance < distance) - distance = nr - distance; - if (distance > best_distance) { - best = p; - best_distance = distance; - } - } - - return best; -} - -struct commit_dist { - struct commit *commit; - int distance; -}; - -static int compare_commit_dist(const void *a_, const void *b_) -{ - struct commit_dist *a, *b; - - a = (struct commit_dist *)a_; - b = (struct commit_dist *)b_; - if (a->distance != b->distance) - return b->distance - a->distance; /* desc sort */ - return hashcmp(a->commit->object.sha1, b->commit->object.sha1); -} - -static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr) -{ - struct commit_list *p; - struct commit_dist *array = xcalloc(nr, sizeof(*array)); - int cnt, i; - - for (p = list, cnt = 0; p; p = p->next) { - int distance; - unsigned flags = p->item->object.flags; - - if (flags & TREESAME) - continue; - distance = weight(p); - if (nr - distance < distance) - distance = nr - distance; - array[cnt].commit = p->item; - array[cnt].distance = distance; - cnt++; - } - qsort(array, cnt, sizeof(*array), compare_commit_dist); - for (p = list, i = 0; i < cnt; i++) { - struct name_decoration *r = xmalloc(sizeof(*r) + 100); - struct object *obj = &(array[i].commit->object); - - sprintf(r->name, "dist=%d", array[i].distance); - r->next = add_decoration(&name_decoration, obj, r); - p->item = array[i].commit; - p = p->next; - } - if (p) - p->next = NULL; - free(array); - return list; -} - -/* - * zero or positive weight is the number of interesting commits it can - * reach, including itself. Especially, weight = 0 means it does not - * reach any tree-changing commits (e.g. just above uninteresting one - * but traversal is with pathspec). - * - * weight = -1 means it has one parent and its distance is yet to - * be computed. - * - * weight = -2 means it has more than one parent and its distance is - * unknown. After running count_distance() first, they will get zero - * or positive distance. - */ -static struct commit_list *do_find_bisection(struct commit_list *list, - int nr, int *weights, - int find_all) -{ - int n, counted; - struct commit_list *p; - - counted = 0; - - for (n = 0, p = list; p; p = p->next) { - struct commit *commit = p->item; - unsigned flags = commit->object.flags; - - p->item->util = &weights[n++]; - switch (count_interesting_parents(commit)) { - case 0: - if (!(flags & TREESAME)) { - weight_set(p, 1); - counted++; - show_list("bisection 2 count one", - counted, nr, list); - } - /* - * otherwise, it is known not to reach any - * tree-changing commit and gets weight 0. - */ - break; - case 1: - weight_set(p, -1); - break; - default: - weight_set(p, -2); - break; - } - } - - show_list("bisection 2 initialize", counted, nr, list); - - /* - * If you have only one parent in the resulting set - * then you can reach one commit more than that parent - * can reach. So we do not have to run the expensive - * count_distance() for single strand of pearls. - * - * However, if you have more than one parents, you cannot - * just add their distance and one for yourself, since - * they usually reach the same ancestor and you would - * end up counting them twice that way. - * - * So we will first count distance of merges the usual - * way, and then fill the blanks using cheaper algorithm. - */ - for (p = list; p; p = p->next) { - if (p->item->object.flags & UNINTERESTING) - continue; - if (weight(p) != -2) - continue; - weight_set(p, count_distance(p)); - clear_distance(list); - - /* Does it happen to be at exactly half-way? */ - if (!find_all && halfway(p, nr)) - return p; - counted++; - } - - show_list("bisection 2 count_distance", counted, nr, list); - - while (counted < nr) { - for (p = list; p; p = p->next) { - struct commit_list *q; - unsigned flags = p->item->object.flags; - - if (0 <= weight(p)) - continue; - for (q = p->item->parents; q; q = q->next) { - if (q->item->object.flags & UNINTERESTING) - continue; - if (0 <= weight(q)) - break; - } - if (!q) - continue; - - /* - * weight for p is unknown but q is known. - * add one for p itself if p is to be counted, - * otherwise inherit it from q directly. - */ - if (!(flags & TREESAME)) { - weight_set(p, weight(q)+1); - counted++; - show_list("bisection 2 count one", - counted, nr, list); - } - else - weight_set(p, weight(q)); - - /* Does it happen to be at exactly half-way? */ - if (!find_all && halfway(p, nr)) - return p; - } - } - - show_list("bisection 2 counted all", counted, nr, list); - - if (!find_all) - return best_bisection(list, nr); - else - return best_bisection_sorted(list, nr); -} - -static struct commit_list *find_bisection(struct commit_list *list, - int *reaches, int *all, - int find_all) -{ - int nr, on_list; - struct commit_list *p, *best, *next, *last; - int *weights; - - show_list("bisection 2 entry", 0, 0, list); - - /* - * Count the number of total and tree-changing items on the - * list, while reversing the list. - */ - for (nr = on_list = 0, last = NULL, p = list; - p; - p = next) { - unsigned flags = p->item->object.flags; - - next = p->next; - if (flags & UNINTERESTING) - continue; - p->next = last; - last = p; - if (!(flags & TREESAME)) - nr++; - on_list++; - } - list = last; - show_list("bisection 2 sorted", 0, nr, list); - - *all = nr; - weights = xcalloc(on_list, sizeof(*weights)); - - /* Do the real work of finding bisection commit. */ - best = do_find_bisection(list, nr, weights, find_all); - if (best) { - if (!find_all) - best->next = NULL; - *reaches = weight(best); - } - free(weights); - return best; -} - static inline int log2i(int n) { int log2 = 0; @@ -613,11 +225,83 @@ static int estimate_bisect_steps(int all) return (e < 3 * x) ? n : n - 1; } +static void show_tried_revs(struct commit_list *tried, int stringed) +{ + printf("bisect_tried='"); + for (;tried; tried = tried->next) { + char *format = tried->next ? "%s|" : "%s"; + printf(format, sha1_to_hex(tried->item->object.sha1)); + } + printf(stringed ? "' &&\n" : "'\n"); +} + +int show_bisect_vars(struct rev_list_info *info, int reaches, int all) +{ + int cnt, flags = info->bisect_show_flags; + char hex[41] = "", *format; + struct commit_list *tried; + struct rev_info *revs = info->revs; + + if (!revs->commits && !(flags & BISECT_SHOW_TRIED)) + return 1; + + revs->commits = filter_skipped(revs->commits, &tried, flags & BISECT_SHOW_ALL); + + /* + * revs->commits can reach "reaches" commits among + * "all" commits. If it is good, then there are + * (all-reaches) commits left to be bisected. + * On the other hand, if it is bad, then the set + * to bisect is "reaches". + * A bisect set of size N has (N-1) commits further + * to test, as we already know one bad one. + */ + cnt = all - reaches; + if (cnt < reaches) + cnt = reaches; + + if (revs->commits) + strcpy(hex, sha1_to_hex(revs->commits->item->object.sha1)); + + if (flags & BISECT_SHOW_ALL) { + traverse_commit_list(revs, show_commit, show_object, info); + printf("------\n"); + } + + if (flags & BISECT_SHOW_TRIED) + show_tried_revs(tried, flags & BISECT_SHOW_STRINGED); + format = (flags & BISECT_SHOW_STRINGED) ? + "bisect_rev=%s &&\n" + "bisect_nr=%d &&\n" + "bisect_good=%d &&\n" + "bisect_bad=%d &&\n" + "bisect_all=%d &&\n" + "bisect_steps=%d\n" + : + "bisect_rev=%s\n" + "bisect_nr=%d\n" + "bisect_good=%d\n" + "bisect_bad=%d\n" + "bisect_all=%d\n" + "bisect_steps=%d\n"; + printf(format, + hex, + cnt - 1, + all - reaches - 1, + reaches - 1, + all, + estimate_bisect_steps(all)); + + return 0; +} + int cmd_rev_list(int argc, const char **argv, const char *prefix) { - struct commit_list *list; + struct rev_info revs; + struct rev_list_info info; int i; int read_from_stdin = 0; + int bisect_list = 0; int bisect_show_vars = 0; int bisect_find_all = 0; int quiet = 0; @@ -628,6 +312,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.commit_format = CMIT_FMT_UNSPECIFIED; argc = setup_revisions(argc, argv, &revs, NULL); + memset(&info, 0, sizeof(info)); + info.revs = &revs; + quiet = DIFF_OPT_TST(&revs.diffopt, QUIET); for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; @@ -637,7 +324,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--timestamp")) { - show_timestamp = 1; + info.show_timestamp = 1; continue; } if (!strcmp(arg, "--bisect")) { @@ -647,6 +334,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (!strcmp(arg, "--bisect-all")) { bisect_list = 1; bisect_find_all = 1; + info.bisect_show_flags = BISECT_SHOW_ALL; revs.show_decorations = 1; continue; } @@ -666,19 +354,17 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) } if (revs.commit_format != CMIT_FMT_UNSPECIFIED) { /* The command line has a --pretty */ - hdr_termination = '\n'; + info.hdr_termination = '\n'; if (revs.commit_format == CMIT_FMT_ONELINE) - header_prefix = ""; + info.header_prefix = ""; else - header_prefix = "commit "; + info.header_prefix = "commit "; } else if (revs.verbose_header) /* Only --header was specified */ revs.commit_format = CMIT_FMT_RAW; - list = revs.commits; - - if ((!list && + if ((!revs.commits && (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending.nr)) || revs.diff) @@ -699,49 +385,15 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.commits = find_bisection(revs.commits, &reaches, &all, bisect_find_all); - if (bisect_show_vars) { - int cnt; - char hex[41]; - if (!revs.commits) - return 1; - /* - * revs.commits can reach "reaches" commits among - * "all" commits. If it is good, then there are - * (all-reaches) commits left to be bisected. - * On the other hand, if it is bad, then the set - * to bisect is "reaches". - * A bisect set of size N has (N-1) commits further - * to test, as we already know one bad one. - */ - cnt = all - reaches; - if (cnt < reaches) - cnt = reaches; - strcpy(hex, sha1_to_hex(revs.commits->item->object.sha1)); - - if (bisect_find_all) { - traverse_commit_list(&revs, show_commit, show_object); - printf("------\n"); - } - printf("bisect_rev=%s\n" - "bisect_nr=%d\n" - "bisect_good=%d\n" - "bisect_bad=%d\n" - "bisect_all=%d\n" - "bisect_steps=%d\n", - hex, - cnt - 1, - all - reaches - 1, - reaches - 1, - all, - estimate_bisect_steps(all)); - return 0; - } + if (bisect_show_vars) + return show_bisect_vars(&info, reaches, all); } traverse_commit_list(&revs, - quiet ? finish_commit : show_commit, - quiet ? finish_object : show_object); + quiet ? finish_commit : show_commit, + quiet ? finish_object : show_object, + &info); return 0; } diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 81d5a6ffc9..22c6d6ad16 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -26,6 +26,8 @@ static int show_type = NORMAL; #define SHOW_SYMBOLIC_FULL 2 static int symbolic; static int abbrev; +static int abbrev_ref; +static int abbrev_ref_strict; static int output_sq; /* @@ -109,8 +111,8 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) return; def = NULL; - if (symbolic && name) { - if (symbolic == SHOW_SYMBOLIC_FULL) { + if ((symbolic || abbrev_ref) && name) { + if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) { unsigned char discard[20]; char *full; @@ -125,6 +127,9 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) */ break; case 1: /* happy */ + if (abbrev_ref) + full = shorten_unambiguous_ref(full, + abbrev_ref_strict); show_with_type(type, full); break; default: /* ambiguous */ @@ -506,6 +511,20 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) symbolic = SHOW_SYMBOLIC_FULL; continue; } + if (!prefixcmp(arg, "--abbrev-ref") && + (!arg[12] || arg[12] == '=')) { + abbrev_ref = 1; + abbrev_ref_strict = warn_ambiguous_refs; + if (arg[12] == '=') { + if (!strcmp(arg + 13, "strict")) + abbrev_ref_strict = 1; + else if (!strcmp(arg + 13, "loose")) + abbrev_ref_strict = 0; + else + die("unknown mode for %s", arg); + } + continue; + } if (!strcmp(arg, "--all")) { for_each_ref(show_reference, NULL); continue; diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 828e6f86de..c8e9b3c723 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -2,12 +2,25 @@ #include "commit.h" #include "refs.h" #include "builtin.h" +#include "color.h" static const char show_branch_usage[] = "git show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n[,b]] <branch>"; static const char show_branch_usage_reflog[] = "--reflog is incompatible with --all, --remotes, --independent or --merge-base"; +static int showbranch_use_color = -1; +static char column_colors[][COLOR_MAXLEN] = { + GIT_COLOR_RED, + GIT_COLOR_GREEN, + GIT_COLOR_YELLOW, + GIT_COLOR_BLUE, + GIT_COLOR_MAGENTA, + GIT_COLOR_CYAN, +}; + +#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors)) + static int default_num; static int default_alloc; static const char **default_arg; @@ -19,6 +32,20 @@ static const char **default_arg; #define DEFAULT_REFLOG 4 +static const char *get_color_code(int idx) +{ + if (showbranch_use_color) + return column_colors[idx]; + return ""; +} + +static const char *get_color_reset_code(void) +{ + if (showbranch_use_color) + return GIT_COLOR_RESET; + return ""; +} + static struct commit *interesting(struct commit_list *list) { while (list) { @@ -545,7 +572,12 @@ static int git_show_branch_config(const char *var, const char *value, void *cb) return 0; } - return git_default_config(var, value, cb); + if (!strcmp(var, "color.showbranch")) { + showbranch_use_color = git_config_colorbool(var, value, -1); + return 0; + } + + return git_color_default_config(var, value, cb); } static int omit_in_dense(struct commit *commit, struct commit **rev, int n) @@ -576,7 +608,7 @@ static void parse_reflog_param(const char *arg, int *cnt, const char **base) if (*ep == ',') *base = ep + 1; else if (*ep) - die("unrecognized reflog param '%s'", arg + 9); + die("unrecognized reflog param '%s'", arg); else *base = NULL; if (*cnt <= 0) @@ -611,6 +643,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) git_config(git_show_branch_config, NULL); + if (showbranch_use_color == -1) + showbranch_use_color = git_use_color_default; + /* If nothing is specified, try the default first */ if (ac == 1 && default_num) { ac = default_num + 1; @@ -658,6 +693,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) parse_reflog_param(arg + 9, &reflog, &reflog_base); else if (!prefixcmp(arg, "-g=")) parse_reflog_param(arg + 3, &reflog, &reflog_base); + else if (!strcmp(arg, "--color")) + showbranch_use_color = 1; + else if (!strcmp(arg, "--no-color")) + showbranch_use_color = 0; else usage(show_branch_usage); ac--; av++; @@ -843,8 +882,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) else { for (j = 0; j < i; j++) putchar(' '); - printf("%c [%s] ", - is_head ? '*' : '!', ref_name[i]); + printf("%s%c%s [%s] ", + get_color_code(i % COLUMN_COLORS_MAX), + is_head ? '*' : '!', + get_color_reset_code(), ref_name[i]); } if (!reflog) { @@ -903,7 +944,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) mark = '*'; else mark = '+'; - putchar(mark); + printf("%s%c%s", + get_color_code(i % COLUMN_COLORS_MAX), + mark, get_color_reset_code()); } putchar(' '); } diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index 0713bca778..f88e721936 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -24,7 +24,7 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix) * git archive --format-tar --prefix=basedir tree-ish */ int i; - const char **nargv = xcalloc(sizeof(*nargv), argc + 2); + const char **nargv = xcalloc(sizeof(*nargv), argc + 3); char *basedir_arg; int nargc = 0; @@ -36,6 +36,13 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix) argv++; argc--; } + + /* + * Because it's just a compatibility wrapper, tar-tree supports only + * the old behaviour of reading attributes from the work tree. + */ + nargv[nargc++] = "--worktree-attributes"; + switch (argc) { default: usage(tar_tree_usage); diff --git a/builtin-update-index.c b/builtin-update-index.c index 1fde893cfa..92beaaf4b3 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -292,7 +292,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length) report("add '%s'", path); free_return: if (p < path || p > path + strlen(path)) - free((char*)p); + free((char *)p); } static void read_index_info(int line_termination) @@ -509,7 +509,7 @@ static int do_unresolve(int ac, const char **av, const char *p = prefix_path(prefix, prefix_length, arg); err |= unresolve_one(p); if (p < arg || p > arg + strlen(arg)) - free((char*)p); + free((char *)p); } return err; } @@ -712,7 +712,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (set_executable_bit) chmod_path(set_executable_bit, p); if (p < path || p > path + strlen(path)) - free((char*)p); + free((char *)p); } if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; @@ -25,6 +25,7 @@ extern int cmd_add(int argc, const char **argv, const char *prefix); extern int cmd_annotate(int argc, const char **argv, const char *prefix); extern int cmd_apply(int argc, const char **argv, const char *prefix); extern int cmd_archive(int argc, const char **argv, const char *prefix); +extern int cmd_bisect__helper(int argc, const char **argv, const char *prefix); extern int cmd_blame(int argc, const char **argv, const char *prefix); extern int cmd_branch(int argc, const char **argv, const char *prefix); extern int cmd_bundle(int argc, const char **argv, const char *prefix); diff --git a/cache-tree.c b/cache-tree.c index 3d8f218a5f..37bf35e636 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -1,5 +1,6 @@ #include "cache.h" #include "tree.h" +#include "tree-walk.h" #include "cache-tree.h" #ifndef DEBUG @@ -591,3 +592,36 @@ int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix) return 0; } + +static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) +{ + struct tree_desc desc; + struct name_entry entry; + int cnt; + + hashcpy(it->sha1, tree->object.sha1); + init_tree_desc(&desc, tree->buffer, tree->size); + cnt = 0; + while (tree_entry(&desc, &entry)) { + if (!S_ISDIR(entry.mode)) + cnt++; + else { + struct cache_tree_sub *sub; + struct tree *subtree = lookup_tree(entry.sha1); + if (!subtree->object.parsed) + parse_tree(subtree); + sub = cache_tree_sub(it, entry.path); + sub->cache_tree = cache_tree(); + prime_cache_tree_rec(sub->cache_tree, subtree); + cnt += sub->cache_tree->entry_count; + } + } + it->entry_count = cnt; +} + +void prime_cache_tree(struct cache_tree **it, struct tree *tree) +{ + cache_tree_free(it); + *it = cache_tree(); + prime_cache_tree_rec(*it, tree); +} diff --git a/cache-tree.h b/cache-tree.h index cf8b790874..e958835236 100644 --- a/cache-tree.h +++ b/cache-tree.h @@ -1,6 +1,8 @@ #ifndef CACHE_TREE_H #define CACHE_TREE_H +#include "tree.h" + struct cache_tree; struct cache_tree_sub { struct cache_tree *cache_tree; @@ -33,4 +35,6 @@ int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int) #define WRITE_TREE_PREFIX_ERROR (-3) int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix); +void prime_cache_tree(struct cache_tree **, struct tree *); + #endif @@ -554,6 +554,13 @@ extern enum branch_track git_branch_track; extern enum rebase_setup_type autorebase; extern enum push_default_type push_default; +enum object_creation_mode { + OBJECT_CREATION_USES_HARDLINKS = 0, + OBJECT_CREATION_USES_RENAMES = 1, +}; + +extern enum object_creation_mode object_creation_mode; + #define GIT_REPO_VERSION 0 extern int repository_format_version; extern int check_repository_format(void); @@ -839,7 +846,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1, extern void pack_report(void); extern int open_pack_index(struct packed_git *); -extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); +extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); extern void close_pack_windows(struct packed_git *); extern void unuse_pack(struct pack_window **); extern void free_pack_by_name(const char *); @@ -11,6 +11,7 @@ #define GIT_COLOR_GREEN "\033[32m" #define GIT_COLOR_YELLOW "\033[33m" #define GIT_COLOR_BLUE "\033[34m" +#define GIT_COLOR_MAGENTA "\033[35m" #define GIT_COLOR_CYAN "\033[36m" #define GIT_COLOR_BG_RED "\033[41m" diff --git a/combine-diff.c b/combine-diff.c index 066ce841ed..60d03676bb 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -6,6 +6,7 @@ #include "quote.h" #include "xdiff-interface.h" #include "log-tree.h" +#include "refs.h" static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent) { @@ -23,7 +24,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, path = q->queue[i]->two->path; len = strlen(path); p = xmalloc(combine_diff_path_size(num_parent, len)); - p->path = (char*) &(p->parent[num_parent]); + p->path = (char *) &(p->parent[num_parent]); memcpy(p->path, path, len); p->path[len] = 0; p->len = len; @@ -90,18 +91,24 @@ struct sline { unsigned long *p_lno; }; -static char *grab_blob(const unsigned char *sha1, unsigned long *size) +static char *grab_blob(const unsigned char *sha1, unsigned int mode, unsigned long *size) { char *blob; enum object_type type; - if (is_null_sha1(sha1)) { + + if (S_ISGITLINK(mode)) { + blob = xmalloc(100); + *size = snprintf(blob, 100, + "Subproject commit %s\n", sha1_to_hex(sha1)); + } else if (is_null_sha1(sha1)) { /* deleted blob */ *size = 0; return xcalloc(1, 1); + } else { + blob = read_sha1_file(sha1, &type, size); + if (type != OBJ_BLOB) + die("object '%s' is not a blob!", sha1_to_hex(sha1)); } - blob = read_sha1_file(sha1, &type, size); - if (type != OBJ_BLOB) - die("object '%s' is not a blob!", sha1_to_hex(sha1)); return blob; } @@ -195,7 +202,8 @@ static void consume_line(void *state_, char *line, unsigned long len) } } -static void combine_diff(const unsigned char *parent, mmfile_t *result_file, +static void combine_diff(const unsigned char *parent, unsigned int mode, + mmfile_t *result_file, struct sline *sline, unsigned int cnt, int n, int num_parent) { @@ -211,7 +219,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file, if (!cnt) return; /* result deleted */ - parent_file.ptr = grab_blob(parent, &sz); + parent_file.ptr = grab_blob(parent, mode, &sz); parent_file.size = sz; memset(&xpp, 0, sizeof(xpp)); xpp.flags = XDF_NEED_MINIMAL; @@ -692,7 +700,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, /* Read the result of merge first */ if (!working_tree_file) - result = grab_blob(elem->sha1, &result_size); + result = grab_blob(elem->sha1, elem->mode, &result_size); else { /* Used by diff-tree to read from the working tree */ struct stat st; @@ -712,6 +720,12 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, result_size = buf.len; result = strbuf_detach(&buf, NULL); elem->mode = canon_mode(st.st_mode); + } else if (S_ISDIR(st.st_mode)) { + unsigned char sha1[20]; + if (resolve_gitlink_ref(elem->path, "HEAD", sha1) < 0) + result = grab_blob(elem->sha1, elem->mode, &result_size); + else + result = grab_blob(sha1, elem->mode, &result_size); } else if (0 <= (fd = open(elem->path, O_RDONLY))) { size_t len = xsize_t(st.st_size); ssize_t done; @@ -804,7 +818,9 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, } } if (i <= j) - combine_diff(elem->parent[i].sha1, &result_file, sline, + combine_diff(elem->parent[i].sha1, + elem->parent[i].mode, + &result_file, sline, cnt, i, num_parent); if (elem->parent[i].mode != elem->mode) mode_differs = 1; @@ -1047,7 +1063,7 @@ void diff_tree_combined_merge(const unsigned char *sha1, for (parents = commit->parents, num_parent = 0; parents; parents = parents->next, num_parent++) - hashcpy((unsigned char*)(parent + num_parent), + hashcpy((unsigned char *)(parent + num_parent), parents->item->object.sha1); diff_tree_combined(sha1, parent, num_parent, dense, rev); } diff --git a/command-list.txt b/command-list.txt index 3583a33ee9..fb03a2ebb5 100644 --- a/command-list.txt +++ b/command-list.txt @@ -33,6 +33,7 @@ git-diff mainporcelain common git-diff-files plumbinginterrogators git-diff-index plumbinginterrogators git-diff-tree plumbinginterrogators +git-difftool ancillaryinterrogators git-fast-export ancillarymanipulators git-fast-import ancillarymanipulators git-fetch mainporcelain common diff --git a/compat/cygwin.c b/compat/cygwin.c index ebac148392..b4a51b958c 100644 --- a/compat/cygwin.c +++ b/compat/cygwin.c @@ -89,10 +89,10 @@ static int cygwin_stat(const char *path, struct stat *buf) /* * At start up, we are trying to determine whether Win32 API or cygwin stat * functions should be used. The choice is determined by core.ignorecygwinfstricks. - * Reading this option is not always possible immediately as git_dir may be + * Reading this option is not always possible immediately as git_dir may * not be set yet. So until it is set, use cygwin lstat/stat functions. * However, if core.filemode is set, we must use the Cygwin posix - * stat/lstat as the Windows stat fuctions do not determine posix filemode. + * stat/lstat as the Windows stat functions do not determine posix filemode. * * Note that git_cygwin_config() does NOT call git_default_config() and this * is deliberate. Many commands read from config to establish initial diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 1f4ead5f98..14feac7fe1 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -39,7 +39,7 @@ # include <stdlib.h> #endif -/* For platform which support the ISO C amendement 1 functionality we +/* For platforms which support the ISO C amendment 1 functionality we support user defined character classes. */ #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ @@ -90,7 +90,7 @@ # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) /* The GNU C library provides support for user-defined character classes - and the functions from ISO C amendement 1. */ + and the functions from ISO C amendment 1. */ # ifdef CHARCLASS_NAME_MAX # define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX # else diff --git a/compat/mingw.c b/compat/mingw.c index 2839d9df6e..cdeda1d985 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -396,7 +396,7 @@ repeat: * its own input data to become available. But since * the process (pack-objects) is itself CPU intensive, * it will happily pick up the time slice that we are - * relinguishing here. + * relinquishing here. */ Sleep(0); goto repeat; @@ -562,7 +562,7 @@ static char **get_path_split(void) if (!n) return NULL; - path = xmalloc((n+1)*sizeof(char*)); + path = xmalloc((n+1)*sizeof(char *)); p = envpath; i = 0; do { @@ -934,7 +934,9 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) #undef rename int mingw_rename(const char *pold, const char *pnew) { - DWORD attrs; + DWORD attrs, gle; + int tries = 0; + static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. @@ -944,10 +946,12 @@ int mingw_rename(const char *pold, const char *pnew) return 0; if (errno != EEXIST) return -1; +repeat: if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ - if (GetLastError() == ERROR_ACCESS_DENIED && + gle = GetLastError(); + if (gle == ERROR_ACCESS_DENIED && (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; @@ -957,10 +961,23 @@ int mingw_rename(const char *pold, const char *pnew) SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; + gle = GetLastError(); /* revert file attributes on failure */ SetFileAttributes(pnew, attrs); } } + if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) { + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + goto repeat; + } errno = EACCES; return -1; } diff --git a/compat/regex/regex.c b/compat/regex/regex.c index 87b33e4669..5ea007567d 100644 --- a/compat/regex/regex.c +++ b/compat/regex/regex.c @@ -1043,7 +1043,7 @@ regex_compile (pattern, size, syntax, bufp) they can be reliably used as array indices. */ register unsigned char c, c1; - /* A random tempory spot in PATTERN. */ + /* A random temporary spot in PATTERN. */ const char *p1; /* Points to the end of the buffer, where we should append. */ @@ -1796,7 +1796,7 @@ regex_compile (pattern, size, syntax, bufp) we're all done, the pattern will look like: set_number_at <jump count> <upper bound> set_number_at <succeed_n count> <lower bound> - succeed_n <after jump addr> <succed_n count> + succeed_n <after jump addr> <succeed_n count> <body of loop> jump_n <succeed_n addr> <jump count> (The upper bound and `jump_n' are omitted if @@ -51,7 +51,7 @@ static char *parse_value(void) for (;;) { int c = get_next_char(); - if (len >= sizeof(value)) + if (len >= sizeof(value) - 1) return NULL; if (c == '\n') { if (quote) @@ -331,9 +331,9 @@ int git_config_bool_or_int(const char *name, const char *value, int *is_bool) return 1; if (!*value) return 0; - if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) + if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) return 1; - if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) + if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) return 0; *is_bool = 0; return git_config_int(name, value); @@ -495,6 +495,16 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.createobject")) { + if (!strcmp(value, "rename")) + object_creation_mode = OBJECT_CREATION_USES_RENAMES; + else if (!strcmp(value, "link")) + object_creation_mode = OBJECT_CREATION_USES_HARDLINKS; + else + die("Invalid mode for object creation: %s", value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } @@ -714,16 +724,16 @@ int git_config(config_fn_t fn, void *data) static struct { int baselen; - char* key; + char *key; int do_not_match; - regex_t* value_regex; + regex_t *value_regex; int multi_replace; size_t offset[MAX_MATCHES]; enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; int seen; } store; -static int matches(const char* key, const char* value) +static int matches(const char *key, const char *value) { return !strcmp(key, store.key) && (store.value_regex == NULL || @@ -731,7 +741,7 @@ static int matches(const char* key, const char* value) !regexec(store.value_regex, value, 0, NULL, 0))); } -static int store_aux(const char* key, const char* value, void *cb) +static int store_aux(const char *key, const char *value, void *cb) { const char *ep; size_t section_len; @@ -800,7 +810,7 @@ static int write_error(const char *filename) return 4; } -static int store_write_section(int fd, const char* key) +static int store_write_section(int fd, const char *key) { const char *dot; int i, success; @@ -825,7 +835,7 @@ static int store_write_section(int fd, const char* key) return success; } -static int store_write_pair(int fd, const char* key, const char* value) +static int store_write_pair(int fd, const char *key, const char *value) { int i, success; int length = strlen(key + store.baselen + 1); @@ -873,8 +883,8 @@ static int store_write_pair(int fd, const char* key, const char* value) return success; } -static ssize_t find_beginning_of_line(const char* contents, size_t size, - size_t offset_, int* found_bracket) +static ssize_t find_beginning_of_line(const char *contents, size_t size, + size_t offset_, int *found_bracket) { size_t equal_offset = size, bracket_offset = size; ssize_t offset; @@ -899,7 +909,7 @@ contline: return offset; } -int git_config_set(const char* key, const char* value) +int git_config_set(const char *key, const char *value) { return git_config_set_multivar(key, value, NULL, 0); } @@ -927,15 +937,15 @@ int git_config_set(const char* key, const char* value) * - the config file is removed and the lock file rename()d to it. * */ -int git_config_set_multivar(const char* key, const char* value, - const char* value_regex, int multi_replace) +int git_config_set_multivar(const char *key, const char *value, + const char *value_regex, int multi_replace) { int i, dot; int fd = -1, in_fd; int ret; - char* config_filename; + char *config_filename; struct lock_file *lock = NULL; - const char* last_dot = strrchr(key, '.'); + const char *last_dot = strrchr(key, '.'); if (config_exclusive_filename) config_filename = xstrdup(config_exclusive_filename); @@ -991,7 +1001,7 @@ int git_config_set_multivar(const char* key, const char* value, lock = xcalloc(sizeof(struct lock_file), 1); fd = hold_lock_file_for_update(lock, config_filename, 0); if (fd < 0) { - error("could not lock config file %s", config_filename); + error("could not lock config file %s: %s", config_filename, strerror(errno)); free(store.key); ret = -1; goto out_free; @@ -1016,13 +1026,13 @@ int git_config_set_multivar(const char* key, const char* value, goto out_free; } - store.key = (char*)key; + store.key = (char *)key; if (!store_write_section(fd, key) || !store_write_pair(fd, key, value)) goto write_err_out; } else { struct stat st; - char* contents; + char *contents; size_t contents_sz, copy_begin, copy_end; int i, new_line = 0; @@ -177,18 +177,11 @@ static enum protocol get_protocol(const char *name) static const char *ai_name(const struct addrinfo *ai) { - static char addr[INET_ADDRSTRLEN]; - if ( AF_INET == ai->ai_family ) { - struct sockaddr_in *in; - in = (struct sockaddr_in *)ai->ai_addr; - inet_ntop(ai->ai_family, &in->sin_addr, addr, sizeof(addr)); - } else if ( AF_INET6 == ai->ai_family ) { - struct sockaddr_in6 *in; - in = (struct sockaddr_in6 *)ai->ai_addr; - inet_ntop(ai->ai_family, &in->sin6_addr, addr, sizeof(addr)); - } else { + static char addr[NI_MAXHOST]; + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, sizeof(addr), NULL, 0, + NI_NUMERICHOST) != 0) strcpy(addr, "(unknown)"); - } + return addr; } diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index c1c879821d..ba13c4948c 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -99,20 +99,32 @@ __git_ps1 () elif [ -d "$g/rebase-merge" ]; then r="|REBASE-m" b="$(cat "$g/rebase-merge/head-name")" - elif [ -f "$g/MERGE_HEAD" ]; then - r="|MERGING" - b="$(git symbolic-ref HEAD 2>/dev/null)" else + if [ -f "$g/MERGE_HEAD" ]; then + r="|MERGING" + fi if [ -f "$g/BISECT_LOG" ]; then r="|BISECTING" fi - if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then - if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then - if [ -r "$g/HEAD" ]; then - b="$(cut -c1-7 "$g/HEAD")..." - fi - fi - fi + + b="$(git symbolic-ref HEAD 2>/dev/null)" || { + + b="$( + case "${GIT_PS1_DESCRIBE_STYLE-}" in + (contains) + git describe --contains HEAD ;; + (branch) + git describe --contains --all HEAD ;; + (describe) + git describe HEAD ;; + (* | default) + git describe --exact-match HEAD ;; + esac 2>/dev/null)" || + + b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." || + b="unknown" + b="($b)" + } fi local w @@ -910,6 +922,26 @@ _git_diff () __git_complete_file } +__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff + tkdiff vimdiff gvimdiff xxdiff +" + +_git_difftool () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --tool=*) + __gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}" + return + ;; + --*) + __gitcomp "--tool=" + return + ;; + esac + COMPREPLY=() +} + __git_fetch_options=" --quiet --verbose --append --upload-pack --force --keep --depth= --tags --no-tags @@ -1096,6 +1128,7 @@ __git_log_shortlog_options=" " __git_log_pretty_formats="oneline short medium full fuller email raw format:" +__git_log_date_formats="relative iso8601 rfc2822 short local default raw" _git_log () { @@ -1119,9 +1152,7 @@ _git_log () return ;; --date=*) - __gitcomp " - relative iso8601 rfc2822 short local default - " "" "${cur##--date=}" + __gitcomp "$__git_log_date_formats" "" "${cur##--date=}" return ;; --*) @@ -1172,10 +1203,7 @@ _git_mergetool () local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --tool=*) - __gitcomp " - kdiff3 tkdiff meld xxdiff emerge - vimdiff gvimdiff ecmerge opendiff - " "" "${cur##--tool=}" + __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}" return ;; --*) @@ -1266,18 +1294,39 @@ _git_rebase () __gitcomp "$(__git_refs)" } +__git_send_email_confirm_options="always never auto cc compose" +__git_send_email_suppresscc_options="author self cc ccbody sob cccmd body all" + _git_send_email () { local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in + --confirm=*) + __gitcomp " + $__git_send_email_confirm_options + " "" "${cur##--confirm=}" + return + ;; + --suppress-cc=*) + __gitcomp " + $__git_send_email_suppresscc_options + " "" "${cur##--suppress-cc=}" + + return + ;; + --smtp-encryption=*) + __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}" + return + ;; --*) __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to - --compose --dry-run --envelope-sender --from --identity + --compose --confirm= --dry-run --envelope-sender + --from --identity --in-reply-to --no-chain-reply-to --no-signed-off-by-cc --no-suppress-from --no-thread --quiet --signed-off-by-cc --smtp-pass --smtp-server - --smtp-server-port --smtp-ssl --smtp-user --subject - --suppress-cc --suppress-from --thread --to + --smtp-server-port --smtp-encryption= --smtp-user + --subject --suppress-cc= --suppress-from --thread --to --validate --no-validate" return ;; @@ -1285,6 +1334,35 @@ _git_send_email () COMPREPLY=() } +__git_config_get_set_variables () +{ + local prevword word config_file= c=$COMP_CWORD + while [ $c -gt 1 ]; do + word="${COMP_WORDS[c]}" + case "$word" in + --global|--system|--file=*) + config_file="$word" + break + ;; + -f|--file) + config_file="$word $prevword" + break + ;; + esac + prevword=$word + c=$((--c)) + done + + for i in $(git --git-dir="$(__gitdir)" config $config_file --list \ + 2>/dev/null); do + case "$i" in + *.*) + echo "${i/=*/}" + ;; + esac + done +} + _git_config () { local cur="${COMP_WORDS[COMP_CWORD]}" @@ -1316,7 +1394,8 @@ _git_config () __gitcomp "$(__git_merge_strategies)" return ;; - color.branch|color.diff|color.interactive|color.status|color.ui) + color.branch|color.diff|color.interactive|\ + color.showbranch|color.status|color.ui) __gitcomp "always never auto" return ;; @@ -1331,6 +1410,30 @@ _git_config () " return ;; + help.format) + __gitcomp "man info web html" + return + ;; + log.date) + __gitcomp "$__git_log_date_formats" + return + ;; + sendemail.aliasesfiletype) + __gitcomp "mutt mailrc pine elm gnus" + return + ;; + sendemail.confirm) + __gitcomp "$__git_send_email_confirm_options" + return + ;; + sendemail.suppresscc) + __gitcomp "$__git_send_email_suppresscc_options" + return + ;; + --get|--get-all|--unset|--unset-all) + __gitcomp "$(__git_config_get_set_variables)" + return + ;; *.*) COMPREPLY=() return @@ -1359,6 +1462,39 @@ _git_config () __gitcomp "$(__git_heads)" "$pfx" "$cur" "." return ;; + guitool.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp " + argprompt cmd confirm needsfile noconsole norescan + prompt revprompt revunmerged title + " "$pfx" "$cur" + return + ;; + difftool.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp "cmd path" "$pfx" "$cur" + return + ;; + man.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp "cmd path" "$pfx" "$cur" + return + ;; + mergetool.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp "cmd path trustExitCode" "$pfx" "$cur" + return + ;; + pager.*) + local pfx="${cur%.*}." + cur="${cur#*.}" + __gitcomp "$(__git_all_commands)" "$pfx" "$cur" + return + ;; remote.*.*) local pfx="${cur%.*}." cur="${cur##*.}" @@ -1374,8 +1510,15 @@ _git_config () __gitcomp "$(__git_remotes)" "$pfx" "$cur" "." return ;; + url.*.*) + local pfx="${cur%.*}." + cur="${cur##*.}" + __gitcomp "insteadof" "$pfx" "$cur" + return + ;; esac __gitcomp " + alias. apply.whitespace branch.autosetupmerge branch.autosetuprebase @@ -1393,11 +1536,15 @@ _git_config () color.diff.old color.diff.plain color.diff.whitespace + color.grep + color.grep.external + color.grep.match color.interactive color.interactive.header color.interactive.help color.interactive.prompt color.pager + color.showbranch color.status color.status.added color.status.changed @@ -1410,6 +1557,7 @@ _git_config () core.autocrlf core.bare core.compression + core.createObject core.deltaBaseCacheLimit core.editor core.excludesfile @@ -1440,11 +1588,21 @@ _git_config () diff.renameLimit diff.renameLimit. diff.renames + diff.suppressBlankEmpty + diff.tool + diff.wordRegex + difftool. + difftool.prompt fetch.unpackLimit + format.attach + format.cc format.headers format.numbered format.pretty + format.signoff + format.subjectprefix format.suffix + format.thread gc.aggressiveWindow gc.auto gc.autopacklimit @@ -1455,6 +1613,7 @@ _git_config () gc.rerereresolved gc.rerereunresolved gitcvs.allbinary + gitcvs.commitmsgannotation gitcvs.dbTableNamePrefix gitcvs.dbdriver gitcvs.dbname @@ -1463,6 +1622,7 @@ _git_config () gitcvs.enabled gitcvs.logfile gitcvs.usecrlfattr + guitool. gui.blamehistoryctx gui.commitmsgwidth gui.copyblamethreshold @@ -1489,13 +1649,24 @@ _git_config () http.sslVerify i18n.commitEncoding i18n.logOutputEncoding + imap.folder + imap.host + imap.pass + imap.port + imap.preformattedHTML + imap.sslverify + imap.tunnel + imap.user instaweb.browser instaweb.httpd instaweb.local instaweb.modulepath instaweb.port + interactive.singlekey log.date log.showroot + mailmap.file + man. man.viewer merge.conflictstyle merge.log @@ -1503,7 +1674,9 @@ _git_config () merge.stat merge.tool merge.verbosity + mergetool. mergetool.keepBackup + mergetool.prompt pack.compression pack.deltaCacheLimit pack.deltaCacheSize @@ -1513,8 +1686,11 @@ _git_config () pack.threads pack.window pack.windowMemory + pager. pull.octopus pull.twohead + push.default + rebase.stat receive.denyCurrentBranch receive.denyDeletes receive.denyNonFastForwards @@ -1523,11 +1699,32 @@ _git_config () repack.usedeltabaseoffset rerere.autoupdate rerere.enabled + sendemail.aliasesfile + sendemail.aliasesfiletype + sendemail.bcc + sendemail.cc + sendemail.cccmd + sendemail.chainreplyto + sendemail.confirm + sendemail.envelopesender + sendemail.multiedit + sendemail.signedoffbycc + sendemail.smtpencryption + sendemail.smtppass + sendemail.smtpserver + sendemail.smtpserverport + sendemail.smtpuser + sendemail.suppresscc + sendemail.suppressfrom + sendemail.thread + sendemail.to + sendemail.validate showbranch.default status.relativePaths status.showUntrackedFiles tar.umask transfer.unpackLimit + url. user.email user.name user.signingkey @@ -1642,7 +1839,7 @@ _git_show () return ;; --*) - __gitcomp "--pretty= --format= + __gitcomp "--pretty= --format= --abbrev-commit --oneline $__git_diff_common_options " return @@ -1659,7 +1856,8 @@ _git_show_branch () __gitcomp " --all --remotes --topo-order --current --more= --list --independent --merge-base --no-name - --sha1-name --topics --reflog + --color --no-color + --sha1-name --sparse --topics --reflog " return ;; @@ -1901,6 +2099,7 @@ _git () config) _git_config ;; describe) _git_describe ;; diff) _git_diff ;; + difftool) _git_difftool ;; fetch) _git_fetch ;; format-patch) _git_format_patch ;; fsck) _git_fsck ;; diff --git a/contrib/convert-objects/convert-objects.c b/contrib/convert-objects/convert-objects.c index 90e7900e6d..f3b57bf1d2 100644 --- a/contrib/convert-objects/convert-objects.c +++ b/contrib/convert-objects/convert-objects.c @@ -59,7 +59,7 @@ static void convert_ascii_sha1(void *buffer) struct entry *entry; if (get_sha1_hex(buffer, sha1)) - die("expected sha1, got '%s'", (char*) buffer); + die("expected sha1, got '%s'", (char *) buffer); entry = convert_entry(sha1); memcpy(buffer, sha1_to_hex(entry->new_sha1), 40); } @@ -100,7 +100,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base if (!slash) { newlen += sprintf(new + newlen, "%o %s", mode, path); new[newlen++] = '\0'; - hashcpy((unsigned char*)new + newlen, (unsigned char *) buffer + len - 20); + hashcpy((unsigned char *)new + newlen, (unsigned char *) buffer + len - 20); newlen += 20; used += len; @@ -271,7 +271,7 @@ static void convert_commit(void *buffer, unsigned long size, unsigned char *resu unsigned long orig_size = size; if (memcmp(buffer, "tree ", 5)) - die("Bad commit '%s'", (char*) buffer); + die("Bad commit '%s'", (char *) buffer); convert_ascii_sha1((char *) buffer + 5); buffer = (char *) buffer + 46; /* "tree " + "hex sha1" + "\n" */ while (!memcmp(buffer, "parent ", 7)) { diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool deleted file mode 100755 index 0deda3a0e4..0000000000 --- a/contrib/difftool/git-difftool +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env perl -# Copyright (c) 2009 David Aguilar -# -# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible -# git-difftool-helper script. This script exports -# GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and -# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper. -# Any arguments that are unknown to this script are forwarded to 'git diff'. - -use strict; -use warnings; -use Cwd qw(abs_path); -use File::Basename qw(dirname); - -my $DIR = abs_path(dirname($0)); - - -sub usage -{ - print << 'USAGE'; -usage: git difftool [--tool=<tool>] [--no-prompt] ["git diff" options] -USAGE - exit 1; -} - -sub setup_environment -{ - $ENV{PATH} = "$DIR:$ENV{PATH}"; - $ENV{GIT_PAGER} = ''; - $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool-helper'; -} - -sub exe -{ - my $exe = shift; - return defined $ENV{COMSPEC} ? "$exe.exe" : $exe; -} - -sub generate_command -{ - my @command = (exe('git'), 'diff'); - my $skip_next = 0; - my $idx = -1; - for my $arg (@ARGV) { - $idx++; - if ($skip_next) { - $skip_next = 0; - next; - } - if ($arg eq '-t' or $arg eq '--tool') { - usage() if $#ARGV <= $idx; - $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1]; - $skip_next = 1; - next; - } - if ($arg =~ /^--tool=/) { - $ENV{GIT_DIFF_TOOL} = substr($arg, 7); - next; - } - if ($arg eq '--no-prompt') { - $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true'; - next; - } - if ($arg eq '-h' or $arg eq '--help') { - usage(); - } - push @command, $arg; - } - return @command -} - -setup_environment(); -exec(generate_command()); diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper deleted file mode 100755 index 9c0a13452a..0000000000 --- a/contrib/difftool/git-difftool-helper +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh -# git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher. -# It supports kdiff3, kompare, tkdiff, xxdiff, meld, opendiff, -# emerge, ecmerge, vimdiff, gvimdiff, and custom user-configurable tools. -# This script is typically launched by using the 'git difftool' -# convenience command. -# -# Copyright (c) 2009 David Aguilar - -# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt. -should_prompt () { - ! test -n "$GIT_DIFFTOOL_NO_PROMPT" -} - -# Should we keep the backup .orig file? -keep_backup_mode="$(git config --bool merge.keepBackup || echo true)" -keep_backup () { - test "$keep_backup_mode" = "true" -} - -# This function manages the backup .orig file. -# A backup $MERGED.orig file is created if changes are detected. -cleanup_temp_files () { - if test -n "$MERGED"; then - if keep_backup && test "$MERGED" -nt "$BACKUP"; then - test -f "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig" - else - rm -f -- "$BACKUP" - fi - fi -} - -# This is called when users Ctrl-C out of git-difftool-helper -sigint_handler () { - cleanup_temp_files - exit 1 -} - -# This function prepares temporary files and launches the appropriate -# merge tool. -launch_merge_tool () { - # Merged is the filename as it appears in the work tree - # Local is the contents of a/filename - # Remote is the contents of b/filename - # Custom merge tool commands might use $BASE so we provide it - MERGED="$1" - LOCAL="$2" - REMOTE="$3" - BASE="$1" - ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')" - BACKUP="$MERGED.BACKUP.$ext" - - # Create and ensure that we clean up $BACKUP - test -f "$MERGED" && cp -- "$MERGED" "$BACKUP" - trap sigint_handler INT - - # $LOCAL and $REMOTE are temporary files so prompt - # the user with the real $MERGED name before launching $merge_tool. - if should_prompt; then - printf "\nViewing: '$MERGED'\n" - printf "Hit return to launch '%s': " "$merge_tool" - read ans - fi - - # Run the appropriate merge tool command - case "$merge_tool" in - kdiff3) - basename=$(basename "$MERGED") - "$merge_tool_path" --auto \ - --L1 "$basename (A)" \ - --L2 "$basename (B)" \ - -o "$MERGED" "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1 - ;; - - kompare) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - tkdiff) - "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE" - ;; - - meld) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - vimdiff) - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE" - ;; - - gvimdiff) - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE" - ;; - - xxdiff) - "$merge_tool_path" \ - -X \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" \ - "$LOCAL" "$REMOTE" - ;; - - opendiff) - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - -merge "$MERGED" | cat - ;; - - ecmerge) - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - --default --mode=merge2 --to="$MERGED" - ;; - - emerge) - "$merge_tool_path" -f emerge-files-command \ - "$LOCAL" "$REMOTE" "$(basename "$MERGED")" - ;; - - *) - if test -n "$merge_tool_cmd"; then - ( eval $merge_tool_cmd ) - fi - ;; - esac - - cleanup_temp_files -} - -# Verifies that (difftool|mergetool).<tool>.cmd exists -valid_custom_tool() { - merge_tool_cmd="$(git config difftool.$1.cmd)" - test -z "$merge_tool_cmd" && - merge_tool_cmd="$(git config mergetool.$1.cmd)" - test -n "$merge_tool_cmd" -} - -# Verifies that the chosen merge tool is properly setup. -# Built-in merge tools are always valid. -valid_tool() { - case "$1" in - kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge) - ;; # happy - *) - if ! valid_custom_tool "$1" - then - return 1 - fi - ;; - esac -} - -# Sets up the merge_tool_path variable. -# This handles the difftool.<tool>.path configuration. -# This also falls back to mergetool defaults. -init_merge_tool_path() { - merge_tool_path=$(git config difftool."$1".path) - test -z "$merge_tool_path" && - merge_tool_path=$(git config mergetool."$1".path) - if test -z "$merge_tool_path"; then - case "$1" in - emerge) - merge_tool_path=emacs - ;; - *) - merge_tool_path="$1" - ;; - esac - fi -} - -# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values -test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL" -test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL" - -# If merge tool was not specified then use the diff.tool -# configuration variable. If that's invalid then reset merge_tool. -# Fallback to merge.tool. -if test -z "$merge_tool"; then - merge_tool=$(git config diff.tool) - test -z "$merge_tool" && - merge_tool=$(git config merge.tool) - if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then - echo >&2 "git config option diff.tool set to unknown tool: $merge_tool" - echo >&2 "Resetting to default..." - unset merge_tool - fi -fi - -# Try to guess an appropriate merge tool if no tool has been set. -if test -z "$merge_tool"; then - # We have a $DISPLAY so try some common UNIX merge tools - if test -n "$DISPLAY"; then - # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare - if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff" - else - merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff" - fi - fi - if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then - # $EDITOR is emacs so add emerge as a candidate - merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff" - elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then - # $EDITOR is vim so add vimdiff as a candidate - merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge" - else - merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff" - fi - echo "merge tool candidates: $merge_tool_candidates" - - # Loop over each candidate and stop when a valid merge tool is found. - for i in $merge_tool_candidates - do - init_merge_tool_path $i - if type "$merge_tool_path" > /dev/null 2>&1; then - merge_tool=$i - break - fi - done - - if test -z "$merge_tool" ; then - echo "No known merge resolution program available." - exit 1 - fi - -else - # A merge tool has been set, so verify that it's valid. - if ! valid_tool "$merge_tool"; then - echo >&2 "Unknown merge tool $merge_tool" - exit 1 - fi - - init_merge_tool_path "$merge_tool" - - if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then - echo "The merge tool $merge_tool is not available as '$merge_tool_path'" - exit 1 - fi -fi - - -# Launch the merge tool on each path provided by 'git diff' -while test $# -gt 6 -do - launch_merge_tool "$1" "$2" "$5" - shift 7 -done diff --git a/contrib/thunderbird-patch-inline/README b/contrib/thunderbird-patch-inline/README index 39f96aa115..000147bbe4 100644 --- a/contrib/thunderbird-patch-inline/README +++ b/contrib/thunderbird-patch-inline/README @@ -1,12 +1,12 @@ appp.sh is a script that is supposed to be used together with ExternalEditor -for Mozilla Thundebird. It will let you include patches inline in e-mails +for Mozilla Thunderbird. It will let you include patches inline in e-mails in an easy way. Usage: - Generate the patch with git format-patch. - Start writing a new e-mail in Thunderbird. - Press the external editor button (or Ctrl-E) to run appp.sh -- Select the previosly generated patch file. +- Select the previously generated patch file. - Finish editing the e-mail. Any text that is entered into the message editor before appp.sh is called @@ -10,7 +10,7 @@ enum { A = GIT_ALPHA, D = GIT_DIGIT, G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ - R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */ + R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | */ }; unsigned char sane_ctype[256] = { @@ -444,27 +444,27 @@ static void parse_extra_args(char *extra_args, int buflen) if (hostname) { #ifndef NO_IPV6 struct addrinfo hints; - struct addrinfo *ai, *ai0; + struct addrinfo *ai; int gai; static char addrbuf[HOST_NAME_MAX + 1]; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; - gai = getaddrinfo(hostname, 0, &hints, &ai0); + gai = getaddrinfo(hostname, 0, &hints, &ai); if (!gai) { - for (ai = ai0; ai; ai = ai->ai_next) { - struct sockaddr_in *sin_addr = (void *)ai->ai_addr; - - inet_ntop(AF_INET, &sin_addr->sin_addr, - addrbuf, sizeof(addrbuf)); - free(canon_hostname); - canon_hostname = xstrdup(ai->ai_canonname); - free(ip_address); - ip_address = xstrdup(addrbuf); - break; - } - freeaddrinfo(ai0); + struct sockaddr_in *sin_addr = (void *)ai->ai_addr; + + inet_ntop(AF_INET, &sin_addr->sin_addr, + addrbuf, sizeof(addrbuf)); + free(ip_address); + ip_address = xstrdup(addrbuf); + + free(canon_hostname); + canon_hostname = xstrdup(ai->ai_canonname ? + ai->ai_canonname : ip_address); + + freeaddrinfo(ai); } #else struct hostent *hent; @@ -871,13 +871,15 @@ unsigned long approxidate(const char *date) int number = 0; struct tm tm, now; struct timeval tv; + time_t time_sec; char buffer[50]; if (parse_date(date, buffer, sizeof(buffer)) > 0) return strtoul(buffer, NULL, 10); gettimeofday(&tv, NULL); - localtime_r(&tv.tv_sec, &tm); + time_sec = tv.tv_sec; + localtime_r(&time_sec, &tm); now = tm; for (;;) { unsigned char c = *date; diff --git a/decorate.c b/decorate.c index 82d9e221ea..e6fd8a7441 100644 --- a/decorate.c +++ b/decorate.c @@ -8,7 +8,9 @@ static unsigned int hash_obj(const struct object *obj, unsigned int n) { - unsigned int hash = *(unsigned int *)obj->sha1; + unsigned int hash; + + memcpy(&hash, obj->sha1, sizeof(unsigned int)); return hash % n; } diff --git a/diff-no-index.c b/diff-no-index.c index 42c1dd8ad3..4ebc1dbd87 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -233,7 +233,7 @@ void diff_no_index(struct rev_info *revs, if (prefix) { int len = strlen(prefix); - revs->diffopt.paths = xcalloc(2, sizeof(char*)); + revs->diffopt.paths = xcalloc(2, sizeof(char *)); for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; /* @@ -839,10 +839,9 @@ static int scale_linear(int it, int width, int max_change) } static void show_name(FILE *file, - const char *prefix, const char *name, int len, - const char *reset, const char *set) + const char *prefix, const char *name, int len) { - fprintf(file, " %s%s%-*s%s |", set, prefix, len, name, reset); + fprintf(file, " %s%-*s |", prefix, len, name); } static void show_graph(FILE *file, char ch, int cnt, const char *set, const char *reset) @@ -876,7 +875,7 @@ static void fill_print_name(struct diffstat_file *file) file->print_name = pname; } -static void show_stats(struct diffstat_t* data, struct diff_options *options) +static void show_stats(struct diffstat_t *data, struct diff_options *options) { int i, len, add, del, adds = 0, dels = 0; int max_change = 0, max_len = 0; @@ -956,7 +955,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) } if (data->files[i]->is_binary) { - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, " Bin "); fprintf(options->file, "%s%d%s", del_c, deleted, reset); fprintf(options->file, " -> "); @@ -966,7 +965,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) continue; } else if (data->files[i]->is_unmerged) { - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, " Unmerged\n"); continue; } @@ -988,7 +987,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) add = scale_linear(add, width, max_change); del = scale_linear(del, width, max_change); } - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, "%5d%s", added + deleted, added + deleted ? " " : ""); show_graph(options->file, '+', add, add_c, reset); @@ -996,8 +995,8 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) fprintf(options->file, "\n"); } fprintf(options->file, - "%s %d files changed, %d insertions(+), %d deletions(-)%s\n", - set, total_files, adds, dels, reset); + " %d files changed, %d insertions(+), %d deletions(-)\n", + total_files, adds, dels); } static void show_shortstats(struct diffstat_t* data, struct diff_options *options) @@ -1025,7 +1024,7 @@ static void show_shortstats(struct diffstat_t* data, struct diff_options *option total_files, adds, dels); } -static void show_numstat(struct diffstat_t* data, struct diff_options *options) +static void show_numstat(struct diffstat_t *data, struct diff_options *options) { int i; diff --git a/diffcore-rename.c b/diffcore-rename.c index 0b0d6b8c8c..63ac998bfa 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -267,7 +267,7 @@ static int find_identical_files(struct file_similarity *src, int score; struct diff_filespec *source = p->filespec; - /* False hash collission? */ + /* False hash collision? */ if (hashcmp(source->sha1, target->sha1)) continue; /* Non-regular files? If so, the modes must match! */ @@ -53,7 +53,7 @@ int common_prefix(const char **pathspec) } /* - * Does 'match' matches the given name? + * Does 'match' match the given name? * A match is found if * * (1) the 'match' string is leading directory of 'name', or @@ -156,7 +156,7 @@ void add_exclude(const char *string, const char *base, if (len && string[len - 1] == '/') { char *s; x = xmalloc(sizeof(*x) + len); - s = (char*)(x+1); + s = (char *)(x+1); memcpy(s, string, len - 1); s[len - 1] = '\0'; string = s; @@ -290,7 +290,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) dir->basebuf[baselen] = '\0'; } -/* Scan the list and let the last match determines the fate. +/* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ static int excluded_1(const char *pathname, @@ -576,7 +576,7 @@ static int get_dtype(struct dirent *de, const char *path) */ static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify) { - DIR *fdir = opendir(path); + DIR *fdir = opendir(*path ? path : "."); int contents = 0; if (fdir) { @@ -147,7 +147,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout wrote = write_in_full(fd, new, size); /* use fstat() only when path == ce->name */ - if (state->refresh_cache && !to_tempfile && !state->base_dir_len) { + if (fstat_is_reliable() && + state->refresh_cache && !to_tempfile && !state->base_dir_len) { fstat(fd, &st); fstat_done = 1; } diff --git a/environment.c b/environment.c index 4696885b22..801a005ef1 100644 --- a/environment.c +++ b/environment.c @@ -43,6 +43,10 @@ unsigned whitespace_rule_cfg = WS_DEFAULT_RULE; enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; enum rebase_setup_type autorebase = AUTOREBASE_NEVER; enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; +#ifndef OBJECT_CREATION_MODE +#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS +#endif +enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/fast-import.c b/fast-import.c index 23c496d683..e9d23ffb2f 100644 --- a/fast-import.c +++ b/fast-import.c @@ -76,7 +76,7 @@ Format of STDIN stream: delim lf; # note: declen indicates the length of binary_data in bytes. - # declen does not include the lf preceeding the binary data. + # declen does not include the lf preceding the binary data. # exact_data ::= 'data' sp declen lf binary_data; @@ -133,8 +133,8 @@ Format of STDIN stream: # always escapes the related input from comment processing. # # In case it is not clear, the '#' that starts the comment - # must be the first character on that the line (an lf have - # preceeded it). + # must be the first character on that line (an lf + # preceded it). # comment ::= '#' not_lf* lf; not_lf ::= # Any byte that is not ASCII newline (LF); @@ -212,7 +212,7 @@ struct tree_content; struct tree_entry { struct tree_content *tree; - struct atom_str* name; + struct atom_str *name; struct tree_entry_ms { uint16_t mode; @@ -313,7 +313,7 @@ static unsigned int object_entry_alloc = 5000; static struct object_entry_pool *blocks; static struct object_entry *object_table[1 << 16]; static struct mark_set *marks; -static const char* mark_file; +static const char *mark_file; /* Our last blob */ static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 }; @@ -672,7 +672,7 @@ static struct branch *lookup_branch(const char *name) static struct branch *new_branch(const char *name) { unsigned int hc = hc_str(name, strlen(name)) % branch_table_sz; - struct branch* b = lookup_branch(name); + struct branch *b = lookup_branch(name); if (b) die("Invalid attempt to create duplicate branch: %s", name); @@ -953,7 +953,7 @@ static void end_packfile(void) close(pack_data->pack_fd); idx_name = keep_pack(create_index()); - /* Register the packfile with core git's machinary. */ + /* Register the packfile with core git's machinery. */ new_p = add_packed_git(idx_name, strlen(idx_name), 1); if (!new_p) die("core git rejected index %s", idx_name); @@ -1035,7 +1035,7 @@ static int store_object( git_SHA_CTX c; z_stream s; - hdrlen = sprintf((char*)hdr,"%s %lu", typename(type), + hdrlen = sprintf((char *)hdr,"%s %lu", typename(type), (unsigned long)dat->len) + 1; git_SHA1_Init(&c); git_SHA1_Update(&c, hdr, hdrlen); @@ -1217,7 +1217,7 @@ static const char *get_mode(const char *str, uint16_t *modep) static void load_tree(struct tree_entry *root) { - unsigned char* sha1 = root->versions[1].sha1; + unsigned char *sha1 = root->versions[1].sha1; struct object_entry *myoe; struct tree_content *t; unsigned long size; @@ -1258,8 +1258,8 @@ static void load_tree(struct tree_entry *root) e->versions[0].mode = e->versions[1].mode; e->name = to_atom(c, strlen(c)); c += e->name->str_len + 1; - hashcpy(e->versions[0].sha1, (unsigned char*)c); - hashcpy(e->versions[1].sha1, (unsigned char*)c); + hashcpy(e->versions[0].sha1, (unsigned char *)c); + hashcpy(e->versions[1].sha1, (unsigned char *)c); c += 20; } free(buf); @@ -23,7 +23,7 @@ int fsck_error_function(struct object *obj, int type, const char *fmt, ...); * the return value is: * -1 error in processing the object * <0 return value of the callback, which lead to an abort - * >0 return value of the first sigaled error >0 (in the case of no other errors) + * >0 return value of the first signaled error >0 (in the case of no other errors) * 0 everything OK */ int fsck_walk(struct object *obj, fsck_walk_func walk, void *data); diff --git a/git-add--interactive.perl b/git-add--interactive.perl index def062a9e2..f6e536ece3 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -620,11 +620,12 @@ sub parse_diff { if ($diff_use_color) { @colored = run_cmd_pipe(qw(git diff-files -p --color --), $path); } - my (@hunk) = { TEXT => [], DISPLAY => [] }; + my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' }; for (my $i = 0; $i < @diff; $i++) { if ($diff[$i] =~ /^@@ /) { - push @hunk, { TEXT => [], DISPLAY => [] }; + push @hunk, { TEXT => [], DISPLAY => [], + TYPE => 'hunk' }; } push @{$hunk[-1]{TEXT}}, $diff[$i]; push @{$hunk[-1]{DISPLAY}}, @@ -636,8 +637,8 @@ sub parse_diff { sub parse_diff_header { my $src = shift; - my $head = { TEXT => [], DISPLAY => [] }; - my $mode = { TEXT => [], DISPLAY => [] }; + my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' }; + my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' }; for (my $i = 0; $i < @{$src->{TEXT}}; $i++) { my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? @@ -684,6 +685,7 @@ sub split_hunk { my $this = +{ TEXT => [], DISPLAY => [], + TYPE => 'hunk', OLD => $o_ofs, NEW => $n_ofs, OCNT => 0, @@ -873,7 +875,11 @@ sub edit_hunk_loop { if (!defined $text) { return undef; } - my $newhunk = { TEXT => $text, USE => 1 }; + my $newhunk = { + TEXT => $text, + TYPE => $hunk->[$ix]->{TYPE}, + USE => 1 + }; if (diff_applies($head, @{$hunk}[0..$ix-1], $newhunk, @@ -894,6 +900,7 @@ sub help_patch_cmd { print colored $help_color, <<\EOF ; y - stage this hunk n - do not stage this hunk +q - quit, do not stage this hunk nor any of the remaining ones a - stage this and all the remaining hunks in the file d - do not stage this hunk nor any of the remaining hunks in the file g - select a hunk to go to @@ -930,7 +937,7 @@ sub patch_update_cmd { @mods); } for (@them) { - patch_update_file($_->{VALUE}); + return 0 if patch_update_file($_->{VALUE}); } } @@ -976,6 +983,7 @@ sub display_hunks { } sub patch_update_file { + my $quit = 0; my ($ix, $num); my $path = shift; my ($head, @hunk) = parse_diff($path); @@ -985,32 +993,7 @@ sub patch_update_file { } if (@{$mode->{TEXT}}) { - while (1) { - print @{$mode->{DISPLAY}}; - print colored $prompt_color, - "Stage mode change [y/n/a/d/?]? "; - my $line = prompt_single_character; - if ($line =~ /^y/i) { - $mode->{USE} = 1; - last; - } - elsif ($line =~ /^n/i) { - $mode->{USE} = 0; - last; - } - elsif ($line =~ /^a/i) { - $_->{USE} = 1 foreach ($mode, @hunk); - last; - } - elsif ($line =~ /^d/i) { - $_->{USE} = 0 foreach ($mode, @hunk); - last; - } - else { - help_patch_cmd(''); - next; - } - } + unshift @hunk, $mode; } $num = scalar @hunk; @@ -1054,14 +1037,19 @@ sub patch_update_file { } last if (!$undecided); - if (hunk_splittable($hunk[$ix]{TEXT})) { + if ($hunk[$ix]{TYPE} eq 'hunk' && + hunk_splittable($hunk[$ix]{TEXT})) { $other .= ',s'; } - $other .= ',e'; + if ($hunk[$ix]{TYPE} eq 'hunk') { + $other .= ',e'; + } for (@{$hunk[$ix]{DISPLAY}}) { print; } - print colored $prompt_color, "Stage this hunk [y,n,a,d,/$other,?]? "; + print colored $prompt_color, 'Stage ', + ($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'), + " [y,n,q,a,d,/$other,?]? "; my $line = prompt_single_character; if ($line) { if ($line =~ /^y/i) { @@ -1113,6 +1101,16 @@ sub patch_update_file { } next; } + elsif ($line =~ /^q/i) { + while ($ix < $num) { + if (!defined $hunk[$ix]{USE}) { + $hunk[$ix]{USE} = 0; + } + $ix++; + } + $quit = 1; + next; + } elsif ($line =~ m|^/(.*)|) { my $regex = $1; if ($1 eq "") { @@ -1193,7 +1191,7 @@ sub patch_update_file { $num = scalar @hunk; next; } - elsif ($line =~ /^e/) { + elsif ($other =~ /e/ && $line =~ /^e/) { my $newhunk = edit_hunk_loop($head, \@hunk, $ix); if (defined $newhunk) { splice @hunk, $ix, 1, $newhunk; @@ -1214,9 +1212,6 @@ sub patch_update_file { my $n_lofs = 0; my @result = (); - if ($mode->{USE}) { - push @result, @{$mode->{TEXT}}; - } for (@hunk) { if ($_->{USE}) { push @result, @{$_->{TEXT}}; @@ -1239,6 +1234,7 @@ sub patch_update_file { } print "\n"; + return $quit; } sub diff_cmd { @@ -36,6 +36,13 @@ cd_to_toplevel git var GIT_COMMITTER_IDENT >/dev/null || die "You need to set your committer info first" +if git rev-parse --verify -q HEAD >/dev/null +then + HAS_HEAD=yes +else + HAS_HEAD= +fi + sq () { for sqarg do @@ -290,16 +297,26 @@ else : >"$dotest/rebasing" else : >"$dotest/applying" - git update-ref ORIG_HEAD HEAD + if test -n "$HAS_HEAD" + then + git update-ref ORIG_HEAD HEAD + else + git update-ref -d ORIG_HEAD >/dev/null 2>&1 + fi fi fi case "$resolved" in '') - files=$(git diff-index --cached --name-only HEAD --) || exit + case "$HAS_HEAD" in + '') + files=$(git ls-files) ;; + ?*) + files=$(git diff-index --cached --name-only HEAD --) ;; + esac || exit if test "$files" then - : >"$dotest/dirtyindex" + test -n "$HAS_HEAD" && : >"$dotest/dirtyindex" die "Dirty index: cannot apply patches (dirty: $files)" fi esac @@ -541,18 +558,20 @@ do fi tree=$(git write-tree) && - parent=$(git rev-parse --verify HEAD) && commit=$( if test -n "$ignore_date" then GIT_AUTHOR_DATE= fi + parent=$(git rev-parse --verify -q HEAD) || + echo >&2 "applying to an empty history" + if test -n "$committer_date_is_author_date" then GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" export GIT_COMMITTER_DATE fi && - git commit-tree $tree -p $parent <"$dotest/final-commit" + git commit-tree $tree ${parent:+-p} $parent <"$dotest/final-commit" ) && git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent || stop_here $this diff --git a/git-bisect.sh b/git-bisect.sh index df0ae63b4e..24712ff304 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -279,87 +279,14 @@ bisect_auto_next() { bisect_next_check && bisect_next || : } -filter_skipped() { - _eval="$1" - _skip="$2" - - if [ -z "$_skip" ]; then - eval "$_eval" | { - while read line - do - echo "$line &&" - done - echo ':' - } - return - fi - - # Let's parse the output of: - # "git rev-list --bisect-vars --bisect-all ..." - eval "$_eval" | { - VARS= FOUND= TRIED= - while read hash line - do - case "$VARS,$FOUND,$TRIED,$hash" in - 1,*,*,*) - # "bisect_foo=bar" read from rev-list output. - echo "$hash &&" - ;; - ,*,*,---*) - # Separator - ;; - ,,,bisect_rev*) - # We had nothing to search. - echo "bisect_rev= &&" - VARS=1 - ;; - ,,*,bisect_rev*) - # We did not find a good bisect rev. - # This should happen only if the "bad" - # commit is also a "skip" commit. - echo "bisect_rev='$TRIED' &&" - VARS=1 - ;; - ,,*,*) - # We are searching. - TRIED="${TRIED:+$TRIED|}$hash" - case "$_skip" in - *$hash*) ;; - *) - echo "bisect_rev=$hash &&" - echo "bisect_tried='$TRIED' &&" - FOUND=1 - ;; - esac - ;; - ,1,*,bisect_rev*) - # We have already found a rev to be tested. - VARS=1 - ;; - ,1,*,*) - ;; - *) - # Unexpected input - echo "die 'filter_skipped error'" - die "filter_skipped error " \ - "VARS: '$VARS' " \ - "FOUND: '$FOUND' " \ - "TRIED: '$TRIED' " \ - "hash: '$hash' " \ - "line: '$line'" - ;; - esac - done - echo ':' - } -} - exit_if_skipped_commits () { _tried=$1 - if expr "$_tried" : ".*[|].*" > /dev/null ; then + _bad=$2 + if test -n "$_tried" ; then echo "There are only 'skip'ped commit left to test." echo "The first bad commit could be any of:" echo "$_tried" | tr '[|]' '[\012]' + test -n "$_bad" && echo "$_bad" echo "We cannot bisect more!" exit 2 fi @@ -490,28 +417,23 @@ bisect_next() { test "$?" -eq "1" && return # Get bisection information - BISECT_OPT='' - test -n "$skip" && BISECT_OPT='--bisect-all' - eval="git rev-list --bisect-vars $BISECT_OPT $good $bad --" && - eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" && - eval=$(filter_skipped "$eval" "$skip") && + eval=$(eval "git bisect--helper --next-vars") && eval "$eval" || exit if [ -z "$bisect_rev" ]; then + # We should exit here only if the "bad" + # commit is also a "skip" commit (see above). + exit_if_skipped_commits "$bisect_tried" echo "$bad was both good and bad" exit 1 fi if [ "$bisect_rev" = "$bad" ]; then - exit_if_skipped_commits "$bisect_tried" + exit_if_skipped_commits "$bisect_tried" "$bad" echo "$bisect_rev is first bad commit" git diff-tree --pretty $bisect_rev exit 0 fi - # We should exit here only if the "bad" - # commit is also a "skip" commit (see above). - exit_if_skipped_commits "$bisect_rev" - bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)" } diff --git a/git-compat-util.h b/git-compat-util.h index f09f244061..1ac16bde5a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -46,6 +46,7 @@ #define _ALL_SOURCE 1 #define _GNU_SOURCE 1 #define _BSD_SOURCE 1 +#define _NETBSD_SOURCE 1 #include <unistd.h> #include <stdio.h> @@ -408,4 +409,10 @@ void git_qsort(void *base, size_t nmemb, size_t size, #endif #endif +#ifdef UNRELIABLE_FSTAT +#define fstat_is_reliable() 0 +#else +#define fstat_is_reliable() 1 +#endif + #endif diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh new file mode 100755 index 0000000000..57e8e3256d --- /dev/null +++ b/git-difftool--helper.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher. +# This script is typically launched by using the 'git difftool' +# convenience command. +# +# Copyright (c) 2009 David Aguilar + +# Load common functions from git-mergetool--lib +TOOL_MODE=diff +. git-mergetool--lib + +# difftool.prompt controls the default prompt/no-prompt behavior +# and is overridden with $GIT_DIFFTOOL*_PROMPT. +should_prompt () { + prompt=$(git config --bool difftool.prompt || echo true) + if test "$prompt" = true; then + test -z "$GIT_DIFFTOOL_NO_PROMPT" + else + test -n "$GIT_DIFFTOOL_PROMPT" + fi +} + +# Sets up shell variables and runs a merge tool +launch_merge_tool () { + # Merged is the filename as it appears in the work tree + # Local is the contents of a/filename + # Remote is the contents of b/filename + # Custom merge tool commands might use $BASE so we provide it + MERGED="$1" + LOCAL="$2" + REMOTE="$3" + BASE="$1" + + # $LOCAL and $REMOTE are temporary files so prompt + # the user with the real $MERGED name before launching $merge_tool. + if should_prompt; then + printf "\nViewing: '$MERGED'\n" + printf "Hit return to launch '%s': " "$merge_tool" + read ans + fi + + # Run the appropriate merge tool command + run_merge_tool "$merge_tool" +} + +# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values +test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL" +test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL" + +if test -z "$merge_tool"; then + merge_tool="$(get_merge_tool)" || exit +fi + +# Launch the merge tool on each path provided by 'git diff' +while test $# -gt 6 +do + launch_merge_tool "$1" "$2" "$5" + shift 7 +done diff --git a/git-difftool.perl b/git-difftool.perl new file mode 100755 index 0000000000..ba5e60a45e --- /dev/null +++ b/git-difftool.perl @@ -0,0 +1,92 @@ +#!/usr/bin/env perl +# Copyright (c) 2009 David Aguilar +# +# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible +# git-difftool--helper script. +# +# This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git. +# GIT_DIFFTOOL_NO_PROMPT, GIT_DIFFTOOL_PROMPT, and GIT_DIFF_TOOL +# are exported for use by git-difftool--helper. +# +# Any arguments that are unknown to this script are forwarded to 'git diff'. + +use strict; +use warnings; +use Cwd qw(abs_path); +use File::Basename qw(dirname); + +my $DIR = abs_path(dirname($0)); + + +sub usage +{ + print << 'USAGE'; +usage: git difftool [--tool=<tool>] [-y|--no-prompt] ["git diff" options] +USAGE + exit 1; +} + +sub setup_environment +{ + $ENV{PATH} = "$DIR:$ENV{PATH}"; + $ENV{GIT_PAGER} = ''; + $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper'; +} + +sub exe +{ + my $exe = shift; + if ($^O eq 'MSWin32' || $^O eq 'msys') { + return "$exe.exe"; + } + return $exe; +} + +sub generate_command +{ + my @command = (exe('git'), 'diff'); + my $skip_next = 0; + my $idx = -1; + for my $arg (@ARGV) { + $idx++; + if ($skip_next) { + $skip_next = 0; + next; + } + if ($arg eq '-t' || $arg eq '--tool') { + usage() if $#ARGV <= $idx; + $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1]; + $skip_next = 1; + next; + } + if ($arg =~ /^--tool=/) { + $ENV{GIT_DIFF_TOOL} = substr($arg, 7); + next; + } + if ($arg eq '-y' || $arg eq '--no-prompt') { + $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true'; + delete $ENV{GIT_DIFFTOOL_PROMPT}; + next; + } + if ($arg eq '--prompt') { + $ENV{GIT_DIFFTOOL_PROMPT} = 'true'; + delete $ENV{GIT_DIFFTOOL_NO_PROMPT}; + next; + } + if ($arg eq '-h' || $arg eq '--help') { + usage(); + } + push @command, $arg; + } + return @command +} + +setup_environment(); + +# ActiveState Perl for Win32 does not implement POSIX semantics of +# exec* system call. It just spawns the given executable and finishes +# the starting program, exiting with code 0. +# system will at least catch the errors returned by git diff, +# allowing the caller of git difftool better handling of failures. +my $rc = system(generate_command()); +exit($rc | ($rc >> 8)); diff --git a/git-filter-branch.sh b/git-filter-branch.sh index b90d3df3a7..37e044db40 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -430,7 +430,7 @@ if [ "$filter_tag_name" ]; then if [ "$type" = "tag" ]; then # Dereference to a commit sha1t="$sha1" - sha1="$(git rev-parse "$sha1"^{commit} 2>/dev/null)" || continue + sha1="$(git rev-parse -q "$sha1"^{commit})" || continue fi [ -f "../map/$sha1" ] || continue diff --git a/git-gui/Makefile b/git-gui/Makefile index 3ad8a21b30..b3580e9e48 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -105,8 +105,11 @@ endif ifeq ($(uname_S),Darwin) TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app - ifeq ($(shell expr "$(uname_R)" : '9\.'),2) - TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app + ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n) + TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish.app + ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n) + TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app + endif endif TKEXECUTABLE = $(shell basename "$(TKFRAMEWORK)" .app) endif diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index e018e076f8..14b92ba786 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -122,6 +122,7 @@ unset oguimsg set _appname {Git Gui} set _gitdir {} set _gitexec {} +set _githtmldir {} set _reponame {} set _iscygwin {} set _search_path {} @@ -168,6 +169,28 @@ proc gitexec {args} { return [eval [list file join $_gitexec] $args] } +proc githtmldir {args} { + global _githtmldir + if {$_githtmldir eq {}} { + if {[catch {set _githtmldir [git --html-path]}]} { + # Git not installed or option not yet supported + return {} + } + if {[is_Cygwin]} { + set _githtmldir [exec cygpath \ + --windows \ + --absolute \ + $_githtmldir] + } else { + set _githtmldir [file normalize $_githtmldir] + } + } + if {$args eq {}} { + return $_githtmldir + } + return [eval [list file join $_githtmldir] $args] +} + proc reponame {} { return $::_reponame } @@ -640,10 +663,13 @@ font create font_diffbold font create font_diffitalic foreach class {Button Checkbutton Entry Label - Labelframe Listbox Menu Message + Labelframe Listbox Message Radiobutton Spinbox Text} { option add *$class.font font_ui } +if {![is_MacOSX]} { + option add *Menu.font font_ui +} unset class if {[is_Windows] || [is_MacOSX]} { @@ -699,7 +725,7 @@ proc apply_config {} { set default_config(branch.autosetupmerge) true set default_config(merge.tool) {} -set default_config(merge.keepbackup) true +set default_config(mergetool.keepbackup) true set default_config(merge.diffstat) true set default_config(merge.summary) false set default_config(merge.verbosity) 2 @@ -769,9 +795,9 @@ if {![regsub {^git version } $_git_version {} _git_version]} { set _real_git_version $_git_version regsub -- {[\-\.]dirty$} $_git_version {} _git_version regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version -regsub {\.rc[0-9]+$} $_git_version {} _git_version +regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version regsub {\.GIT$} $_git_version {} _git_version -regsub {\.[a-zA-Z]+\.[0-9]+$} $_git_version {} _git_version +regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} { catch {wm withdraw .} @@ -1108,6 +1134,7 @@ set current_diff_path {} set is_3way_diff 0 set is_conflict_diff 0 set selected_commit_type new +set diff_empty_count 0 set nullid "0000000000000000000000000000000000000000" set nullid2 "0000000000000000000000000000000000000001" @@ -1924,7 +1951,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer [file dirname [gitdir]] & + eval exec $explorer [list [file nativename [file dirname [gitdir]]]] & } set is_quitting 0 @@ -2277,6 +2304,12 @@ set ui_comm {} # -- Menu Bar # menu .mbar -tearoff 0 +if {[is_MacOSX]} { + # -- Apple Menu (Mac OS X only) + # + .mbar add cascade -label Apple -menu .mbar.apple + menu .mbar.apple +} .mbar add cascade -label [mc Repository] -menu .mbar.repository .mbar add cascade -label [mc Edit] -menu .mbar.edit if {[is_enabled branch]} { @@ -2292,7 +2325,6 @@ if {[is_enabled transport]} { if {[is_enabled multicommit] || [is_enabled singlecommit]} { .mbar add cascade -label [mc Tools] -menu .mbar.tools } -. configure -menu .mbar # -- Repository Menu # @@ -2545,19 +2577,7 @@ if {[is_enabled transport]} { } if {[is_MacOSX]} { - # -- Apple Menu (Mac OS X only) - # - .mbar add cascade -label Apple -menu .mbar.apple - menu .mbar.apple - - .mbar.apple add command -label [mc "About %s" [appname]] \ - -command do_about - .mbar.apple add separator - .mbar.apple add command \ - -label [mc "Preferences..."] \ - -command do_options \ - -accelerator $M1T-, - bind . <$M1B-,> do_options + proc ::tk::mac::ShowPreferences {} {do_options} } else { # -- Edit Menu # @@ -2585,17 +2605,23 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} { .mbar add cascade -label [mc Help] -menu .mbar.help menu .mbar.help -if {![is_MacOSX]} { +if {[is_MacOSX]} { + .mbar.apple add command -label [mc "About %s" [appname]] \ + -command do_about + .mbar.apple add separator +} else { .mbar.help add command -label [mc "About %s" [appname]] \ -command do_about } +. configure -menu .mbar +set doc_path [githtmldir] +if {$doc_path ne {}} { + set doc_path [file join $doc_path index.html] -set doc_path [file dirname [gitexec]] -set doc_path [file join $doc_path Documentation index.html] - -if {[is_Cygwin]} { - set doc_path [exec cygpath --mixed $doc_path] + if {[is_Cygwin]} { + set doc_path [exec cygpath --mixed $doc_path] + } } if {[file isfile $doc_path]} { @@ -2944,7 +2970,7 @@ $ctxm add command \ -command {tk_textPaste $ui_comm} $ctxm add command \ -label [mc Delete] \ - -command {$ui_comm delete sel.first sel.last} + -command {catch {$ui_comm delete sel.first sel.last}} $ctxm add separator $ctxm add command \ -label [mc "Select All"] \ diff --git a/git-gui/lib/branch_delete.tcl b/git-gui/lib/branch_delete.tcl index ef1930b491..20d5e42307 100644 --- a/git-gui/lib/branch_delete.tcl +++ b/git-gui/lib/branch_delete.tcl @@ -51,7 +51,7 @@ constructor dialog {} { $w.check \ [mc "Delete Only If Merged Into"] \ ] - $w_check none [mc "Always (Do not perform merge test.)"] + $w_check none [mc "Always (Do not perform merge checks)"] pack $w.check -anchor nw -fill x -pady 5 -padx 5 foreach h [load_all_heads] { @@ -112,7 +112,7 @@ method _delete {} { } if {$to_delete eq {}} return if {$check_cmt eq {}} { - set msg [mc "Recovering deleted branches is difficult. \n\n Delete the selected branches?"] + set msg [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"] if {[tk_messageBox \ -icon warning \ -type yesno \ diff --git a/git-gui/lib/checkout_op.tcl b/git-gui/lib/checkout_op.tcl index caca88831b..9e7412c446 100644 --- a/git-gui/lib/checkout_op.tcl +++ b/git-gui/lib/checkout_op.tcl @@ -9,6 +9,7 @@ field w_cons {}; # embedded console window object field new_expr ; # expression the user saw/thinks this is field new_hash ; # commit SHA-1 we are switching to field new_ref ; # ref we are updating/creating +field old_hash ; # commit SHA-1 that was checked out when we started field parent_w .; # window that started us field merge_type none; # type of merge to apply to existing branch @@ -280,11 +281,11 @@ method _start_checkout {} { # -- Our in memory state should match the repository. # - repository_state curType curHEAD curMERGE_HEAD + repository_state curType old_hash curMERGE_HEAD if {[string match amend* $commit_type] && $curType eq {normal} - && $curHEAD eq $HEAD} { - } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { + && $old_hash eq $HEAD} { + } elseif {$commit_type ne $curType || $HEAD ne $old_hash} { info_popup [mc "Last scanned state does not match repository state. Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed. @@ -297,7 +298,7 @@ The rescan will be automatically started now. return } - if {$curHEAD eq $new_hash} { + if {$old_hash eq $new_hash} { _after_readtree $this } elseif {[is_config_true gui.trustmtime]} { _readtree $this @@ -453,13 +454,47 @@ method _after_readtree {} { If you wanted to be on a branch, create one now starting from 'This Detached Checkout'."] } + # -- Run the post-checkout hook. + # + set fd_ph [githook_read post-checkout $old_hash $new_hash 1] + if {$fd_ph ne {}} { + global pch_error + set pch_error {} + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] + } else { + _update_repo_state $this + } +} + +method _postcheckout_wait {fd_ph} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + hook_failed_popup post-checkout $pch_error 0 + } + unset pch_error + _update_repo_state $this + return + } + fconfigure $fd_ph -blocking 0 +} + +method _update_repo_state {} { # -- Update our repository state. If we were previously in # amend mode we need to toss the current buffer and do a # full rescan to update our file lists. If we weren't in # amend mode our file lists are accurate and we can avoid # the rescan. # + global selected_commit_type commit_type HEAD MERGE_HEAD PARENT + global ui_comm + unlock_index + set name [_name $this] set selected_commit_type new if {[string match amend* $commit_type]} { $ui_comm delete 0.0 end diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index f9ff62a3b2..633cc572bb 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -398,6 +398,8 @@ method _do_new {} { grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew pack $w_body.where -fill x + grid columnconfigure $w_body.where 1 -weight 1 + trace add variable @local_path write [cb _write_local_path] bind $w_body.h <Destroy> [list trace remove variable @local_path write [cb _write_local_path]] update @@ -964,7 +966,34 @@ method _readtree_wait {fd} { return } - set done 1 + # -- Run the post-checkout hook. + # + set fd_ph [githook_read post-checkout [string repeat 0 40] \ + [git rev-parse HEAD] 1] + if {$fd_ph ne {}} { + global pch_error + set pch_error {} + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] + } else { + set done 1 + } +} + +method _postcheckout_wait {fd_ph} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + hook_failed_popup post-checkout $pch_error 0 + } + unset pch_error + set done 1 + return + } + fconfigure $fd_ph -blocking 0 } ###################################################################### @@ -998,6 +1027,8 @@ method _do_open {} { grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew pack $w_body.where -fill x + grid columnconfigure $w_body.where 1 -weight 1 + trace add variable @local_path write [cb _write_local_path] bind $w_body.h <Destroy> [list trace remove variable @local_path write [cb _write_local_path]] update diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl index 9cc8410595..7f459cd564 100644 --- a/git-gui/lib/commit.tcl +++ b/git-gui/lib/commit.tcl @@ -115,6 +115,23 @@ proc create_new_commit {} { rescan ui_ready } +proc setup_commit_encoding {msg_wt {quiet 0}} { + global repo_config + + if {[catch {set enc $repo_config(i18n.commitencoding)}]} { + set enc utf-8 + } + set use_enc [tcl_encoding $enc] + if {$use_enc ne {}} { + fconfigure $msg_wt -encoding $use_enc + } else { + if {!$quiet} { + error_popup [mc "warning: Tcl does not support encoding '%s'." $enc] + } + fconfigure $msg_wt -encoding utf-8 + } +} + proc commit_tree {} { global HEAD commit_type file_states ui_comm repo_config global pch_error @@ -200,16 +217,7 @@ A good commit message has the following format: set msg_p [gitdir GITGUI_EDITMSG] set msg_wt [open $msg_p w] fconfigure $msg_wt -translation lf - if {[catch {set enc $repo_config(i18n.commitencoding)}]} { - set enc utf-8 - } - set use_enc [tcl_encoding $enc] - if {$use_enc ne {}} { - fconfigure $msg_wt -encoding $use_enc - } else { - error_popup [mc "warning: Tcl does not support encoding '%s'." $enc] - fconfigure $msg_wt -encoding utf-8 - } + setup_commit_encoding $msg_wt puts $msg_wt $msg close $msg_wt @@ -362,6 +370,7 @@ A rescan will be automatically started now. append reflogm " ($commit_type)" } set msg_fd [open $msg_p r] + setup_commit_encoding $msg_fd 1 gets $msg_fd subject close $msg_fd append reflogm {: } $subject @@ -398,8 +407,8 @@ A rescan will be automatically started now. # set fd_ph [githook_read post-commit] if {$fd_ph ne {}} { - upvar #0 pch_error$cmt_id pc_err - set pc_err {} + global pch_error + set pch_error {} fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} fileevent $fd_ph readable \ [list commit_postcommit_wait $fd_ph $cmt_id] @@ -461,7 +470,7 @@ A rescan will be automatically started now. } proc commit_postcommit_wait {fd_ph cmt_id} { - upvar #0 pch_error$cmt_id pch_error + global pch_error append pch_error [read $fd_ph] fconfigure $fd_ph -blocking 1 diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index bbbf15c875..925b3f56c1 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -51,11 +51,16 @@ proc force_diff_encoding {enc} { proc handle_empty_diff {} { global current_diff_path file_states file_lists + global diff_empty_count set path $current_diff_path set s $file_states($path) if {[lindex $s 0] ne {_M}} return + # Prevent infinite rescan loops + incr diff_empty_count + if {$diff_empty_count > 1} return + info_popup [mc "No differences detected. %s has no changes. @@ -310,6 +315,7 @@ proc read_diff {fd cont_info} { global ui_diff diff_active global is_3way_diff is_conflict_diff current_diff_header global current_diff_queue + global diff_empty_count $ui_diff conf -state normal while {[gets $fd line] >= 0} { @@ -415,7 +421,10 @@ proc read_diff {fd cont_info} { if {[$ui_diff index end] eq {2.0}} { handle_empty_diff + } else { + set diff_empty_count 0 } + set callback [lindex $cont_info 1] if {$callback ne {}} { eval $callback diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl index eb2b4b56a4..3fe90e6970 100644 --- a/git-gui/lib/mergetool.tcl +++ b/git-gui/lib/mergetool.tcl @@ -88,7 +88,7 @@ proc merge_load_stages {path cont} { set merge_stages(3) {} set merge_stages_buf {} - set merge_stages_fd [eval git_read ls-files -u -z -- $path] + set merge_stages_fd [eval git_read ls-files -u -z -- {$path}] fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] @@ -382,7 +382,7 @@ proc merge_tool_finish {fd} { delete_temp_files $mtool_tmpfiles ui_status [mc "Merge tool failed."] } else { - if {[is_config_true merge.keepbackup]} { + if {[is_config_true mergetool.keepbackup]} { file rename -force -- $backup "$mtool_target.orig" } diff --git a/git-gui/lib/remote_branch_delete.tcl b/git-gui/lib/remote_branch_delete.tcl index 89eb0f70f2..4e02fc0d39 100644 --- a/git-gui/lib/remote_branch_delete.tcl +++ b/git-gui/lib/remote_branch_delete.tcl @@ -213,9 +213,7 @@ method _delete {} { -type yesno \ -title [wm title $w] \ -parent $w \ - -message [mc "Recovering deleted branches is difficult. - -Delete the selected branches?"]] ne yes} { + -message [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"]] ne yes} { return } diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 38c3151b05..2f20eb39c0 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -54,7 +54,7 @@ proc do_cygwin_shortcut {} { $argv0] win32_create_lnk $fn [list \ $sh -c \ - "CHERE_INVOKING=1 source /etc/profile;[sq $me]" \ + "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ [file dirname [file normalize [gitdir]]] } err]} { diff --git a/git-gui/lib/tools.tcl b/git-gui/lib/tools.tcl index 6ae63b6c7c..95e6e5553e 100644 --- a/git-gui/lib/tools.tcl +++ b/git-gui/lib/tools.tcl @@ -146,7 +146,7 @@ proc tools_complete {fullname w {ok 1}} { } if {$ok} { - set msg [mc "Tool completed succesfully: %s" $fullname] + set msg [mc "Tool completed successfully: %s" $fullname] } else { set msg [mc "Tool failed: %s" $fullname] } diff --git a/git-gui/po/de.po b/git-gui/po/de.po index a6f730b4eb..51abb50bb6 100644 --- a/git-gui/po/de.po +++ b/git-gui/po/de.po @@ -773,16 +773,6 @@ msgstr "Immer (ohne Zusammenführungstest)" msgid "The following branches are not completely merged into %s:" msgstr "Folgende Zweige sind noch nicht mit »%s« zusammengeführt:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Gelöschte Zweige können nur mit größerem Aufwand wiederhergestellt werden.\n" -"\n" -"Gewählte Zweige jetzt löschen?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2506,7 +2496,7 @@ msgstr "Starten: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Werkzeug erfolgreich abgeschlossen: %s" #: lib/tools.tcl:151 diff --git a/git-gui/po/fr.po b/git-gui/po/fr.po index 45773ab3d8..a944ace6ce 100644 --- a/git-gui/po/fr.po +++ b/git-gui/po/fr.po @@ -62,7 +62,7 @@ msgstr "" "\n" "%s nécessite au moins Git 1.5.0.\n" "\n" -"Peut'on considérer que '%s' est en version 1.5.0 ?\n" +"Peut-on considérer que '%s' est en version 1.5.0 ?\n" #: git-gui.sh:1062 msgid "Git directory not found:" @@ -82,7 +82,7 @@ msgstr "Aucun répertoire de travail" #: git-gui.sh:1247 lib/checkout_op.tcl:305 msgid "Refreshing file status..." -msgstr "Rafraichissement du status des fichiers..." +msgstr "Rafraîchissement du statut des fichiers..." #: git-gui.sh:1303 msgid "Scanning for modified files ..." @@ -163,7 +163,7 @@ msgstr "Dépôt" #: git-gui.sh:2281 msgid "Edit" -msgstr "Edition" +msgstr "Édition" #: git-gui.sh:2283 lib/choose_rev.tcl:561 msgid "Branch" @@ -199,7 +199,7 @@ msgstr "Naviguer dans la branche..." #: git-gui.sh:2316 msgid "Visualize Current Branch's History" -msgstr "Visualiser historique branche courante" +msgstr "Visualiser l'historique de la branche courante" #: git-gui.sh:2320 msgid "Visualize All Branch History" @@ -208,12 +208,12 @@ msgstr "Voir l'historique de toutes les branches" #: git-gui.sh:2327 #, tcl-format msgid "Browse %s's Files" -msgstr "Naviguer l'arborescence de %s" +msgstr "Parcourir l'arborescence de %s" #: git-gui.sh:2329 #, tcl-format msgid "Visualize %s's History" -msgstr "Voir l'historique de la branche: %s" +msgstr "Voir l'historique de la branche : %s" #: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67 msgid "Database Statistics" @@ -230,7 +230,7 @@ msgstr "Vérifier le dépôt" #: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7 #: lib/shortcut.tcl:39 lib/shortcut.tcl:71 msgid "Create Desktop Icon" -msgstr "Créer icône sur bureau" +msgstr "Créer une icône sur le bureau" #: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 msgid "Quit" @@ -320,7 +320,7 @@ msgstr "Désindexer" #: git-gui.sh:2484 lib/index.tcl:410 msgid "Revert Changes" -msgstr "Annuler les modifications (revert)" +msgstr "Annuler les modifications" #: git-gui.sh:2491 git-gui.sh:3069 msgid "Show Less Context" @@ -382,7 +382,7 @@ msgstr "Documentation en ligne" #: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 msgid "Show SSH Key" -msgstr "Montrer clé SSH" +msgstr "Montrer la clé SSH" #: git-gui.sh:2707 #, tcl-format @@ -445,7 +445,7 @@ msgstr "Fichier :" #: git-gui.sh:3078 msgid "Refresh" -msgstr "Rafraichir" +msgstr "Rafraîchir" #: git-gui.sh:3099 msgid "Decrease Font Size" @@ -457,7 +457,7 @@ msgstr "Agrandir la police" #: git-gui.sh:3111 lib/blame.tcl:281 msgid "Encoding" -msgstr "Encodage" +msgstr "Codage des caractères" #: git-gui.sh:3122 msgid "Apply/Reverse Hunk" @@ -469,7 +469,7 @@ msgstr "Appliquer/Inverser la ligne" #: git-gui.sh:3137 msgid "Run Merge Tool" -msgstr "Lancer outil de merge" +msgstr "Lancer l'outil de fusion" #: git-gui.sh:3142 msgid "Use Remote Version" @@ -527,7 +527,7 @@ msgid "" "Tcl binary distributed by Cygwin." msgstr "" "\n" -"Ceci est du à un problème connu avec\n" +"Ceci est dû à un problème connu avec\n" "le binaire Tcl distribué par Cygwin." #: git-gui.sh:3336 @@ -630,11 +630,11 @@ msgstr "Fichier original :" #: lib/blame.tcl:1021 msgid "Cannot find HEAD commit:" -msgstr "Impossible de trouver le commit HEAD:" +msgstr "Impossible de trouver le commit HEAD :" #: lib/blame.tcl:1076 msgid "Cannot find parent commit:" -msgstr "Impossible de trouver le commit parent:" +msgstr "Impossible de trouver le commit parent :" #: lib/blame.tcl:1091 msgid "Unable to display parent" @@ -646,7 +646,7 @@ msgstr "Erreur lors du chargement des différences :" #: lib/blame.tcl:1232 msgid "Originally By:" -msgstr "A l'origine par :" +msgstr "À l'origine par :" #: lib/blame.tcl:1238 msgid "In File:" @@ -691,11 +691,11 @@ msgstr "Détacher de la branche locale" #: lib/branch_create.tcl:22 msgid "Create Branch" -msgstr "Créer branche" +msgstr "Créer une branche" #: lib/branch_create.tcl:27 msgid "Create New Branch" -msgstr "Créer nouvelle branche" +msgstr "Créer une nouvelle branche" #: lib/branch_create.tcl:31 lib/choose_repository.tcl:377 msgid "Create" @@ -719,7 +719,7 @@ msgstr "Révision initiale" #: lib/branch_create.tcl:72 msgid "Update Existing Branch:" -msgstr "Mettre à jour branche existante :" +msgstr "Mettre à jour une branche existante :" #: lib/branch_create.tcl:75 msgid "No" @@ -727,7 +727,7 @@ msgstr "Non" #: lib/branch_create.tcl:80 msgid "Fast Forward Only" -msgstr "Mise-à-jour rectiligne seulement (fast-forward)" +msgstr "Mise à jour rectiligne seulement (fast-forward)" #: lib/branch_create.tcl:85 lib/checkout_op.tcl:536 msgid "Reset" @@ -769,7 +769,7 @@ msgstr "Branches locales" #: lib/branch_delete.tcl:52 msgid "Delete Only If Merged Into" -msgstr "Supprimer seulement si fusionnée dans:" +msgstr "Supprimer seulement si fusionnée dans :" #: lib/branch_delete.tcl:54 msgid "Always (Do not perform merge test.)" @@ -780,23 +780,13 @@ msgstr "Toujours (Ne pas faire de test de fusion.)" msgid "The following branches are not completely merged into %s:" msgstr "Les branches suivantes ne sont pas complètement fusionnées dans %s :" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Récupérer des branches supprimées est difficile.\n" -"\n" -"Supprimer les branches sélectionnées ?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" "Failed to delete branches:\n" "%s" msgstr "" -"La suppression des branches suivantes a échouée :\n" +"La suppression des branches suivantes a échoué :\n" "%s" #: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22 @@ -902,11 +892,11 @@ msgstr "La stratégie de fusion '%s' n'est pas supportée." #: lib/checkout_op.tcl:261 #, tcl-format msgid "Failed to update '%s'." -msgstr "La mise à jour de '%s' a échouée." +msgstr "La mise à jour de '%s' a échoué." #: lib/checkout_op.tcl:273 msgid "Staging area (index) is already locked." -msgstr "L'index (staging area) est déjà vérouillé" +msgstr "L'index (staging area) est déjà verrouillé." #: lib/checkout_op.tcl:288 msgid "" @@ -918,7 +908,7 @@ msgid "" "The rescan will be automatically started now.\n" msgstr "" "L'état lors de la dernière synchronisation ne correspond plus à l'état du " -"dépôt\n" +"dépôt.\n" "\n" "Un autre programme Git a modifié ce dépôt depuis la dernière " "synchronisation. Une resynchronisation doit être effectuée avant de pouvoir " @@ -956,9 +946,9 @@ msgid "" "If you wanted to be on a branch, create one now starting from 'This Detached " "Checkout'." msgstr "" -"Vous n'êtes plus ur une branche locale.\n" +"Vous n'êtes plus sur une branche locale.\n" "\n" -"Si vous vouliez être sur une branche, créez en une maintenant en partant de " +"Si vous vouliez être sur une branche, créez-en une maintenant en partant de " "'Cet emprunt détaché'." #: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472 @@ -1000,7 +990,7 @@ msgstr "" "mis à jour avec succès, mais la mise à jour d'un fichier interne à Git a " "échouée.\n" "\n" -"Cela n'aurait pas du se produire. %s va abandonner et se terminer." +"Cela n'aurait pas dû se produire. %s va abandonner et se terminer." #: lib/choose_font.tcl:39 msgid "Select" @@ -1023,8 +1013,8 @@ msgid "" "This is example text.\n" "If you like this text, it can be your font." msgstr "" -"C'est un texte d'exemple.\n" -"Si vous aimez ce texte, vous pouvez choisir cette police" +"Ceci est un texte d'exemple.\n" +"Si vous aimez ce texte, vous pouvez choisir cette police." #: lib/choose_repository.tcl:28 msgid "Git Gui" @@ -1040,7 +1030,7 @@ msgstr "Nouveau..." #: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465 msgid "Clone Existing Repository" -msgstr "Cloner dépôt existant" +msgstr "Cloner un dépôt existant" #: lib/choose_repository.tcl:106 msgid "Clone..." @@ -1048,7 +1038,7 @@ msgstr "Cloner..." #: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983 msgid "Open Existing Repository" -msgstr "Ouvrir dépôt existant" +msgstr "Ouvrir un dépôt existant" #: lib/choose_repository.tcl:119 msgid "Open..." @@ -1056,17 +1046,17 @@ msgstr "Ouvrir..." #: lib/choose_repository.tcl:132 msgid "Recent Repositories" -msgstr "Dépôt récemment utilisés" +msgstr "Dépôts récemment utilisés" #: lib/choose_repository.tcl:138 msgid "Open Recent Repository:" -msgstr "Ouvrir dépôt récent :" +msgstr "Ouvrir un dépôt récent :" #: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309 #: lib/choose_repository.tcl:316 #, tcl-format msgid "Failed to create repository %s:" -msgstr "La création du dépôt %s a échouée :" +msgstr "La création du dépôt %s a échoué :" #: lib/choose_repository.tcl:387 msgid "Directory:" @@ -1093,11 +1083,11 @@ msgstr "Cloner" #: lib/choose_repository.tcl:473 msgid "Source Location:" -msgstr "Emplacement source:" +msgstr "Emplacement source :" #: lib/choose_repository.tcl:484 msgid "Target Directory:" -msgstr "Répertoire cible:" +msgstr "Répertoire cible :" #: lib/choose_repository.tcl:496 msgid "Clone Type:" @@ -1137,7 +1127,7 @@ msgstr "L'emplacement %s existe déjà." #: lib/choose_repository.tcl:622 msgid "Failed to configure origin" -msgstr "La configuration de l'origine a échouée." +msgstr "La configuration de l'origine a échoué." #: lib/choose_repository.tcl:634 msgid "Counting objects" @@ -1242,7 +1232,7 @@ msgstr "fichiers" #: lib/choose_repository.tcl:962 msgid "Initial file checkout failed." -msgstr "Chargement initial du fichier échoué." +msgstr "Le chargement initial du fichier a échoué." #: lib/choose_repository.tcl:978 msgid "Open" @@ -1284,7 +1274,7 @@ msgstr "Révision invalide : %s" #: lib/choose_rev.tcl:338 msgid "No revision selected." -msgstr "Pas de révision selectionnée." +msgstr "Pas de révision sélectionnée." #: lib/choose_rev.tcl:346 msgid "Revision expression is empty." @@ -1292,7 +1282,7 @@ msgstr "L'expression de révision est vide." #: lib/choose_rev.tcl:531 msgid "Updated" -msgstr "Mise-à-jour:" +msgstr "Mise à jour:" #: lib/choose_rev.tcl:559 msgid "URL" @@ -1320,8 +1310,8 @@ msgid "" msgstr "" "Impossible de corriger pendant une fusion.\n" "\n" -"Vous êtes actuellement au milieu d'une fusion qui n'a pas été completement " -"terminée. Vous ne pouvez pas corriger le commit précédant sauf si vous " +"Vous êtes actuellement au milieu d'une fusion qui n'a pas été complètement " +"terminée. Vous ne pouvez pas corriger le commit précédent sauf si vous " "abandonnez la fusion courante.\n" #: lib/commit.tcl:49 @@ -1409,7 +1399,7 @@ msgstr "" #: lib/commit.tcl:211 #, tcl-format msgid "warning: Tcl does not support encoding '%s'." -msgstr "attention : Tcl ne supporte pas l'encodage '%s'." +msgstr "attention : Tcl ne supporte pas le codage '%s'." #: lib/commit.tcl:227 msgid "Calling pre-commit hook..." @@ -1469,12 +1459,12 @@ msgstr "commit-tree a échoué :" #: lib/commit.tcl:373 msgid "update-ref failed:" -msgstr "update-ref a échoué" +msgstr "update-ref a échoué :" #: lib/commit.tcl:461 #, tcl-format msgid "Created commit %s: %s" -msgstr "Commit créé %s : %s" +msgstr "Commit %s créé : %s" #: lib/console.tcl:59 msgid "Working... please wait..." @@ -1581,24 +1571,24 @@ msgid "" "LOCAL: deleted\n" "REMOTE:\n" msgstr "" -"LOCAL: supprimé\n" -"DISTANT:\n" +"LOCAL : supprimé\n" +"DISTANT :\n" #: lib/diff.tcl:125 msgid "" "REMOTE: deleted\n" "LOCAL:\n" msgstr "" -"DISTANT: supprimé\n" -"LOCAL:\n" +"DISTANT : supprimé\n" +"LOCAL :\n" #: lib/diff.tcl:132 msgid "LOCAL:\n" -msgstr "LOCAL:\n" +msgstr "LOCAL :\n" #: lib/diff.tcl:135 msgid "REMOTE:\n" -msgstr "DISTANT:\n" +msgstr "DISTANT :\n" #: lib/diff.tcl:197 lib/diff.tcl:296 #, tcl-format @@ -1624,7 +1614,7 @@ msgid "" "* Showing only first %d bytes.\n" msgstr "" "* Le fichier non suivi fait %d octets.\n" -"* On montre seulement les premiers %d octets.\n" +"* Seuls les %d premiers octets sont montrés.\n" #: lib/diff.tcl:228 #, tcl-format @@ -1635,7 +1625,7 @@ msgid "" msgstr "" "\n" "* Fichier suivi raccourcis ici de %s.\n" -"* Pour voir le fichier entier, utiliser un éditeur externe.\n" +"* Pour voir le fichier entier, utilisez un éditeur externe.\n" #: lib/diff.tcl:436 msgid "Failed to unstage selected hunk." @@ -1680,7 +1670,7 @@ msgstr "Vous devez corriger les erreurs suivantes avant de pouvoir commiter." #: lib/index.tcl:6 msgid "Unable to unlock the index." -msgstr "Impossible de dévérouiller l'index." +msgstr "Impossible de déverrouiller l'index." #: lib/index.tcl:15 msgid "Index Error" @@ -1700,12 +1690,12 @@ msgstr "Continuer" #: lib/index.tcl:31 msgid "Unlock Index" -msgstr "Déverouiller l'index" +msgstr "Déverrouiller l'index" #: lib/index.tcl:287 #, tcl-format msgid "Unstaging %s from commit" -msgstr "Désindexation de: %s" +msgstr "Désindexation de : %s" #: lib/index.tcl:326 msgid "Ready to commit." @@ -1804,11 +1794,11 @@ msgid "" msgstr "" "Vous êtes au milieu d'une modification.\n" "\n" -"Le fichier %s est modifié.\n" +"Le fichier %s a été modifié.\n" "\n" "Vous devriez terminer le commit courant avant de lancer une fusion. En " "faisait comme cela, vous éviterez de devoir éventuellement abandonner une " -"fusion ayant échouée.\n" +"fusion ayant échoué.\n" #: lib/merge.tcl:107 #, tcl-format @@ -1826,7 +1816,7 @@ msgstr "La fusion s'est faite avec succès." #: lib/merge.tcl:133 msgid "Merge failed. Conflict resolution is required." -msgstr "La fusion a echouée. Il est nécessaire de résoudre les conflicts." +msgstr "La fusion a echoué. Il est nécessaire de résoudre les conflits." #: lib/merge.tcl:158 #, tcl-format @@ -1914,16 +1904,16 @@ msgid "" "\n" "This operation can be undone only by restarting the merge." msgstr "" -"Noter que le diff ne montre que les modifications en conflict.\n" +"Noter que le diff ne montre que les modifications en conflit.\n" "\n" "%s sera écrasé.\n" "\n" -"Cette opération ne peut être défaite qu'en relançant la fusion." +"Cette opération ne peut être inversée qu'en relançant la fusion." #: lib/mergetool.tcl:45 #, tcl-format msgid "File %s seems to have unresolved conflicts, still stage?" -msgstr "Le fichier %s semble avoir des conflicts non résolus, indéxer quand même ?" +msgstr "Le fichier %s semble avoir des conflits non résolus, indexer quand même ?" #: lib/mergetool.tcl:60 #, tcl-format @@ -1932,11 +1922,11 @@ msgstr "Ajouter une résolution pour %s" #: lib/mergetool.tcl:141 msgid "Cannot resolve deletion or link conflicts using a tool" -msgstr "Impossible de résoudre la suppression ou de relier des conflicts en utilisant un outil" +msgstr "Impossible de résoudre la suppression ou de relier des conflits en utilisant un outil" #: lib/mergetool.tcl:146 msgid "Conflict file does not exist" -msgstr "Le fichier en conflict n'existe pas." +msgstr "Le fichier en conflit n'existe pas." #: lib/mergetool.tcl:264 #, tcl-format @@ -1958,7 +1948,7 @@ msgid "" "Error retrieving versions:\n" "%s" msgstr "" -"Erreur lors de la récupération des versions:\n" +"Erreur lors de la récupération des versions :\n" "%s" #: lib/mergetool.tcl:343 @@ -1968,7 +1958,7 @@ msgid "" "\n" "%s" msgstr "" -"Impossible de lancer l'outil de fusion:\n" +"Impossible de lancer l'outil de fusion :\n" "\n" "%s" @@ -1983,12 +1973,12 @@ msgstr "L'outil de fusion a échoué." #: lib/option.tcl:11 #, tcl-format msgid "Invalid global encoding '%s'" -msgstr "Encodage global invalide '%s'" +msgstr "Codage global '%s' invalide" #: lib/option.tcl:19 #, tcl-format msgid "Invalid repo encoding '%s'" -msgstr "Encodage de dépôt invalide '%s'" +msgstr "Codage de dépôt '%s' invalide" #: lib/option.tcl:117 msgid "Restore Defaults" @@ -2001,7 +1991,7 @@ msgstr "Sauvegarder" #: lib/option.tcl:131 #, tcl-format msgid "%s Repository" -msgstr "Dépôt: %s" +msgstr "Dépôt : %s" #: lib/option.tcl:132 msgid "Global (All Repositories)" @@ -2069,7 +2059,7 @@ msgstr "Nouveau modèle de nom de branche" #: lib/option.tcl:155 msgid "Default File Contents Encoding" -msgstr "Encodage du contenu des fichiers par défaut" +msgstr "Codage du contenu des fichiers par défaut" #: lib/option.tcl:203 msgid "Change" @@ -2098,11 +2088,11 @@ msgstr "Préférences" #: lib/option.tcl:314 msgid "Failed to completely save options:" -msgstr "La sauvegarde complète des options a échouée :" +msgstr "La sauvegarde complète des options a échoué :" #: lib/remote.tcl:163 msgid "Remove Remote" -msgstr "Supprimer dépôt distant" +msgstr "Supprimer un dépôt distant" #: lib/remote.tcl:168 msgid "Prune from" @@ -2118,11 +2108,11 @@ msgstr "Pousser vers" #: lib/remote_add.tcl:19 msgid "Add Remote" -msgstr "Ajouter dépôt distant" +msgstr "Ajouter un dépôt distant" #: lib/remote_add.tcl:24 msgid "Add New Remote" -msgstr "Ajouter nouveau dépôt distant" +msgstr "Ajouter un nouveau dépôt distant" #: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 msgid "Add" @@ -2134,7 +2124,7 @@ msgstr "Détails des dépôts distants" #: lib/remote_add.tcl:50 msgid "Location:" -msgstr "Emplacement:" +msgstr "Emplacement :" #: lib/remote_add.tcl:62 msgid "Further Action" @@ -2146,7 +2136,7 @@ msgstr "Récupérer immédiatement" #: lib/remote_add.tcl:71 msgid "Initialize Remote Repository and Push" -msgstr "Initialiser dépôt distant et pousser" +msgstr "Initialiser un dépôt distant et pousser" #: lib/remote_add.tcl:77 msgid "Do Nothing Else Now" @@ -2193,7 +2183,7 @@ msgstr "Mise en place de %s (à %s)" #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 msgid "Delete Branch Remotely" -msgstr "Supprimer branche à distance" +msgstr "Supprimer une branche à distance" #: lib/remote_branch_delete.tcl:47 msgid "From Repository" @@ -2244,8 +2234,8 @@ msgid "" "One or more of the merge tests failed because you have not fetched the " "necessary commits. Try fetching from %s first." msgstr "" -"Une ou plusieurs des tests de fusion ont échoués parce que vous n'avez pas " -"récupéré les commits nécessaires. Essayez de récupéré à partir de %s d'abord." +"Un ou plusieurs des tests de fusion ont échoué parce que vous n'avez pas " +"récupéré les commits nécessaires. Essayez de récupérer à partir de %s d'abord." #: lib/remote_branch_delete.tcl:207 msgid "Please select one or more branches to delete." @@ -2257,14 +2247,14 @@ msgid "" "\n" "Delete the selected branches?" msgstr "" -"Récupérer des branches supprimées est difficile.\n" +"Il est difficile de récupérer des branches supprimées.\n" "\n" -"Souhaitez vous supprimer les branches sélectionnées ?" +"Supprimer les branches sélectionnées ?" #: lib/remote_branch_delete.tcl:226 #, tcl-format msgid "Deleting branches from %s" -msgstr "Supprimer les branches de %s" +msgstr "Suppression des branches de %s" #: lib/remote_branch_delete.tcl:286 msgid "No repository selected." @@ -2285,7 +2275,7 @@ msgstr "Suivant" #: lib/search.tcl:24 msgid "Prev" -msgstr "Précédant" +msgstr "Précédent" #: lib/search.tcl:25 msgid "Case-Sensitive" @@ -2293,7 +2283,7 @@ msgstr "Sensible à la casse" #: lib/shortcut.tcl:20 lib/shortcut.tcl:61 msgid "Cannot write shortcut:" -msgstr "Impossible d'écrire le raccourcis :" +msgstr "Impossible d'écrire le raccourci :" #: lib/shortcut.tcl:136 msgid "Cannot write icon:" @@ -2318,7 +2308,7 @@ msgstr "Réinitialisation du dictionnaire à %s." #: lib/spellcheck.tcl:73 msgid "Spell checker silently failed on startup" -msgstr "La vérification d'orthographe a échouée silentieusement au démarrage" +msgstr "La vérification d'orthographe a échoué silencieusement au démarrage" #: lib/spellcheck.tcl:80 msgid "Unrecognized spell checker" @@ -2351,11 +2341,11 @@ msgstr "Générer une clé" #: lib/sshkey.tcl:56 msgid "Copy To Clipboard" -msgstr "Copier dans le presse papier" +msgstr "Copier dans le presse-papier" #: lib/sshkey.tcl:70 msgid "Your OpenSSH Public Key" -msgstr "Votre clé publique Open SSH" +msgstr "Votre clé publique OpenSSH" #: lib/sshkey.tcl:78 msgid "Generating..." @@ -2368,7 +2358,7 @@ msgid "" "\n" "%s" msgstr "" -"Impossible de lancer ssh-keygen:\n" +"Impossible de lancer ssh-keygen :\n" "\n" "%s" @@ -2398,7 +2388,7 @@ msgstr "Lancer %s nécessite qu'un fichier soit sélectionné." #: lib/tools.tcl:90 #, tcl-format msgid "Are you sure you want to run %s?" -msgstr "Êtes vous sûr de vouloir lancer %s ?" +msgstr "Êtes-vous sûr de vouloir lancer %s ?" #: lib/tools.tcl:110 #, tcl-format @@ -2412,7 +2402,7 @@ msgstr "Lancement de : %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "L'outil a terminé avec succès : %s" #: lib/tools.tcl:151 @@ -2422,11 +2412,11 @@ msgstr "L'outil a échoué : %s" #: lib/tools_dlg.tcl:22 msgid "Add Tool" -msgstr "Ajouter outil" +msgstr "Ajouter un outil" #: lib/tools_dlg.tcl:28 msgid "Add New Tool Command" -msgstr "Ajouter nouvelle commande d'outil" +msgstr "Ajouter une nouvelle commande d'outil" #: lib/tools_dlg.tcl:33 msgid "Add globally" @@ -2438,7 +2428,7 @@ msgstr "Détails sur l'outil" #: lib/tools_dlg.tcl:48 msgid "Use '/' separators to create a submenu tree:" -msgstr "Utiliser les séparateurs '/' pour créer un arbre de sous menus :" +msgstr "Utiliser les séparateurs '/' pour créer un arbre de sous-menus :" #: lib/tools_dlg.tcl:61 msgid "Command:" @@ -2462,7 +2452,7 @@ msgstr "Ne pas montrer la fenêtre de sortie des commandes" #: lib/tools_dlg.tcl:97 msgid "Run only if a diff is selected ($FILENAME not empty)" -msgstr "Lancer seulement si un diff est selectionné ($FILENAME non vide)" +msgstr "Lancer seulement si un diff est sélectionné ($FILENAME non vide)" #: lib/tools_dlg.tcl:121 msgid "Please supply a name for the tool." @@ -2479,7 +2469,7 @@ msgid "" "Could not add tool:\n" "%s" msgstr "" -"Impossible d'ajouter l'outil:\n" +"Impossible d'ajouter l'outil :\n" "%s" #: lib/tools_dlg.tcl:190 diff --git a/git-gui/po/git-gui.pot b/git-gui/po/git-gui.pot index 15aea0dc64..53b7d3634d 100644 --- a/git-gui/po/git-gui.pot +++ b/git-gui/po/git-gui.pot @@ -753,13 +753,6 @@ msgstr "" msgid "The following branches are not completely merged into %s:" msgstr "" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2220,7 +2213,7 @@ msgstr "" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "" #: lib/tools.tcl:151 diff --git a/git-gui/po/hu.po b/git-gui/po/hu.po index f761b64152..0f87bc1cbe 100644 --- a/git-gui/po/hu.po +++ b/git-gui/po/hu.po @@ -776,16 +776,6 @@ msgstr "Mindig (Ne legyen merge teszt.)" msgid "The following branches are not completely merged into %s:" msgstr "A következő branchek nem teljesen lettek merge-ölve ebbe: %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"A törölt branchek visszaállítása bonyolult. \n" -"\n" -" Biztosan törli a kiválasztott brancheket?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2399,7 +2389,7 @@ msgstr "Futtatás: %s..." #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Az eszköz sikeresen befejeződött: %s" #: lib/tools.tcl:151 diff --git a/git-gui/po/it.po b/git-gui/po/it.po index 294e595887..762632c22f 100644 --- a/git-gui/po/it.po +++ b/git-gui/po/it.po @@ -778,16 +778,6 @@ msgstr "Sempre (Non effettuare verifiche di fusione)." msgid "The following branches are not completely merged into %s:" msgstr "I rami seguenti non sono stati fusi completamente in %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Ricomporre rami cancellati può essere complicato. \n" -"\n" -" Eliminare i rami selezionati?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2418,7 +2408,7 @@ msgstr "Eseguo: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Il programma esterno è terminato con successo: %s" #: lib/tools.tcl:151 diff --git a/git-gui/po/ja.po b/git-gui/po/ja.po index 09d60bef74..63c4695103 100644 --- a/git-gui/po/ja.po +++ b/git-gui/po/ja.po @@ -773,16 +773,6 @@ msgstr "無条件(マージテストしない)" msgid "The following branches are not completely merged into %s:" msgstr "以下のブランチは %s に完全にマージされていません:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"ブランチを削除すると元に戻すのは困難です。 \n" -"\n" -" 選択したブランチを削除しますか?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2382,7 +2372,7 @@ msgstr "実行中: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "ツールが完了しました: %s" #: lib/tools.tcl:151 diff --git a/git-gui/po/nb.po b/git-gui/po/nb.po index 1c5137d84c..6de93c28c2 100644 --- a/git-gui/po/nb.po +++ b/git-gui/po/nb.po @@ -761,16 +761,6 @@ msgstr "Alltid (Ikke utfør sammenslåingstest.)" msgid "The following branches are not completely merged into %s:" msgstr "Følgende grener er ikke fullstendig slått sammen med %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Gjenoppretting av fjernede grener er vanskelig. \n" -"\n" -" Fjern valgte grener?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2331,7 +2321,7 @@ msgstr "Kjører: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Verktøyet ble fullført med suksess: %s" #: lib/tools.tcl:151 diff --git a/git-gui/po/ru.po b/git-gui/po/ru.po index db55b3e0a6..0ffc4a418f 100644 --- a/git-gui/po/ru.po +++ b/git-gui/po/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: git-gui\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-03-14 07:18+0100\n" +"POT-Creation-Date: 2008-12-08 08:31-0800\n" "PO-Revision-Date: 2007-10-22 22:30-0200\n" "Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n" "Language-Team: Russian Translation <git@vger.kernel.org>\n" @@ -15,33 +15,33 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: git-gui.sh:41 git-gui.sh:634 git-gui.sh:648 git-gui.sh:661 git-gui.sh:744 -#: git-gui.sh:763 +#: git-gui.sh:41 git-gui.sh:737 git-gui.sh:751 git-gui.sh:764 git-gui.sh:847 +#: git-gui.sh:866 msgid "git-gui: fatal error" msgstr "git-gui: критическая ошибка" -#: git-gui.sh:593 +#: git-gui.sh:689 #, tcl-format msgid "Invalid font specified in %s:" msgstr "В %s установлен неверный шрифт:" -#: git-gui.sh:620 +#: git-gui.sh:723 msgid "Main Font" msgstr "Шрифт интерфейса" -#: git-gui.sh:621 +#: git-gui.sh:724 msgid "Diff/Console Font" msgstr "Шрифт консоли и изменений (diff)" -#: git-gui.sh:635 +#: git-gui.sh:738 msgid "Cannot find git in PATH." msgstr "git не найден в PATH." -#: git-gui.sh:662 +#: git-gui.sh:765 msgid "Cannot parse Git version string:" msgstr "Невозможно распознать строку версии Git: " -#: git-gui.sh:680 +#: git-gui.sh:783 #, tcl-format msgid "" "Git version cannot be determined.\n" @@ -53,384 +53,451 @@ msgid "" "Assume '%s' is version 1.5.0?\n" msgstr "" "Невозможно определить версию Git\n" +"\n" "%s указывает на версию '%s'.\n" "\n" "для %s требуется версия Git, начиная с 1.5.0\n" "\n" "Принять '%s' как версию 1.5.0?\n" -#: git-gui.sh:918 +#: git-gui.sh:1062 msgid "Git directory not found:" msgstr "Каталог Git не найден:" -#: git-gui.sh:925 +#: git-gui.sh:1069 msgid "Cannot move to top of working directory:" msgstr "Невозможно перейти к корню рабочего каталога репозитория: " -#: git-gui.sh:932 +#: git-gui.sh:1076 msgid "Cannot use funny .git directory:" -msgstr "Каталог.git испорчен: " +msgstr "Каталог .git испорчен: " -#: git-gui.sh:937 +#: git-gui.sh:1081 msgid "No working directory" msgstr "Отсутствует рабочий каталог" -#: git-gui.sh:1084 lib/checkout_op.tcl:283 +#: git-gui.sh:1247 lib/checkout_op.tcl:305 msgid "Refreshing file status..." msgstr "Обновление информации о состоянии файлов..." -#: git-gui.sh:1149 +#: git-gui.sh:1303 msgid "Scanning for modified files ..." msgstr "Поиск измененных файлов..." -#: git-gui.sh:1324 lib/browser.tcl:246 +#: git-gui.sh:1367 +msgid "Calling prepare-commit-msg hook..." +msgstr "Вызов программы поддержки репозитория prepare-commit-msg..." + +#: git-gui.sh:1384 +msgid "Commit declined by prepare-commit-msg hook." +msgstr "Сохранение прервано программой поддержки репозитория prepare-commit-msg" + +#: git-gui.sh:1542 lib/browser.tcl:246 msgid "Ready." msgstr "Готово." -#: git-gui.sh:1590 +#: git-gui.sh:1819 msgid "Unmodified" msgstr "Не изменено" -#: git-gui.sh:1592 +#: git-gui.sh:1821 msgid "Modified, not staged" msgstr "Изменено, не подготовлено" -#: git-gui.sh:1593 git-gui.sh:1598 +#: git-gui.sh:1822 git-gui.sh:1830 msgid "Staged for commit" msgstr "Подготовлено для сохранения" -#: git-gui.sh:1594 git-gui.sh:1599 +#: git-gui.sh:1823 git-gui.sh:1831 msgid "Portions staged for commit" msgstr "Части, подготовленные для сохранения" -#: git-gui.sh:1595 git-gui.sh:1600 +#: git-gui.sh:1824 git-gui.sh:1832 msgid "Staged for commit, missing" msgstr "Подготовлено для сохранения, отсутствует" -#: git-gui.sh:1597 +#: git-gui.sh:1826 +msgid "File type changed, not staged" +msgstr "Тип файла изменён, не подготовлено" + +#: git-gui.sh:1827 +msgid "File type changed, staged" +msgstr "Тип файла изменён, подготовлено" + +#: git-gui.sh:1829 msgid "Untracked, not staged" msgstr "Не отслеживается, не подготовлено" -#: git-gui.sh:1602 +#: git-gui.sh:1834 msgid "Missing" msgstr "Отсутствует" -#: git-gui.sh:1603 +#: git-gui.sh:1835 msgid "Staged for removal" msgstr "Подготовлено для удаления" -#: git-gui.sh:1604 +#: git-gui.sh:1836 msgid "Staged for removal, still present" msgstr "Подготовлено для удаления, еще не удалено" -#: git-gui.sh:1606 git-gui.sh:1607 git-gui.sh:1608 git-gui.sh:1609 +#: git-gui.sh:1838 git-gui.sh:1839 git-gui.sh:1840 git-gui.sh:1841 +#: git-gui.sh:1842 git-gui.sh:1843 msgid "Requires merge resolution" -msgstr "Требуется разрешение конфликта при объединении" +msgstr "Требуется разрешение конфликта при слиянии" -#: git-gui.sh:1644 +#: git-gui.sh:1878 msgid "Starting gitk... please wait..." -msgstr "Запускается gitk... пожалуйста, ждите..." +msgstr "Запускается gitk... Подождите, пожалуйста..." -#: git-gui.sh:1653 -#, tcl-format -msgid "" -"Unable to start gitk:\n" -"\n" -"%s does not exist" -msgstr "" -"Не удалось запустить gitk:\n" -"\n" -"%s не существует" +#: git-gui.sh:1887 +msgid "Couldn't find gitk in PATH" +msgstr "gitk не найден в PATH." -#: git-gui.sh:1860 lib/choose_repository.tcl:36 +#: git-gui.sh:2280 lib/choose_repository.tcl:36 msgid "Repository" msgstr "Репозиторий" -#: git-gui.sh:1861 +#: git-gui.sh:2281 msgid "Edit" msgstr "Редактировать" -#: git-gui.sh:1863 lib/choose_rev.tcl:561 +#: git-gui.sh:2283 lib/choose_rev.tcl:561 msgid "Branch" msgstr "Ветвь" -#: git-gui.sh:1866 lib/choose_rev.tcl:548 +#: git-gui.sh:2286 lib/choose_rev.tcl:548 msgid "Commit@@noun" msgstr "Состояние" -#: git-gui.sh:1869 lib/merge.tcl:120 lib/merge.tcl:149 lib/merge.tcl:167 +#: git-gui.sh:2289 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 msgid "Merge" -msgstr "Объединить" +msgstr "Слияние" -#: git-gui.sh:1870 lib/choose_rev.tcl:557 +#: git-gui.sh:2290 lib/choose_rev.tcl:557 msgid "Remote" msgstr "Внешние репозитории" -#: git-gui.sh:1879 +#: git-gui.sh:2293 +msgid "Tools" +msgstr "Вспомогательные операции" + +#: git-gui.sh:2302 +msgid "Explore Working Copy" +msgstr "Просмотр рабочего каталога" + +#: git-gui.sh:2307 msgid "Browse Current Branch's Files" msgstr "Просмотреть файлы текущей ветви" -#: git-gui.sh:1883 +#: git-gui.sh:2311 msgid "Browse Branch Files..." msgstr "Показать файлы ветви..." -#: git-gui.sh:1888 +#: git-gui.sh:2316 msgid "Visualize Current Branch's History" -msgstr "История текущей ветви наглядно" +msgstr "Показать историю текущей ветви" -#: git-gui.sh:1892 +#: git-gui.sh:2320 msgid "Visualize All Branch History" -msgstr "История всех ветвей наглядно" +msgstr "Показать историю всех ветвей" -#: git-gui.sh:1899 +#: git-gui.sh:2327 #, tcl-format msgid "Browse %s's Files" msgstr "Показать файлы ветви %s" -#: git-gui.sh:1901 +#: git-gui.sh:2329 #, tcl-format msgid "Visualize %s's History" -msgstr "История ветви %s наглядно" +msgstr "Показать историю ветви %s" -#: git-gui.sh:1906 lib/database.tcl:27 lib/database.tcl:67 +#: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67 msgid "Database Statistics" msgstr "Статистика базы данных" -#: git-gui.sh:1909 lib/database.tcl:34 +#: git-gui.sh:2337 lib/database.tcl:34 msgid "Compress Database" msgstr "Сжать базу данных" -#: git-gui.sh:1912 +#: git-gui.sh:2340 msgid "Verify Database" msgstr "Проверить базу данных" -#: git-gui.sh:1919 git-gui.sh:1923 git-gui.sh:1927 lib/shortcut.tcl:7 +#: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7 #: lib/shortcut.tcl:39 lib/shortcut.tcl:71 msgid "Create Desktop Icon" msgstr "Создать ярлык на рабочем столе" -#: git-gui.sh:1932 lib/choose_repository.tcl:177 lib/choose_repository.tcl:185 +#: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 msgid "Quit" msgstr "Выход" -#: git-gui.sh:1939 +#: git-gui.sh:2371 msgid "Undo" msgstr "Отменить" -#: git-gui.sh:1942 +#: git-gui.sh:2374 msgid "Redo" msgstr "Повторить" -#: git-gui.sh:1946 git-gui.sh:2443 +#: git-gui.sh:2378 git-gui.sh:2937 msgid "Cut" msgstr "Вырезать" -#: git-gui.sh:1949 git-gui.sh:2446 git-gui.sh:2520 git-gui.sh:2614 +#: git-gui.sh:2381 git-gui.sh:2940 git-gui.sh:3014 git-gui.sh:3096 #: lib/console.tcl:69 msgid "Copy" msgstr "Копировать" -#: git-gui.sh:1952 git-gui.sh:2449 +#: git-gui.sh:2384 git-gui.sh:2943 msgid "Paste" msgstr "Вставить" -#: git-gui.sh:1955 git-gui.sh:2452 lib/branch_delete.tcl:26 +#: git-gui.sh:2387 git-gui.sh:2946 lib/branch_delete.tcl:26 #: lib/remote_branch_delete.tcl:38 msgid "Delete" msgstr "Удалить" -#: git-gui.sh:1959 git-gui.sh:2456 git-gui.sh:2618 lib/console.tcl:71 +#: git-gui.sh:2391 git-gui.sh:2950 git-gui.sh:3100 lib/console.tcl:71 msgid "Select All" msgstr "Выделить все" -#: git-gui.sh:1968 +#: git-gui.sh:2400 msgid "Create..." msgstr "Создать..." -#: git-gui.sh:1974 +#: git-gui.sh:2406 msgid "Checkout..." msgstr "Перейти..." -#: git-gui.sh:1980 +#: git-gui.sh:2412 msgid "Rename..." msgstr "Переименовать..." -#: git-gui.sh:1985 git-gui.sh:2085 +#: git-gui.sh:2417 msgid "Delete..." msgstr "Удалить..." -#: git-gui.sh:1990 +#: git-gui.sh:2422 msgid "Reset..." msgstr "Сбросить..." -#: git-gui.sh:2002 git-gui.sh:2389 +#: git-gui.sh:2432 +msgid "Done" +msgstr "Завершено" + +#: git-gui.sh:2434 +msgid "Commit@@verb" +msgstr "Сохранить" + +#: git-gui.sh:2443 git-gui.sh:2878 msgid "New Commit" msgstr "Новое состояние" -#: git-gui.sh:2010 git-gui.sh:2396 +#: git-gui.sh:2451 git-gui.sh:2885 msgid "Amend Last Commit" msgstr "Исправить последнее состояние" -#: git-gui.sh:2019 git-gui.sh:2356 lib/remote_branch_delete.tcl:99 +#: git-gui.sh:2461 git-gui.sh:2839 lib/remote_branch_delete.tcl:99 msgid "Rescan" msgstr "Перечитать" -#: git-gui.sh:2025 +#: git-gui.sh:2467 msgid "Stage To Commit" msgstr "Подготовить для сохранения" -#: git-gui.sh:2031 +#: git-gui.sh:2473 msgid "Stage Changed Files To Commit" msgstr "Подготовить измененные файлы для сохранения" -#: git-gui.sh:2037 +#: git-gui.sh:2479 msgid "Unstage From Commit" msgstr "Убрать из подготовленного" -#: git-gui.sh:2042 lib/index.tcl:395 +#: git-gui.sh:2484 lib/index.tcl:410 msgid "Revert Changes" msgstr "Отменить изменения" -#: git-gui.sh:2049 git-gui.sh:2368 git-gui.sh:2467 -msgid "Sign Off" -msgstr "Подписать" +#: git-gui.sh:2491 git-gui.sh:3083 +msgid "Show Less Context" +msgstr "Меньше контекста" -#: git-gui.sh:2053 git-gui.sh:2372 -msgid "Commit@@verb" -msgstr "Сохранить" +#: git-gui.sh:2495 git-gui.sh:3087 +msgid "Show More Context" +msgstr "Больше контекста" + +#: git-gui.sh:2502 git-gui.sh:2852 git-gui.sh:2961 +msgid "Sign Off" +msgstr "Вставить Signed-off-by" -#: git-gui.sh:2064 +#: git-gui.sh:2518 msgid "Local Merge..." -msgstr "Локальное объединение..." +msgstr "Локальное слияние..." -#: git-gui.sh:2069 +#: git-gui.sh:2523 msgid "Abort Merge..." -msgstr "Прервать объединение..." +msgstr "Прервать слияние..." + +#: git-gui.sh:2535 git-gui.sh:2575 +msgid "Add..." +msgstr "Добавить..." -#: git-gui.sh:2081 +#: git-gui.sh:2539 msgid "Push..." msgstr "Отправить..." -#: git-gui.sh:2092 lib/choose_repository.tcl:41 -msgid "Apple" -msgstr "" +#: git-gui.sh:2543 +msgid "Delete Branch..." +msgstr "Удалить ветвь..." -#: git-gui.sh:2095 git-gui.sh:2117 lib/about.tcl:14 -#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:50 +#: git-gui.sh:2553 git-gui.sh:2589 lib/about.tcl:14 +#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 #, tcl-format msgid "About %s" msgstr "О %s" -#: git-gui.sh:2099 +#: git-gui.sh:2557 msgid "Preferences..." msgstr "Настройки..." -#: git-gui.sh:2107 git-gui.sh:2639 +#: git-gui.sh:2565 git-gui.sh:3129 msgid "Options..." msgstr "Настройки..." -#: git-gui.sh:2113 lib/choose_repository.tcl:47 +#: git-gui.sh:2576 +msgid "Remove..." +msgstr "Удалить..." + +#: git-gui.sh:2585 lib/choose_repository.tcl:50 msgid "Help" msgstr "Помощь" -#: git-gui.sh:2154 +#: git-gui.sh:2611 msgid "Online Documentation" msgstr "Документация в интернете" -#: git-gui.sh:2238 +#: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 +msgid "Show SSH Key" +msgstr "Показать ключ SSH" + +#: git-gui.sh:2721 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" msgstr "критическая ошибка: %s: нет такого файла или каталога" -#: git-gui.sh:2271 +#: git-gui.sh:2754 msgid "Current Branch:" msgstr "Текущая ветвь:" -#: git-gui.sh:2292 +#: git-gui.sh:2775 msgid "Staged Changes (Will Commit)" msgstr "Подготовлено (будет сохранено)" -#: git-gui.sh:2312 +#: git-gui.sh:2795 msgid "Unstaged Changes" msgstr "Изменено (не будет сохранено)" -#: git-gui.sh:2362 +#: git-gui.sh:2845 msgid "Stage Changed" msgstr "Подготовить все" -#: git-gui.sh:2378 lib/transport.tcl:93 lib/transport.tcl:182 +#: git-gui.sh:2864 lib/transport.tcl:104 lib/transport.tcl:193 msgid "Push" msgstr "Отправить" -#: git-gui.sh:2408 +#: git-gui.sh:2899 msgid "Initial Commit Message:" msgstr "Комментарий к первому состоянию:" -#: git-gui.sh:2409 +#: git-gui.sh:2900 msgid "Amended Commit Message:" msgstr "Комментарий к исправленному состоянию:" -#: git-gui.sh:2410 +#: git-gui.sh:2901 msgid "Amended Initial Commit Message:" msgstr "Комментарий к исправленному первоначальному состоянию:" -#: git-gui.sh:2411 +#: git-gui.sh:2902 msgid "Amended Merge Commit Message:" -msgstr "Комментарий к исправленному объединению:" +msgstr "Комментарий к исправленному слиянию:" -#: git-gui.sh:2412 +#: git-gui.sh:2903 msgid "Merge Commit Message:" -msgstr "Комментарий к объединению:" +msgstr "Комментарий к слиянию:" -#: git-gui.sh:2413 +#: git-gui.sh:2904 msgid "Commit Message:" msgstr "Комментарий к состоянию:" -#: git-gui.sh:2459 git-gui.sh:2622 lib/console.tcl:73 +#: git-gui.sh:2953 git-gui.sh:3104 lib/console.tcl:73 msgid "Copy All" msgstr "Копировать все" -#: git-gui.sh:2483 lib/blame.tcl:107 +#: git-gui.sh:2977 lib/blame.tcl:104 msgid "File:" msgstr "Файл:" -#: git-gui.sh:2589 -msgid "Apply/Reverse Hunk" -msgstr "Применить/Убрать изменение" - -#: git-gui.sh:2595 -msgid "Show Less Context" -msgstr "Меньше контекста" - -#: git-gui.sh:2602 -msgid "Show More Context" -msgstr "Больше контекста" - -#: git-gui.sh:2610 +#: git-gui.sh:3092 msgid "Refresh" msgstr "Обновить" -#: git-gui.sh:2631 +#: git-gui.sh:3113 msgid "Decrease Font Size" msgstr "Уменьшить размер шрифта" -#: git-gui.sh:2635 +#: git-gui.sh:3117 msgid "Increase Font Size" msgstr "Увеличить размер шрифта" -#: git-gui.sh:2646 +#: git-gui.sh:3125 lib/blame.tcl:281 +msgid "Encoding" +msgstr "Кодировка" + +#: git-gui.sh:3136 +msgid "Apply/Reverse Hunk" +msgstr "Применить/Убрать изменение" + +#: git-gui.sh:3141 +msgid "Apply/Reverse Line" +msgstr "Применить/Убрать строку" + +#: git-gui.sh:3151 +msgid "Run Merge Tool" +msgstr "Запустить программу слияния" + +#: git-gui.sh:3156 +msgid "Use Remote Version" +msgstr "Взять внешнюю версию" + +#: git-gui.sh:3160 +msgid "Use Local Version" +msgstr "Взять локальную версию" + +#: git-gui.sh:3164 +msgid "Revert To Base" +msgstr "Отменить изменения" + +#: git-gui.sh:3183 msgid "Unstage Hunk From Commit" msgstr "Не сохранять часть" -#: git-gui.sh:2648 +#: git-gui.sh:3184 +msgid "Unstage Line From Commit" +msgstr "Убрать строку из подготовленного" + +#: git-gui.sh:3186 msgid "Stage Hunk For Commit" msgstr "Подготовить часть для сохранения" -#: git-gui.sh:2667 +#: git-gui.sh:3187 +msgid "Stage Line For Commit" +msgstr "Подготовить строку для сохранения" + +#: git-gui.sh:3210 msgid "Initializing..." msgstr "Инициализация..." -#: git-gui.sh:2762 +#: git-gui.sh:3315 #, tcl-format msgid "" "Possible environment issues exist.\n" @@ -447,7 +514,7 @@ msgstr "" "запущенными из %s\n" "\n" -#: git-gui.sh:2792 +#: git-gui.sh:3345 msgid "" "\n" "This is due to a known issue with the\n" @@ -457,7 +524,7 @@ msgstr "" "Это известная проблема с Tcl,\n" "распространяемым Cygwin." -#: git-gui.sh:2797 +#: git-gui.sh:3350 #, tcl-format msgid "" "\n" @@ -478,64 +545,108 @@ msgstr "" msgid "git-gui - a graphical user interface for Git." msgstr "git-gui - графический пользовательский интерфейс к Git." -#: lib/blame.tcl:77 +#: lib/blame.tcl:72 msgid "File Viewer" msgstr "Просмотр файла" -#: lib/blame.tcl:81 +#: lib/blame.tcl:78 msgid "Commit:" msgstr "Сохраненное состояние:" -#: lib/blame.tcl:264 +#: lib/blame.tcl:271 msgid "Copy Commit" msgstr "Скопировать SHA-1" -#: lib/blame.tcl:384 +#: lib/blame.tcl:275 +msgid "Find Text..." +msgstr "Найти текст..." + +#: lib/blame.tcl:284 +msgid "Do Full Copy Detection" +msgstr "Провести полный поиск копий" + +#: lib/blame.tcl:288 +msgid "Show History Context" +msgstr "Показать исторический контекст" + +#: lib/blame.tcl:291 +msgid "Blame Parent Commit" +msgstr "Рассмотреть состояние предка" + +#: lib/blame.tcl:450 #, tcl-format msgid "Reading %s..." msgstr "Чтение %s..." -#: lib/blame.tcl:488 +#: lib/blame.tcl:557 msgid "Loading copy/move tracking annotations..." msgstr "Загрузка аннотации копирований/переименований..." -#: lib/blame.tcl:508 +#: lib/blame.tcl:577 msgid "lines annotated" msgstr "строк прокомментировано" -#: lib/blame.tcl:689 +#: lib/blame.tcl:769 msgid "Loading original location annotations..." msgstr "Загрузка аннотаций первоначального положения объекта..." -#: lib/blame.tcl:692 +#: lib/blame.tcl:772 msgid "Annotation complete." msgstr "Аннотация завершена." -#: lib/blame.tcl:746 +#: lib/blame.tcl:802 +msgid "Busy" +msgstr "Занят" + +#: lib/blame.tcl:803 +msgid "Annotation process is already running." +msgstr "Аннотация уже запущена" + +#: lib/blame.tcl:842 +msgid "Running thorough copy detection..." +msgstr "Выполнение полного поиска копий..." + +#: lib/blame.tcl:910 msgid "Loading annotation..." msgstr "Загрузка аннотации..." -#: lib/blame.tcl:802 +#: lib/blame.tcl:963 msgid "Author:" msgstr "Автор:" -#: lib/blame.tcl:806 +#: lib/blame.tcl:967 msgid "Committer:" msgstr "Сохранил:" -#: lib/blame.tcl:811 +#: lib/blame.tcl:972 msgid "Original File:" msgstr "Исходный файл:" -#: lib/blame.tcl:925 +#: lib/blame.tcl:1020 +msgid "Cannot find HEAD commit:" +msgstr "Невозможно найти текущее состояние:" + +#: lib/blame.tcl:1075 +msgid "Cannot find parent commit:" +msgstr "Невозможно найти состояние предка:" + +#: lib/blame.tcl:1090 +msgid "Unable to display parent" +msgstr "Не могу показать предка" + +#: lib/blame.tcl:1091 lib/diff.tcl:297 +msgid "Error loading diff:" +msgstr "Ошибка загрузки изменений:" + +#: lib/blame.tcl:1231 msgid "Originally By:" msgstr "Источник:" -#: lib/blame.tcl:931 +#: lib/blame.tcl:1237 msgid "In File:" msgstr "Файл:" -#: lib/blame.tcl:936 +#: lib/blame.tcl:1242 msgid "Copied Or Moved Here By:" msgstr "Скопировано/перемещено в:" @@ -549,16 +660,18 @@ msgstr "Перейти" #: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35 #: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282 -#: lib/checkout_op.tcl:522 lib/choose_font.tcl:43 lib/merge.tcl:171 -#: lib/option.tcl:103 lib/remote_branch_delete.tcl:42 lib/transport.tcl:97 +#: lib/checkout_op.tcl:544 lib/choose_font.tcl:43 lib/merge.tcl:172 +#: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42 +#: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352 +#: lib/transport.tcl:108 msgid "Cancel" -msgstr "Отменить" +msgstr "Отмена" -#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 +#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328 msgid "Revision" msgstr "Версия" -#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:242 +#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280 msgid "Options" msgstr "Настройки" @@ -578,7 +691,7 @@ msgstr "Создание ветви" msgid "Create New Branch" msgstr "Создать новую ветвь" -#: lib/branch_create.tcl:31 lib/choose_repository.tcl:371 +#: lib/branch_create.tcl:31 lib/choose_repository.tcl:377 msgid "Create" msgstr "Создать" @@ -586,7 +699,7 @@ msgstr "Создать" msgid "Branch Name" msgstr "Название ветви" -#: lib/branch_create.tcl:43 +#: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50 msgid "Name:" msgstr "Название:" @@ -610,7 +723,7 @@ msgstr "Нет" msgid "Fast Forward Only" msgstr "Только Fast Forward" -#: lib/branch_create.tcl:85 lib/checkout_op.tcl:514 +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536 msgid "Reset" msgstr "Сброс" @@ -650,26 +763,16 @@ msgstr "Локальные ветви" #: lib/branch_delete.tcl:52 msgid "Delete Only If Merged Into" -msgstr "Удалить только в случае, если было объединение с" +msgstr "Удалить только в случае, если было слияние с" #: lib/branch_delete.tcl:54 msgid "Always (Do not perform merge test.)" -msgstr "Всегда (не выполнять проверку на объединение)" +msgstr "Всегда (не выполнять проверку на слияние)" #: lib/branch_delete.tcl:103 #, tcl-format msgid "The following branches are not completely merged into %s:" -msgstr "Следующие ветви объединены с %s не полностью:" - -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Восстанавливать удаленные ветви сложно. \n" -"\n" -" Удалить выбранные ветви?" +msgstr "Ветви, которые не полностью сливаются с %s:" #: lib/branch_delete.tcl:141 #, tcl-format @@ -700,7 +803,7 @@ msgstr "Новое название:" msgid "Please select a branch to rename." msgstr "Укажите ветвь для переименования." -#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:179 +#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:201 #, tcl-format msgid "Branch '%s' already exists." msgstr "Ветвь '%s' уже существует." @@ -731,32 +834,38 @@ msgstr "[На уровень выше]" msgid "Browse Branch Files" msgstr "Показать файлы ветви" -#: lib/browser.tcl:278 lib/choose_repository.tcl:387 -#: lib/choose_repository.tcl:474 lib/choose_repository.tcl:484 -#: lib/choose_repository.tcl:987 +#: lib/browser.tcl:278 lib/choose_repository.tcl:394 +#: lib/choose_repository.tcl:480 lib/choose_repository.tcl:491 +#: lib/choose_repository.tcl:995 msgid "Browse" msgstr "Показать" -#: lib/checkout_op.tcl:79 +#: lib/checkout_op.tcl:84 #, tcl-format msgid "Fetching %s from %s" msgstr "Получение %s из %s " -#: lib/checkout_op.tcl:127 +#: lib/checkout_op.tcl:132 #, tcl-format msgid "fatal: Cannot resolve %s" msgstr "критическая ошибка: невозможно разрешить %s" -#: lib/checkout_op.tcl:140 lib/console.tcl:81 lib/database.tcl:31 +#: lib/checkout_op.tcl:145 lib/console.tcl:81 lib/database.tcl:31 +#: lib/sshkey.tcl:53 msgid "Close" msgstr "Закрыть" -#: lib/checkout_op.tcl:169 +#: lib/checkout_op.tcl:174 #, tcl-format msgid "Branch '%s' does not exist." msgstr "Ветвь '%s' не существует " -#: lib/checkout_op.tcl:206 +#: lib/checkout_op.tcl:193 +#, tcl-format +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "Ошибка создания упрощённой конфигурации git pull для '%s'." + +#: lib/checkout_op.tcl:228 #, tcl-format msgid "" "Branch '%s' already exists.\n" @@ -767,23 +876,23 @@ msgstr "" "Ветвь '%s' уже существует.\n" "\n" "Она не может быть прокручена(fast-forward) к %s.\n" -"Требуется объединение." +"Требуется слияние." -#: lib/checkout_op.tcl:220 +#: lib/checkout_op.tcl:242 #, tcl-format msgid "Merge strategy '%s' not supported." -msgstr "Стратегия объединения '%s' не поддерживается." +msgstr "Неизвестная стратегия слияния: '%s'." -#: lib/checkout_op.tcl:239 +#: lib/checkout_op.tcl:261 #, tcl-format msgid "Failed to update '%s'." msgstr "Не удалось обновить '%s'." -#: lib/checkout_op.tcl:251 +#: lib/checkout_op.tcl:273 msgid "Staging area (index) is already locked." msgstr "Рабочая область заблокирована другим процессом." -#: lib/checkout_op.tcl:266 +#: lib/checkout_op.tcl:288 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -799,30 +908,30 @@ msgstr "" "\n" "Это будет сделано сейчас автоматически.\n" -#: lib/checkout_op.tcl:322 +#: lib/checkout_op.tcl:344 #, tcl-format msgid "Updating working directory to '%s'..." msgstr "Обновление рабочего каталога из '%s'..." -#: lib/checkout_op.tcl:323 +#: lib/checkout_op.tcl:345 msgid "files checked out" msgstr "файлы извлечены" -#: lib/checkout_op.tcl:353 +#: lib/checkout_op.tcl:375 #, tcl-format msgid "Aborted checkout of '%s' (file level merging is required)." -msgstr "Прерван переход на '%s' (требуется объединение на уровне файлов)" +msgstr "Прерван переход на '%s' (требуется слияние содержания файлов)" -#: lib/checkout_op.tcl:354 +#: lib/checkout_op.tcl:376 msgid "File level merge required." -msgstr "Требуется объединение на уровне файлов." +msgstr "Требуется слияние содержания файлов." -#: lib/checkout_op.tcl:358 +#: lib/checkout_op.tcl:380 #, tcl-format msgid "Staying on branch '%s'." msgstr "Ветвь '%s' остается текущей." -#: lib/checkout_op.tcl:429 +#: lib/checkout_op.tcl:451 msgid "" "You are no longer on a local branch.\n" "\n" @@ -834,30 +943,30 @@ msgstr "" "Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, " "начиная с 'Текущего отсоединенного состояния'." -#: lib/checkout_op.tcl:446 lib/checkout_op.tcl:450 +#: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472 #, tcl-format msgid "Checked out '%s'." msgstr "Ветвь '%s' сделана текущей." -#: lib/checkout_op.tcl:478 +#: lib/checkout_op.tcl:500 #, tcl-format msgid "Resetting '%s' to '%s' will lose the following commits:" msgstr "Сброс '%s' в '%s' приведет к потере следующих сохраненных состояний: " -#: lib/checkout_op.tcl:500 +#: lib/checkout_op.tcl:522 msgid "Recovering lost commits may not be easy." msgstr "Восстановить потерянные сохраненные состояния будет сложно." -#: lib/checkout_op.tcl:505 +#: lib/checkout_op.tcl:527 #, tcl-format msgid "Reset '%s'?" msgstr "Сбросить '%s'?" -#: lib/checkout_op.tcl:510 lib/merge.tcl:163 +#: lib/checkout_op.tcl:532 lib/merge.tcl:164 lib/tools_dlg.tcl:343 msgid "Visualize" msgstr "Наглядно" -#: lib/checkout_op.tcl:578 +#: lib/checkout_op.tcl:600 #, tcl-format msgid "" "Failed to set current branch.\n" @@ -900,224 +1009,228 @@ msgstr "" #: lib/choose_repository.tcl:28 msgid "Git Gui" -msgstr "" +msgstr "Git Gui" -#: lib/choose_repository.tcl:81 lib/choose_repository.tcl:376 +#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:382 msgid "Create New Repository" msgstr "Создать новый репозиторий" -#: lib/choose_repository.tcl:87 +#: lib/choose_repository.tcl:93 msgid "New..." msgstr "Новый..." -#: lib/choose_repository.tcl:94 lib/choose_repository.tcl:460 +#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465 msgid "Clone Existing Repository" msgstr "Склонировать существующий репозиторий" -#: lib/choose_repository.tcl:100 +#: lib/choose_repository.tcl:106 msgid "Clone..." msgstr "Склонировать..." -#: lib/choose_repository.tcl:107 lib/choose_repository.tcl:976 +#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983 msgid "Open Existing Repository" msgstr "Выбрать существующий репозиторий" -#: lib/choose_repository.tcl:113 +#: lib/choose_repository.tcl:119 msgid "Open..." msgstr "Открыть..." -#: lib/choose_repository.tcl:126 +#: lib/choose_repository.tcl:132 msgid "Recent Repositories" msgstr "Недавние репозитории" -#: lib/choose_repository.tcl:132 +#: lib/choose_repository.tcl:138 msgid "Open Recent Repository:" msgstr "Открыть последний репозиторий" -#: lib/choose_repository.tcl:296 lib/choose_repository.tcl:303 -#: lib/choose_repository.tcl:310 +#: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309 +#: lib/choose_repository.tcl:316 #, tcl-format msgid "Failed to create repository %s:" msgstr "Не удалось создать репозиторий %s:" -#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478 +#: lib/choose_repository.tcl:387 msgid "Directory:" msgstr "Каталог:" -#: lib/choose_repository.tcl:412 lib/choose_repository.tcl:537 -#: lib/choose_repository.tcl:1011 +#: lib/choose_repository.tcl:417 lib/choose_repository.tcl:544 +#: lib/choose_repository.tcl:1017 msgid "Git Repository" msgstr "Репозиторий" -#: lib/choose_repository.tcl:437 +#: lib/choose_repository.tcl:442 #, tcl-format msgid "Directory %s already exists." msgstr "Каталог '%s' уже существует." -#: lib/choose_repository.tcl:441 +#: lib/choose_repository.tcl:446 #, tcl-format msgid "File %s already exists." msgstr "Файл '%s' уже существует." -#: lib/choose_repository.tcl:455 +#: lib/choose_repository.tcl:460 msgid "Clone" msgstr "Склонировать" -#: lib/choose_repository.tcl:468 -msgid "URL:" -msgstr "Ссылка:" +#: lib/choose_repository.tcl:473 +msgid "Source Location:" +msgstr "Исходное положение:" + +#: lib/choose_repository.tcl:484 +msgid "Target Directory:" +msgstr "Каталог назначения:" -#: lib/choose_repository.tcl:489 +#: lib/choose_repository.tcl:496 msgid "Clone Type:" msgstr "Тип клона:" -#: lib/choose_repository.tcl:495 +#: lib/choose_repository.tcl:502 msgid "Standard (Fast, Semi-Redundant, Hardlinks)" msgstr "Стандартный (Быстрый, полуизбыточный, \"жесткие\" ссылки)" -#: lib/choose_repository.tcl:501 +#: lib/choose_repository.tcl:508 msgid "Full Copy (Slower, Redundant Backup)" msgstr "Полная копия (Медленный, создает резервную копию)" -#: lib/choose_repository.tcl:507 +#: lib/choose_repository.tcl:514 msgid "Shared (Fastest, Not Recommended, No Backup)" msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)" -#: lib/choose_repository.tcl:543 lib/choose_repository.tcl:590 -#: lib/choose_repository.tcl:736 lib/choose_repository.tcl:806 -#: lib/choose_repository.tcl:1017 lib/choose_repository.tcl:1025 +#: lib/choose_repository.tcl:550 lib/choose_repository.tcl:597 +#: lib/choose_repository.tcl:743 lib/choose_repository.tcl:813 +#: lib/choose_repository.tcl:1023 lib/choose_repository.tcl:1031 #, tcl-format msgid "Not a Git repository: %s" msgstr "Каталог не является репозиторием: %s" -#: lib/choose_repository.tcl:579 +#: lib/choose_repository.tcl:586 msgid "Standard only available for local repository." msgstr "Стандартный клон возможен только для локального репозитория." -#: lib/choose_repository.tcl:583 +#: lib/choose_repository.tcl:590 msgid "Shared only available for local repository." msgstr "Общий клон возможен только для локального репозитория." -#: lib/choose_repository.tcl:604 +#: lib/choose_repository.tcl:611 #, tcl-format msgid "Location %s already exists." msgstr "Путь '%s' уже существует." -#: lib/choose_repository.tcl:615 +#: lib/choose_repository.tcl:622 msgid "Failed to configure origin" msgstr "Не могу сконфигурировать исходный репозиторий." -#: lib/choose_repository.tcl:627 +#: lib/choose_repository.tcl:634 msgid "Counting objects" msgstr "Считаю объекты" -#: lib/choose_repository.tcl:628 +#: lib/choose_repository.tcl:635 msgid "buckets" msgstr "" -#: lib/choose_repository.tcl:652 +#: lib/choose_repository.tcl:659 #, tcl-format msgid "Unable to copy objects/info/alternates: %s" msgstr "Не могу скопировать objects/info/alternates: %s" -#: lib/choose_repository.tcl:688 +#: lib/choose_repository.tcl:695 #, tcl-format msgid "Nothing to clone from %s." msgstr "Нечего клонировать с %s." -#: lib/choose_repository.tcl:690 lib/choose_repository.tcl:904 -#: lib/choose_repository.tcl:916 +#: lib/choose_repository.tcl:697 lib/choose_repository.tcl:911 +#: lib/choose_repository.tcl:923 msgid "The 'master' branch has not been initialized." msgstr "Не инициализирована ветвь 'master'." -#: lib/choose_repository.tcl:703 +#: lib/choose_repository.tcl:710 msgid "Hardlinks are unavailable. Falling back to copying." -msgstr "\"Жесткие ссылки\" не доступны. Буду использовать копирование." +msgstr "\"Жесткие ссылки\" недоступны. Будет использовано копирование." -#: lib/choose_repository.tcl:715 +#: lib/choose_repository.tcl:722 #, tcl-format msgid "Cloning from %s" msgstr "Клонирование %s" -#: lib/choose_repository.tcl:746 +#: lib/choose_repository.tcl:753 msgid "Copying objects" msgstr "Копирование objects" -#: lib/choose_repository.tcl:747 +#: lib/choose_repository.tcl:754 msgid "KiB" msgstr "КБ" -#: lib/choose_repository.tcl:771 +#: lib/choose_repository.tcl:778 #, tcl-format msgid "Unable to copy object: %s" msgstr "Не могу скопировать объект: %s" -#: lib/choose_repository.tcl:781 +#: lib/choose_repository.tcl:788 msgid "Linking objects" msgstr "Создание ссылок на objects" -#: lib/choose_repository.tcl:782 +#: lib/choose_repository.tcl:789 msgid "objects" msgstr "объекты" -#: lib/choose_repository.tcl:790 +#: lib/choose_repository.tcl:797 #, tcl-format msgid "Unable to hardlink object: %s" msgstr "Не могу \"жестко связать\" объект: %s" -#: lib/choose_repository.tcl:845 +#: lib/choose_repository.tcl:852 msgid "Cannot fetch branches and objects. See console output for details." msgstr "" "Не могу получить ветви и объекты. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:856 +#: lib/choose_repository.tcl:863 msgid "Cannot fetch tags. See console output for details." msgstr "Не могу получить метки. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:880 +#: lib/choose_repository.tcl:887 msgid "Cannot determine HEAD. See console output for details." msgstr "Не могу определить HEAD. Дополнительная информация на консоли." -#: lib/choose_repository.tcl:889 +#: lib/choose_repository.tcl:896 #, tcl-format msgid "Unable to cleanup %s" msgstr "Не могу очистить %s" -#: lib/choose_repository.tcl:895 +#: lib/choose_repository.tcl:902 msgid "Clone failed." msgstr "Клонирование не удалось." -#: lib/choose_repository.tcl:902 +#: lib/choose_repository.tcl:909 msgid "No default branch obtained." msgstr "Не было получено ветви по умолчанию." -#: lib/choose_repository.tcl:913 +#: lib/choose_repository.tcl:920 #, tcl-format msgid "Cannot resolve %s as a commit." msgstr "Не могу распознать %s как состояние." -#: lib/choose_repository.tcl:925 +#: lib/choose_repository.tcl:932 msgid "Creating working directory" msgstr "Создаю рабочий каталог" -#: lib/choose_repository.tcl:926 lib/index.tcl:65 lib/index.tcl:127 -#: lib/index.tcl:193 +#: lib/choose_repository.tcl:933 lib/index.tcl:65 lib/index.tcl:128 +#: lib/index.tcl:196 msgid "files" msgstr "файлов" -#: lib/choose_repository.tcl:955 +#: lib/choose_repository.tcl:962 msgid "Initial file checkout failed." msgstr "Не удалось получить начальное состояние файлов репозитория." -#: lib/choose_repository.tcl:971 +#: lib/choose_repository.tcl:978 msgid "Open" msgstr "Открыть" -#: lib/choose_repository.tcl:981 +#: lib/choose_repository.tcl:988 msgid "Repository:" msgstr "Репозиторий:" -#: lib/choose_repository.tcl:1031 +#: lib/choose_repository.tcl:1037 #, tcl-format msgid "Failed to open repository %s:" msgstr "Не удалось открыть репозиторий %s:" @@ -1140,7 +1253,7 @@ msgstr "Ветвь слежения" #: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538 msgid "Tag" -msgstr "Таг" +msgstr "Метка" #: lib/choose_rev.tcl:317 #, tcl-format @@ -1182,24 +1295,24 @@ msgid "" "completed. You cannot amend the prior commit unless you first abort the " "current merge activity.\n" msgstr "" -"Невозможно исправить состояние во время объединения.\n" +"Невозможно исправить состояние во время операции слияния.\n" "\n" -"Текущее объединение не завершено. Невозможно исправить предыдущее " -"сохраненное состояние не прерывая текущее объединение.\n" +"Текущее слияние не завершено. Невозможно исправить предыдущее " +"сохраненное состояние, не прерывая эту операцию.\n" -#: lib/commit.tcl:49 +#: lib/commit.tcl:48 msgid "Error loading commit data for amend:" msgstr "Ошибка при загрузке данных для исправления сохраненного состояния:" -#: lib/commit.tcl:76 +#: lib/commit.tcl:75 msgid "Unable to obtain your identity:" msgstr "Невозможно получить информацию об авторстве:" -#: lib/commit.tcl:81 +#: lib/commit.tcl:80 msgid "Invalid GIT_COMMITTER_IDENT:" msgstr "Неверный GIT_COMMITTER_IDENT:" -#: lib/commit.tcl:133 +#: lib/commit.tcl:132 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -1215,7 +1328,7 @@ msgstr "" "\n" "Это будет сделано сейчас автоматически.\n" -#: lib/commit.tcl:154 +#: lib/commit.tcl:155 #, tcl-format msgid "" "Unmerged files cannot be committed.\n" @@ -1223,12 +1336,12 @@ msgid "" "File %s has merge conflicts. You must resolve them and stage the file " "before committing.\n" msgstr "" -"Нельзя сохранить необъединенные файлы.\n" +"Нельзя сохранить файлы с незавершённой операцей слияния.\n" "\n" -"Для файла %s возник конфликт объединения. Разрешите конфликт и добавьте к " +"Для файла %s возник конфликт слияния. Разрешите конфликт и добавьте к " "подготовленным файлам перед сохранением.\n" -#: lib/commit.tcl:162 +#: lib/commit.tcl:163 #, tcl-format msgid "" "Unknown file state %s detected.\n" @@ -1239,7 +1352,7 @@ msgstr "" "\n" "Файл %s не может быть сохранен данной программой.\n" -#: lib/commit.tcl:170 +#: lib/commit.tcl:171 msgid "" "No changes to commit.\n" "\n" @@ -1249,7 +1362,7 @@ msgstr "" "\n" "Подготовьте хотя бы один файл до создания сохраненного состояния.\n" -#: lib/commit.tcl:183 +#: lib/commit.tcl:186 msgid "" "Please supply a commit message.\n" "\n" @@ -1267,45 +1380,45 @@ msgstr "" "- вторая строка пустая\n" "- оставшиеся строки: опишите, что дают ваши изменения.\n" -#: lib/commit.tcl:207 +#: lib/commit.tcl:210 #, tcl-format msgid "warning: Tcl does not support encoding '%s'." msgstr "предупреждение: Tcl не поддерживает кодировку '%s'." -#: lib/commit.tcl:221 +#: lib/commit.tcl:226 msgid "Calling pre-commit hook..." msgstr "Вызов программы поддержки репозитория pre-commit..." -#: lib/commit.tcl:236 +#: lib/commit.tcl:241 msgid "Commit declined by pre-commit hook." msgstr "Сохранение прервано программой поддержки репозитория pre-commit" -#: lib/commit.tcl:259 +#: lib/commit.tcl:264 msgid "Calling commit-msg hook..." msgstr "Вызов программы поддержки репозитория commit-msg..." -#: lib/commit.tcl:274 +#: lib/commit.tcl:279 msgid "Commit declined by commit-msg hook." msgstr "Сохранение прервано программой поддержки репозитория commit-msg" -#: lib/commit.tcl:287 +#: lib/commit.tcl:292 msgid "Committing changes..." msgstr "Сохранение изменений..." -#: lib/commit.tcl:303 +#: lib/commit.tcl:308 msgid "write-tree failed:" msgstr "Программа write-tree завершилась с ошибкой:" -#: lib/commit.tcl:304 lib/commit.tcl:348 lib/commit.tcl:368 +#: lib/commit.tcl:309 lib/commit.tcl:353 lib/commit.tcl:373 msgid "Commit failed." msgstr "Сохранить состояние не удалось." -#: lib/commit.tcl:321 +#: lib/commit.tcl:326 #, tcl-format msgid "Commit %s appears to be corrupt" msgstr "Состояние %s выглядит поврежденным" -#: lib/commit.tcl:326 +#: lib/commit.tcl:331 msgid "" "No changes to commit.\n" "\n" @@ -1315,23 +1428,23 @@ msgid "" msgstr "" "Отсутствуют изменения для сохранения.\n" "\n" -"Ни один файл не был изменен и не было объединения.\n" +"Ни один файл не был изменен и не было слияния.\n" "\n" "Сейчас автоматически запустится перечитывание репозитория.\n" -#: lib/commit.tcl:333 +#: lib/commit.tcl:338 msgid "No changes to commit." msgstr "Отуствуют измения для сохранения." -#: lib/commit.tcl:347 +#: lib/commit.tcl:352 msgid "commit-tree failed:" msgstr "Программа commit-tree завершилась с ошибкой:" -#: lib/commit.tcl:367 +#: lib/commit.tcl:372 msgid "update-ref failed:" msgstr "Программа update-ref завершилась с ошибкой:" -#: lib/commit.tcl:454 +#: lib/commit.tcl:460 #, tcl-format msgid "Created commit %s: %s" msgstr "Создано состояние %s: %s " @@ -1406,7 +1519,7 @@ msgstr "" msgid "Invalid date from Git: %s" msgstr "Неправильная дата в репозитории: %s" -#: lib/diff.tcl:42 +#: lib/diff.tcl:59 #, tcl-format msgid "" "No differences detected.\n" @@ -1428,40 +1541,101 @@ msgstr "" "\n" "Сейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы." -#: lib/diff.tcl:81 +#: lib/diff.tcl:99 #, tcl-format msgid "Loading diff of %s..." msgstr "Загрузка изменений в %s..." -#: lib/diff.tcl:114 lib/diff.tcl:184 +#: lib/diff.tcl:120 +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"ЛОКАЛЬНО: удалён\n" +"ВНЕШНИЙ:\n" + +#: lib/diff.tcl:125 +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"ВНЕШНИЙ: удалён\n" +"ЛОКАЛЬНО:\n" + +#: lib/diff.tcl:132 +msgid "LOCAL:\n" +msgstr "ЛОКАЛЬНО:\n" + +#: lib/diff.tcl:135 +msgid "REMOTE:\n" +msgstr "ВНЕШНИЙ:\n" + +#: lib/diff.tcl:197 lib/diff.tcl:296 #, tcl-format msgid "Unable to display %s" msgstr "Не могу показать %s" -#: lib/diff.tcl:115 +#: lib/diff.tcl:198 msgid "Error loading file:" msgstr "Ошибка загрузки файла:" -#: lib/diff.tcl:122 +#: lib/diff.tcl:205 msgid "Git Repository (subproject)" msgstr "Репозиторий Git (подпроект)" -#: lib/diff.tcl:134 +#: lib/diff.tcl:217 msgid "* Binary file (not showing content)." msgstr "* Двоичный файл (содержимое не показано)" -#: lib/diff.tcl:185 -msgid "Error loading diff:" -msgstr "Ошибка загрузки diff:" +#: lib/diff.tcl:222 +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" +"* Размер неподготовленого файла %d байт.\n" +"* Показано первых %d байт.\n" + +#: lib/diff.tcl:228 +#, tcl-format +msgid "" +"\n" +"* Untracked file clipped here by %s.\n" +"* To see the entire file, use an external editor.\n" +msgstr "" +"\n" +"* Неподготовленый файл обрезан: %s.\n" +"* Чтобы увидеть весь файл, используйте программу-редактор.\n" -#: lib/diff.tcl:303 +#: lib/diff.tcl:436 msgid "Failed to unstage selected hunk." msgstr "Не удалось исключить выбранную часть." -#: lib/diff.tcl:310 +#: lib/diff.tcl:443 msgid "Failed to stage selected hunk." msgstr "Не удалось подготовить к сохранению выбранную часть." +#: lib/diff.tcl:509 +msgid "Failed to unstage selected line." +msgstr "Не удалось исключить выбранную строку." + +#: lib/diff.tcl:517 +msgid "Failed to stage selected line." +msgstr "Не удалось подготовить к сохранению выбранную строку." + +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "По умолчанию" + +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "Системная (%s)" + +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Другая" + #: lib/error.tcl:20 lib/error.tcl:114 msgid "error" msgstr "ошибка" @@ -1480,7 +1654,7 @@ msgstr "Не удалось разблокировать индекс" #: lib/index.tcl:15 msgid "Index Error" -msgstr "Ошибка индекса" +msgstr "Ошибка в индексе" #: lib/index.tcl:21 msgid "" @@ -1498,50 +1672,59 @@ msgstr "Продолжить" msgid "Unlock Index" msgstr "Разблокировать индекс" -#: lib/index.tcl:282 +#: lib/index.tcl:287 #, tcl-format msgid "Unstaging %s from commit" msgstr "Удаление %s из подготовленного" -#: lib/index.tcl:313 +#: lib/index.tcl:326 msgid "Ready to commit." msgstr "Подготовлено для сохранения" -#: lib/index.tcl:326 +#: lib/index.tcl:339 #, tcl-format msgid "Adding %s" msgstr "Добавление %s..." -#: lib/index.tcl:381 +#: lib/index.tcl:396 #, tcl-format msgid "Revert changes in file %s?" msgstr "Отменить изменения в файле %s?" -#: lib/index.tcl:383 +#: lib/index.tcl:398 #, tcl-format msgid "Revert changes in these %i files?" msgstr "Отменить изменения в %i файле(-ах)?" -#: lib/index.tcl:391 +#: lib/index.tcl:406 msgid "Any unstaged changes will be permanently lost by the revert." msgstr "" "Любые изменения, не подготовленные к сохранению, будут потеряны при данной " "операции." -#: lib/index.tcl:394 +#: lib/index.tcl:409 msgid "Do Nothing" msgstr "Ничего не делать" +#: lib/index.tcl:427 +msgid "Reverting selected files" +msgstr "Удаление изменений в выбраных файлах" + +#: lib/index.tcl:431 +#, tcl-format +msgid "Reverting %s" +msgstr "Отмена изменений в %s" + #: lib/merge.tcl:13 msgid "" "Cannot merge while amending.\n" "\n" "You must finish amending this commit before starting any type of merge.\n" msgstr "" -"Невозможно выполнить объединение во время исправления.\n" +"Невозможно выполнить слияние во время исправления.\n" "\n" "Завершите исправление данного состояния перед выполнением операции " -"объединения.\n" +"слияния.\n" #: lib/merge.tcl:27 msgid "" @@ -1559,7 +1742,7 @@ msgstr "" "\n" "Это будет сделано сейчас автоматически.\n" -#: lib/merge.tcl:44 +#: lib/merge.tcl:45 #, tcl-format msgid "" "You are in the middle of a conflicted merge.\n" @@ -1569,14 +1752,14 @@ msgid "" "You must resolve them, stage the file, and commit to complete the current " "merge. Only then can you begin another merge.\n" msgstr "" -"Предыдущее объединение не завершено из-за конфликта.\n" +"Предыдущее слияние не завершено из-за конфликта.\n" "\n" -"Для файла %s возник конфликт объединения.\n" +"Для файла %s возник конфликт слияния.\n" "\n" "Разрешите конфликт, подготовьте файл и сохраните. Только после этого можно " -"начать следующее объединение.\n" +"начать следующее слияние.\n" -#: lib/merge.tcl:54 +#: lib/merge.tcl:55 #, tcl-format msgid "" "You are in the middle of a change.\n" @@ -1590,36 +1773,37 @@ msgstr "" "\n" "Файл %s изменен.\n" "\n" -"Подготовьте и сохраните измения перед началом объединения. В случае " -"необходимости это позволит прервать операцию объединения.\n" +"Подготовьте и сохраните измения перед началом слияния. В случае " +"необходимости это позволит прервать операцию слияния.\n" -#: lib/merge.tcl:106 +#: lib/merge.tcl:107 #, tcl-format msgid "%s of %s" msgstr "%s из %s" -#: lib/merge.tcl:119 +#: lib/merge.tcl:120 +#, tcl-format msgid "Merging %s and %s..." -msgstr "Объединение %s и %s..." +msgstr "Слияние %s и %s..." -#: lib/merge.tcl:130 +#: lib/merge.tcl:131 msgid "Merge completed successfully." -msgstr "Объединение успешно завершено." +msgstr "Слияние успешно завершено." -#: lib/merge.tcl:132 +#: lib/merge.tcl:133 msgid "Merge failed. Conflict resolution is required." -msgstr "Не удалось завершить объединение. Требуется разрешение конфликта." +msgstr "Не удалось завершить слияние. Требуется разрешение конфликта." -#: lib/merge.tcl:157 +#: lib/merge.tcl:158 #, tcl-format msgid "Merge Into %s" -msgstr "Объединить с %s" +msgstr "Слияние с %s" -#: lib/merge.tcl:176 +#: lib/merge.tcl:177 msgid "Revision To Merge" -msgstr "Версия для объединения" +msgstr "Версия, с которой провести слияние" -#: lib/merge.tcl:211 +#: lib/merge.tcl:212 msgid "" "Cannot abort while amending.\n" "\n" @@ -1629,7 +1813,7 @@ msgstr "" "\n" "Завершите текущее исправление сохраненного состояния.\n" -#: lib/merge.tcl:221 +#: lib/merge.tcl:222 msgid "" "Abort merge?\n" "\n" @@ -1637,13 +1821,13 @@ msgid "" "\n" "Continue with aborting the current merge?" msgstr "" -"Прервать объединение?\n" +"Прервать операцию слияния?\n" "\n" -"Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n" +"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n" "\n" "Продолжить?" -#: lib/merge.tcl:227 +#: lib/merge.tcl:228 msgid "" "Reset changes?\n" "\n" @@ -1651,130 +1835,346 @@ msgid "" "\n" "Continue with resetting the current changes?" msgstr "" -"Прервать объединение?\n" +"Прервать операцию слияния?\n" "\n" -"Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n" +"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n" "\n" "Продолжить?" -#: lib/merge.tcl:238 +#: lib/merge.tcl:239 msgid "Aborting" msgstr "Прерываю" -#: lib/merge.tcl:238 +#: lib/merge.tcl:239 msgid "files reset" msgstr "изменения в файлах отменены" -#: lib/merge.tcl:265 +#: lib/merge.tcl:267 msgid "Abort failed." msgstr "Прервать не удалось." -#: lib/merge.tcl:267 +#: lib/merge.tcl:269 msgid "Abort completed. Ready." msgstr "Прервано." -#: lib/option.tcl:95 +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Использовать базовую версию для разрешения конфликта?" + +#: lib/mergetool.tcl:9 +msgid "Force resolution to this branch?" +msgstr "Использовать версию этой ветви для разрешения конфликта?" + +#: lib/mergetool.tcl:10 +msgid "Force resolution to the other branch?" +msgstr "Использовать версию другой ветви для разрешения конфликта?" + +#: 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 "" +"Внимание! Список изменений показывает только конфликтующие отличия.\n" +"\n" +"%s будет переписан.\n" +"\n" +"Это действие можно отменить только перезапуском операции слияния." + +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "" +"Файл %s кажется содержит необработаные конфликты. " +"Продолжить подготовку к сохранению?" + +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Добавляю результат разрешения для %s" + +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "" +"Программа слияния не обрабатывает конфликты с удалением или участием ссылок" + +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "Конфликтующий файл не существует" + +#: lib/mergetool.tcl:264 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "'%s' не является программой слияния" + +#: lib/mergetool.tcl:268 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Неизвестная программа слияния '%s'" + +#: lib/mergetool.tcl:303 +msgid "Merge tool is already running, terminate it?" +msgstr "Программа слияния уже работает. Прервать?" + +#: lib/mergetool.tcl:323 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Ошибка получения версий:\n" +"%s" + +#: lib/mergetool.tcl:343 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Ошибка запуска программы слияния:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:347 +msgid "Running merge tool..." +msgstr "Запуск программы слияния..." + +#: lib/mergetool.tcl:375 lib/mergetool.tcl:383 +msgid "Merge tool failed." +msgstr "Ошибка выполнения программы слияния." + +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Ошибка в глобальной установке кодировки '%s'" + +#: lib/option.tcl:19 +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Неверная кодировка репозитория: '%s'" + +#: lib/option.tcl:117 msgid "Restore Defaults" msgstr "Восстановить настройки по умолчанию" -#: lib/option.tcl:99 +#: lib/option.tcl:121 msgid "Save" msgstr "Сохранить" -#: lib/option.tcl:109 +#: lib/option.tcl:131 #, tcl-format msgid "%s Repository" -msgstr "для репозитория %s" +msgstr "Для репозитория %s" -#: lib/option.tcl:110 +#: lib/option.tcl:132 msgid "Global (All Repositories)" msgstr "Общие (для всех репозиториев)" -#: lib/option.tcl:116 +#: lib/option.tcl:138 msgid "User Name" msgstr "Имя пользователя" -#: lib/option.tcl:117 +#: lib/option.tcl:139 msgid "Email Address" msgstr "Адрес электронной почты" -#: lib/option.tcl:119 +#: lib/option.tcl:141 msgid "Summarize Merge Commits" -msgstr "Суммарный комментарий при объединении" +msgstr "Суммарный комментарий при слиянии" -#: lib/option.tcl:120 +#: lib/option.tcl:142 msgid "Merge Verbosity" -msgstr "Уровень детальности сообщений при объединении" +msgstr "Уровень детальности сообщений при слиянии" -#: lib/option.tcl:121 +#: lib/option.tcl:143 msgid "Show Diffstat After Merge" -msgstr "Показать отчет об изменениях после объединения" +msgstr "Показать отчет об изменениях после слияния" + +#: lib/option.tcl:144 +msgid "Use Merge Tool" +msgstr "Использовать для слияния программу" -#: lib/option.tcl:123 +#: lib/option.tcl:146 msgid "Trust File Modification Timestamps" msgstr "Доверять времени модификации файла" -#: lib/option.tcl:124 +#: lib/option.tcl:147 msgid "Prune Tracking Branches During Fetch" msgstr "Чистка ветвей слежения при получении изменений" -#: lib/option.tcl:125 +#: lib/option.tcl:148 msgid "Match Tracking Branches" msgstr "Имя новой ветви взять из имен ветвей слежения" -#: lib/option.tcl:126 +#: lib/option.tcl:149 +msgid "Blame Copy Only On Changed Files" +msgstr "Поиск копий только в изменённых файлах" + +#: lib/option.tcl:150 +msgid "Minimum Letters To Blame Copy On" +msgstr "Минимальное количество символов для поиска копий" + +#: lib/option.tcl:151 +msgid "Blame History Context Radius (days)" +msgstr "Радиус исторического контекста (в днях)" + +#: lib/option.tcl:152 msgid "Number of Diff Context Lines" msgstr "Число строк в контексте diff" -#: lib/option.tcl:127 +#: lib/option.tcl:153 msgid "Commit Message Text Width" -msgstr "Ширина комментария к состоянию:" +msgstr "Ширина текста комментария" -#: lib/option.tcl:128 +#: lib/option.tcl:154 msgid "New Branch Name Template" msgstr "Шаблон для имени новой ветви" -#: lib/option.tcl:192 +#: lib/option.tcl:155 +msgid "Default File Contents Encoding" +msgstr "Кодировка содержания файла по умолчанию" + +#: lib/option.tcl:203 +msgid "Change" +msgstr "Изменить" + +#: lib/option.tcl:230 msgid "Spelling Dictionary:" msgstr "Словарь для проверки правописания:" -#: lib/option.tcl:216 +#: lib/option.tcl:254 msgid "Change Font" -msgstr "Изменить шрифт" +msgstr "Изменить" -#: lib/option.tcl:220 +#: lib/option.tcl:258 #, tcl-format msgid "Choose %s" msgstr "Выберите %s" # carbon copy -#: lib/option.tcl:226 +#: lib/option.tcl:264 msgid "pt." -msgstr "" +msgstr "pt." -#: lib/option.tcl:240 +#: lib/option.tcl:278 msgid "Preferences" msgstr "Настройки" -#: lib/option.tcl:275 +#: lib/option.tcl:314 msgid "Failed to completely save options:" msgstr "Не удалось полностью сохранить настройки:" +#: lib/remote.tcl:163 +msgid "Remove Remote" +msgstr "Удалить ссылку на внешний репозиторий" + +#: lib/remote.tcl:168 +msgid "Prune from" +msgstr "Чистка" + +#: lib/remote.tcl:173 +msgid "Fetch from" +msgstr "Получение из" + +#: lib/remote.tcl:215 +msgid "Push to" +msgstr "Отправить" + +#: lib/remote_add.tcl:19 +msgid "Add Remote" +msgstr "Зарегистрировать внешний репозиторий" + +#: lib/remote_add.tcl:24 +msgid "Add New Remote" +msgstr "Добавить внешний репозиторий" + +#: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 +msgid "Add" +msgstr "" + +#: lib/remote_add.tcl:37 +msgid "Remote Details" +msgstr "Информация о внешнем репозитории" + +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Положение:" + +#: lib/remote_add.tcl:62 +msgid "Further Action" +msgstr "Следующая операция" + +#: lib/remote_add.tcl:65 +msgid "Fetch Immediately" +msgstr "Скачать сразу" + +#: lib/remote_add.tcl:71 +msgid "Initialize Remote Repository and Push" +msgstr "Инициализировать внешний репозиторий и отправить" + +#: lib/remote_add.tcl:77 +msgid "Do Nothing Else Now" +msgstr "Больше ничего не делать" + +#: lib/remote_add.tcl:101 +msgid "Please supply a remote name." +msgstr "Укажите название внешнего репозитория." + +#: lib/remote_add.tcl:114 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "Недопустимое название внешнего репозитория '%s'." + +#: lib/remote_add.tcl:125 +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Не удалось добавить '%s' из '%s'. " + +#: lib/remote_add.tcl:133 lib/transport.tcl:6 +#, tcl-format +msgid "fetch %s" +msgstr "получение %s" + +#: lib/remote_add.tcl:134 +#, tcl-format +msgid "Fetching the %s" +msgstr "Получение %s" + +#: lib/remote_add.tcl:157 +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Невозможно инициалировать репозиторий в '%s'." + +#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63 +#: lib/transport.tcl:81 +#, tcl-format +msgid "push %s" +msgstr "отправить %s" + +#: lib/remote_add.tcl:164 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Настройка %s (в %s)" + #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 -msgid "Delete Remote Branch" -msgstr "Удалить внешнюю ветвь" +msgid "Delete Branch Remotely" +msgstr "Удаление ветви во внешнем репозитории" #: lib/remote_branch_delete.tcl:47 msgid "From Repository" msgstr "Из репозитория" -#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:123 +#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134 msgid "Remote:" msgstr "внешний:" -#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:138 -msgid "Arbitrary URL:" -msgstr "по указанному URL:" +#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149 +msgid "Arbitrary Location:" +msgstr "Указаное положение:" #: lib/remote_branch_delete.tcl:84 msgid "Branches" @@ -1786,15 +2186,15 @@ msgstr "Удалить только в случае, если" #: lib/remote_branch_delete.tcl:111 msgid "Merged Into:" -msgstr "Объединено с:" +msgstr "Слияние с:" #: lib/remote_branch_delete.tcl:119 msgid "Always (Do not perform merge checks)" -msgstr "Всегда (не выполнять проверку объединений)" +msgstr "Всегда (не выполнять проверку на слияние)" #: lib/remote_branch_delete.tcl:152 msgid "A branch is required for 'Merged Into'." -msgstr "Для опции 'Объединено с' требуется указать ветвь." +msgstr "Для опции 'Слияние с' требуется указать ветвь." #: lib/remote_branch_delete.tcl:184 #, tcl-format @@ -1803,7 +2203,8 @@ msgid "" "\n" " - %s" msgstr "" -"Следующие ветви объединены с %s не полностью:\n" +"Следующие ветви могут быть объединены с %s при помощи операции слияния:\n" +"\n" " - %s" #: lib/remote_branch_delete.tcl:189 @@ -1812,7 +2213,7 @@ msgid "" "One or more of the merge tests failed because you have not fetched the " "necessary commits. Try fetching from %s first." msgstr "" -"Один или несколько тестов на объединение не прошли, потому что Вы не " +"Некоторые тесты на слияние не прошли, потому что Вы не " "получили необходимые состояния. Попытайтесь получить их из %s." #: lib/remote_branch_delete.tcl:207 @@ -1843,17 +2244,21 @@ msgstr "Не указан репозиторий." msgid "Scanning %s..." msgstr "Перечитывание %s... " -#: lib/remote.tcl:165 -msgid "Prune from" -msgstr "Чистка" +#: lib/search.tcl:21 +msgid "Find:" +msgstr "Поиск:" -#: lib/remote.tcl:170 -msgid "Fetch from" -msgstr "Получение из" +#: lib/search.tcl:23 +msgid "Next" +msgstr "Дальше" -#: lib/remote.tcl:213 -msgid "Push to" -msgstr "Отправить" +#: lib/search.tcl:24 +msgid "Prev" +msgstr "Обратно" + +#: lib/search.tcl:25 +msgid "Case-Sensitive" +msgstr "Игн. большие/маленькие" #: lib/shortcut.tcl:20 lib/shortcut.tcl:61 msgid "Cannot write shortcut:" @@ -1888,27 +2293,192 @@ msgstr "Программа проверки правописания не смо msgid "Unrecognized spell checker" msgstr "Нераспознаная программа проверки правописания" -#: lib/spellcheck.tcl:180 +#: lib/spellcheck.tcl:186 msgid "No Suggestions" msgstr "Исправлений не найдено" -#: lib/spellcheck.tcl:381 +#: lib/spellcheck.tcl:388 msgid "Unexpected EOF from spell checker" msgstr "Программа проверки правописания прервала передачу данных" -#: lib/spellcheck.tcl:385 +#: lib/spellcheck.tcl:392 msgid "Spell Checker Failed" msgstr "Ошибка проверки правописания" +#: lib/sshkey.tcl:31 +msgid "No keys found." +msgstr "Ключ не найден" + +#: lib/sshkey.tcl:34 +#, tcl-format +msgid "Found a public key in: %s" +msgstr "Публичный ключ из %s" + +#: lib/sshkey.tcl:40 +msgid "Generate Key" +msgstr "Создать ключ" + +#: lib/sshkey.tcl:56 +msgid "Copy To Clipboard" +msgstr "Скопировать в буфер обмена" + +#: lib/sshkey.tcl:70 +msgid "Your OpenSSH Public Key" +msgstr "Ваш публичный ключ OpenSSH" + +#: lib/sshkey.tcl:78 +msgid "Generating..." +msgstr "Создание..." + +#: lib/sshkey.tcl:84 +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Ошибка запуска ssh-keygen:\n" +"\n" +"%s" + +#: lib/sshkey.tcl:111 +msgid "Generation failed." +msgstr "Ключ не создан." + +#: lib/sshkey.tcl:118 +msgid "Generation succeded, but no keys found." +msgstr "Создание ключа завершилось, но результат не был найден" + +#: lib/sshkey.tcl:121 +#, tcl-format +msgid "Your key is in: %s" +msgstr "Ваш ключ находится в: %s" + #: lib/status_bar.tcl:83 #, tcl-format msgid "%s ... %*i of %*i %s (%3i%%)" msgstr "%s ... %*i из %*i %s (%3i%%)" -#: lib/transport.tcl:6 +#: lib/tools.tcl:75 #, tcl-format -msgid "fetch %s" -msgstr "получение %s" +msgid "Running %s requires a selected file." +msgstr "Запуск %s требует выбранного файла." + +#: lib/tools.tcl:90 +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Действительно запустить %s?" + +#: lib/tools.tcl:110 +#, tcl-format +msgid "Tool: %s" +msgstr "Вспомогательная операция: %s" + +#: lib/tools.tcl:111 +#, tcl-format +msgid "Running: %s" +msgstr "Выполнение: %s" + +#: lib/tools.tcl:149 +#, tcl-format +msgid "Tool completed succesfully: %s" +msgstr "Программа %s успешно завершилась." + +#: lib/tools.tcl:151 +#, tcl-format +msgid "Tool failed: %s" +msgstr "Ошибка выполнения программы: %s" + +#: lib/tools_dlg.tcl:22 +msgid "Add Tool" +msgstr "Добавить вспомогательную операцию" + +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Новая вспомогательная операция" + +#: lib/tools_dlg.tcl:33 +msgid "Add globally" +msgstr "Добавить для всех репозиториев" + +#: lib/tools_dlg.tcl:45 +msgid "Tool Details" +msgstr "Описание вспомогательной операции" + +#: lib/tools_dlg.tcl:48 +msgid "Use '/' separators to create a submenu tree:" +msgstr "Испольуйте '/' для создания подменю" + +#: lib/tools_dlg.tcl:61 +msgid "Command:" +msgstr "Команда:" + +#: lib/tools_dlg.tcl:74 +msgid "Show a dialog before running" +msgstr "Показать диалог перед запуском" + +#: lib/tools_dlg.tcl:80 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Запрос на выбор версии (устанавливает $REVISION)" + +#: lib/tools_dlg.tcl:85 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Запрос дополнительных аргументов (устанавливает $ARGS)" + +#: lib/tools_dlg.tcl:92 +msgid "Don't show the command output window" +msgstr "Не показывать окно вывода команды" + +#: lib/tools_dlg.tcl:97 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Запуск только если показан список изменений ($FILENAME не пусто)" + +#: lib/tools_dlg.tcl:121 +msgid "Please supply a name for the tool." +msgstr "Укажите название вспомогательной операции." + +#: lib/tools_dlg.tcl:129 +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "Вспомогательная операция '%s' уже существует." + +#: lib/tools_dlg.tcl:151 +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Ошибка добавления программы:\n" +"%s" + +#: lib/tools_dlg.tcl:190 +msgid "Remove Tool" +msgstr "Удалить программу" + +#: lib/tools_dlg.tcl:196 +msgid "Remove Tool Commands" +msgstr "Удалить команды программы" + +#: lib/tools_dlg.tcl:200 +msgid "Remove" +msgstr "Удалить" + +#: lib/tools_dlg.tcl:236 +msgid "(Blue denotes repository-local tools)" +msgstr "(Синим выделены программы локальные репозиторию)" + +#: lib/tools_dlg.tcl:297 +#, tcl-format +msgid "Run Command: %s" +msgstr "Запуск команды: %s" + +#: lib/tools_dlg.tcl:311 +msgid "Arguments" +msgstr "Аргументы" + +#: lib/tools_dlg.tcl:348 +msgid "OK" +msgstr "OK" #: lib/transport.tcl:7 #, tcl-format @@ -1926,48 +2496,46 @@ msgstr "чистка внешнего %s" msgid "Pruning tracking branches deleted from %s" msgstr "Чистка ветвей слежения, удаленных из %s" -#: lib/transport.tcl:25 lib/transport.tcl:71 -#, tcl-format -msgid "push %s" -msgstr "отправить %s" - #: lib/transport.tcl:26 #, tcl-format msgid "Pushing changes to %s" msgstr "Отправка изменений в %s " -#: lib/transport.tcl:72 +#: lib/transport.tcl:64 +#, tcl-format +msgid "Mirroring to %s" +msgstr "Точное копирование в %s" + +#: lib/transport.tcl:82 #, tcl-format msgid "Pushing %s %s to %s" msgstr "Отправка %s %s в %s" -#: lib/transport.tcl:89 +#: lib/transport.tcl:100 msgid "Push Branches" msgstr "Отправить изменения в ветвях" -#: lib/transport.tcl:103 +#: lib/transport.tcl:114 msgid "Source Branches" msgstr "Исходные ветви" -#: lib/transport.tcl:120 +#: lib/transport.tcl:131 msgid "Destination Repository" msgstr "Репозиторий назначения" -#: lib/transport.tcl:158 +#: lib/transport.tcl:169 msgid "Transfer Options" msgstr "Настройки отправки" -#: lib/transport.tcl:160 +#: lib/transport.tcl:171 msgid "Force overwrite existing branch (may discard changes)" msgstr "Намеренно переписать существующую ветвь (возможна потеря изменений)" -#: lib/transport.tcl:164 +#: lib/transport.tcl:175 msgid "Use thin pack (for slow network connections)" msgstr "Использовать thin pack (для медленных сетевых подключений)" -#: lib/transport.tcl:168 +#: lib/transport.tcl:179 msgid "Include tags" -msgstr "Передать таги" +msgstr "Передать метки" -#~ msgid "Next >" -#~ msgstr "Дальше >" diff --git a/git-gui/po/sv.po b/git-gui/po/sv.po index 167654c709..c1535f94e8 100644 --- a/git-gui/po/sv.po +++ b/git-gui/po/sv.po @@ -780,16 +780,6 @@ msgstr "Alltid (utför inte sammanslagningstest)." msgid "The following branches are not completely merged into %s:" msgstr "Följande grenar är inte till fullo sammanslagna med %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"Det är svårt att återställa borttagna grenar.\n" -"\n" -" Ta bort valda grenar?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" @@ -2398,7 +2388,7 @@ msgstr "Exekverar: %s" #: lib/tools.tcl:149 #, tcl-format -msgid "Tool completed succesfully: %s" +msgid "Tool completed successfully: %s" msgstr "Verktyget avslutades framgångsrikt: %s" #: lib/tools.tcl:151 diff --git a/git-gui/po/zh_cn.po b/git-gui/po/zh_cn.po index d2c6866671..91c1be23c2 100644 --- a/git-gui/po/zh_cn.po +++ b/git-gui/po/zh_cn.po @@ -676,16 +676,6 @@ msgstr "总是合并 (不作合并测试.)" msgid "The following branches are not completely merged into %s:" msgstr "下列分支没有完全被合并到 %s:" -#: lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult. \n" -"\n" -" Delete the selected branches?" -msgstr "" -"恢复被删除的分支非常困难.\n" -"\n" -"是否要删除所选分支?" - #: lib/branch_delete.tcl:141 #, tcl-format msgid "" diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 53c3a94686..66bbb2f8fa 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -3,7 +3,12 @@ exec wish "$0" -- "$@" if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { - cd [lindex $argv 1] + set workdir [lindex $argv 1] + cd $workdir + if {[lindex [file split $workdir] end] eq {.git}} { + # Workaround for Explorer right click "Git GUI Here" on .git/ + cd .. + } set argv [lrange $argv 2 end] incr argc -2 } diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index e1eb963266..9c2c1b7202 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -113,6 +113,10 @@ case "${1:-.}${2:-.}${3:-.}" in src1=`git-unpack-file $2` git merge-file "$src1" "$orig" "$src2" ret=$? + msg= + if [ $ret -ne 0 ]; then + msg='content conflict' + fi # Create the working tree file, using "our tree" version from the # index, and then store the result of the merge. @@ -120,7 +124,10 @@ case "${1:-.}${2:-.}${3:-.}" in rm -f -- "$orig" "$src1" "$src2" if [ "$6" != "$7" ]; then - echo "ERROR: Permissions conflict: $5->$6,$7." + if [ -n "$msg" ]; then + msg="$msg, " + fi + msg="${msg}permissions conflict: $5->$6,$7" ret=1 fi if [ "$1" = '' ]; then @@ -128,7 +135,7 @@ case "${1:-.}${2:-.}${3:-.}" in fi if [ $ret -ne 0 ]; then - echo "ERROR: Merge conflict in $4" + echo "ERROR: $msg in $4" exit 1 fi exec git update-index -- "$4" diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh index 93bcfc2f5d..c9da747fcf 100755 --- a/git-merge-resolve.sh +++ b/git-merge-resolve.sh @@ -37,10 +37,10 @@ then exit 2 fi -git update-index --refresh 2>/dev/null +git update-index -q --refresh git read-tree -u -m --aggressive $bases $head $remotes || exit 2 echo "Trying simple merge." -if result_tree=$(git write-tree 2>/dev/null) +if result_tree=$(git write-tree 2>/dev/null) then exit 0 else diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh new file mode 100644 index 0000000000..a16a2795d7 --- /dev/null +++ b/git-mergetool--lib.sh @@ -0,0 +1,385 @@ +# git-mergetool--lib is a library for common merge tool functions +diff_mode() { + test "$TOOL_MODE" = diff +} + +merge_mode() { + test "$TOOL_MODE" = merge +} + +translate_merge_tool_path () { + case "$1" in + vimdiff) + echo vim + ;; + gvimdiff) + echo gvim + ;; + emerge) + echo emacs + ;; + *) + echo "$1" + ;; + esac +} + +check_unchanged () { + if test "$MERGED" -nt "$BACKUP"; then + status=0 + else + while true; do + echo "$MERGED seems unchanged." + printf "Was the merge successful? [y/n] " + read answer < /dev/tty + case "$answer" in + y*|Y*) status=0; break ;; + n*|N*) status=1; break ;; + esac + done + fi +} + +valid_tool () { + case "$1" in + kdiff3 | tkdiff | xxdiff | meld | opendiff | \ + emerge | vimdiff | gvimdiff | ecmerge | diffuse) + ;; # happy + tortoisemerge) + if ! merge_mode; then + return 1 + fi + ;; + kompare) + if ! diff_mode; then + return 1 + fi + ;; + *) + if test -z "$(get_merge_tool_cmd "$1")"; then + return 1 + fi + ;; + esac +} + +get_merge_tool_cmd () { + # Prints the custom command for a merge tool + if test -n "$1"; then + merge_tool="$1" + else + merge_tool="$(get_merge_tool)" + fi + if diff_mode; then + echo "$(git config difftool.$merge_tool.cmd || + git config mergetool.$merge_tool.cmd)" + else + echo "$(git config mergetool.$merge_tool.cmd)" + fi +} + +run_merge_tool () { + merge_tool_path="$(get_merge_tool_path "$1")" || exit + base_present="$2" + status=0 + + case "$1" in + kdiff3) + if merge_mode; then + if $base_present; then + ("$merge_tool_path" --auto \ + --L1 "$MERGED (Base)" \ + --L2 "$MERGED (Local)" \ + --L3 "$MERGED (Remote)" \ + -o "$MERGED" \ + "$BASE" "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) + else + ("$merge_tool_path" --auto \ + --L1 "$MERGED (Local)" \ + --L2 "$MERGED (Remote)" \ + -o "$MERGED" \ + "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) + fi + status=$? + else + ("$merge_tool_path" --auto \ + --L1 "$MERGED (A)" \ + --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) + fi + ;; + kompare) + "$merge_tool_path" "$LOCAL" "$REMOTE" + ;; + tkdiff) + if merge_mode; then + if $base_present; then + "$merge_tool_path" -a "$BASE" \ + -o "$MERGED" "$LOCAL" "$REMOTE" + else + "$merge_tool_path" \ + -o "$MERGED" "$LOCAL" "$REMOTE" + fi + status=$? + else + "$merge_tool_path" "$LOCAL" "$REMOTE" + fi + ;; + meld) + if merge_mode; then + touch "$BACKUP" + "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE" + check_unchanged + else + "$merge_tool_path" "$LOCAL" "$REMOTE" + fi + ;; + diffuse) + if merge_mode; then + touch "$BACKUP" + if $base_present; then + "$merge_tool_path" \ + "$LOCAL" "$MERGED" "$REMOTE" \ + "$BASE" | cat + else + "$merge_tool_path" \ + "$LOCAL" "$MERGED" "$REMOTE" | cat + fi + check_unchanged + else + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat + fi + ;; + vimdiff) + if merge_mode; then + touch "$BACKUP" + "$merge_tool_path" -d -c "wincmd l" \ + "$LOCAL" "$MERGED" "$REMOTE" + check_unchanged + else + "$merge_tool_path" -d -c "wincmd l" \ + "$LOCAL" "$REMOTE" + fi + ;; + gvimdiff) + if merge_mode; then + touch "$BACKUP" + "$merge_tool_path" -d -c "wincmd l" -f \ + "$LOCAL" "$MERGED" "$REMOTE" + check_unchanged + else + "$merge_tool_path" -d -c "wincmd l" -f \ + "$LOCAL" "$REMOTE" + fi + ;; + xxdiff) + if merge_mode; then + touch "$BACKUP" + if $base_present; then + "$merge_tool_path" -X --show-merged-pane \ + -R 'Accel.SaveAsMerged: "Ctrl-S"' \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + --merged-file "$MERGED" \ + "$LOCAL" "$BASE" "$REMOTE" + else + "$merge_tool_path" -X $extra \ + -R 'Accel.SaveAsMerged: "Ctrl-S"' \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + --merged-file "$MERGED" \ + "$LOCAL" "$REMOTE" + fi + check_unchanged + else + "$merge_tool_path" \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + "$LOCAL" "$REMOTE" + fi + ;; + opendiff) + if merge_mode; then + touch "$BACKUP" + if $base_present; then + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + -ancestor "$BASE" \ + -merge "$MERGED" | cat + else + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + -merge "$MERGED" | cat + fi + check_unchanged + else + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat + fi + ;; + ecmerge) + if merge_mode; then + touch "$BACKUP" + if $base_present; then + "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \ + --default --mode=merge3 --to="$MERGED" + else + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + --default --mode=merge2 --to="$MERGED" + fi + check_unchanged + else + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + --default --mode=merge2 --to="$MERGED" + fi + ;; + emerge) + if merge_mode; then + if $base_present; then + "$merge_tool_path" \ + -f emerge-files-with-ancestor-command \ + "$LOCAL" "$REMOTE" "$BASE" \ + "$(basename "$MERGED")" + else + "$merge_tool_path" \ + -f emerge-files-command \ + "$LOCAL" "$REMOTE" \ + "$(basename "$MERGED")" + fi + status=$? + else + "$merge_tool_path" -f emerge-files-command \ + "$LOCAL" "$REMOTE" "$(basename "$MERGED")" + fi + ;; + tortoisemerge) + if $base_present; then + touch "$BACKUP" + "$merge_tool_path" \ + -base:"$BASE" -mine:"$LOCAL" \ + -theirs:"$REMOTE" -merged:"$MERGED" + check_unchanged + else + echo "TortoiseMerge cannot be used without a base" 1>&2 + status=1 + fi + ;; + *) + merge_tool_cmd="$(get_merge_tool_cmd "$1")" + if test -z "$merge_tool_cmd"; then + if merge_mode; then + status=1 + fi + break + fi + if merge_mode; then + trust_exit_code="$(git config --bool \ + mergetool."$1".trustExitCode || echo false)" + if test "$trust_exit_code" = "false"; then + touch "$BACKUP" + ( eval $merge_tool_cmd ) + check_unchanged + else + ( eval $merge_tool_cmd ) + status=$? + fi + else + ( eval $merge_tool_cmd ) + fi + ;; + esac + return $status +} + +guess_merge_tool () { + if merge_mode; then + tools="tortoisemerge" + else + tools="kompare" + fi + if test -n "$DISPLAY"; then + if test -n "$GNOME_DESKTOP_SESSION_ID" ; then + tools="meld opendiff kdiff3 tkdiff xxdiff $tools" + else + tools="opendiff kdiff3 tkdiff xxdiff meld $tools" + fi + tools="$tools gvimdiff diffuse ecmerge" + fi + if echo "${VISUAL:-$EDITOR}" | grep emacs > /dev/null 2>&1; then + # $EDITOR is emacs so add emerge as a candidate + tools="$tools emerge vimdiff" + elif echo "${VISUAL:-$EDITOR}" | grep vim > /dev/null 2>&1; then + # $EDITOR is vim so add vimdiff as a candidate + tools="$tools vimdiff emerge" + else + tools="$tools emerge vimdiff" + fi + echo >&2 "merge tool candidates: $tools" + + # Loop over each candidate and stop when a valid merge tool is found. + for i in $tools + do + merge_tool_path="$(translate_merge_tool_path "$i")" + if type "$merge_tool_path" > /dev/null 2>&1; then + echo "$i" + return 0 + fi + done + + echo >&2 "No known merge resolution program available." + return 1 +} + +get_configured_merge_tool () { + # Diff mode first tries diff.tool and falls back to merge.tool. + # Merge mode only checks merge.tool + if diff_mode; then + merge_tool=$(git config diff.tool || git config merge.tool) + else + merge_tool=$(git config merge.tool) + fi + if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then + echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool" + echo >&2 "Resetting to default..." + return 1 + fi + echo "$merge_tool" +} + +get_merge_tool_path () { + # A merge tool has been set, so verify that it's valid. + if test -n "$1"; then + merge_tool="$1" + else + merge_tool="$(get_merge_tool)" + fi + if ! valid_tool "$merge_tool"; then + echo >&2 "Unknown merge tool $merge_tool" + exit 1 + fi + if diff_mode; then + merge_tool_path=$(git config difftool."$merge_tool".path || + git config mergetool."$merge_tool".path) + else + merge_tool_path=$(git config mergetool."$merge_tool".path) + fi + if test -z "$merge_tool_path"; then + merge_tool_path="$(translate_merge_tool_path "$merge_tool")" + fi + if test -z "$(get_merge_tool_cmd "$merge_tool")" && + ! type "$merge_tool_path" > /dev/null 2>&1; then + echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\ + "'$merge_tool_path'" + exit 1 + fi + echo "$merge_tool_path" +} + +get_merge_tool () { + # Check if a merge tool has been configured + merge_tool=$(get_configured_merge_tool) + # Try to guess an appropriate merge tool if no tool has been set. + if test -z "$merge_tool"; then + merge_tool="$(guess_merge_tool)" || exit + fi + echo "$merge_tool" +} diff --git a/git-mergetool.sh b/git-mergetool.sh index 87fa88af55..b52a7410bc 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -11,7 +11,9 @@ USAGE='[--tool=tool] [-y|--no-prompt|--prompt] [file to merge] ...' SUBDIRECTORY_OK=Yes OPTIONS_SPEC= +TOOL_MODE=merge . git-sh-setup +. git-mergetool--lib require_work_tree # Returns true if the mode reflects a symlink @@ -110,22 +112,6 @@ resolve_deleted_merge () { done } -check_unchanged () { - if test "$MERGED" -nt "$BACKUP" ; then - status=0; - else - while true; do - echo "$MERGED seems unchanged." - printf "Was the merge successful? [y/n] " - read answer < /dev/tty - case "$answer" in - y*|Y*) status=0; break ;; - n*|N*) status=1; break ;; - esac - done - fi -} - checkout_staged_file () { tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^ ]*\) ') @@ -137,7 +123,7 @@ checkout_staged_file () { merge_file () { MERGED="$1" - f=`git ls-files -u -- "$MERGED"` + f=$(git ls-files -u -- "$MERGED") if test -z "$f" ; then if test ! -f "$MERGED" ; then echo "$MERGED: file not found" @@ -156,9 +142,9 @@ merge_file () { mv -- "$MERGED" "$BACKUP" cp -- "$BACKUP" "$MERGED" - base_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}'` - local_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}'` - remote_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}'` + base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}') + local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}') + remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}') base_present && checkout_staged_file 1 "$MERGED" "$BASE" local_present && checkout_staged_file 2 "$MERGED" "$LOCAL" @@ -188,97 +174,13 @@ merge_file () { read ans fi - case "$merge_tool" in - kdiff3) - if base_present ; then - ("$merge_tool_path" --auto --L1 "$MERGED (Base)" --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" \ - -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) - else - ("$merge_tool_path" --auto --L1 "$MERGED (Local)" --L2 "$MERGED (Remote)" \ - -o "$MERGED" "$LOCAL" "$REMOTE" > /dev/null 2>&1) - fi - status=$? - ;; - tkdiff) - if base_present ; then - "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE" - else - "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE" - fi - status=$? - ;; - meld) - touch "$BACKUP" - "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - ;; - vimdiff) - touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - ;; - gvimdiff) - touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - ;; - xxdiff) - touch "$BACKUP" - if base_present ; then - "$merge_tool_path" -X --show-merged-pane \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE" - else - "$merge_tool_path" -X --show-merged-pane \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" "$LOCAL" "$REMOTE" - fi - check_unchanged - ;; - opendiff) - touch "$BACKUP" - if base_present; then - "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED" | cat - else - "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED" | cat - fi - check_unchanged - ;; - ecmerge) - touch "$BACKUP" - if base_present; then - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED" - else - "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED" - fi - check_unchanged - ;; - emerge) - if base_present ; then - "$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$MERGED")" - else - "$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$MERGED")" - fi - status=$? - ;; - *) - if test -n "$merge_tool_cmd"; then - if test "$merge_tool_trust_exit_code" = "false"; then - touch "$BACKUP" - ( eval $merge_tool_cmd ) - check_unchanged - else - ( eval $merge_tool_cmd ) - status=$? - fi - fi - ;; - esac - if test "$status" -ne 0; then + if base_present; then + present=true + else + present=false + fi + + if ! run_merge_tool "$merge_tool" "$present"; then echo "merge of $MERGED failed" 1>&2 mv -- "$BACKUP" "$MERGED" @@ -308,7 +210,7 @@ do -t|--tool*) case "$#,$1" in *,*=*) - merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'` + merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; 1,*) usage ;; @@ -337,38 +239,6 @@ do shift done -valid_custom_tool() -{ - merge_tool_cmd="$(git config mergetool.$1.cmd)" - test -n "$merge_tool_cmd" -} - -valid_tool() { - case "$1" in - kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge) - ;; # happy - *) - if ! valid_custom_tool "$1"; then - return 1 - fi - ;; - esac -} - -init_merge_tool_path() { - merge_tool_path=`git config mergetool.$1.path` - if test -z "$merge_tool_path" ; then - case "$1" in - emerge) - merge_tool_path=emacs - ;; - *) - merge_tool_path=$1 - ;; - esac - fi -} - prompt_after_failed_merge() { while true; do printf "Continue merging other unresolved paths (y/n) ? " @@ -387,67 +257,16 @@ prompt_after_failed_merge() { } if test -z "$merge_tool"; then - merge_tool=`git config merge.tool` - if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then - echo >&2 "git config option merge.tool set to unknown tool: $merge_tool" - echo >&2 "Resetting to default..." - unset merge_tool - fi -fi - -if test -z "$merge_tool" ; then - if test -n "$DISPLAY"; then - if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 tkdiff xxdiff gvimdiff" - else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff" - fi - fi - if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then - merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff" - elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then - merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge" - else - merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff" - fi - echo "merge tool candidates: $merge_tool_candidates" - for i in $merge_tool_candidates; do - init_merge_tool_path $i - if type "$merge_tool_path" > /dev/null 2>&1; then - merge_tool=$i - break - fi - done - if test -z "$merge_tool" ; then - echo "No known merge resolution program available." - exit 1 - fi -else - if ! valid_tool "$merge_tool"; then - echo >&2 "Unknown merge_tool $merge_tool" - exit 1 - fi - - init_merge_tool_path "$merge_tool" - - merge_keep_backup="$(git config --bool merge.keepBackup || echo true)" - merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)" - - if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then - echo "The merge tool $merge_tool is not available as '$merge_tool_path'" - exit 1 - fi - - if ! test -z "$merge_tool_cmd"; then - merge_tool_trust_exit_code="$(git config --bool mergetool.$merge_tool.trustExitCode || echo false)" - fi + merge_tool=$(get_merge_tool "$merge_tool") || exit fi +merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)" +merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)" last_status=0 rollup_status=0 if test $# -eq 0 ; then - files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u` + files=$(git ls-files -u | sed -e 's/^[^ ]* //' | sort -u) if test -z "$files" ; then echo "No files need merging" exit 0 diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 695a4094bb..a296719861 100755 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -2,7 +2,7 @@ # git-ls-remote could be called from outside a git managed repository; # this would fail in that case and would issue an error message. -GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) || :; +GIT_DIR=$(git rev-parse -q --git-dir) || :; get_data_source () { case "$1" in diff --git a/git-pull.sh b/git-pull.sh index 8c750270e9..35261539ab 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -147,7 +147,7 @@ then echo >&2 "Warning: fetch updated the current branch head." echo >&2 "Warning: fast forwarding your working tree from" echo >&2 "Warning: commit $orig_head." - git update-index --refresh 2>/dev/null + git update-index -q --refresh git read-tree -u -m "$orig_head" "$curr_head" || die 'Cannot fast-forward your working tree. After making sure that you saved anything precious from diff --git a/git-send-email.perl b/git-send-email.perl index 172b53c2d5..cccbf4517a 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -418,6 +418,14 @@ my %parse_alias = ( $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next; $aliases{$1} = [ split_addrs($2) ]; }}, + elm => sub { my $fh = shift; + while (<$fh>) { + if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) { + my ($alias, $addr) = ($1, $2); + $aliases{$alias} = [ split_addrs($addr) ]; + } + } }, + gnus => sub { my $fh = shift; while (<$fh>) { if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) { $aliases{$1} = [ $2 ]; diff --git a/git-submodule.sh b/git-submodule.sh index 7c2e060ae7..8e234a4028 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -204,8 +204,15 @@ cmd_add() else module_clone "$path" "$realrepo" || exit - (unset GIT_DIR; cd "$path" && git checkout -f -q ${branch:+-b "$branch" "origin/$branch"}) || - die "Unable to checkout submodule '$path'" + ( + unset GIT_DIR + cd "$path" && + # ash fails to wordsplit ${branch:+-b "$branch"...} + case "$branch" in + '') git checkout -f -q ;; + ?*) git checkout -f -q -b "$branch" "origin/$branch" ;; + esac + ) || die "Unable to checkout submodule '$path'" fi git add "$path" || diff --git a/git-svn.perl b/git-svn.perl index c5965c9aaf..ef1d30db38 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -147,7 +147,7 @@ my %cmd = ( 'dry-run|n' => \$_dry_run } ], 'set-tree' => [ \&cmd_set_tree, "Set an SVN repository to a git tree-ish", - { 'stdin|' => \$_stdin, %cmt_opts, %fc_opts, } ], + { 'stdin' => \$_stdin, %cmt_opts, %fc_opts, } ], 'create-ignore' => [ \&cmd_create_ignore, 'Create a .gitignore per svn:ignore', { 'revision|r=i' => \$_revision @@ -47,7 +47,7 @@ static void commit_pager_choice(void) { } } -static int handle_options(const char*** argv, int* argc, int* envchanged) +static int handle_options(const char ***argv, int *argc, int *envchanged) { int handled = 0; @@ -136,7 +136,7 @@ static int handle_alias(int *argcp, const char ***argv) int envchanged = 0, ret = 0, saved_errno = errno; const char *subdir; int count, option_count; - const char** new_argv; + const char **new_argv; const char *alias_command; char *alias_string; int unused_nongit; @@ -187,10 +187,10 @@ static int handle_alias(int *argcp, const char ***argv) "trace: alias expansion: %s =>", alias_command); - new_argv = xrealloc(new_argv, sizeof(char*) * + new_argv = xrealloc(new_argv, sizeof(char *) * (count + *argcp + 1)); /* insert after command name */ - memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); + memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); new_argv[count+*argcp] = NULL; *argv = new_argv; @@ -274,6 +274,7 @@ static void handle_internal_command(int argc, const char **argv) { "annotate", cmd_annotate, RUN_SETUP }, { "apply", cmd_apply }, { "archive", cmd_archive }, + { "bisect--helper", cmd_bisect__helper, RUN_SETUP | NEED_WORK_TREE }, { "blame", cmd_blame, RUN_SETUP }, { "branch", cmd_branch, RUN_SETUP }, { "bundle", cmd_bundle }, @@ -496,7 +497,7 @@ int main(int argc, const char **argv) /* * We use PATH to find git commands, but we prepend some higher - * precidence paths: the "--exec-path" option, the GIT_EXEC_PATH + * precedence paths: the "--exec-path" option, the GIT_EXEC_PATH * environment, and the $(gitexecdir) from the Makefile at build * time. */ diff --git a/gitk-git/gitk b/gitk-git/gitk index 1773ae63eb..1a7887b252 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -521,7 +521,7 @@ proc updatecommits {} { incr viewactive($view) set viewcomplete($view) 0 reset_pending_select {} - nowbusy $view "Reading" + nowbusy $view [mc "Reading"] if {$showneartags} { getallcommits } @@ -1830,7 +1830,9 @@ proc setoptions {} { option add *Button.font uifont startupFile option add *Checkbutton.font uifont startupFile option add *Radiobutton.font uifont startupFile - option add *Menu.font uifont startupFile + if {[tk windowingsystem] ne "aqua"} { + option add *Menu.font uifont startupFile + } option add *Menubutton.font uifont startupFile option add *Label.font uifont startupFile option add *Message.font uifont startupFile @@ -1910,8 +1912,8 @@ proc makewindow {} { # The "mc" arguments here are purely so that xgettext # sees the following string as needing to be translated - makemenu .bar { - {mc "File" cascade { + set file { + mc "File" cascade { {mc "Update" command updatecommits -accelerator F5} {mc "Reload" command reloadcommits -accelerator Meta1-F5} {mc "Reread references" command rereadrefs} @@ -1921,21 +1923,41 @@ proc makewindow {} { {xx "" separator} {mc "Quit" command doquit -accelerator Meta1-Q} }} - {mc "Edit" cascade { + set edit { + mc "Edit" cascade { {mc "Preferences" command doprefs} }} - {mc "View" cascade { + set view { + mc "View" cascade { {mc "New view..." command {newview 0} -accelerator Shift-F4} {mc "Edit view..." command editview -state disabled -accelerator F4} {mc "Delete view" command delview -state disabled} {xx "" separator} {mc "All files" radiobutton {selectedview 0} -command {showview 0}} }} - {mc "Help" cascade { + if {[tk windowingsystem] ne "aqua"} { + set help { + mc "Help" cascade { {mc "About gitk" command about} {mc "Key bindings" command keys} }} + set bar [list $file $edit $view $help] + } else { + proc ::tk::mac::ShowPreferences {} {doprefs} + proc ::tk::mac::Quit {} {doquit} + lset file end [lreplace [lindex $file end] end-1 end] + set apple { + xx "Apple" cascade { + {mc "About gitk" command about} + {xx "" separator} + }} + set help { + mc "Help" cascade { + {mc "Key bindings" command keys} + }} + set bar [list $apple $file $view $help] } + makemenu .bar $bar . configure -menu .bar # the gui has upper and lower half, parts of a paned window. @@ -2229,10 +2251,16 @@ proc makewindow {} { } } + if {[info exists geometry(state)] && $geometry(state) eq "zoomed"} { + wm state . $geometry(state) + } + if {[tk windowingsystem] eq {aqua}} { set M1B M1 + set ::BM "3" } else { set M1B Control + set ::BM "2" } bind .pwbottom <Configure> {resizecdetpanes %W %w} @@ -2250,10 +2278,14 @@ proc makewindow {} { set delta [expr {- (%D)}] allcanvs yview scroll $delta units } + bindall <Shift-MouseWheel> { + set delta [expr {- (%D)}] + $canv xview scroll $delta units + } } } - bindall <2> "canvscan mark %W %x %y" - bindall <B2-Motion> "canvscan dragto %W %x %y" + bindall <$::BM> "canvscan mark %W %x %y" + bindall <B$::BM-Motion> "canvscan dragto %W %x %y" bindkey <Home> selfirstline bindkey <End> sellastline bind . <Key-Up> "selnextline -1" @@ -2285,6 +2317,7 @@ proc makewindow {} { bindkey d "$ctext yview scroll 18 units" bindkey u "$ctext yview scroll -18 units" bindkey / {focus $fstring} + bindkey <Key-KP_Divide> {focus $fstring} bindkey <Key-Return> {dofind 1 1} bindkey ? {dofind -1 1} bindkey f nextfile @@ -2331,6 +2364,10 @@ proc makewindow {} { {mc "Create new branch" command mkbranch} {mc "Cherry-pick this commit" command cherrypick} {mc "Reset HEAD branch to here" command resethead} + {mc "Mark this commit" command markhere} + {mc "Return to mark" command gotomark} + {mc "Find descendant of this and mark" command find_common_desc} + {mc "Compare with marked commit" command compare_commits} } $rowctxmenu configure -tearoff 0 @@ -2487,6 +2524,9 @@ proc savestuff {w} { if {![winfo viewable .]} return catch { set f [open "~/.gitk-new" w] + if {$::tcl_platform(platform) eq {windows}} { + file attributes "~/.gitk-new" -hidden true + } puts $f [list set mainfont $mainfont] puts $f [list set textfont $textfont] puts $f [list set uifont $uifont] @@ -2512,6 +2552,7 @@ proc savestuff {w} { puts $f [list set perfile_attrs $perfile_attrs] puts $f "set geometry(main) [wm geometry .]" + puts $f "set geometry(state) [wm state .]" puts $f "set geometry(topwidth) [winfo width .tf]" puts $f "set geometry(topheight) [winfo height .tf]" puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sash coord 0]\"" @@ -3204,9 +3245,8 @@ proc external_diff {} { set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir] if {$difffromfile ne {} && $difftofile ne {}} { - set cmd [concat | [shellsplit $extdifftool] \ - [list $difffromfile $difftofile]] - if {[catch {set fl [open $cmd r]} err]} { + set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile] + if {[catch {set fl [open |$cmd r]} err]} { file delete -force $diffdir error_popup "$extdifftool: [mc "command failed:"] $err" } else { @@ -3737,7 +3777,7 @@ proc editview {} { set newviewopts($curview,perm) $viewperm($curview) set newviewopts($curview,cmd) $viewargscmd($curview) decode_view_opts $curview $viewargs($curview) - vieweditor $top $curview "Gitk: edit view $viewname($curview)" + vieweditor $top $curview "[mc "Gitk: edit view"] $viewname($curview)" } proc vieweditor {top n title} { @@ -4046,7 +4086,7 @@ proc ishighlighted {id} { } proc bolden {id font} { - global canv linehtag currentid boldids need_redisplay + global canv linehtag currentid boldids need_redisplay markedid # need_redisplay = 1 means the display is stale and about to be redrawn if {$need_redisplay} return @@ -4059,6 +4099,9 @@ proc bolden {id font} { -fill [$canv cget -selectbackground]] $canv lower $t } + if {[info exists markedid] && $id eq $markedid} { + make_idmark $id + } } proc bolden_name {id font} { @@ -5563,7 +5606,7 @@ proc drawcmittext {id row col} { global cmitlisted commitinfo rowidlist parentlist global rowtextx idpos idtags idheads idotherrefs global linehtag linentag linedtag selectedline - global canvxmax boldids boldnameids fgcolor + global canvxmax boldids boldnameids fgcolor markedid global mainheadid nullid nullid2 circleitem circlecolors ctxbut # listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right @@ -5645,6 +5688,9 @@ proc drawcmittext {id row col} { if {$selectedline == $row} { make_secsel $id } + if {[info exists markedid] && $markedid eq $id} { + make_idmark $id + } set xr [expr {$xt + [font measure $font $headline]}] if {$xr > $canvxmax} { set canvxmax $xr @@ -6443,6 +6489,17 @@ proc setlink {id lk} { } } +proc appendshortlink {id {pre {}} {post {}}} { + global ctext linknum + + $ctext insert end $pre + $ctext tag delete link$linknum + $ctext insert end [string range $id 0 7] link$linknum + $ctext insert end $post + setlink $id link$linknum + incr linknum +} + proc makelink {id} { global pendinglinks @@ -6499,7 +6556,7 @@ proc appendrefs {pos ids var} { } } if {[llength $tags] > $maxrefs} { - $ctext insert $pos "many ([llength $tags])" + $ctext insert $pos "[mc "many"] ([llength $tags])" } else { set tags [lsort -index 0 -decreasing $tags] set sep {} @@ -6586,6 +6643,16 @@ proc make_secsel {id} { $canv3 lower $t } +proc make_idmark {id} { + global linehtag canv fgcolor + + if {![info exists linehtag($id)]} return + $canv delete markid + set t [eval $canv create rect [$canv bbox $linehtag($id)] \ + -tags markid -outline $fgcolor] + $canv raise $t +} + proc selectline {l isnew {desired_loc {}}} { global canv ctext commitinfo selectedline global canvy0 linespc parents children curview @@ -7216,7 +7283,7 @@ proc getblobdiffs {ids} { set diffnparents 0 set diffinhdr 0 set diffencoding [get_path_encoding {}] - fconfigure $bdf -blocking 0 -encoding binary + fconfigure $bdf -blocking 0 -encoding binary -eofchar {} set blobdifffd($ids) $bdf filerun $bdf [list getblobdiffline $bdf $diffids] } @@ -7367,7 +7434,8 @@ proc getblobdiffline {bdf ids} { $ctext insert end "$line\n" filesep } else { - set line [encoding convertfrom $diffencoding $line] + set line [string map {\x1A ^Z} \ + [encoding convertfrom $diffencoding $line]] # parse the prefix - one ' ', '-' or '+' for each parent set prefix [string range $line 0 [expr {$diffnparents - 1}]] set tag [expr {$diffnparents > 1? "m": "d"}] @@ -7970,7 +8038,7 @@ proc mstime {} { proc rowmenu {x y id} { global rowctxmenu selectedline rowmenuid curview - global nullid nullid2 fakerowmenu mainhead + global nullid nullid2 fakerowmenu mainhead markedid stopfinding set rowmenuid $id @@ -7986,6 +8054,15 @@ proc rowmenu {x y id} { } else { $menu entryconfigure 7 -label [mc "Detached head: can't reset" $mainhead] -state disabled } + if {[info exists markedid] && $markedid ne $id} { + $menu entryconfigure 9 -state normal + $menu entryconfigure 10 -state normal + $menu entryconfigure 11 -state normal + } else { + $menu entryconfigure 9 -state disabled + $menu entryconfigure 10 -state disabled + $menu entryconfigure 11 -state disabled + } } else { set menu $fakerowmenu } @@ -7995,6 +8072,162 @@ proc rowmenu {x y id} { tk_popup $menu $x $y } +proc markhere {} { + global rowmenuid markedid canv + + set markedid $rowmenuid + make_idmark $markedid +} + +proc gotomark {} { + global markedid + + if {[info exists markedid]} { + selbyid $markedid + } +} + +proc replace_by_kids {l r} { + global curview children + + set id [commitonrow $r] + set l [lreplace $l 0 0] + foreach kid $children($curview,$id) { + lappend l [rowofcommit $kid] + } + return [lsort -integer -decreasing -unique $l] +} + +proc find_common_desc {} { + global markedid rowmenuid curview children + + if {![info exists markedid]} return + if {![commitinview $markedid $curview] || + ![commitinview $rowmenuid $curview]} return + #set t1 [clock clicks -milliseconds] + set l1 [list [rowofcommit $markedid]] + set l2 [list [rowofcommit $rowmenuid]] + while 1 { + set r1 [lindex $l1 0] + set r2 [lindex $l2 0] + if {$r1 eq {} || $r2 eq {}} break + if {$r1 == $r2} { + selectline $r1 1 + break + } + if {$r1 > $r2} { + set l1 [replace_by_kids $l1 $r1] + } else { + set l2 [replace_by_kids $l2 $r2] + } + } + #set t2 [clock clicks -milliseconds] + #puts "took [expr {$t2-$t1}]ms" +} + +proc compare_commits {} { + global markedid rowmenuid curview children + + if {![info exists markedid]} return + if {![commitinview $markedid $curview]} return + addtohistory [list do_cmp_commits $markedid $rowmenuid] + do_cmp_commits $markedid $rowmenuid +} + +proc getpatchid {id} { + global patchids + + if {![info exists patchids($id)]} { + set cmd [diffcmd [list $id] {-p --root}] + # trim off the initial "|" + set cmd [lrange $cmd 1 end] + if {[catch { + set x [eval exec $cmd | git patch-id] + set patchids($id) [lindex $x 0] + }]} { + set patchids($id) "error" + } + } + return $patchids($id) +} + +proc do_cmp_commits {a b} { + global ctext curview parents children patchids commitinfo + + $ctext conf -state normal + clear_ctext + init_flist {} + for {set i 0} {$i < 100} {incr i} { + set skipa 0 + set skipb 0 + if {[llength $parents($curview,$a)] > 1} { + appendshortlink $a [mc "Skipping merge commit "] "\n" + set skipa 1 + } else { + set patcha [getpatchid $a] + } + if {[llength $parents($curview,$b)] > 1} { + appendshortlink $b [mc "Skipping merge commit "] "\n" + set skipb 1 + } else { + set patchb [getpatchid $b] + } + if {!$skipa && !$skipb} { + set heada [lindex $commitinfo($a) 0] + set headb [lindex $commitinfo($b) 0] + if {$patcha eq "error"} { + appendshortlink $a [mc "Error getting patch ID for "] \ + [mc " - stopping\n"] + break + } + if {$patchb eq "error"} { + appendshortlink $b [mc "Error getting patch ID for "] \ + [mc " - stopping\n"] + break + } + if {$patcha eq $patchb} { + if {$heada eq $headb} { + appendshortlink $a [mc "Commit "] + appendshortlink $b " == " " $heada\n" + } else { + appendshortlink $a [mc "Commit "] " $heada\n" + appendshortlink $b [mc " is the same patch as\n "] \ + " $headb\n" + } + set skipa 1 + set skipb 1 + } else { + $ctext insert end "\n" + appendshortlink $a [mc "Commit "] " $heada\n" + appendshortlink $b [mc " differs from\n "] \ + " $headb\n" + $ctext insert end [mc "- stopping\n"] + break + } + } + if {$skipa} { + if {[llength $children($curview,$a)] != 1} { + $ctext insert end "\n" + appendshortlink $a [mc "Commit "] \ + [mc " has %s children - stopping\n" \ + [llength $children($curview,$a)]] + break + } + set a [lindex $children($curview,$a) 0] + } + if {$skipb} { + if {[llength $children($curview,$b)] != 1} { + appendshortlink $b [mc "Commit "] \ + [mc " has %s children - stopping\n" \ + [llength $children($curview,$b)]] + break + } + set b [lindex $children($curview,$b) 0] + } + } + $ctext conf -state disabled +} + proc diffvssel {dirn} { global rowmenuid selectedline @@ -8189,7 +8422,7 @@ proc domktag {} { } proc redrawtags {id} { - global canv linehtag idpos currentid curview cmitlisted + global canv linehtag idpos currentid curview cmitlisted markedid global canvxmax iddrawn circleitem mainheadid circlecolors if {![commitinview $id $curview]} return @@ -8214,6 +8447,9 @@ proc redrawtags {id} { if {[info exists currentid] && $currentid == $id} { make_secsel $id } + if {[info exists markedid] && $markedid eq $id} { + make_idmark $id + } } proc mktagcan {} { @@ -10197,7 +10433,7 @@ proc doprefs {} { proc choose_extdiff {} { global extdifftool - set prog [tk_getOpenFile -title "External diff tool" -multiple false] + set prog [tk_getOpenFile -title [mc "External diff tool"] -multiple false] if {$prog ne {}} { set extdifftool $prog } @@ -10240,6 +10476,7 @@ proc setfg {c} { } allcanvs itemconf text -fill $c $canv itemconf circle -outline $c + $canv itemconf markid -outline $c } proc prefscan {} { @@ -10689,9 +10926,15 @@ catch { } } -set mainfont {Helvetica 9} -set textfont {Courier 9} -set uifont {Helvetica 9 bold} +if {[tk windowingsystem] eq "aqua"} { + set mainfont {{Lucida Grande} 9} + set textfont {Monaco 9} + set uifont {{Lucida Grande} 9 bold} +} else { + set mainfont {Helvetica 9} + set textfont {Courier 9} + set uifont {Helvetica 9 bold} +} set tabstop 8 set findmergefiles 0 set maxgraphpct 50 @@ -10712,7 +10955,11 @@ set datetimeformat "%Y-%m-%d %H:%M:%S" set autoselect 1 set perfile_attrs 0 -set extdifftool "meld" +if {[tk windowingsystem] eq "aqua"} { + set extdifftool "opendiff" +} else { + set extdifftool "meld" +} set colors {green red blue magenta darkgrey brown orange} set bgcolor white @@ -10883,9 +11130,33 @@ set lserial 0 set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}] setcoords makewindow +catch { + image create photo gitlogo -width 16 -height 16 + + image create photo gitlogominus -width 4 -height 2 + gitlogominus put #C00000 -to 0 0 4 2 + gitlogo copy gitlogominus -to 1 5 + gitlogo copy gitlogominus -to 6 5 + gitlogo copy gitlogominus -to 11 5 + image delete gitlogominus + + image create photo gitlogoplus -width 4 -height 4 + gitlogoplus put #008000 -to 1 0 3 4 + gitlogoplus put #008000 -to 0 1 4 3 + gitlogo copy gitlogoplus -to 1 9 + gitlogo copy gitlogoplus -to 6 9 + gitlogo copy gitlogoplus -to 11 9 + image delete gitlogoplus + + image create photo gitlogo32 -width 32 -height 32 + gitlogo32 copy gitlogo -zoom 2 2 + + wm iconphoto . -default gitlogo gitlogo32 +} # wait for the window to become visible tkwait visibility . wm title . "[file tail $argv0]: [file tail [pwd]]" +update readrefs if {$cmdline_files ne {} || $revtreeargs ne {} || $revtreeargscmd ne {}} { diff --git a/gitk-git/po/ru.po b/gitk-git/po/ru.po new file mode 100644 index 0000000000..704eba8f9d --- /dev/null +++ b/gitk-git/po/ru.po @@ -0,0 +1,1085 @@ +# +# Translation of gitk to Russian. +# +msgid "" +msgstr "" +"Project-Id-Version: gitk\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-04-24 16:00+0200\n" +"PO-Revision-Date: 2009-04-24 16:00+0200\n" +"Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n" +"Language-Team: Russian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gitk:113 +msgid "Couldn't get list of unmerged files:" +msgstr "" +"Невозможно получить список файлов незавершённой операции слияния:" + +#: gitk:268 +msgid "Error parsing revisions:" +msgstr "Ошибка в идентификаторе версии:" + +#: gitk:323 +msgid "Error executing --argscmd command:" +msgstr "Ошибка выполнения команды заданой --argscmd:" + +#: gitk:336 +msgid "No files selected: --merge specified but no files are unmerged." +msgstr "" +"Файлы не выбраны: указан --merge, но не было найдено ни одного файла " +"где эта операция должна быть завершена." + +#: gitk:339 +msgid "" +"No files selected: --merge specified but no unmerged files are within file " +"limit." +msgstr "" +"Файлы не выбраны: указан --merge, но в рамках указаного " +"ограничения на имена файлов нет ни одного " +"где эта операция должна быть завершена." + +#: gitk:361 gitk:508 +msgid "Error executing git log:" +msgstr "Ошибка запуска git log:" + +#: gitk:379 +msgid "Reading" +msgstr "Чтение" + +#: gitk:439 gitk:4021 +msgid "Reading commits..." +msgstr "Чтение версий..." + +#: gitk:442 gitk:1560 gitk:4024 +msgid "No commits selected" +msgstr "Ничего не выбрано" + +#: gitk:1436 +msgid "Can't parse git log output:" +msgstr "Ошибка обработки вывода команды git log:" + +#: gitk:1656 +msgid "No commit information available" +msgstr "Нет информации о состоянии" + +#: gitk:1791 gitk:1815 gitk:3814 gitk:8478 gitk:10014 gitk:10186 +msgid "OK" +msgstr "Ok" + +#: gitk:1817 gitk:3816 gitk:8078 gitk:8152 gitk:8259 gitk:8308 gitk:8480 +#: gitk:10015 gitk:10187 +msgid "Cancel" +msgstr "Отмена" + +#: gitk:1915 +msgid "Update" +msgstr "Обновить" + +#: gitk:1916 +msgid "Reload" +msgstr "Перечитать" + +#: gitk:1917 +msgid "Reread references" +msgstr "Обновить список ссылок" + +#: gitk:1918 +msgid "List references" +msgstr "Список ссылок" + +#: gitk:1920 +msgid "Start git gui" +msgstr "Запустить git gui" + +#: gitk:1922 +msgid "Quit" +msgstr "Завершить" + +#: gitk:1914 +msgid "File" +msgstr "Файл" + +#: gitk:1925 +msgid "Preferences" +msgstr "Настройки" + +#: gitk:1924 +msgid "Edit" +msgstr "Редактировать" + +#: gitk:1928 +msgid "New view..." +msgstr "Новое представление..." + +#: gitk:1929 +msgid "Edit view..." +msgstr "Редактировать представление..." + +#: gitk:1930 +msgid "Delete view" +msgstr "Удалить представление" + +#: gitk:1932 +msgid "All files" +msgstr "Все файлы" + +#: gitk:1927 gitk:3626 +msgid "View" +msgstr "Представление" + +#: gitk:1935 gitk:2609 +msgid "About gitk" +msgstr "О gitk" + +#: gitk:1936 +msgid "Key bindings" +msgstr "Назначения клавиатуры" + +#: gitk:1934 +msgid "Help" +msgstr "Подсказка" + +#: gitk:1994 +msgid "SHA1 ID: " +msgstr "SHA1:" + +#: gitk:2025 +msgid "Row" +msgstr "Строка" + +#: gitk:2056 +msgid "Find" +msgstr "Поиск" + +#: gitk:2057 +msgid "next" +msgstr "След." + +#: gitk:2058 +msgid "prev" +msgstr "Пред." + +#: gitk:2059 +msgid "commit" +msgstr "состояние" + +#: gitk:2062 gitk:2064 gitk:4179 gitk:4202 gitk:4226 gitk:6164 gitk:6236 +#: gitk:6320 +msgid "containing:" +msgstr "содержащее:" + +#: gitk:2065 gitk:3117 gitk:3122 gitk:4254 +msgid "touching paths:" +msgstr "касательно файлов:" + +#: gitk:2066 gitk:4259 +msgid "adding/removing string:" +msgstr "добавив/удалив строку:" + +#: gitk:2075 gitk:2077 +msgid "Exact" +msgstr "Точно" + +#: gitk:2077 gitk:4334 gitk:6132 +msgid "IgnCase" +msgstr "Игнорировать большие/маленькие" + +#: gitk:2077 gitk:4228 gitk:4332 gitk:6128 +msgid "Regexp" +msgstr "Регулярные выражения" + +#: gitk:2079 gitk:2080 gitk:4353 gitk:4383 gitk:4390 gitk:6256 gitk:6324 +msgid "All fields" +msgstr "Во всех полях" + +#: gitk:2080 gitk:4351 gitk:4383 gitk:6195 +msgid "Headline" +msgstr "Заголовок" + +#: gitk:2081 gitk:4351 gitk:6195 gitk:6324 gitk:6737 +msgid "Comments" +msgstr "Комментарии" + +#: gitk:2081 gitk:4351 gitk:4355 gitk:4390 gitk:6195 gitk:6672 gitk:7923 +#: gitk:7938 +msgid "Author" +msgstr "Автор" + +#: gitk:2081 gitk:4351 gitk:6195 gitk:6674 +msgid "Committer" +msgstr "Сохранивший состояние" + +#: gitk:2110 +msgid "Search" +msgstr "Найти" + +#: gitk:2117 +msgid "Diff" +msgstr "Сравнить" + +#: gitk:2119 +msgid "Old version" +msgstr "Старая версия" + +#: gitk:2121 +msgid "New version" +msgstr "Новая версия" + +#: gitk:2123 +msgid "Lines of context" +msgstr "Строк контекста" + +#: gitk:2133 +msgid "Ignore space change" +msgstr "Игнорировать пробелы" + +#: gitk:2191 +msgid "Patch" +msgstr "Патч" + +#: gitk:2193 +msgid "Tree" +msgstr "Файлы" + +#: gitk:2326 gitk:2339 +msgid "Diff this -> selected" +msgstr "Сравнить это состояние с выделеным" + +#: gitk:2327 gitk:2340 +msgid "Diff selected -> this" +msgstr "Сравнить выделеное с этим состоянием" + +#: gitk:2328 gitk:2341 +msgid "Make patch" +msgstr "Создать патч" + +#: gitk:2329 gitk:8136 +msgid "Create tag" +msgstr "Создать метку" + +#: gitk:2330 gitk:8239 +msgid "Write commit to file" +msgstr "Сохранить изменения в файл" + +#: gitk:2331 gitk:8296 +msgid "Create new branch" +msgstr "Создать ветвь" + +#: gitk:2332 +msgid "Cherry-pick this commit" +msgstr "Скопировать это состояние" + +#: gitk:2333 +msgid "Reset HEAD branch to here" +msgstr "Установить HEAD на это состояние" + +#: gitk:2347 +msgid "Check out this branch" +msgstr "Перейти на эту ветвь" + +#: gitk:2348 +msgid "Remove this branch" +msgstr "Удалить эту ветвь" + +#: gitk:2355 +msgid "Highlight this too" +msgstr "Подсветить этот тоже" + +#: gitk:2356 +msgid "Highlight this only" +msgstr "Подсветить только этот" + +#: gitk:2357 +msgid "External diff" +msgstr "Программа сравнения" + +#: gitk:2358 +msgid "Blame parent commit" +msgstr "Аннотировать родительское состояние" + +#: gitk:2365 +msgid "Show origin of this line" +msgstr "Показать источник этой строки" + +#: gitk:2366 +msgid "Run git gui blame on this line" +msgstr "Запустить git gui blame для этой строки" + +#: gitk:2611 +msgid "" +"\n" +"Gitk - a commit viewer for git\n" +"\n" +"Copyright © 2005-2008 Paul Mackerras\n" +"\n" +"Use and redistribute under the terms of the GNU General Public License" +msgstr "" +"\n" +"Gitk - программа просмотра истории репозиториев Git\n" +"\n" +"Copyright (c) 2005-2008 Paul Mackerras\n" +"\n" +"Использование и распространение согласно условиям GNU General Public License" + +#: gitk:2619 gitk:2681 gitk:8661 +msgid "Close" +msgstr "Закрыть" + +#: gitk:2638 +msgid "Gitk key bindings" +msgstr "Назначения клавиатуры в Gitk" + +#: gitk:2641 +msgid "Gitk key bindings:" +msgstr "Назначения клавиатуры в Gitk:" + +#: gitk:2643 +#, tcl-format +msgid "<%s-Q>\t\tQuit" +msgstr "<%s-Q>\t\tЗавершить" + +#: gitk:2644 +msgid "<Home>\t\tMove to first commit" +msgstr "<Home>\t\tПерейти к первому состоянию" + +#: gitk:2645 +msgid "<End>\t\tMove to last commit" +msgstr "<End>\t\tПерейти к последнему состоянию" + +#: gitk:2646 +msgid "<Up>, p, i\tMove up one commit" +msgstr "<Up>, p, i\tПерейти к следующему состоянию" + +#: gitk:2647 +msgid "<Down>, n, k\tMove down one commit" +msgstr "<Down>, n, k\tПерейти к предыдущему состоянию" + +#: gitk:2648 +msgid "<Left>, z, j\tGo back in history list" +msgstr "<Left>, z, j\tПоказать ранее посещённое состояние" + +#: gitk:2649 +msgid "<Right>, x, l\tGo forward in history list" +msgstr "<Right>, x, l\tПоказать следующее посещённое состояние" + +#: gitk:2650 +msgid "<PageUp>\tMove up one page in commit list" +msgstr "<PageUp>\tПерейти на страницу выше в списке состояний" + +#: gitk:2651 +msgid "<PageDown>\tMove down one page in commit list" +msgstr "<PageDown>\tПерейти на страницу ниже в списке состояний" + +#: gitk:2652 +#, tcl-format +msgid "<%s-Home>\tScroll to top of commit list" +msgstr "<%s-Home>\tПоказать начало списка состояний" + +#: gitk:2653 +#, tcl-format +msgid "<%s-End>\tScroll to bottom of commit list" +msgstr "<%s-End>\tПоказать конец списка состояний" + +#: gitk:2654 +#, tcl-format +msgid "<%s-Up>\tScroll commit list up one line" +msgstr "<%s-Up>\tПровернуть список состояний вверх" + +#: gitk:2655 +#, tcl-format +msgid "<%s-Down>\tScroll commit list down one line" +msgstr "<%s-Down>\tПровернуть список состояний вниз" + +#: gitk:2656 +#, tcl-format +msgid "<%s-PageUp>\tScroll commit list up one page" +msgstr "<%s-PageUp>\tПровернуть список состояний на страницу вверх" + +#: gitk:2657 +#, tcl-format +msgid "<%s-PageDown>\tScroll commit list down one page" +msgstr "<%s-PageDown>\tПровернуть список состояний на страницу вниз" + +#: gitk:2658 +msgid "<Shift-Up>\tFind backwards (upwards, later commits)" +msgstr "" +"<Shift-Up>\tПоиск в обратном порядке (вверх, среди новых состояний)" + +#: gitk:2659 +msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)" +msgstr "<Shift-Down>\tПоиск (вниз, среди старых состояний)" + +#: gitk:2660 +msgid "<Delete>, b\tScroll diff view up one page" +msgstr "<Delete>, b\tПрокрутить список изменений на страницу выше" + +#: gitk:2661 +msgid "<Backspace>\tScroll diff view up one page" +msgstr "<Backspace>\tПрокрутить список изменений на страницу выше" + +#: gitk:2662 +msgid "<Space>\t\tScroll diff view down one page" +msgstr "<Leertaste>\t\tПрокрутить список изменений на страницу ниже" + +#: gitk:2663 +msgid "u\t\tScroll diff view up 18 lines" +msgstr "u\t\tПрокрутить список изменений на 18 строк вверх" + +#: gitk:2664 +msgid "d\t\tScroll diff view down 18 lines" +msgstr "d\t\tПрокрутить список изменений на 18 строк вниз" + +#: gitk:2665 +#, tcl-format +msgid "<%s-F>\t\tFind" +msgstr "<%s-F>\t\tПоиск" + +#: gitk:2666 +#, tcl-format +msgid "<%s-G>\t\tMove to next find hit" +msgstr "<%s-G>\t\tПерейти к следующему найденому состоянию" + +#: gitk:2667 +msgid "<Return>\tMove to next find hit" +msgstr "<Return>\tПерейти к следующему найденому состоянию" + +#: gitk:2668 +msgid "/\t\tFocus the search box" +msgstr "/\t\tПерейти к полю поиска" + +#: gitk:2669 +msgid "?\t\tMove to previous find hit" +msgstr "?\t\tПерейти к предыдущему найденому состоянию" + +#: gitk:2670 +msgid "f\t\tScroll diff view to next file" +msgstr "f\t\tПрокрутить список изменений к следующему файлу" + +#: gitk:2671 +#, tcl-format +msgid "<%s-S>\t\tSearch for next hit in diff view" +msgstr "<%s-S>\t\tПродолжить поиск в списке изменений" + +#: gitk:2672 +#, tcl-format +msgid "<%s-R>\t\tSearch for previous hit in diff view" +msgstr "<%s-R>\t\tПерейти к предыдущему найденому тексту в списке изменений" + +#: gitk:2673 +#, tcl-format +msgid "<%s-KP+>\tIncrease font size" +msgstr "<%s-KP+>\tУвеличить размер шрифта" + +#: gitk:2674 +#, tcl-format +msgid "<%s-plus>\tIncrease font size" +msgstr "<%s-plus>\tУвеличить размер шрифта" + +#: gitk:2675 +#, tcl-format +msgid "<%s-KP->\tDecrease font size" +msgstr "<%s-KP->\tУменьшить размер шрифта" + +#: gitk:2676 +#, tcl-format +msgid "<%s-minus>\tDecrease font size" +msgstr "<%s-minus>\tУменьшить размер шрифта" + +#: gitk:2677 +msgid "<F5>\t\tUpdate" +msgstr "<F5>\t\tОбновить" + +#: gitk:3132 +#, tcl-format +msgid "Error getting \"%s\" from %s:" +msgstr "Ошибка получения \"%s\" из %s:" + +#: gitk:3189 gitk:3198 +#, tcl-format +msgid "Error creating temporary directory %s:" +msgstr "Ошибка создания временного каталога %s:" + +#: gitk:3211 +msgid "command failed:" +msgstr "ошибка выполнения команды:" + +#: gitk:3357 +msgid "No such commit" +msgstr "Состояние не найдено" + +#: gitk:3371 +msgid "git gui blame: command failed:" +msgstr "git gui blame: ошибка выполнения команды:" + +#: gitk:3402 +#, tcl-format +msgid "Couldn't read merge head: %s" +msgstr "Ошибка чтения MERGE_HEAD: %s" + +#: gitk:3410 +#, tcl-format +msgid "Error reading index: %s" +msgstr "Ошибка чтения индекса: %s" + +#: gitk:3435 +#, tcl-format +msgid "Couldn't start git blame: %s" +msgstr "Ошибка запуска git blame: %s" + +#: gitk:3438 gitk:6163 +msgid "Searching" +msgstr "Поиск" + +#: gitk:3470 +#, tcl-format +msgid "Error running git blame: %s" +msgstr "Ошибка выполнения git blame: %s" + +#: gitk:3498 +#, tcl-format +msgid "That line comes from commit %s, which is not in this view" +msgstr "" +"Эта строка принадлежит состоянию %s, которое не показано в этом " +"представлении" + +#: gitk:3512 +msgid "External diff viewer failed:" +msgstr "Ошибка выполнения программы сравнения:" + +#: gitk:3630 +msgid "Gitk view definition" +msgstr "Gitk определение представлений" + +#: gitk:3634 +msgid "Remember this view" +msgstr "Запомнить представление" + +#: gitk:3635 +msgid "Commits to include (arguments to git log):" +msgstr "Включить состояния (аргументы для git-log):" + +#: gitk:3636 +msgid "Use all refs" +msgstr "Использовать все ветви" + +#: gitk:3637 +msgid "Strictly sort by date" +msgstr "Строгая сортировка по дате" + +#: gitk:3638 +msgid "Mark branch sides" +msgstr "Отметить стороны ветвей" + +#: gitk:3639 +msgid "Since date:" +msgstr "С даты:" + +#: gitk:3640 +msgid "Until date:" +msgstr "По дату:" + +#: gitk:3641 +msgid "Max count:" +msgstr "Макс. количество:" + +#: gitk:3642 +msgid "Skip:" +msgstr "Пропустить:" + +#: gitk:3643 +msgid "Limit to first parent" +msgstr "Ограничить первым предком" + +#: gitk:3644 +msgid "Command to generate more commits to include:" +msgstr "Дополнительная команда для списка состояний:" + +#: gitk:3753 +msgid "Name" +msgstr "Имя" + +#: gitk:3801 +msgid "Enter files and directories to include, one per line:" +msgstr "Файлы и каталоги для ограничения истории, по одному на строку:" + +#: gitk:3815 +msgid "Apply (F5)" +msgstr "Применить (F5)" + +#: gitk:3853 +msgid "Error in commit selection arguments:" +msgstr "Ошибка в параметрах выбора состояний:" + +#: gitk:3906 gitk:3958 gitk:4403 gitk:4417 gitk:5675 gitk:10867 gitk:10868 +msgid "None" +msgstr "Ни одного" + +#: gitk:4351 gitk:6195 gitk:7925 gitk:7940 +msgid "Date" +msgstr "Дата" + +#: gitk:4351 gitk:6195 +msgid "CDate" +msgstr "Дата ввода" + +#: gitk:4500 gitk:4505 +msgid "Descendant" +msgstr "Порождённое" + +#: gitk:4501 +msgid "Not descendant" +msgstr "Не порождённое" + +#: gitk:4508 gitk:4513 +msgid "Ancestor" +msgstr "Предок" + +#: gitk:4509 +msgid "Not ancestor" +msgstr "Не предок" + +#: gitk:4799 +msgid "Local changes checked in to index but not committed" +msgstr "Изменения зарегистрированные в индексе, но не сохранённые" + +#: gitk:4835 +msgid "Local uncommitted changes, not checked in to index" +msgstr "Изменения в рабочем каталоге, не зарегистрированные в индексе" + +#: gitk:6676 +msgid "Tags:" +msgstr "Таги:" + +#: gitk:6693 gitk:6699 gitk:7918 +msgid "Parent" +msgstr "Предок" + +#: gitk:6704 +msgid "Child" +msgstr "Потомок" + +#: gitk:6713 +msgid "Branch" +msgstr "Ветвь" + +#: gitk:6716 +msgid "Follows" +msgstr "Следует за" + +#: gitk:6719 +msgid "Precedes" +msgstr "Предшествует" + +#: gitk:7212 +#, tcl-format +msgid "Error getting diffs: %s" +msgstr "Ошибка получения изменений: %s" + +#: gitk:7751 +msgid "Goto:" +msgstr "Перейти к:" + +#: gitk:7753 +msgid "SHA1 ID:" +msgstr "SHA1 ID:" + +#: gitk:7772 +#, tcl-format +msgid "Short SHA1 id %s is ambiguous" +msgstr "Сокращённый SHA1 идентификатор %s неоднозначен" + +#: gitk:7784 +#, tcl-format +msgid "SHA1 id %s is not known" +msgstr "SHA1 идентификатор %s не найден" + +#: gitk:7786 +#, tcl-format +msgid "Tag/Head %s is not known" +msgstr "Метка или ветвь %s не найдена" + +#: gitk:7928 +msgid "Children" +msgstr "Потомки" + +#: gitk:7985 +#, tcl-format +msgid "Reset %s branch to here" +msgstr "Установить ветвь %s на это состояние" + +#: gitk:7987 +msgid "Detached head: can't reset" +msgstr "Состояние не принадлежит ни одной ветви, переход невозможен" + +#: gitk:8019 +msgid "Top" +msgstr "Верх" + +#: gitk:8020 +msgid "From" +msgstr "От" + +#: gitk:8025 +msgid "To" +msgstr "До" + +#: gitk:8049 +msgid "Generate patch" +msgstr "Создать патч" + +#: gitk:8051 +msgid "From:" +msgstr "От:" + +#: gitk:8060 +msgid "To:" +msgstr "До:" + +#: gitk:8069 +msgid "Reverse" +msgstr "В обратном порядке" + +#: gitk:8071 gitk:8253 +msgid "Output file:" +msgstr "Файл для сохранения:" + +#: gitk:8077 +msgid "Generate" +msgstr "Создать" + +#: gitk:8115 +msgid "Error creating patch:" +msgstr "Ошибка создания патча:" + +#: gitk:8138 gitk:8241 gitk:8298 +msgid "ID:" +msgstr "ID:" + +#: gitk:8147 +msgid "Tag name:" +msgstr "Имя метки:" + +#: gitk:8151 gitk:8307 +msgid "Create" +msgstr "Создать" + +#: gitk:8168 +msgid "No tag name specified" +msgstr "Не задано имя метки" + +#: gitk:8172 +#, tcl-format +msgid "Tag \"%s\" already exists" +msgstr "Метка \"%s\" уже существует" + +#: gitk:8178 +msgid "Error creating tag:" +msgstr "Ошибка создания метки:" + +#: gitk:8250 +msgid "Command:" +msgstr "Команда:" + +#: gitk:8258 +msgid "Write" +msgstr "Запись" + +#: gitk:8276 +msgid "Error writing commit:" +msgstr "Ошибка сохранения состояния:" + +#: gitk:8303 +msgid "Name:" +msgstr "Имя:" + +#: gitk:8326 +msgid "Please specify a name for the new branch" +msgstr "Укажите имя для новой ветви" + +#: gitk:8331 +#, tcl-format +msgid "Branch '%s' already exists. Overwrite?" +msgstr "Ветвь '%s' уже существует. Переписать?" + +#: gitk:8397 +#, tcl-format +msgid "Commit %s is already included in branch %s -- really re-apply it?" +msgstr "" +"Состояние %s уже принадлежит ветви %s. Продолжить операцию?" + +#: gitk:8402 +msgid "Cherry-picking" +msgstr "Копирование изменений" + +#: gitk:8411 +#, tcl-format +msgid "" +"Cherry-pick failed because of local changes to file '%s'.\n" +"Please commit, reset or stash your changes and try again." +msgstr "" +"Копирование невозможно из-за изменений в файле '%s'.\n" +"Сохраните или отмените изменения и повторите операцию." + +#: gitk:8417 +msgid "" +"Cherry-pick failed because of merge conflict.\n" +"Do you wish to run git citool to resolve it?" +msgstr "" +"Копирование изменений невозможно из-за незавершённой операции " +"слияния.\nЗапустить git citool для завершения этой операции?" + +#: gitk:8433 +msgid "No changes committed" +msgstr "Изменения не сохранены" + +#: gitk:8459 +msgid "Confirm reset" +msgstr "Подтвердите операцию перехода" + +#: gitk:8461 +#, tcl-format +msgid "Reset branch %s to %s?" +msgstr "Установить ветвь %s на состояние %s?" + +#: gitk:8465 +msgid "Reset type:" +msgstr "Тип операции перехода:" + +#: gitk:8469 +msgid "Soft: Leave working tree and index untouched" +msgstr "Лёгкий: оставить рабочий каталог и индекс неизменными" + +#: gitk:8472 +msgid "Mixed: Leave working tree untouched, reset index" +msgstr "" +"Смешаный: оставить рабочий каталог неизменным, установить индекс" + +#: gitk:8475 +msgid "" +"Hard: Reset working tree and index\n" +"(discard ALL local changes)" +msgstr "" +"Жесткий: переписать индекс и рабочий каталог\n" +"(все изменения в рабочем каталоги будут потеряны)" + +#: gitk:8492 +msgid "Resetting" +msgstr "Установка" + +#: gitk:8549 +msgid "Checking out" +msgstr "Переход" + +#: gitk:8602 +msgid "Cannot delete the currently checked-out branch" +msgstr "Активная ветвь не может быть удалена" + +#: gitk:8608 +#, tcl-format +msgid "" +"The commits on branch %s aren't on any other branch.\n" +"Really delete branch %s?" +msgstr "" +"Состояния ветви %s больше не принадлежат никакой другой ветви.\n" +"Действительно удалить ветвь %s?" + +#: gitk:8639 +#, tcl-format +msgid "Tags and heads: %s" +msgstr "Метки и ветви: %s" + +#: gitk:8654 +msgid "Filter" +msgstr "Фильтровать" + +#: gitk:8949 +msgid "" +"Error reading commit topology information; branch and preceding/following " +"tag information will be incomplete." +msgstr "" +"Ошибка чтения истории проекта; информация о ветвях и состояниях " +"вокруг меток (до/после) может быть неполной." + +#: gitk:9935 +msgid "Tag" +msgstr "Метка" + +#: gitk:9935 +msgid "Id" +msgstr "Id" + +#: gitk:9983 +msgid "Gitk font chooser" +msgstr "Шрифт Gitk" + +#: gitk:10000 +msgid "B" +msgstr "Ж" + +#: gitk:10003 +msgid "I" +msgstr "К" + +#: gitk:10098 +msgid "Gitk preferences" +msgstr "Настройки Gitk" + +#: gitk:10100 +msgid "Commit list display options" +msgstr "Параметры показа списка состояний" + +#: gitk:10103 +msgid "Maximum graph width (lines)" +msgstr "Макс. ширина графа (строк)" + +#: gitk:10107 +#, tcl-format +msgid "Maximum graph width (% of pane)" +msgstr "Макс. ширина графа (% ширины панели)" + +#: gitk:10111 +msgid "Show local changes" +msgstr "Показывать изменения в рабочем каталоге" + +#: gitk:10114 +msgid "Auto-select SHA1" +msgstr "Выделить SHA1" + +#: gitk:10118 +msgid "Diff display options" +msgstr "Параметры показа изменений" + +#: gitk:10120 +msgid "Tab spacing" +msgstr "Ширина табуляции" + +#: gitk:10123 +msgid "Display nearby tags" +msgstr "Показывать близкие метки" + +#: gitk:10126 +msgid "Limit diffs to listed paths" +msgstr "Ограничить показ изменений выбраными файлами" + +#: gitk:10129 +msgid "Support per-file encodings" +msgstr "Поддержка кодировок в отдельных файлах" + +#: gitk:10135 +msgid "External diff tool" +msgstr "Программа для показа изменений" + +#: gitk:10137 +msgid "Choose..." +msgstr "Выберите..." + +#: gitk:10142 +msgid "Colors: press to choose" +msgstr "Цвета: нажмите для выбора" + +#: gitk:10145 +msgid "Background" +msgstr "Фон" + +#: gitk:10146 gitk:10176 +msgid "background" +msgstr "фон" + +#: gitk:10149 +msgid "Foreground" +msgstr "Передний план" + +#: gitk:10150 +msgid "foreground" +msgstr "передний план" + +#: gitk:10153 +msgid "Diff: old lines" +msgstr "Изменения: старый текст" + +#: gitk:10154 +msgid "diff old lines" +msgstr "старый текст изменения" + +#: gitk:10158 +msgid "Diff: new lines" +msgstr "Изменения: новый текст" + +#: gitk:10159 +msgid "diff new lines" +msgstr "новый текст изменения" + +#: gitk:10163 +msgid "Diff: hunk header" +msgstr "Изменения: заголовок блока" + +#: gitk:10165 +msgid "diff hunk header" +msgstr "заголовок блока изменений" + +#: gitk:10169 +msgid "Marked line bg" +msgstr "Фон выбраной строки" + +#: gitk:10171 +msgid "marked line background" +msgstr "фон выбраной строки" + +#: gitk:10175 +msgid "Select bg" +msgstr "Выберите фон" + +#: gitk:10179 +msgid "Fonts: press to choose" +msgstr "Шрифт: нажмите для выбора" + +#: gitk:10181 +msgid "Main font" +msgstr "Основной шрифт" + +#: gitk:10182 +msgid "Diff display font" +msgstr "Шрифт показа изменений" + +#: gitk:10183 +msgid "User interface font" +msgstr "Шрифт интерфейса" + +#: gitk:10210 +#, tcl-format +msgid "Gitk: choose color for %s" +msgstr "Gitk: выберите цвет для %s" + +#: gitk:10656 +msgid "" +"Sorry, gitk cannot run with this version of Tcl/Tk.\n" +" Gitk requires at least Tcl/Tk 8.4." +msgstr "" +"К сожалению gitk не может работать с этой версий Tcl/Tk.\n" +"Требуется как минимум Tcl/Tk 8.4." + +#: gitk:10773 +msgid "Cannot find a git repository here." +msgstr "Git-репозитарий не найден в текущем каталоге." + +#: gitk:10777 +#, tcl-format +msgid "Cannot find the git directory \"%s\"." +msgstr "Git-репозитарий \"%s\" не найден." + +#: gitk:10824 +#, tcl-format +msgid "Ambiguous argument '%s': both revision and filename" +msgstr "Неоднозначный аргумент '%s': существует как версия и имя файла" + +#: gitk:10836 +msgid "Bad arguments to gitk:" +msgstr "Неправильные аргументы для gitk:" + +#: gitk:10896 +msgid "Command line" +msgstr "Командная строка" + diff --git a/gitweb/README b/gitweb/README index 8433dd1d45..ccda890c0e 100644 --- a/gitweb/README +++ b/gitweb/README @@ -206,7 +206,7 @@ not include variables usually directly set during build): * $fallback_encoding Gitweb assumes this charset if line contains non-UTF-8 characters. Fallback decoding is used without error checking, so it can be even - 'utf-8'. Value mist be valid encodig; see Encoding::Supported(3pm) man + 'utf-8'. Value must be valid encoding; see Encoding::Supported(3pm) man page for a list. By default 'latin1', aka. 'iso-8859-1'. * @diff_opts Rename detection options for git-diff and git-diff-tree. By default diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 33ef190ceb..06e91608fa 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -688,10 +688,10 @@ sub evaluate_path_info { # extensions. Allowed extensions are both the defined suffix # (which includes the initial dot already) and the snapshot # format key itself, with a prepended dot - while (my ($fmt, %opt) = each %known_snapshot_formats) { + while (my ($fmt, $opt) = each %known_snapshot_formats) { my $hash = $refname; my $sfx; - $hash =~ s/(\Q$opt{'suffix'}\E|\Q.$fmt\E)$//; + $hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//; next unless $sfx = $1; # a valid suffix was found, so set the snapshot format # and reset the hash parameter @@ -838,7 +838,7 @@ exit; ## ====================================================================== ## action links -sub href (%) { +sub href { my %params = @_; # default is to use -absolute url() i.e. $my_uri my $href = $params{-full} ? $my_url : $my_uri; @@ -1036,7 +1036,7 @@ sub esc_url { } # replace invalid utf8 character with SUBSTITUTION sequence -sub esc_html ($;%) { +sub esc_html { my $str = shift; my %opts = @_; @@ -1296,7 +1296,7 @@ use constant { }; # submodule/subproject, a commit object reference -sub S_ISGITLINK($) { +sub S_ISGITLINK { my $mode = shift; return (($mode & S_IFMT) == S_IFGITLINK) @@ -2615,7 +2615,7 @@ sub parsed_difftree_line { } # parse line of git-ls-tree output -sub parse_ls_tree_line ($;%) { +sub parse_ls_tree_line { my $line = shift; my %opts = @_; my %res; @@ -3213,7 +3213,6 @@ sub git_print_header_div { "\n</div>\n"; } -#sub git_print_authorship (\%) { sub git_print_authorship { my $co = shift; @@ -3269,8 +3268,7 @@ sub git_print_page_path { print "<br/></div>\n"; } -# sub git_print_log (\@;%) { -sub git_print_log ($;%) { +sub git_print_log { my $log = shift; my %opts = @_; @@ -1,5 +1,6 @@ #include "cache.h" #include "commit.h" +#include "color.h" #include "graph.h" #include "diff.h" #include "revision.h" @@ -34,7 +35,7 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb); * newline. A new graph line will not be printed after the final newline. * If the strbuf is empty, no output will be printed. * - * Since the first line will not include the graph ouput, the caller is + * Since the first line will not include the graph output, the caller is * responsible for printing this line's graph (perhaps via * graph_show_commit() or graph_show_oneline()) before calling * graph_show_strbuf(). @@ -43,27 +44,9 @@ static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb); /* * TODO: - * - Add colors to the graph. - * Pick a color for each column, and print all characters - * in that column with the specified color. - * * - Limit the number of columns, similar to the way gitk does. * If we reach more than a specified number of columns, omit * sections of some columns. - * - * - The output during the GRAPH_PRE_COMMIT and GRAPH_COLLAPSING states - * could be made more compact by printing horizontal lines, instead of - * long diagonal lines. For example, during collapsing, something like - * this: instead of this: - * | | | | | | | | | | - * | |_|_|/ | | | |/ - * |/| | | | | |/| - * | | | | | |/| | - * |/| | | - * | | | | - * - * If there are several parallel diagonal lines, they will need to be - * replaced with horizontal lines on subsequent rows. */ struct column { @@ -72,9 +55,10 @@ struct column { */ struct commit *commit; /* - * XXX: Once we add support for colors, struct column could also - * contain the color of its branch line. + * The color to (optionally) print this column in. This is an + * index into column_colors. */ + unsigned short color; }; enum graph_state { @@ -86,6 +70,41 @@ enum graph_state { GRAPH_COLLAPSING }; +/* + * The list of available column colors. + */ +static char column_colors[][COLOR_MAXLEN] = { + GIT_COLOR_RED, + GIT_COLOR_GREEN, + GIT_COLOR_YELLOW, + GIT_COLOR_BLUE, + GIT_COLOR_MAGENTA, + GIT_COLOR_CYAN, + GIT_COLOR_BOLD GIT_COLOR_RED, + GIT_COLOR_BOLD GIT_COLOR_GREEN, + GIT_COLOR_BOLD GIT_COLOR_YELLOW, + GIT_COLOR_BOLD GIT_COLOR_BLUE, + GIT_COLOR_BOLD GIT_COLOR_MAGENTA, + GIT_COLOR_BOLD GIT_COLOR_CYAN, +}; + +#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors)) + +static const char *column_get_color_code(const struct column *c) +{ + return column_colors[c->color]; +} + +static void strbuf_write_column(struct strbuf *sb, const struct column *c, + char col_char) +{ + if (c->color < COLUMN_COLORS_MAX) + strbuf_addstr(sb, column_get_color_code(c)); + strbuf_addch(sb, col_char); + if (c->color < COLUMN_COLORS_MAX) + strbuf_addstr(sb, GIT_COLOR_RESET); +} + struct git_graph { /* * The commit currently being processed @@ -185,6 +204,11 @@ struct git_graph { * temporary array each time we have to output a collapsing line. */ int *new_mapping; + /* + * The current default column color being used. This is + * stored as an index into the array column_colors. + */ + unsigned short default_column_color; }; struct git_graph *graph_init(struct rev_info *opt) @@ -201,6 +225,7 @@ struct git_graph *graph_init(struct rev_info *opt) graph->num_columns = 0; graph->num_new_columns = 0; graph->mapping_size = 0; + graph->default_column_color = 0; /* * Allocate a reasonably large default number of columns @@ -312,6 +337,33 @@ static struct commit_list *first_interesting_parent(struct git_graph *graph) return next_interesting_parent(graph, parents); } +static unsigned short graph_get_current_column_color(const struct git_graph *graph) +{ + if (!DIFF_OPT_TST(&graph->revs->diffopt, COLOR_DIFF)) + return COLUMN_COLORS_MAX; + return graph->default_column_color; +} + +/* + * Update the graph's default column color. + */ +static void graph_increment_column_color(struct git_graph *graph) +{ + graph->default_column_color = (graph->default_column_color + 1) % + COLUMN_COLORS_MAX; +} + +static unsigned short graph_find_commit_color(const struct git_graph *graph, + const struct commit *commit) +{ + int i; + for (i = 0; i < graph->num_columns; i++) { + if (graph->columns[i].commit == commit) + return graph->columns[i].color; + } + return graph_get_current_column_color(graph); +} + static void graph_insert_into_new_columns(struct git_graph *graph, struct commit *commit, int *mapping_index) @@ -334,6 +386,7 @@ static void graph_insert_into_new_columns(struct git_graph *graph, * This commit isn't already in new_columns. Add it. */ graph->new_columns[graph->num_new_columns].commit = commit; + graph->new_columns[graph->num_new_columns].color = graph_find_commit_color(graph, commit); graph->mapping[*mapping_index] = graph->num_new_columns; *mapping_index += 2; graph->num_new_columns++; @@ -445,6 +498,12 @@ static void graph_update_columns(struct git_graph *graph) for (parent = first_interesting_parent(graph); parent; parent = next_interesting_parent(graph, parent)) { + /* + * If this is a merge increment the current + * color. + */ + if (graph->num_parents > 1) + graph_increment_column_color(graph); graph_insert_into_new_columns(graph, parent->item, &mapping_idx); @@ -560,7 +619,8 @@ static int graph_is_mapping_correct(struct git_graph *graph) return 1; } -static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb) +static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb, + int chars_written) { /* * Add additional spaces to the end of the strbuf, so that all @@ -570,10 +630,10 @@ static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb) * aligned for the entire commit. */ int extra; - if (sb->len >= graph->width) + if (chars_written >= graph->width) return; - extra = graph->width - sb->len; + extra = graph->width - chars_written; strbuf_addf(sb, "%*s", (int) extra, ""); } @@ -596,10 +656,11 @@ static void graph_output_padding_line(struct git_graph *graph, * Output a padding row, that leaves all branch lines unchanged */ for (i = 0; i < graph->num_new_columns; i++) { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, &graph->new_columns[i], '|'); + strbuf_addch(sb, ' '); } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, graph->num_new_columns * 2); } static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb) @@ -609,7 +670,7 @@ static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb) * of the graph is missing. */ strbuf_addstr(sb, "..."); - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, 3); if (graph->num_parents >= 3 && graph->commit_index < (graph->num_columns - 1)) @@ -623,6 +684,7 @@ static void graph_output_pre_commit_line(struct git_graph *graph, { int num_expansion_rows; int i, seen_this; + int chars_written; /* * This function formats a row that increases the space around a commit @@ -645,11 +707,14 @@ static void graph_output_pre_commit_line(struct git_graph *graph, * Output the row */ seen_this = 0; + chars_written = 0; for (i = 0; i < graph->num_columns; i++) { struct column *col = &graph->columns[i]; if (col->commit == graph->commit) { seen_this = 1; - strbuf_addf(sb, "| %*s", graph->expansion_row, ""); + strbuf_write_column(sb, col, '|'); + strbuf_addf(sb, "%*s", graph->expansion_row, ""); + chars_written += 1 + graph->expansion_row; } else if (seen_this && (graph->expansion_row == 0)) { /* * This is the first line of the pre-commit output. @@ -662,17 +727,22 @@ static void graph_output_pre_commit_line(struct git_graph *graph, */ if (graph->prev_state == GRAPH_POST_MERGE && graph->prev_commit_index < i) - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); else - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + chars_written++; } else if (seen_this && (graph->expansion_row > 0)) { - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); + chars_written++; } else { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + chars_written++; } + strbuf_addch(sb, ' '); + chars_written++; } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, chars_written); /* * Increment graph->expansion_row, @@ -714,10 +784,34 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb) strbuf_addch(sb, '*'); } +/* + * Draw an octopus merge and return the number of characters written. + */ +static int graph_draw_octopus_merge(struct git_graph *graph, + struct strbuf *sb) +{ + /* + * Here dashless_commits represents the number of parents + * which don't need to have dashes (because their edges fit + * neatly under the commit). + */ + const int dashless_commits = 2; + int col_num, i; + int num_dashes = + ((graph->num_parents - dashless_commits) * 2) - 1; + for (i = 0; i < num_dashes; i++) { + col_num = (i / 2) + dashless_commits; + strbuf_write_column(sb, &graph->new_columns[col_num], '-'); + } + col_num = (i / 2) + dashless_commits; + strbuf_write_column(sb, &graph->new_columns[col_num], '.'); + return num_dashes + 1; +} + static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) { int seen_this = 0; - int i, j; + int i, chars_written; /* * Output the row containing this commit @@ -727,7 +821,9 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) * children that we have already processed.) */ seen_this = 0; + chars_written = 0; for (i = 0; i <= graph->num_columns; i++) { + struct column *col = &graph->columns[i]; struct commit *col_commit; if (i == graph->num_columns) { if (seen_this) @@ -740,18 +836,14 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) if (col_commit == graph->commit) { seen_this = 1; graph_output_commit_char(graph, sb); + chars_written++; - if (graph->num_parents < 3) - strbuf_addch(sb, ' '); - else { - int num_dashes = - ((graph->num_parents - 2) * 2) - 1; - for (j = 0; j < num_dashes; j++) - strbuf_addch(sb, '-'); - strbuf_addstr(sb, ". "); - } + if (graph->num_parents > 2) + chars_written += graph_draw_octopus_merge(graph, + sb); } else if (seen_this && (graph->num_parents > 2)) { - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); + chars_written++; } else if (seen_this && (graph->num_parents == 2)) { /* * This is a 2-way merge commit. @@ -768,15 +860,19 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) */ if (graph->prev_state == GRAPH_POST_MERGE && graph->prev_commit_index < i) - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); else - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + chars_written++; } else { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + chars_written++; } + strbuf_addch(sb, ' '); + chars_written++; } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, chars_written); /* * Update graph->state @@ -789,37 +885,75 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) graph_update_state(graph, GRAPH_COLLAPSING); } +static struct column *find_new_column_by_commit(struct git_graph *graph, + struct commit *commit) +{ + int i; + for (i = 0; i < graph->num_new_columns; i++) { + if (graph->new_columns[i].commit == commit) + return &graph->new_columns[i]; + } + return 0; +} + static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb) { int seen_this = 0; - int i, j; + int i, j, chars_written; /* * Output the post-merge row */ + chars_written = 0; for (i = 0; i <= graph->num_columns; i++) { + struct column *col = &graph->columns[i]; struct commit *col_commit; if (i == graph->num_columns) { if (seen_this) break; col_commit = graph->commit; } else { - col_commit = graph->columns[i].commit; + col_commit = col->commit; } if (col_commit == graph->commit) { + /* + * Since the current commit is a merge find + * the columns for the parent commits in + * new_columns and use those to format the + * edges. + */ + struct commit_list *parents = NULL; + struct column *par_column; seen_this = 1; - strbuf_addch(sb, '|'); - for (j = 0; j < graph->num_parents - 1; j++) - strbuf_addstr(sb, "\\ "); + parents = first_interesting_parent(graph); + assert(parents); + par_column = find_new_column_by_commit(graph, parents->item); + assert(par_column); + + strbuf_write_column(sb, par_column, '|'); + chars_written++; + for (j = 0; j < graph->num_parents - 1; j++) { + parents = next_interesting_parent(graph, parents); + assert(parents); + par_column = find_new_column_by_commit(graph, parents->item); + assert(par_column); + strbuf_write_column(sb, par_column, '\\'); + strbuf_addch(sb, ' '); + } + chars_written += j * 2; } else if (seen_this) { - strbuf_addstr(sb, "\\ "); + strbuf_write_column(sb, col, '\\'); + strbuf_addch(sb, ' '); + chars_written += 2; } else { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + strbuf_addch(sb, ' '); + chars_written += 2; } } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, chars_written); /* * Update graph->state @@ -834,6 +968,9 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf { int i; int *tmp_mapping; + short used_horizontal = 0; + int horizontal_edge = -1; + int horizontal_edge_target = -1; /* * Clear out the new_mapping array @@ -871,6 +1008,23 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf * Move to the left by one */ graph->new_mapping[i - 1] = target; + /* + * If there isn't already an edge moving horizontally + * select this one. + */ + if (horizontal_edge == -1) { + int j; + horizontal_edge = i; + horizontal_edge_target = target; + /* + * The variable target is the index of the graph + * column, and therefore target*2+3 is the + * actual screen column of the first horizontal + * line. + */ + for (j = (target * 2)+3; j < (i - 2); j += 2) + graph->new_mapping[j] = target; + } } else if (graph->new_mapping[i - 1] == target) { /* * There is a branch line to our left @@ -891,10 +1045,21 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf * * The space just to the left of this * branch should always be empty. + * + * The branch to the left of that space + * should be our eventual target. */ assert(graph->new_mapping[i - 1] > target); assert(graph->new_mapping[i - 2] < 0); + assert(graph->new_mapping[i - 3] == target); graph->new_mapping[i - 2] = target; + /* + * Mark this branch as the horizontal edge to + * prevent any other edges from moving + * horizontally. + */ + if (horizontal_edge == -1) + horizontal_edge = i; } } @@ -912,12 +1077,27 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf if (target < 0) strbuf_addch(sb, ' '); else if (target * 2 == i) - strbuf_addch(sb, '|'); - else - strbuf_addch(sb, '/'); + strbuf_write_column(sb, &graph->new_columns[target], '|'); + else if (target == horizontal_edge_target && + i != horizontal_edge - 1) { + /* + * Set the mappings for all but the + * first segment to -1 so that they + * won't continue into the next line. + */ + if (i != (target * 2)+3) + graph->new_mapping[i] = -1; + used_horizontal = 1; + strbuf_write_column(sb, &graph->new_columns[target], '_'); + } else { + if (used_horizontal && i < horizontal_edge) + graph->new_mapping[i] = -1; + strbuf_write_column(sb, &graph->new_columns[target], '/'); + + } } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, graph->mapping_size); /* * Swap mapping and new_mapping @@ -979,9 +1159,10 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb) * children that we have already processed.) */ for (i = 0; i < graph->num_columns; i++) { - struct commit *col_commit = graph->columns[i].commit; + struct column *col = &graph->columns[i]; + struct commit *col_commit = col->commit; if (col_commit == graph->commit) { - strbuf_addch(sb, '|'); + strbuf_write_column(sb, col, '|'); if (graph->num_parents < 3) strbuf_addch(sb, ' '); @@ -991,11 +1172,12 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb) strbuf_addch(sb, ' '); } } else { - strbuf_addstr(sb, "| "); + strbuf_write_column(sb, col, '|'); + strbuf_addch(sb, ' '); } } - graph_pad_horizontally(graph, sb); + graph_pad_horizontally(graph, sb, graph->num_columns); /* * Update graph->prev_state since we have output a padding line @@ -72,6 +72,8 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list) struct grep_expr *x; p = *list; + if (!p) + return NULL; switch (p->token) { case GREP_PATTERN: /* atom */ case GREP_PATTERN_HEAD: @@ -84,8 +86,6 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list) case GREP_OPEN_PAREN: *list = p->next; x = compile_pattern_or(list); - if (!x) - return NULL; if (!*list || (*list)->token != GREP_CLOSE_PAREN) die("unmatched parenthesis"); *list = (*list)->next; @@ -101,6 +101,8 @@ static struct grep_expr *compile_pattern_not(struct grep_pat **list) struct grep_expr *x; p = *list; + if (!p) + return NULL; switch (p->token) { case GREP_NOT: if (!p->next) @@ -372,6 +374,8 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, int h = 0; regmatch_t match; + if (!x) + die("Not a valid grep expression"); switch (x->node) { case GREP_NODE_ATOM: h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0); diff --git a/levenshtein.c b/levenshtein.c index a32f4cdc45..fc281597fd 100644 --- a/levenshtein.c +++ b/levenshtein.c @@ -27,7 +27,7 @@ * * It does so by calculating the costs of the path ending in characters * i (in string1) and j (in string2), respectively, given that the last - * operation is a substition, a swap, a deletion, or an insertion. + * operation is a substitution, a swap, a deletion, or an insertion. * * This implementation allows the costs to be weighted: * diff --git a/list-objects.c b/list-objects.c index dd243c7c66..8953548c07 100644 --- a/list-objects.c +++ b/list-objects.c @@ -10,7 +10,7 @@ static void process_blob(struct rev_info *revs, struct blob *blob, - struct object_array *p, + show_object_fn show, struct name_path *path, const char *name) { @@ -23,7 +23,7 @@ static void process_blob(struct rev_info *revs, if (obj->flags & (UNINTERESTING | SEEN)) return; obj->flags |= SEEN; - add_object(obj, p, path, name); + show(obj, path, name); } /* @@ -50,7 +50,7 @@ static void process_blob(struct rev_info *revs, */ static void process_gitlink(struct rev_info *revs, const unsigned char *sha1, - struct object_array *p, + show_object_fn show, struct name_path *path, const char *name) { @@ -59,7 +59,7 @@ static void process_gitlink(struct rev_info *revs, static void process_tree(struct rev_info *revs, struct tree *tree, - struct object_array *p, + show_object_fn show, struct name_path *path, const char *name) { @@ -77,7 +77,7 @@ static void process_tree(struct rev_info *revs, if (parse_tree(tree) < 0) die("bad tree object %s", sha1_to_hex(obj->sha1)); obj->flags |= SEEN; - add_object(obj, p, path, name); + show(obj, path, name); me.up = path; me.elem = name; me.elem_len = strlen(name); @@ -88,14 +88,14 @@ static void process_tree(struct rev_info *revs, if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), - p, &me, entry.path); + show, &me, entry.path); else if (S_ISGITLINK(entry.mode)) process_gitlink(revs, entry.sha1, - p, &me, entry.path); + show, &me, entry.path); else process_blob(revs, lookup_blob(entry.sha1), - p, &me, entry.path); + show, &me, entry.path); } free(tree->buffer); tree->buffer = NULL; @@ -134,17 +134,22 @@ void mark_edges_uninteresting(struct commit_list *list, } } +static void add_pending_tree(struct rev_info *revs, struct tree *tree) +{ + add_pending_object(revs, &tree->object, ""); +} + void traverse_commit_list(struct rev_info *revs, - void (*show_commit)(struct commit *), - void (*show_object)(struct object_array_entry *)) + show_commit_fn show_commit, + show_object_fn show_object, + void *data) { int i; struct commit *commit; - struct object_array objects = { 0, 0, NULL }; while ((commit = get_revision(revs)) != NULL) { - process_tree(revs, commit->tree, &objects, NULL, ""); - show_commit(commit); + add_pending_tree(revs, commit->tree); + show_commit(commit, data); } for (i = 0; i < revs->pending.nr; i++) { struct object_array_entry *pending = revs->pending.objects + i; @@ -154,25 +159,22 @@ void traverse_commit_list(struct rev_info *revs, continue; if (obj->type == OBJ_TAG) { obj->flags |= SEEN; - add_object_array(obj, name, &objects); + show_object(obj, NULL, name); continue; } if (obj->type == OBJ_TREE) { - process_tree(revs, (struct tree *)obj, &objects, + process_tree(revs, (struct tree *)obj, show_object, NULL, name); continue; } if (obj->type == OBJ_BLOB) { - process_blob(revs, (struct blob *)obj, &objects, + process_blob(revs, (struct blob *)obj, show_object, NULL, name); continue; } die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name); } - for (i = 0; i < objects.nr; i++) - show_object(&objects.objects[i]); - free(objects.objects); if (revs->pending.nr) { free(revs->pending.objects); revs->pending.nr = 0; diff --git a/list-objects.h b/list-objects.h index 0f41391ecc..d65dbf03e6 100644 --- a/list-objects.h +++ b/list-objects.h @@ -1,11 +1,11 @@ #ifndef LIST_OBJECTS_H #define LIST_OBJECTS_H -typedef void (*show_commit_fn)(struct commit *); -typedef void (*show_object_fn)(struct object_array_entry *); +typedef void (*show_commit_fn)(struct commit *, void *); +typedef void (*show_object_fn)(struct object *, const struct name_path *, const char *); typedef void (*show_edge_fn)(struct commit *); -void traverse_commit_list(struct rev_info *revs, show_commit_fn, show_object_fn); +void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *); void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn); diff --git a/lockfile.c b/lockfile.c index 3dbb2d1ff9..828d19f452 100644 --- a/lockfile.c +++ b/lockfile.c @@ -109,7 +109,7 @@ static char *resolve_symlink(char *p, size_t s) * link is a relative path, so I must replace the * last element of p with it. */ - char *r = (char*)last_path_elm(p); + char *r = (char *)last_path_elm(p); if (r - p + link_len < s) strcpy(r, link); else { diff --git a/merge-recursive.c b/merge-recursive.c index d6f0582238..a3721efcaf 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -520,8 +520,12 @@ static void update_file_flags(struct merge_options *o, unsigned long size; if (S_ISGITLINK(mode)) - die("cannot read object %s '%s': It is a submodule!", - sha1_to_hex(sha), path); + /* + * We may later decide to recursively descend into + * the submodule directory and update its index + * and/or work tree, but we do not do that now. + */ + goto update_index; buf = read_sha1_file(sha, &type, &size); if (!buf) @@ -45,7 +45,8 @@ int type_from_string(const char *str) static unsigned int hash_obj(struct object *obj, unsigned int n) { - unsigned int hash = *(unsigned int *)obj->sha1; + unsigned int hash; + memcpy(&hash, obj->sha1, sizeof(unsigned int)); return hash % n; } diff --git a/parse-options.h b/parse-options.h index f8ef1db128..b54eec128b 100644 --- a/parse-options.h +++ b/parse-options.h @@ -52,7 +52,7 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); * * `argh`:: * token to explain the kind of argument this option wants. Keep it - * homogenous across the repository. + * homogeneous across the repository. * * `help`:: * the short help associated to what the option does. @@ -61,7 +61,7 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); * * `flags`:: * mask of parse_opt_option_flags. - * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs) + * PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs) * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs * PARSE_OPT_NONEG: says that this option cannot be negated * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in @@ -105,7 +105,7 @@ struct option { { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) } /* parse_options() will filter out the processed options and leave the - * non-option argments in argv[]. + * non-option arguments in argv[]. * Returns the number of arguments left in argv[]. */ extern int parse_options(int argc, const char **argv, @@ -115,7 +115,7 @@ extern int parse_options(int argc, const char **argv, extern NORETURN void usage_with_options(const char * const *usagestr, const struct option *options); -/*----- incremantal advanced APIs -----*/ +/*----- incremental advanced APIs -----*/ enum { PARSE_OPT_HELP = -1, diff --git a/patch-ids.c b/patch-ids.c index 3be5d3165e..5717257051 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -1,6 +1,7 @@ #include "cache.h" #include "diff.h" #include "commit.h" +#include "sha1-lookup.h" #include "patch-ids.h" static int commit_patch_id(struct commit *commit, struct diff_options *options, @@ -15,99 +16,15 @@ static int commit_patch_id(struct commit *commit, struct diff_options *options, return diff_flush_patch_id(options, sha1); } -static uint32_t take2(const unsigned char *id) +static const unsigned char *patch_id_access(size_t index, void *table) { - return ((id[0] << 8) | id[1]); + struct patch_id **id_table = table; + return id_table[index]->patch_id; } -/* - * Conventional binary search loop looks like this: - * - * do { - * int mi = (lo + hi) / 2; - * int cmp = "entry pointed at by mi" minus "target"; - * if (!cmp) - * return (mi is the wanted one) - * if (cmp > 0) - * hi = mi; "mi is larger than target" - * else - * lo = mi+1; "mi is smaller than target" - * } while (lo < hi); - * - * The invariants are: - * - * - When entering the loop, lo points at a slot that is never - * above the target (it could be at the target), hi points at a - * slot that is guaranteed to be above the target (it can never - * be at the target). - * - * - We find a point 'mi' between lo and hi (mi could be the same - * as lo, but never can be the same as hi), and check if it hits - * the target. There are three cases: - * - * - if it is a hit, we are happy. - * - * - if it is strictly higher than the target, we update hi with - * it. - * - * - if it is strictly lower than the target, we update lo to be - * one slot after it, because we allow lo to be at the target. - * - * When choosing 'mi', we do not have to take the "middle" but - * anywhere in between lo and hi, as long as lo <= mi < hi is - * satisfied. When we somehow know that the distance between the - * target and lo is much shorter than the target and hi, we could - * pick mi that is much closer to lo than the midway. - */ static int patch_pos(struct patch_id **table, int nr, const unsigned char *id) { - int hi = nr; - int lo = 0; - int mi = 0; - - if (!nr) - return -1; - - if (nr != 1) { - unsigned lov, hiv, miv, ofs; - - for (ofs = 0; ofs < 18; ofs += 2) { - lov = take2(table[0]->patch_id + ofs); - hiv = take2(table[nr-1]->patch_id + ofs); - miv = take2(id + ofs); - if (miv < lov) - return -1; - if (hiv < miv) - return -1 - nr; - if (lov != hiv) { - /* - * At this point miv could be equal - * to hiv (but id could still be higher); - * the invariant of (mi < hi) should be - * kept. - */ - mi = (nr-1) * (miv - lov) / (hiv - lov); - if (lo <= mi && mi < hi) - break; - die("oops"); - } - } - if (18 <= ofs) - die("cannot happen -- lo and hi are identical"); - } - - do { - int cmp; - cmp = hashcmp(table[mi]->patch_id, id); - if (!cmp) - return mi; - if (cmp > 0) - hi = mi; - else - lo = mi + 1; - mi = (hi + lo) / 2; - } while (lo < hi); - return -lo-1; + return sha1_pos(id, table, nr, patch_id_access); } #define BUCKET_SIZE 190 /* 190 * 21 = 3990, with slop close enough to 4K */ diff --git a/progress.c b/progress.c index 55a8687ad1..621c34edc2 100644 --- a/progress.c +++ b/progress.c @@ -121,13 +121,13 @@ static void throughput_string(struct throughput *tp, off_t total, (int)(total >> 30), (int)(total & ((1 << 30) - 1)) / 10737419); } else if (total > 1 << 20) { + int x = total + 5243; /* for rounding */ l -= snprintf(tp->display, l, ", %u.%2.2u MiB", - (int)(total >> 20), - ((int)(total & ((1 << 20) - 1)) * 100) >> 20); + x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20); } else if (total > 1 << 10) { + int x = total + 5; /* for rounding */ l -= snprintf(tp->display, l, ", %u.%2.2u KiB", - (int)(total >> 10), - ((int)(total & ((1 << 10) - 1)) * 100) >> 10); + x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10); } else { l -= snprintf(tp->display, l, ", %u bytes", (int)total); } @@ -72,7 +72,7 @@ void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) } } -char *sq_dequote(char *arg) +char *sq_dequote_step(char *arg, char **next) { char *dst = arg; char *src = arg; @@ -92,6 +92,8 @@ char *sq_dequote(char *arg) switch (*++src) { case '\0': *dst = 0; + if (next) + *next = NULL; return arg; case '\\': c = *++src; @@ -101,11 +103,40 @@ char *sq_dequote(char *arg) } /* Fallthrough */ default: - return NULL; + if (!next || !isspace(*src)) + return NULL; + do { + c = *++src; + } while (isspace(c)); + *dst = 0; + *next = src; + return arg; } } } +char *sq_dequote(char *arg) +{ + return sq_dequote_step(arg, NULL); +} + +int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc) +{ + char *next = arg; + + if (!*arg) + return 0; + do { + char *dequoted = sq_dequote_step(next, &next); + if (!dequoted) + return -1; + ALLOC_GROW(*argv, *nr + 1, *alloc); + (*argv)[(*nr)++] = dequoted; + } while (next); + + return 0; +} + /* 1 means: quote as octal * 0 means: quote as octal if (quote_path_fully) * -1 means: never quote @@ -39,6 +39,15 @@ extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); */ extern char *sq_dequote(char *); +/* + * Same as the above, but can be used to unwrap many arguments in the + * same string separated by space. "next" is changed to point to the + * next argument that should be passed as first parameter. When there + * is no more argument to be dequoted, "next" is updated to point to NULL. + */ +extern char *sq_dequote_step(char *arg, char **next); +extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc); + extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq); extern void quote_two_c_style(struct strbuf *, const char *, const char *, int); diff --git a/reflog-walk.c b/reflog-walk.c index fd065f4e1a..5623ea6b48 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -241,7 +241,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) commit->object.flags &= ~(ADDED | SEEN | SHOWN); } -void show_reflog_message(struct reflog_walk_info* info, int oneline, +void show_reflog_message(struct reflog_walk_info *info, int oneline, enum date_mode dmode) { if (info && info->last_commit_reflog) { @@ -647,19 +647,24 @@ int for_each_ref(each_ref_fn fn, void *cb_data) return do_for_each_ref("refs/", fn, 0, 0, cb_data); } +int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data) +{ + return do_for_each_ref(prefix, fn, strlen(prefix), 0, cb_data); +} + int for_each_tag_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref("refs/tags/", fn, 10, 0, cb_data); + return for_each_ref_in("refs/tags/", fn, cb_data); } int for_each_branch_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref("refs/heads/", fn, 11, 0, cb_data); + return for_each_ref_in("refs/heads/", fn, cb_data); } int for_each_remote_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref("refs/remotes/", fn, 13, 0, cb_data); + return for_each_ref_in("refs/remotes/", fn, cb_data); } int for_each_rawref(each_ref_fn fn, void *cb_data) @@ -1652,3 +1657,114 @@ struct ref *find_ref_by_name(const struct ref *list, const char *name) return (struct ref *)list; return NULL; } + +/* + * generate a format suitable for scanf from a ref_rev_parse_rules + * rule, that is replace the "%.*s" spec with a "%s" spec + */ +static void gen_scanf_fmt(char *scanf_fmt, const char *rule) +{ + char *spec; + + spec = strstr(rule, "%.*s"); + if (!spec || strstr(spec + 4, "%.*s")) + die("invalid rule in ref_rev_parse_rules: %s", rule); + + /* copy all until spec */ + strncpy(scanf_fmt, rule, spec - rule); + scanf_fmt[spec - rule] = '\0'; + /* copy new spec */ + strcat(scanf_fmt, "%s"); + /* copy remaining rule */ + strcat(scanf_fmt, spec + 4); + + return; +} + +char *shorten_unambiguous_ref(const char *ref, int strict) +{ + int i; + static char **scanf_fmts; + static int nr_rules; + char *short_name; + + /* pre generate scanf formats from ref_rev_parse_rules[] */ + if (!nr_rules) { + size_t total_len = 0; + + /* the rule list is NULL terminated, count them first */ + for (; ref_rev_parse_rules[nr_rules]; nr_rules++) + /* no +1 because strlen("%s") < strlen("%.*s") */ + total_len += strlen(ref_rev_parse_rules[nr_rules]); + + scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len); + + total_len = 0; + for (i = 0; i < nr_rules; i++) { + scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + + total_len; + gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]); + total_len += strlen(ref_rev_parse_rules[i]); + } + } + + /* bail out if there are no rules */ + if (!nr_rules) + return xstrdup(ref); + + /* buffer for scanf result, at most ref must fit */ + short_name = xstrdup(ref); + + /* skip first rule, it will always match */ + for (i = nr_rules - 1; i > 0 ; --i) { + int j; + int rules_to_fail = i; + int short_name_len; + + if (1 != sscanf(ref, scanf_fmts[i], short_name)) + continue; + + short_name_len = strlen(short_name); + + /* + * in strict mode, all (except the matched one) rules + * must fail to resolve to a valid non-ambiguous ref + */ + if (strict) + rules_to_fail = nr_rules; + + /* + * check if the short name resolves to a valid ref, + * but use only rules prior to the matched one + */ + for (j = 0; j < rules_to_fail; j++) { + const char *rule = ref_rev_parse_rules[j]; + unsigned char short_objectname[20]; + char refname[PATH_MAX]; + + /* skip matched rule */ + if (i == j) + continue; + + /* + * the short name is ambiguous, if it resolves + * (with this previous rule) to a valid ref + * read_ref() returns 0 on success + */ + mksnpath(refname, sizeof(refname), + rule, short_name_len, short_name); + if (!read_ref(refname, short_objectname)) + break; + } + + /* + * short name is non-ambiguous if all previous rules + * haven't resolved to a valid ref + */ + if (j == rules_to_fail) + return short_name; + } + + free(short_name); + return xstrdup(ref); +} @@ -20,6 +20,7 @@ struct ref_lock { typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data); extern int head_ref(each_ref_fn, void *); extern int for_each_ref(each_ref_fn, void *); +extern int for_each_ref_in(const char *, each_ref_fn, void *); extern int for_each_tag_ref(each_ref_fn, void *); extern int for_each_branch_ref(each_ref_fn, void *); extern int for_each_remote_ref(each_ref_fn, void *); @@ -80,6 +81,7 @@ extern int for_each_reflog(each_ref_fn, void *); extern int check_ref_format(const char *target); extern const char *prettify_ref(const struct ref *ref); +extern char *shorten_unambiguous_ref(const char *ref, int strict); /** rename ref, return 0 on success **/ extern int rename_ref(const char *oldref, const char *newref, const char *logmsg); @@ -366,7 +366,7 @@ static int handle_config(const char *key, const char *value, void *cb) } subkey = strrchr(name, '.'); if (!subkey) - return error("Config with no key for remote %s", name); + return 0; remote = make_remote(name, subkey - name); remote->origin = REMOTE_CONFIG; if (!strcmp(subkey, ".mirror")) @@ -667,6 +667,17 @@ struct remote *remote_get(const char *name) return ret; } +int remote_is_configured(const char *name) +{ + int i; + read_config(); + + for (i = 0; i < remotes_nr; i++) + if (!strcmp(name, remotes[i]->name)) + return 1; + return 0; +} + int for_each_remote(each_remote_fn fn, void *priv) { int i, result = 0; @@ -1402,10 +1413,9 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) if (theirs == ours) return 0; - /* Run "rev-list --no-merges --left-right ours...theirs" internally... */ + /* Run "rev-list --left-right ours...theirs" internally... */ rev_argc = 0; rev_argv[rev_argc++] = NULL; - rev_argv[rev_argc++] = "--no-merges"; rev_argv[rev_argc++] = "--left-right"; rev_argv[rev_argc++] = symmetric; rev_argv[rev_argc++] = "--"; @@ -1450,11 +1460,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) return 0; base = branch->merge[0]->dst; - if (!prefixcmp(base, "refs/remotes/")) { - base += strlen("refs/remotes/"); - } else if (!prefixcmp(base, "refs/heads/")) { - base += strlen("refs/heads/"); - } + base = shorten_unambiguous_ref(base, 0); if (!num_theirs) strbuf_addf(sb, "Your branch is ahead of '%s' " "by %d commit%s.\n", @@ -1493,7 +1499,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1, int fla struct ref *get_local_heads(void) { - struct ref *local_refs, **local_tail = &local_refs; + struct ref *local_refs = NULL, **local_tail = &local_refs; for_each_ref(one_local_ref, &local_tail); return local_refs; } @@ -45,6 +45,7 @@ struct remote { }; struct remote *remote_get(const char *name); +int remote_is_configured(const char *name); typedef int each_remote_fn(struct remote *remote, void *priv); int for_each_remote(each_remote_fn fn, void *priv); diff --git a/revision.c b/revision.c index b6215cc72c..18b7ebbbd5 100644 --- a/revision.c +++ b/revision.c @@ -15,9 +15,9 @@ volatile show_early_output_fn_t show_early_output; -static char *path_name(struct name_path *path, const char *name) +char *path_name(const struct name_path *path, const char *name) { - struct name_path *p; + const struct name_path *p; char *n, *m; int nlen = strlen(name); int len = nlen + 1; @@ -209,7 +209,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object } /* - * Tree object? Either mark it uniniteresting, or add it + * Tree object? Either mark it uninteresting, or add it * to the list of objects to look at later.. */ if (object->type == OBJ_TREE) { diff --git a/revision.h b/revision.h index 5adfc91405..be39e7d386 100644 --- a/revision.h +++ b/revision.h @@ -146,6 +146,8 @@ struct name_path { const char *elem; }; +char *path_name(const struct name_path *path, const char *name); + extern void add_object(struct object *obj, struct object_array *p, struct name_path *path, diff --git a/run-command.c b/run-command.c index b05c734d05..eb2efc3307 100644 --- a/run-command.c +++ b/run-command.c @@ -106,7 +106,7 @@ int start_command(struct child_process *cmd) if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - putenv((char*)*cmd->env); + putenv((char *)*cmd->env); else unsetenv(*cmd->env); } diff --git a/server-info.c b/server-info.c index 66b0d9d878..906ce5b272 100644 --- a/server-info.c +++ b/server-info.c @@ -132,8 +132,8 @@ static int read_pack_info_file(const char *infofile) static int compare_info(const void *a_, const void *b_) { - struct pack_info * const* a = a_; - struct pack_info * const* b = b_; + struct pack_info *const *a = a_; + struct pack_info *const *b = b_; if (0 <= (*a)->old_num && 0 <= (*b)->old_num) /* Keep the order in the original */ diff --git a/sha1-lookup.c b/sha1-lookup.c index da357479cf..c4dc55d1f5 100644 --- a/sha1-lookup.c +++ b/sha1-lookup.c @@ -1,6 +1,107 @@ #include "cache.h" #include "sha1-lookup.h" +static uint32_t take2(const unsigned char *sha1) +{ + return ((sha1[0] << 8) | sha1[1]); +} + +/* + * Conventional binary search loop looks like this: + * + * do { + * int mi = (lo + hi) / 2; + * int cmp = "entry pointed at by mi" minus "target"; + * if (!cmp) + * return (mi is the wanted one) + * if (cmp > 0) + * hi = mi; "mi is larger than target" + * else + * lo = mi+1; "mi is smaller than target" + * } while (lo < hi); + * + * The invariants are: + * + * - When entering the loop, lo points at a slot that is never + * above the target (it could be at the target), hi points at a + * slot that is guaranteed to be above the target (it can never + * be at the target). + * + * - We find a point 'mi' between lo and hi (mi could be the same + * as lo, but never can be the same as hi), and check if it hits + * the target. There are three cases: + * + * - if it is a hit, we are happy. + * + * - if it is strictly higher than the target, we update hi with + * it. + * + * - if it is strictly lower than the target, we update lo to be + * one slot after it, because we allow lo to be at the target. + * + * When choosing 'mi', we do not have to take the "middle" but + * anywhere in between lo and hi, as long as lo <= mi < hi is + * satisfied. When we somehow know that the distance between the + * target and lo is much shorter than the target and hi, we could + * pick mi that is much closer to lo than the midway. + */ +/* + * The table should contain "nr" elements. + * The sha1 of element i (between 0 and nr - 1) should be returned + * by "fn(i, table)". + */ +int sha1_pos(const unsigned char *sha1, void *table, size_t nr, + sha1_access_fn fn) +{ + size_t hi = nr; + size_t lo = 0; + size_t mi = 0; + + if (!nr) + return -1; + + if (nr != 1) { + size_t lov, hiv, miv, ofs; + + for (ofs = 0; ofs < 18; ofs += 2) { + lov = take2(fn(0, table) + ofs); + hiv = take2(fn(nr - 1, table) + ofs); + miv = take2(sha1 + ofs); + if (miv < lov) + return -1; + if (hiv < miv) + return -1 - nr; + if (lov != hiv) { + /* + * At this point miv could be equal + * to hiv (but sha1 could still be higher); + * the invariant of (mi < hi) should be + * kept. + */ + mi = (nr - 1) * (miv - lov) / (hiv - lov); + if (lo <= mi && mi < hi) + break; + die("BUG: assertion failed in binary search"); + } + } + if (18 <= ofs) + die("cannot happen -- lo and hi are identical"); + } + + do { + int cmp; + cmp = hashcmp(fn(mi, table), sha1); + if (!cmp) + return mi; + if (cmp > 0) + hi = mi; + else + lo = mi + 1; + mi = (hi + lo) / 2; + } while (lo < hi); + return -lo-1; +} + /* * Conventional binary search loop looks like this: * diff --git a/sha1-lookup.h b/sha1-lookup.h index 3249a81b3d..20af285681 100644 --- a/sha1-lookup.h +++ b/sha1-lookup.h @@ -1,6 +1,13 @@ #ifndef SHA1_LOOKUP_H #define SHA1_LOOKUP_H +typedef const unsigned char *sha1_access_fn(size_t index, void *table); + +extern int sha1_pos(const unsigned char *sha1, + void *table, + size_t nr, + sha1_access_fn fn); + extern int sha1_entry_pos(const void *table, size_t elem_size, size_t key_offset, diff --git a/sha1_file.c b/sha1_file.c index 8fe135dc61..28bd9082fc 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -791,7 +791,7 @@ static int in_window(struct pack_window *win, off_t offset) && (offset + 20) <= (win_off + win->len); } -unsigned char* use_pack(struct packed_git *p, +unsigned char *use_pack(struct packed_git *p, struct pack_window **w_cursor, off_t offset, unsigned int *left) @@ -2225,7 +2225,9 @@ int move_temp_to_file(const char *tmpfile, const char *filename) { int ret = 0; - if (link(tmpfile, filename)) + if (object_creation_mode == OBJECT_CREATION_USES_RENAMES) + goto try_rename; + else if (link(tmpfile, filename)) ret = errno; /* @@ -2240,6 +2242,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename) * left to unlink. */ if (ret && ret != EEXIST) { + try_rename: if (!rename(tmpfile, filename)) goto out; ret = errno; @@ -40,6 +40,7 @@ static struct commands { } cmd_list[] = { { "git-receive-pack", do_generic_cmd }, { "git-upload-pack", do_generic_cmd }, + { "git-upload-archive", do_generic_cmd }, { "cvs", do_cvs_cmd }, { NULL }, }; @@ -11,7 +11,7 @@ * build complex strings/buffers whose final size isn't easily known. * * It is NOT legal to copy the ->buf pointer away. - * `strbuf_detach' is the operation that detachs a buffer from its shell + * `strbuf_detach' is the operation that detaches a buffer from its shell * while keeping the shell valid wrt its invariants. * * 2. the ->buf member is a byte array that has at least ->len + 1 bytes diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index cacb273aff..396b9653a3 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -114,7 +114,10 @@ test_expect_success \ test_expect_success \ 'some edit' \ 'mv file file.orig && - sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" < file.orig > file && + { + cat file.orig && + echo + } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" > file && echo "incomplete" | tr -d "\\012" >>file && GIT_AUTHOR_NAME="D" git commit -a -m "edit"' diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index cdd7ccdd2a..773d47cf3c 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -8,6 +8,10 @@ then say 'skipping git svn tests, NO_SVN_TESTS defined' test_done fi +if ! test_have_prereq PERL; then + say 'skipping git svn tests, perl not available' + test_done +fi GIT_DIR=$PWD/.git GIT_SVN_DIR=$GIT_DIR/svn/git-svn diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 5ac0a273a9..e3d846420d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -199,4 +199,13 @@ test_expect_success 'init honors global core.sharedRepository' ' x`git config -f shared-honor-global/.git/config core.sharedRepository` ' +test_expect_success 'init rejects insanely long --template' ' + ( + insane=$(printf "x%09999dx" 1) && + mkdir test && + cd test && + test_must_fail git init --template=$insane + ) +' + test_done diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 750fbb32e8..de42d21c92 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -126,7 +126,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' esac ' -test_expect_success 'forced modes' ' +test_expect_success POSIXPERM 'forced modes' ' mkdir -p templates/hooks && echo update-server-info >templates/hooks/post-update && chmod +x templates/hooks/post-update && @@ -141,11 +141,14 @@ test_expect_success 'forced modes' ' git commit -a -m initial && git repack ) && - find new/.git -print | + # List repository files meant to be protected; note that + # COMMIT_EDITMSG does not matter---0mode is not about a + # repository with a work tree. + find new/.git -type f -name COMMIT_EDITMSG -prune -o -print | xargs ls -ld >actual && # Everything must be unaccessible to others - test -z "$(sed -n -e "/^.......---/d" actual)" && + test -z "$(sed -e "/^.......---/d" actual)" && # All directories must have either 2770 or 770 test -z "$(sed -n -e "/^drwxrw[sx]---/d" -e "/^d/p" actual)" && @@ -156,10 +159,11 @@ test_expect_success 'forced modes' ' p }" actual)" && - # All files inside objects must be 0440 + # All files inside objects must be accessible by us test -z "$(sed -n -e "/objects\//{ /^d/d - /^-r--r-----/d + /^-r.-r.----/d + p }" actual)" ' diff --git a/t/t1303-wacky-config.sh b/t/t1303-wacky-config.sh index 1983076c75..080117c6bc 100755 --- a/t/t1303-wacky-config.sh +++ b/t/t1303-wacky-config.sh @@ -10,7 +10,7 @@ setup() { check() { echo "$2" >expected - git config --get "$1" >actual + git config --get "$1" >actual 2>&1 test_cmp actual expected } @@ -40,4 +40,11 @@ test_expect_success 'make sure git config escapes section names properly' ' check "$SECTION" bar ' +LONG_VALUE=$(printf "x%01021dx a" 7) +test_expect_success 'do not crash on special long config line' ' + setup && + git config section.key "$LONG_VALUE" && + check section.key "fatal: bad config file line 2 in .git/config" +' + test_done diff --git a/t/t2014-switch.sh b/t/t2014-switch.sh new file mode 100755 index 0000000000..ccfb147113 --- /dev/null +++ b/t/t2014-switch.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +test_description='Peter MacMillan' +. ./test-lib.sh + +test_expect_success setup ' + echo Hello >file && + git add file && + test_tick && + git commit -m V1 && + echo Hello world >file && + git add file && + git checkout -b other +' + +test_expect_success 'check all changes are staged' ' + git diff --exit-code +' + +test_expect_success 'second commit' ' + git commit -m V2 +' + +test_expect_success 'check' ' + git diff --cached --exit-code +' + +test_done diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index fe017839c4..dfc65601aa 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -3,6 +3,11 @@ test_description='add -i basic tests' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git add -i tests, perl not available' + test_done +fi + test_expect_success 'setup (initial)' ' echo content >file && git add file && diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 784c31aec9..b4ec2b53de 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -9,7 +9,15 @@ test_description='commit and log output encodings' compare_with () { git show -s $1 | sed -e '1,/^$/d' -e 's/^ //' >current && - test_cmp current "$2" + case "$3" in + '') + test_cmp "$2" current ;; + ?*) + iconv -f "$3" -t UTF-8 >current.utf8 <current && + iconv -f "$3" -t UTF-8 >expect.utf8 <"$2" && + test_cmp expect.utf8 current.utf8 + ;; + esac } test_expect_success setup ' @@ -103,11 +111,17 @@ done for J in EUCJP ISO-2022-JP do + if test "$J" = ISO-2022-JP + then + ICONV=$J + else + ICONV= + fi git config i18n.logoutputencoding $J for H in EUCJP ISO-2022-JP do test_expect_success "$H should be shown in $J now" ' - compare_with '$H' "$TEST_DIRECTORY"/t3900/'$J'.txt + compare_with '$H' "$TEST_DIRECTORY"/t3900/'$J'.txt $ICONV ' done done diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 11061ddd5b..922a8941ed 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -505,4 +505,15 @@ test_expect_success 'format-patch from a subdirectory (3)' ' test -f "$basename" ' +test_expect_success 'format-patch --in-reply-to' ' + git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 && + grep "^In-Reply-To: <baz@foo.bar>" patch8 && + grep "^References: <baz@foo.bar>" patch8 +' + +test_expect_success 'format-patch --signoff' ' + git format-patch -1 --signoff --stdout | + grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" +' + test_done diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index be541348c6..5b10e976a3 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -32,7 +32,7 @@ EOF sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java -builtin_patterns="bibtex html java objc pascal php python ruby tex" +builtin_patterns="bibtex cpp html java objc pascal php python ruby tex" for p in $builtin_patterns do test_expect_success "builtin $p pattern compiles" ' diff --git a/t/t4021-format-patch-numbered.sh b/t/t4021-format-patch-numbered.sh index 390af2389f..3c27f0dc19 100755 --- a/t/t4021-format-patch-numbered.sh +++ b/t/t4021-format-patch-numbered.sh @@ -108,4 +108,10 @@ test_expect_success 'format.numbered = auto && --no-numbered' ' ' +test_expect_success '--start-number && --numbered' ' + + git format-patch --start-number 3 --numbered --stdout HEAD~1 > patch8 && + grep "^Subject: \[PATCH 3/3\]" patch8 +' + test_done diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index 1c2edebb09..5cf8924b21 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -57,4 +57,43 @@ test_expect_success 'git diff (empty submodule dir)' ' test_cmp empty actual.empty ' +test_expect_success 'conflicted submodule setup' ' + + # 39 efs + c=fffffffffffffffffffffffffffffffffffffff + ( + echo "000000 $_z40 0 sub" + echo "160000 1$c 1 sub" + echo "160000 2$c 2 sub" + echo "160000 3$c 3 sub" + ) | git update-index --index-info && + echo >expect.nosub '\''diff --cc sub +index 2ffffff,3ffffff..0000000 +--- a/sub ++++ b/sub +@@@ -1,1 -1,1 +1,1 @@@ +- Subproject commit 2fffffffffffffffffffffffffffffffffffffff + -Subproject commit 3fffffffffffffffffffffffffffffffffffffff +++Subproject commit 0000000000000000000000000000000000000000'\'' && + + hh=$(git rev-parse HEAD) && + sed -e "s/$_z40/$hh/" expect.nosub >expect.withsub + +' + +test_expect_success 'combined (empty submodule)' ' + rm -fr sub && mkdir sub && + git diff >actual && + test_cmp expect.nosub actual +' + +test_expect_success 'combined (with submodule)' ' + rm -fr sub && + git clone --no-checkout . sub && + git diff >actual && + test_cmp expect.withsub actual +' + + + test_done diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh index 9ddbbcde57..3ccc237a8d 100755 --- a/t/t4029-diff-trailing-space.sh +++ b/t/t4029-diff-trailing-space.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Copyright (c) Jim Meyering # diff --git a/t/t4118-apply-empty-context.sh b/t/t4118-apply-empty-context.sh index f92e259cc6..65f2e4c3ef 100755 --- a/t/t4118-apply-empty-context.sh +++ b/t/t4118-apply-empty-context.sh @@ -20,10 +20,10 @@ test_expect_success setup ' cat file1 && echo Q | tr -d "\\012" } >file2 && - cat file2 >file2.orig + cat file2 >file2.orig && git add file1 file2 && sed -e "/^B/d" <file1.orig >file1 && - sed -e "/^[BQ]/d" <file2.orig >file2 && + cat file1 > file2 && echo Q | tr -d "\\012" >>file2 && cat file1 >file1.mods && cat file2 >file2.mods && diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh new file mode 100755 index 0000000000..7cfa2d6287 --- /dev/null +++ b/t/t4130-apply-criss-cross-rename.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +test_description='git apply handling criss-cross rename patch.' +. ./test-lib.sh + +create_file() { + cnt=0 + while test $cnt -le 100 + do + cnt=$(($cnt + 1)) + echo "$2" >> "$1" + done +} + +test_expect_success 'setup' ' + create_file file1 "File1 contents" && + create_file file2 "File2 contents" && + create_file file3 "File3 contents" && + git add file1 file2 file3 && + git commit -m 1 +' + +test_expect_success 'criss-cross rename' ' + mv file1 tmp && + mv file2 file1 && + mv tmp file2 && + cp file1 file1-swapped && + cp file2 file2-swapped +' + +test_expect_success 'diff -M -B' ' + git diff -M -B > diff && + git reset --hard + +' + +test_expect_success 'apply' ' + git apply diff && + test_cmp file1 file1-swapped && + test_cmp file2 file2-swapped +' + +test_expect_success 'criss-cross rename' ' + git reset --hard && + mv file1 tmp && + mv file2 file1 && + mv file3 file2 + mv tmp file3 && + cp file1 file1-swapped && + cp file2 file2-swapped && + cp file3 file3-swapped +' + +test_expect_success 'diff -M -B' ' + git diff -M -B > diff && + git reset --hard +' + +test_expect_success 'apply' ' + git apply diff && + test_cmp file1 file1-swapped && + test_cmp file2 file2-swapped && + test_cmp file3 file3-swapped +' + +test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 5e65afa0c1..d6ebbaebe2 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -290,4 +290,19 @@ test_expect_success 'am --ignore-date' ' echo "$at" | grep "+0000" ' +test_expect_success 'am into an unborn branch' ' + rm -fr subdir && + mkdir -p subdir && + git format-patch --numbered-files -o subdir -1 first && + ( + cd subdir && + git init && + git am 1 + ) && + result=$( + cd subdir && git rev-parse HEAD^{tree} + ) && + test "z$result" = "z$(git rev-parse first^{tree})" +' + test_done diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index b68ab11f29..a6bc028a57 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -57,7 +57,7 @@ test_expect_success 'conflicting merge' ' test_must_fail git merge first ' -sha1=$(sed -e 's/ .*//' .git/MERGE_RR) +sha1=$(perl -pe 's/ .*//' .git/MERGE_RR) rr=.git/rr-cache/$sha1 test_expect_success 'recorded preimage' "grep ^=======$ $rr/preimage" @@ -190,8 +190,6 @@ test_expect_success 'file2 added differently in two branches' ' git add file2 && git commit -m version2 && test_must_fail git merge fourth && - sha1=$(sed -e "s/ .*//" .git/MERGE_RR) && - rr=.git/rr-cache/$sha1 && echo Cello > file2 && git add file2 && git commit -m resolution diff --git a/t/t4202-log.sh b/t/t4202-log.sh index b98619035c..aad3894ad4 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -284,10 +284,36 @@ test_expect_success 'set up more tangled history' ' git merge master~3 && git merge side~1 && git checkout master && - git merge tangle + git merge tangle && + git checkout -b reach && + test_commit reach && + git checkout master && + git checkout -b octopus-a && + test_commit octopus-a && + git checkout master && + git checkout -b octopus-b && + test_commit octopus-b && + git checkout master && + test_commit seventh && + git merge octopus-a octopus-b + git merge reach ' cat > expect <<\EOF +* Merge branch 'reach' +|\ +| \ +| \ +*-. \ Merge branches 'octopus-a' and 'octopus-b' +|\ \ \ +* | | | seventh +| | * | octopus-b +| |/ / +|/| | +| * | octopus-a +|/ / +| * reach +|/ * Merge branch 'tangle' |\ | * Merge branch 'side' (early part) into tangle @@ -298,14 +324,12 @@ cat > expect <<\EOF * | | | Merge branch 'side' |\ \ \ \ | * | | | side-2 -| | | |/ -| | |/| +| | |_|/ | |/| | | * | | side-1 * | | | Second * | | | sixth -| | |/ -| |/| +| |_|/ |/| | * | | fifth * | | fourth diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 7641e0dd46..abb41b07ef 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -50,7 +50,7 @@ test_expect_success \ test_expect_success \ 'add ignored file' \ 'echo ignore me >a/ignored && - echo ignored export-ignore >.gitattributes' + echo ignored export-ignore >.git/info/attributes' test_expect_success \ 'add files to repository' \ @@ -64,7 +64,7 @@ test_expect_success \ test_expect_success \ 'create bare clone' \ 'git clone --bare . bare.git && - cp .gitattributes bare.git/info/attributes' + cp .git/info/attributes bare.git/info/attributes' test_expect_success \ 'remove ignored file' \ @@ -139,10 +139,11 @@ test_expect_success \ test_expect_success \ 'create archives with substfiles' \ - 'echo "substfile?" export-subst >a/.gitattributes && + 'cp .git/info/attributes .git/info/attributes.before && + echo "substfile?" export-subst >>.git/info/attributes && git archive HEAD >f.tar && git archive --prefix=prefix/ HEAD >g.tar && - rm a/.gitattributes' + mv .git/info/attributes.before .git/info/attributes' test_expect_success \ 'extract substfiles' \ diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh new file mode 100755 index 0000000000..426b319bd3 --- /dev/null +++ b/t/t5001-archive-attr.sh @@ -0,0 +1,91 @@ +#!/bin/sh + +test_description='git archive attribute tests' + +. ./test-lib.sh + +SUBSTFORMAT=%H%n + +test_expect_exists() { + test_expect_success " $1 exists" "test -e $1" +} + +test_expect_missing() { + test_expect_success " $1 does not exist" "test ! -e $1" +} + +test_expect_success 'setup' ' + echo ignored >ignored && + echo ignored export-ignore >>.git/info/attributes && + git add ignored && + + echo ignored by tree >ignored-by-tree && + echo ignored-by-tree export-ignore >.gitattributes && + git add ignored-by-tree .gitattributes && + + echo ignored by worktree >ignored-by-worktree && + echo ignored-by-worktree export-ignore >.gitattributes && + git add ignored-by-worktree && + + printf "A\$Format:%s\$O" "$SUBSTFORMAT" >nosubstfile && + printf "A\$Format:%s\$O" "$SUBSTFORMAT" >substfile1 && + printf "A not substituted O" >substfile2 && + echo "substfile?" export-subst >>.git/info/attributes && + git add nosubstfile substfile1 substfile2 && + + git commit -m. && + + git clone --bare . bare && + cp .git/info/attributes bare/info/attributes +' + +test_expect_success 'git archive' ' + git archive HEAD >archive.tar && + (mkdir archive && cd archive && "$TAR" xf -) <archive.tar +' + +test_expect_missing archive/ignored +test_expect_missing archive/ignored-by-tree +test_expect_exists archive/ignored-by-worktree + +test_expect_success 'git archive with worktree attributes' ' + git archive --worktree-attributes HEAD >worktree.tar && + (mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar +' + +test_expect_missing worktree/ignored +test_expect_exists worktree/ignored-by-tree +test_expect_missing worktree/ignored-by-worktree + +test_expect_success 'git archive vs. bare' ' + (cd bare && git archive HEAD) >bare-archive.tar && + test_cmp archive.tar bare-archive.tar +' + +test_expect_success 'git archive with worktree attributes, bare' ' + (cd bare && git archive --worktree-attributes HEAD) >bare-worktree.tar && + (mkdir bare-worktree && cd bare-worktree && "$TAR" xf -) <bare-worktree.tar +' + +test_expect_missing bare-worktree/ignored +test_expect_exists bare-worktree/ignored-by-tree +test_expect_exists bare-worktree/ignored-by-worktree + +test_expect_success 'export-subst' ' + git log "--pretty=format:A${SUBSTFORMAT}O" HEAD >substfile1.expected && + test_cmp nosubstfile archive/nosubstfile && + test_cmp substfile1.expected archive/substfile1 && + test_cmp substfile2 archive/substfile2 +' + +test_expect_success 'git tar-tree vs. git archive with worktree attributes' ' + git tar-tree HEAD >tar-tree.tar && + test_cmp worktree.tar tar-tree.tar +' + +test_expect_success 'git tar-tree vs. git archive with worktree attrs, bare' ' + (cd bare && git tar-tree HEAD) >bare-tar-tree.tar && + test_cmp bare-worktree.tar bare-tar-tree.tar +' + +test_done diff --git a/t/t5506-remote-groups.sh b/t/t5506-remote-groups.sh new file mode 100755 index 0000000000..2a1806b0b4 --- /dev/null +++ b/t/t5506-remote-groups.sh @@ -0,0 +1,81 @@ +#!/bin/sh + +test_description='git remote group handling' +. ./test-lib.sh + +mark() { + echo "$1" >mark +} + +update_repo() { + (cd $1 && + echo content >>file && + git add file && + git commit -F ../mark) +} + +update_repos() { + update_repo one $1 && + update_repo two $1 +} + +repo_fetched() { + if test "`git log -1 --pretty=format:%s $1 --`" = "`cat mark`"; then + echo >&2 "repo was fetched: $1" + return 0 + fi + echo >&2 "repo was not fetched: $1" + return 1 +} + +test_expect_success 'setup' ' + mkdir one && (cd one && git init) && + mkdir two && (cd two && git init) && + git remote add -m master one one && + git remote add -m master two two +' + +test_expect_success 'no group updates all' ' + mark update-all && + update_repos && + git remote update && + repo_fetched one && + repo_fetched two +' + +test_expect_success 'nonexistant group produces error' ' + mark nonexistant && + update_repos && + test_must_fail git remote update nonexistant && + ! repo_fetched one && + ! repo_fetched two +' + +test_expect_success 'updating group updates all members' ' + mark group-all && + update_repos && + git config --add remotes.all one && + git config --add remotes.all two && + git remote update all && + repo_fetched one && + repo_fetched two +' + +test_expect_success 'updating group does not update non-members' ' + mark group-some && + update_repos && + git config --add remotes.some one && + git remote update some && + repo_fetched one && + ! repo_fetched two +' + +test_expect_success 'updating remote name updates that remote' ' + mark remote-name && + update_repos && + git remote update one && + repo_fetched one && + ! repo_fetched two +' + +test_done diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index 3559d17964..19b5c0d552 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -132,4 +132,14 @@ test_expect_success 'clone empty repository' ' test $actual = $expected) ' +test_expect_success 'clone empty repository, and then push should not segfault.' ' + cd "$D" && + rm -fr empty/ empty-clone/ && + mkdir empty && + (cd empty && git init) && + git clone empty empty-clone && + (cd empty-clone && + test_must_fail git push) +' + test_done diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 052a6c90f5..54b7ea6505 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -506,6 +506,66 @@ test_expect_success 'optimized merge base checks' ' unset GIT_TRACE ' +# This creates another side branch called "parallel" with some files +# in some directories, to test bisecting with paths. +# +# We should have the following: +# +# P1-P2-P3-P4-P5-P6-P7 +# / / / +# H1-H2-H3-H4-H5-H6-H7 +# \ \ \ +# S5-A \ +# \ \ +# S6-S7----B +# +test_expect_success '"parallel" side branch creation' ' + git bisect reset && + git checkout -b parallel $HASH1 && + mkdir dir1 dir2 && + add_line_into_file "1(para): line 1 on parallel branch" dir1/file1 && + PARA_HASH1=$(git rev-parse --verify HEAD) && + add_line_into_file "2(para): line 2 on parallel branch" dir2/file2 && + PARA_HASH2=$(git rev-parse --verify HEAD) && + add_line_into_file "3(para): line 3 on parallel branch" dir2/file3 && + PARA_HASH3=$(git rev-parse --verify HEAD) + git merge -m "merge HASH4 and PARA_HASH3" "$HASH4" && + PARA_HASH4=$(git rev-parse --verify HEAD) + add_line_into_file "5(para): add line on parallel branch" dir1/file1 && + PARA_HASH5=$(git rev-parse --verify HEAD) + add_line_into_file "6(para): add line on parallel branch" dir2/file2 && + PARA_HASH6=$(git rev-parse --verify HEAD) + git merge -m "merge HASH7 and PARA_HASH6" "$HASH7" && + PARA_HASH7=$(git rev-parse --verify HEAD) +' + +test_expect_success 'restricting bisection on one dir' ' + git bisect reset && + git bisect start HEAD $HASH1 -- dir1 && + para1=$(git rev-parse --verify HEAD) && + test "$para1" = "$PARA_HASH1" && + git bisect bad > my_bisect_log.txt && + grep "$PARA_HASH1 is first bad commit" my_bisect_log.txt +' + +test_expect_success 'restricting bisection on one dir and a file' ' + git bisect reset && + git bisect start HEAD $HASH1 -- dir1 hello && + para4=$(git rev-parse --verify HEAD) && + test "$para4" = "$PARA_HASH4" && + git bisect bad && + hash3=$(git rev-parse --verify HEAD) && + test "$hash3" = "$HASH3" && + git bisect good && + hash4=$(git rev-parse --verify HEAD) && + test "$hash4" = "$HASH4" && + git bisect good && + para1=$(git rev-parse --verify HEAD) && + test "$para1" = "$PARA_HASH1" && + git bisect good > my_bisect_log.txt && + grep "$PARA_HASH4 is first bad commit" my_bisect_log.txt +' + # # test_done diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 8bfae44a83..8052c86ad3 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -26,6 +26,13 @@ test_expect_success 'Create sample commit with known timestamp' ' git tag -a -m "Tagging at $datestamp" testtag ' +test_expect_success 'Create upstream config' ' + git update-ref refs/remotes/origin/master master && + git remote add origin nowhere && + git config branch.master.remote origin && + git config branch.master.merge refs/heads/master +' + test_atom() { case "$1" in head) ref=refs/heads/master ;; @@ -39,6 +46,7 @@ test_atom() { } test_atom head refname refs/heads/master +test_atom head upstream refs/remotes/origin/master test_atom head objecttype commit test_atom head objectsize 171 test_atom head objectname 67a36f10722846e891fbada1ba48ed035de75581 @@ -68,6 +76,7 @@ test_atom head contents 'Initial ' test_atom tag refname refs/tags/testtag +test_atom tag upstream '' test_atom tag objecttype tag test_atom tag objectsize 154 test_atom tag objectname 98b46b1d36e5b07909de1b3886224e3e81e87322 @@ -203,6 +212,7 @@ test_expect_success 'Check format "rfc2822" date fields output' ' cat >expected <<\EOF refs/heads/master +refs/remotes/origin/master refs/tags/testtag EOF @@ -214,6 +224,7 @@ test_expect_success 'Verify ascending sort' ' cat >expected <<\EOF refs/tags/testtag +refs/remotes/origin/master refs/heads/master EOF @@ -224,6 +235,7 @@ test_expect_success 'Verify descending sort' ' cat >expected <<\EOF 'refs/heads/master' +'refs/remotes/origin/master' 'refs/tags/testtag' EOF @@ -244,6 +256,7 @@ test_expect_success 'Quoting style: python' ' cat >expected <<\EOF "refs/heads/master" +"refs/remotes/origin/master" "refs/tags/testtag" EOF @@ -273,16 +286,26 @@ test_expect_success 'Check short refname format' ' test_cmp expected actual ' +cat >expected <<EOF +origin/master +EOF + +test_expect_success 'Check short upstream format' ' + git for-each-ref --format="%(upstream:short)" refs/heads >actual && + test_cmp expected actual +' + test_expect_success 'Check for invalid refname format' ' test_must_fail git for-each-ref --format="%(refname:INVALID)" ' cat >expected <<\EOF heads/master -master +tags/master EOF -test_expect_success 'Check ambiguous head and tag refs' ' +test_expect_success 'Check ambiguous head and tag refs (strict)' ' + git config --bool core.warnambiguousrefs true && git checkout -b newtag && echo "Using $datestamp" > one && git add one && @@ -294,11 +317,22 @@ test_expect_success 'Check ambiguous head and tag refs' ' ' cat >expected <<\EOF +heads/master +master +EOF + +test_expect_success 'Check ambiguous head and tag refs (loose)' ' + git config --bool core.warnambiguousrefs false && + git for-each-ref --format "%(refname:short)" refs/heads/master refs/tags/master >actual && + test_cmp expected actual +' + +cat >expected <<\EOF heads/ambiguous ambiguous EOF -test_expect_success 'Check ambiguous head and tag refs II' ' +test_expect_success 'Check ambiguous head and tag refs II (loose)' ' git checkout master && git tag ambiguous testtag^0 && git branch ambiguous testtag^0 && diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index c4938544d4..b81593780a 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -26,6 +26,10 @@ test_expect_success setup ' git commit -m initial ' +test_expect_success 'grep should not segfault with a bad input' ' + test_must_fail git grep "(" +' + for H in HEAD '' do case "$H" in diff --git a/t/t7201-co.sh b/t/t7201-co.sh index bdb808af1a..ebfd34df36 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -534,4 +534,12 @@ test_expect_success 'failing checkout -b should not break working tree' ' ' +test_expect_success 'switch out of non-branch' ' + git reset --hard master && + git checkout master^0 && + echo modified >one && + test_must_fail git checkout renamer 2>error.log && + ! grep "^Previous HEAD" error.log +' + test_done diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index af690ec6c1..0f2ccc6cf0 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -64,6 +64,16 @@ test_expect_success 'submodule add' ' ) ' +test_expect_success 'submodule add --branch' ' + ( + cd addtest && + git submodule add -b initial "$submodurl" submod-branch && + git submodule init && + cd submod-branch && + git branch | grep initial + ) +' + test_expect_success 'submodule add with ./ in path' ' ( cd addtest && diff --git a/t/t7405-submodule-merge.sh b/t/t7405-submodule-merge.sh index aa6c44ce4f..9a21f783d3 100755 --- a/t/t7405-submodule-merge.sh +++ b/t/t7405-submodule-merge.sh @@ -54,13 +54,13 @@ test_expect_success setup ' git merge -s ours a ' -test_expect_failure 'merging with modify/modify conflict' ' +test_expect_success 'merging with modify/modify conflict' ' git checkout -b test1 a && test_must_fail git merge b && test -f .git/MERGE_MSG && - git diff - + git diff && + test -n "$(git ls-files -u)" ' test_expect_success 'merging with a modify/modify conflict between merge bases' ' diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index b4e2b4db84..e2ef53228e 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -38,7 +38,7 @@ test_expect_success \ "echo King of the bongo >file && test_must_fail git commit -m foo -a file" -test_expect_success \ +test_expect_success PERL \ "using paths with --interactive" \ "echo bong-o-bong >file && ! (echo 7 | git commit -m foo --interactive file)" @@ -119,7 +119,7 @@ test_expect_success \ "echo 'gak' >file && \ git commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a" -test_expect_success \ +test_expect_success PERL \ "interactive add" \ "echo 7 | git commit --interactive | grep 'What now'" diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 6b29bff782..87c9b0e121 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -69,7 +69,7 @@ test_expect_success 'packed obs in alt ODB are repacked even when local repo is done ' -test_expect_failure 'packed obs in alt ODB are repacked when local repo has packs' ' +test_expect_success 'packed obs in alt ODB are repacked when local repo has packs' ' rm -f .git/objects/pack/* && echo new_content >> file1 && git add file1 && diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh new file mode 100755 index 0000000000..ebdccf9a1e --- /dev/null +++ b/t/t7800-difftool.sh @@ -0,0 +1,216 @@ +#!/bin/sh +# +# Copyright (c) 2009 David Aguilar +# + +test_description='git-difftool + +Testing basic diff tool invocation +' + +. ./test-lib.sh + +if ! test_have_prereq PERL; then + say 'skipping difftool tests, perl not available' + test_done +fi + +remove_config_vars() +{ + # Unset all config variables used by git-difftool + git config --unset diff.tool + git config --unset difftool.test-tool.cmd + git config --unset difftool.prompt + git config --unset merge.tool + git config --unset mergetool.test-tool.cmd + return 0 +} + +restore_test_defaults() +{ + # Restores the test defaults used by several tests + remove_config_vars + unset GIT_DIFF_TOOL + unset GIT_MERGE_TOOL + unset GIT_DIFFTOOL_PROMPT + unset GIT_DIFFTOOL_NO_PROMPT + git config diff.tool test-tool && + git config difftool.test-tool.cmd 'cat $LOCAL' +} + +prompt_given() +{ + prompt="$1" + test "$prompt" = "Hit return to launch 'test-tool': branch" +} + +# Create a file on master and change it on branch +test_expect_success 'setup' ' + echo master >file && + git add file && + git commit -m "added file" && + + git checkout -b branch master && + echo branch >file && + git commit -a -m "branch changed file" && + git checkout master +' + +# Configure a custom difftool.<tool>.cmd and use it +test_expect_success 'custom commands' ' + restore_test_defaults && + git config difftool.test-tool.cmd "cat \$REMOTE" && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "master" && + + restore_test_defaults && + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" +' + +# Ensures that git-difftool ignores bogus --tool values +test_expect_success 'difftool ignores bad --tool values' ' + diff=$(git difftool --no-prompt --tool=bogus-tool branch) + test "$?" = 1 && + test "$diff" = "" +' + +# Specify the diff tool using $GIT_DIFF_TOOL +test_expect_success 'GIT_DIFF_TOOL variable' ' + git config --unset diff.tool + GIT_DIFF_TOOL=test-tool && + export GIT_DIFF_TOOL && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# Test the $GIT_*_TOOL variables and ensure +# that $GIT_DIFF_TOOL always wins unless --tool is specified +test_expect_success 'GIT_DIFF_TOOL overrides' ' + git config diff.tool bogus-tool && + git config merge.tool bogus-tool && + + GIT_MERGE_TOOL=test-tool && + export GIT_MERGE_TOOL && + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + unset GIT_MERGE_TOOL && + + GIT_MERGE_TOOL=bogus-tool && + GIT_DIFF_TOOL=test-tool && + export GIT_MERGE_TOOL && + export GIT_DIFF_TOOL && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + + GIT_DIFF_TOOL=bogus-tool && + export GIT_DIFF_TOOL && + + diff=$(git difftool --no-prompt --tool=test-tool branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# Test that we don't have to pass --no-prompt to difftool +# when $GIT_DIFFTOOL_NO_PROMPT is true +test_expect_success 'GIT_DIFFTOOL_NO_PROMPT variable' ' + GIT_DIFFTOOL_NO_PROMPT=true && + export GIT_DIFFTOOL_NO_PROMPT && + + diff=$(git difftool branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# git-difftool supports the difftool.prompt variable. +# Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false +test_expect_success 'GIT_DIFFTOOL_PROMPT variable' ' + git config difftool.prompt false && + GIT_DIFFTOOL_PROMPT=true && + export GIT_DIFFTOOL_PROMPT && + + prompt=$(echo | git difftool --prompt branch | tail -1) && + prompt_given "$prompt" && + + restore_test_defaults +' + +# Test that we don't have to pass --no-prompt when difftool.prompt is false +test_expect_success 'difftool.prompt config variable is false' ' + git config difftool.prompt false && + + diff=$(git difftool branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# Test that the -y flag can override difftool.prompt = true +test_expect_success 'difftool.prompt can overridden with -y' ' + git config difftool.prompt true && + + diff=$(git difftool -y branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +# Test that the --prompt flag can override difftool.prompt = false +test_expect_success 'difftool.prompt can overridden with --prompt' ' + git config difftool.prompt false && + + prompt=$(echo | git difftool --prompt branch | tail -1) && + prompt_given "$prompt" && + + restore_test_defaults +' + +# Test that the last flag passed on the command-line wins +test_expect_success 'difftool last flag wins' ' + diff=$(git difftool --prompt --no-prompt branch) && + test "$diff" = "branch" && + + restore_test_defaults && + + prompt=$(echo | git difftool --no-prompt --prompt branch | tail -1) && + prompt_given "$prompt" && + + restore_test_defaults +' + +# git-difftool falls back to git-mergetool config variables +# so test that behavior here +test_expect_success 'difftool + mergetool config variables' ' + remove_config_vars + git config merge.tool test-tool && + git config mergetool.test-tool.cmd "cat \$LOCAL" && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + + # set merge.tool to something bogus, diff.tool to test-tool + git config merge.tool bogus-tool && + git config diff.tool test-tool && + + diff=$(git difftool --no-prompt branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + +test_expect_success 'difftool.<tool>.path' ' + git config difftool.tkdiff.path echo && + diff=$(git difftool --tool=tkdiff --no-prompt branch) && + git config --unset difftool.tkdiff.path && + lines=$(echo "$diff" | grep file | wc -l) && + test "$lines" -eq 1 +' + +test_done diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh index 4470a92bb2..fcd5c26675 100755 --- a/t/t8005-blame-i18n.sh +++ b/t/t8005-blame-i18n.sh @@ -36,7 +36,7 @@ EOF test_expect_success \ 'blame respects i18n.commitencoding' ' git blame --incremental file | \ - grep "^\(author\|summary\) " > actual && + egrep "^(author|summary) " > actual && test_cmp actual expected ' @@ -53,7 +53,7 @@ test_expect_success \ 'blame respects i18n.logoutputencoding' ' git config i18n.logoutputencoding cp1251 && git blame --incremental file | \ - grep "^\(author\|summary\) " > actual && + egrep "^(author|summary) " > actual && test_cmp actual expected ' @@ -69,7 +69,7 @@ EOF test_expect_success \ 'blame respects --encoding=utf-8' ' git blame --incremental --encoding=utf-8 file | \ - grep "^\(author\|summary\) " > actual && + egrep "^(author|summary) " > actual && test_cmp actual expected ' @@ -85,7 +85,7 @@ EOF test_expect_success \ 'blame respects --encoding=none' ' git blame --incremental --encoding=none file | \ - grep "^\(author\|summary\) " > actual && + egrep "^(author|summary) " > actual && test_cmp actual expected ' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 3c90c4fc1c..ce26ea4ac5 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -3,6 +3,11 @@ test_description='git send-email' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git send-email tests, perl not available' + test_done +fi + PROG='git send-email' test_expect_success \ 'prepare reference tree' \ @@ -611,7 +616,7 @@ test_expect_success 'in-reply-to but no threading' ' --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --in-reply-to="<in-reply-id@example.com>" \ - --no-thread \ + --nothread \ $patches | grep "In-Reply-To: <in-reply-id@example.com>" ' diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 36656923ac..56b7c06921 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -6,6 +6,11 @@ test_description='Test export of commits to CVS' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git cvsexportcommit tests, perl not available' + test_done +fi + cvs >/dev/null 2>&1 if test $? -ne 1 then diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 39185db6c9..64f947d75b 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -10,6 +10,10 @@ cvs CLI client via git-cvsserver server' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git cvsserver tests, perl not available' + test_done +fi cvs >/dev/null 2>&1 if test $? -ne 1 then diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index 12e0e50822..aca40c1b1f 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -52,6 +52,11 @@ then say 'skipping git-cvsserver tests, cvs not found' test_done fi +if ! test_have_prereq PERL +then + say 'skipping git-cvsserver tests, perl not available' + test_done +fi perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { say 'skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 0bd332c493..f4210fbb04 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -65,6 +65,11 @@ gitweb_run () { . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping gitweb tests, perl not available' + test_done +fi + perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { say 'skipping gitweb tests, perl version is too old' test_done diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh index 33eb51938d..4322a0c1ed 100755 --- a/t/t9600-cvsimport.sh +++ b/t/t9600-cvsimport.sh @@ -3,6 +3,11 @@ test_description='git cvsimport basic tests' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping git cvsimport tests, perl not available' + test_done +fi + CVSROOT=$(pwd)/cvsroot export CVSROOT unset CVS_SERVER diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh index 4a501c6847..b4ca244626 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -6,6 +6,11 @@ test_description='perl interface (Git.pm)' . ./test-lib.sh +if ! test_have_prereq PERL; then + say 'skipping perl interface tests, perl not available' + test_done +fi + perl -MTest::More -e 0 2>/dev/null || { say "Perl Test::More unavailable, skipping test" test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index b050196cb7..dad1437fa4 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -491,7 +491,7 @@ test_create_repo () { repo="$1" mkdir -p "$repo" cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git-init" "--template=$owd/../templates/blt/" >&3 2>&4 || + "$GIT_EXEC_PATH/git-init" "--template=$TEST_DIRECTORY/../templates/blt/" >&3 2>&4 || error "cannot run git init -- have you built things yet?" mv .git/hooks .git/hooks-disabled cd "$owd" @@ -698,6 +698,8 @@ case $(uname -s) in ;; esac +test -z "$NO_PERL" && test_set_prereq PERL + # test whether the filesystem supports symbolic links ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS rm -f y diff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample index 0e49279c7f..0ba62076fb 100755 --- a/templates/hooks--pre-commit.sample +++ b/templates/hooks--pre-commit.sample @@ -7,7 +7,7 @@ # # To enable this hook, rename this file to "pre-commit". -if git-rev-parse --verify HEAD 2>/dev/null +if git-rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD else diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample index a3f68ae3b4..f8bf490cff 100755 --- a/templates/hooks--update.sample +++ b/templates/hooks--update.sample @@ -16,6 +16,9 @@ # hooks.allowdeletebranch # This boolean sets whether deleting branches will be allowed in the # repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. # # --- Command line @@ -39,6 +42,7 @@ fi # --- Config allowunannotated=$(git config --bool hooks.allowunannotated) allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) allowdeletetag=$(git config --bool hooks.allowdeletetag) # check for no description @@ -52,7 +56,8 @@ esac # --- Check types # if $newrev is 0000...0000, it's a commit to delete a ref. -if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then newrev_type=delete else newrev_type=$(git-cat-file -t $newrev) @@ -80,6 +85,10 @@ case "$refname","$newrev_type" in ;; refs/heads/*,commit) # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi ;; refs/heads/*,delete) # delete branch diff --git a/test-genrandom.c b/test-genrandom.c index 8cefe6cfed..8ad276d062 100644 --- a/test-genrandom.c +++ b/test-genrandom.c @@ -13,7 +13,7 @@ int main(int argc, char *argv[]) unsigned char *c; if (argc < 2 || argc > 3) { - fprintf( stderr, "Usage: %s <seed_string> [<size>]", argv[0]); + fprintf(stderr, "Usage: %s <seed_string> [<size>]\n", argv[0]); return 1; } diff --git a/transport.c b/transport.c index 3dfb03c06e..8ad317bf32 100644 --- a/transport.c +++ b/transport.c @@ -1083,3 +1083,51 @@ int transport_disconnect(struct transport *transport) free(transport); return ret; } + +/* + * Strip username (and password) from an url and return + * it in a newly allocated string. + */ +char *transport_anonymize_url(const char *url) +{ + char *anon_url, *scheme_prefix, *anon_part; + size_t anon_len, prefix_len = 0; + + anon_part = strchr(url, '@'); + if (is_local(url) || !anon_part) + goto literal_copy; + + anon_len = strlen(++anon_part); + scheme_prefix = strstr(url, "://"); + if (!scheme_prefix) { + if (!strchr(anon_part, ':')) + /* cannot be "me@there:/path/name" */ + goto literal_copy; + } else { + const char *cp; + /* make sure scheme is reasonable */ + for (cp = url; cp < scheme_prefix; cp++) { + switch (*cp) { + /* RFC 1738 2.1 */ + case '+': case '.': case '-': + break; /* ok */ + default: + if (isalnum(*cp)) + break; + /* it isn't */ + goto literal_copy; + } + } + /* @ past the first slash does not count */ + cp = strchr(scheme_prefix + 3, '/'); + if (cp && cp < anon_part) + goto literal_copy; + prefix_len = scheme_prefix - url + 3; + } + anon_url = xcalloc(1, 1 + prefix_len + anon_len); + memcpy(anon_url, url, prefix_len); + memcpy(anon_url + prefix_len, anon_part, anon_len); + return anon_url; +literal_copy: + return xstrdup(url); +} diff --git a/transport.h b/transport.h index b1c2252766..27bfc528ac 100644 --- a/transport.h +++ b/transport.h @@ -74,5 +74,6 @@ const struct ref *transport_get_remote_refs(struct transport *transport); int transport_fetch_refs(struct transport *transport, const struct ref *refs); void transport_unlock_pack(struct transport *transport); int transport_disconnect(struct transport *transport); +char *transport_anonymize_url(const char *url); #endif diff --git a/tree-diff.c b/tree-diff.c index b05d0f4355..edd83949bf 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -374,7 +374,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co } /* - * Then, discard all the non-relevane file pairs... + * Then, discard all the non-relevant file pairs... */ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; @@ -62,6 +62,7 @@ static int match_tree_entry(const char *base, int baselen, const char *path, uns continue; /* pathspecs match only at the directory boundaries */ if (!matchlen || + baselen == matchlen || base[matchlen] == '/' || match[matchlen - 1] == '/') return 1; diff --git a/unimplemented.sh b/unimplemented.sh new file mode 100644 index 0000000000..5252de4b25 --- /dev/null +++ b/unimplemented.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo >&2 "fatal: git was built without support for `basename $0` (@@REASON@@)." +exit 128 diff --git a/unpack-trees.c b/unpack-trees.c index 6847c2d966..e4eb8fa3af 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -87,7 +87,8 @@ static int check_updates(struct unpack_trees_options *o) cnt = 0; } - git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result); + if (o->update) + git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result); for (i = 0; i < index->cache_nr; i++) { struct cache_entry *ce = index->cache[i]; @@ -112,7 +113,8 @@ static int check_updates(struct unpack_trees_options *o) } } stop_progress(&progress); - git_attr_set_direction(GIT_ATTR_CHECKIN, NULL); + if (o->update) + git_attr_set_direction(GIT_ATTR_CHECKIN, NULL); return errs != 0; } diff --git a/upload-pack.c b/upload-pack.c index a49d872447..edc7861228 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -66,7 +66,7 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz) } static FILE *pack_pipe = NULL; -static void show_commit(struct commit *commit) +static void show_commit(struct commit *commit, void *data) { if (commit->object.flags & BOUNDARY) fputc('-', pack_pipe); @@ -78,20 +78,22 @@ static void show_commit(struct commit *commit) commit->buffer = NULL; } -static void show_object(struct object_array_entry *p) +static void show_object(struct object *obj, const struct name_path *path, const char *component) { /* An object with name "foo\n0000000..." can be used to * confuse downstream git-pack-objects very badly. */ - const char *ep = strchr(p->name, '\n'); + const char *name = path_name(path, component); + const char *ep = strchr(name, '\n'); if (ep) { - fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(p->item->sha1), - (int) (ep - p->name), - p->name); + fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(obj->sha1), + (int) (ep - name), + name); } else fprintf(pack_pipe, "%s %s\n", - sha1_to_hex(p->item->sha1), p->name); + sha1_to_hex(obj->sha1), name); + free((char *)name); } static void show_edge(struct commit *commit) @@ -134,7 +136,7 @@ static int do_rev_list(int fd, void *create_full_pack) if (prepare_revision_walk(&revs)) die("revision walk setup failed"); mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, show_object); + traverse_commit_list(&revs, show_commit, show_object, NULL); fflush(pack_pipe); fclose(pack_pipe); return 0; diff --git a/wt-status.c b/wt-status.c index 929b00f592..1b6df45450 100644 --- a/wt-status.c +++ b/wt-status.c @@ -40,7 +40,7 @@ static int parse_status_slot(const char *var, int offset) die("bad config variable '%s'", var); } -static const char* color(int slot) +static const char *color(int slot) { return wt_status_use_color > 0 ? wt_status_colors[slot] : ""; } diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index 02184d9cde..1ebab687f7 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -456,7 +456,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { /* * 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 enf-of-group index in the other + * change record before the end-of-group index in the other * file is set). */ ixref = rchgo[ixo - 1] ? ix: nrec; |