git-diff-files
git-diff-index
git-diff-tree
+git-difftool
+git-difftool--helper
git-describe
git-fast-export
git-fast-import
git-merge-resolve
git-merge-subtree
git-mergetool
+git-mergetool--lib
git-mktag
git-mktree
git-name-rev
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))
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
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.
--
--- /dev/null
+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
--- /dev/null
+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.
+
+
--- /dev/null
+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.
--- /dev/null
+GIT v1.6.3.2 Release Notes
+==========================
+
+Fixes since v1.6.3.1
+--------------------
+
+ * A few codepaths picked up the first few bytes from an sha1[] by
+ casting the (char *) pointer to (int *); GCC 4.4 did not like this,
+ and aborted compilation.
+
+ * http-push had a small use-after-free bug.
+
+ * command completion code in bash did not reliably detect that we are
+ in a bare repository.
+
+ * "git for-each-ref" had a segfaulting bug when dealing with a tag object
+ created by an ancient git.
+
+ * Some unlink(2) failures went undiagnosed.
+
+ * The "recursive" merge strategy misbehaved when faced rename/delete
+ conflicts while coming up with an intermediate merge base.
+
+ * GIT_TRACE mechanism segfaulted when tracing a shell-quoted aliases.
+
+ * "git add ." in an empty directory complained that pathspec "." did not
+ match anything, which may be technically correct, but not useful. We
+ silently make it a no-op now.
+
+ * "git format-patch -k" still added patch numbers if format.numbered
+ configuration was set.
+
+ * OpenBSD also uses st_ctimspec in "struct stat", instead of "st_ctim".
+
+ * With NO_CROSS_DIRECTORY_HARDLINKS, "make install" can be told not to
+ create hardlinks between $(gitexecdir)/git-$builtin_commands and
+ $(bindir)/git.
+
+ * "git push" was converting OFS_DELTA pack representation into less
+ efficient REF_DELTA representation unconditionally upon transfer,
+ making the transferred data unnecessarily larger.
+
+Many other general usability updates around help text, diagnostic messages
+and documentation are included as well.
+
+---
+exec >/var/tmp/1
+O=v1.6.3.1-51-g2a1feb9
+echo O=$(git describe maint)
+git shortlog --no-merges $O..maint
+
* 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.
* "--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.
* 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.
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
------------------
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.3-497-g54a4749
-echo O=$(git describe master)
-git shortlog --no-merges $O..master ^maint
--- /dev/null
+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)
+
+ * gitweb Perl style clean-up.
+
+ * git-svn updates, including a new --authors-prog option to map author
+ names by invoking an external program.
+
+(portability)
+
+ * We feed iconv with "UTF-8" instead of "utf8"; the former is
+ understood more widely.
+
+(performance)
+
+(usability, bells and whistles)
+
+ * "git add --edit" lets users edit the whole patch text to fine-tune what
+ is added to the index.
+
+ * "git log --graph" draws graphs more compactly by using horizonal lines
+ when able.
+
+ * "git log --decorate" shows shorter refnames by stripping well-known
+ refs/* prefix.
+
+ * "git send-email" understands quoted aliases in .mailrc files (might
+ have to be backported to 1.6.3.X).
+
+ * "git send-email" can fetch the sender address from the configuration
+ variable "sendmail.from" (and "sendmail.<identity>.from").
+
+ * "git show-branch" can color its output.
+
+ * "add" and "update" subcommands to "git submodule" learned --reference
+ option to use local clone with references.
+
+(developers)
+
+ * A major part of the "git bisect" wrapper has moved to C.
+
+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.
+
+ * The way Git.pm sets up a Repository object was not friendly to callers
+ that chdir around. It now internally records the repository location
+ as an absolute path when autodetected.
+
+---
+exec >/var/tmp/1
+echo O=$(git describe master)
+O=v1.6.3.1-168-g23807fa
+git shortlog --no-merges $O..master ^maint
- 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
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
------------------
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.
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
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:
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
~~~~~~~
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.
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.
+
+add.ignore-errors::
+ Tells 'git-add' to continue adding files when some files cannot be
+ added due to indexing errors. Equivalent to the '--ignore-errors'
+ option of linkgit:git-add[1].
+
alias.*::
Command aliases for the linkgit:git[1] command wrapper - e.g.
after defining "alias.last = cat-file commit HEAD", the invocation
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`,
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
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
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
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.
--------
[verse]
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
- [--all | [--update | -u]] [--intent-to-add | -N]
+ [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
[--refresh] [--ignore-errors] [--] <filepattern>...
DESCRIPTION
bypassed and the 'patch' subcommand is invoked using each of
the specified filepatterns before exiting.
+-e, \--edit::
+ Open the diff vs. the index in an editor and let the user
+ edit it. After the editor was closed, adjust the hunk headers
+ and apply the patch to the index.
++
+*NOTE*: Obviously, if you change anything else than the first character
+on lines beginning with a space or a minus, the patch will no longer
+apply.
+
-u::
--update::
Update only files that git already knows about, staging modified
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
-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::
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
----------
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:
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:
NAME
----
-git-apply - Apply a patch on a git index file and a working tree
+git-apply - Apply a patch on a git index file and/or a working tree
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...]
--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.
--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.
SYNOPSIS
--------
[verse]
-'git cat-file' [-t | -s | -e | -p | <type>] <object>
-'git cat-file' [--batch | --batch-check] < <list-of-objects>
+'git cat-file' (-t | -s | -e | -p | <type>) <object>
+'git cat-file' (--batch | --batch-check) < <list-of-objects>
DESCRIPTION
-----------
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
. They cannot contain a sequence `@{`.
+- They cannot contain a `\\`.
+
These rules make it easy for shell script based tools to parse
reference names, pathname expansion by the shell when a reference name is used
unquoted (by mistake), and also avoids ambiguities in certain
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
-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/"
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::
"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
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::
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[]
--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
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
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`
'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
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.
--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.
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::
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.
`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`.
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
----------------
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
--------
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`).
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>]
[--subject-prefix=Subject-Prefix]
[--cc=<email>]
[--cover-letter]
+ [<common diff options>]
[ <since> | <revision range> ]
DESCRIPTION
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.
--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
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]
+
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
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::
- '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
-------------
<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
--- /dev/null
+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
--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
-s <strategy>::
--strategy=<strategy>::
- Use the given merge strategy; can be supplied more than
- once to specify them in the order they should be tried.
+ Use the given merge strategy.
If there is no `-s` option, a built-in list of strategies
is used instead ('git-merge-recursive' when merging a single
head, 'git-merge-octopus' otherwise). This implies --merge.
--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.
+--sq-quote::
+ Use 'git-rev-parse' in shell quoting mode (see SQ-QUOTE
+ section below). In contrast to the `--sq` option below, this
+ mode does only quoting. Nothing else is done to command input.
+
--revs-only::
Do not output flags and parameters not meant for
'git-rev-list' command.
properly quoted for consumption by shell. Useful when
you expect your parameter to contain whitespaces and
newlines (e.g. when using pickaxe `-S` with
- 'git-diff-\*').
+ 'git-diff-\*'). In contrast to the `--sq-quote` option,
+ the command input is still interpreted as usual.
--not::
When showing object names, prefix them with '{caret}' and
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`.
eval `echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?`
------------
+SQ-QUOTE
+--------
+
+In `--sq-quote` mode, 'git-rev-parse' echoes on the standard output a
+single line suitable for `sh(1)` `eval`. This line is made by
+normalizing the arguments following `--sq-quote`. Nothing other than
+quoting the arguments is done.
+
+If you want command input to still be interpreted as usual by
+'git-rev-parse' before the output is shell quoted, see the `--sq`
+option.
+
+Example
+~~~~~~~
+
+------------
+$ cat >your-git-script.sh <<\EOF
+#!/bin/sh
+args=$(git rev-parse --sq-quote "$@") # quote user-supplied arguments
+command="git frotz -n24 $args" # and use it inside a handcrafted
+ # command line
+eval "$command"
+EOF
+
+$ sh your-git-script.sh "a b'c"
+------------
+
EXAMPLES
--------
See the CONFIGURATION section for 'sendemail.multiedit'.
--from=<address>::
- Specify the sender of the emails. This will default to
- the value GIT_COMMITTER_IDENT, as returned by "git var -l".
- The user will still be prompted to confirm this entry.
+ Specify the sender of the emails. If not specified on the command line,
+ the value of the 'sendemail.from' configuration option is used. If
+ neither the command line option nor 'sendemail.from' are set, then the
+ user will be prompted for the value. The default for the prompt will be
+ the value of GIT_AUTHOR_IDENT, or GIT_COMMITTER_IDENT if that is not
+ set, as returned by "git var -l".
--in-reply-to=<identifier>::
Specify the contents of the first In-Reply-To header.
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
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
------
[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>]
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.
------------------------------------------------
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
it will accept any format known to 'git-diff' (e.g., `git stash show
-p stash@\{1}` to view the second most recent stash in patch form).
-apply [--index] [<stash>]::
+pop [<stash>]::
- Restore the changes recorded in the stash on top of the current
- working tree state. When no `<stash>` is given, applies the latest
- one. The working directory must match the index.
+ Remove a single stashed state from the stash list and apply it
+ on top of the current working tree state, i.e., do the inverse
+ operation of `git stash save`. The working directory must
+ match the index.
+
-This operation can fail with conflicts; you need to resolve them
-by hand in the working tree.
+Applying the state can fail with conflicts; in this case, it is not
+removed from the stash list. You need to resolve the conflicts by hand
+and call `git stash drop` manually afterwards.
++
+When no `<stash>` is given, `stash@\{0}` is assumed. See also `apply`.
+
+apply [--index] [<stash>]::
+
+ Like `pop`, but do not remove the state from the stash list.
+
If the `--index` option is used, then tries to reinstate not only the working
tree's changes, but also the index's ones. However, this can fail, when you
Remove a single stashed state from the stash list. When no `<stash>`
is given, it removes the latest one. i.e. `stash@\{0}`
-pop [<stash>]::
-
- Remove a single stashed state from the stash list and apply on top
- of the current working tree state. When no `<stash>` is given,
- `stash@\{0}` is assumed. See also `apply`.
-
create::
Create a stash (which is a regular commit object) and return its
file foobar not up to date, cannot merge.
$ git stash
$ git pull
-$ git stash apply
+$ git stash pop
----------------------------------------------------------------
Interrupted workflow::
$ git stash
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
-$ git stash apply
+$ git stash pop
# ... continue hacking ...
----------------------------------------------------------------
SYNOPSIS
--------
[verse]
-'git submodule' [--quiet] add [-b branch] [--] <repository> <path>
+'git submodule' [--quiet] add [-b branch]
+ [--reference <repository>] [--] <repository> <path>
'git submodule' [--quiet] status [--cached] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
-'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--] [<path>...]
+'git submodule' [--quiet] update [--init] [-N|--no-fetch]
+ [--reference <repository>] [--] [<path>...]
'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
'git submodule' [--quiet] foreach <command>
'git submodule' [--quiet] sync [--] [<path>...]
This option is only valid for the update command.
Don't fetch new objects from the remote site.
+--reference <repository>::
+ This option is only valid for add and update commands. These
+ commands sometimes need to clone a remote repository. In this case,
+ this option will be passed to the linkgit:git-clone[1] command.
++
+*NOTE*: Do *not* use this option unless you have read the note
+for linkgit:git-clone[1]'s --reference and --shared options carefully.
+
<path>...::
Paths to submodule(s). When specified this will restrict the command
to only operate on the submodules found at the specified paths.
config key: svn.authorsfile
+--authors-prog=<filename>::
+
+If this option is specified, for each SVN committer name that does not
+exist in the authors file, the given file is executed with the committer
+name as the first argument. The program is expected to return a single
+line of the form "Name <email>", which will be treated as if included in
+the authors file.
+
-q::
--quiet::
Make 'git-svn' less verbose. Specify a second time to make it
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'.
* 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>
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.6.2.3/git.html[documentation for release 1.6.2.3]
+* 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],
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"]
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"]
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"]
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>
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.
--squash::
Produce the working tree and index state as if a real
- merge happened, but do not actually make a commit or
+ merge happened (except for the merge information),
+ but do not actually make a commit or
move the `HEAD`, nor record `$GIT_DIR/MERGE_HEAD` to
cause the next `git commit` command to create a merge
commit. This allows you to create a single commit on
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`.
Introduce a boolean option.
If used, `int_var` is bitwise-ored with `mask`.
+`OPT_NEGBIT(short, long, &int_var, description, mask)`::
+ Introduce a boolean option.
+ If used, `int_var` is bitwise-anded with the inverted `mask`.
+
`OPT_SET_INT(short, long, &int_var, description, integer)`::
Introduce a boolean option.
If used, set `int_var` to `integer`.
`OPT_ARGUMENT(long, description)`::
Introduce a long-option argument that will be kept in `argv[]`.
+`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
+ Recognize numerical options like -123 and feed the integer as
+ if it was an argument to the function given by `func_ptr`.
+ The result will be put into `var`. There can be only one such
+ option definition. It cannot be negated and it takes no
+ arguments. Short options that happen to be digits take
+ precedence over it.
+
The last element of the array must be `OPT_END()`.
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()`.
------------------------------------------------
After that, you can go back to what you were working on with
-`git stash apply`:
+`git stash pop`:
------------------------------------------------
-$ git stash apply
+$ git stash pop
------------------------------------------------
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.6.2.GIT
+DEF_VER=v1.6.3.GIT
LF='
'
# 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).
+#
+# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed
+# programs as a tar, where bin/ and libexec/ might be on different file systems.
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
endif
lib = lib
# DESTDIR=
+pathsep = :
# default configuration for gitweb
GITWEB_CONFIG = gitweb_config.perl
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
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
# ... 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
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
# what 'all' will build but not install in gitexecdir
OTHER_PROGRAMS = git$X
-ifndef NO_PERL
-OTHER_PROGRAMS += gitweb/gitweb.cgi
-endif
# Set paths to tools early so that they can be used for version tests.
ifndef SHELL_PATH
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
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
endif
ifneq (,$(findstring CYGWIN,$(uname_S)))
COMPAT_OBJS += compat/cygwin.o
+ UNRELIABLE_FSTAT = UnfortunatelyYes
endif
ifneq (,$(findstring MINGW,$(uname_S)))
+ pathsep = ;
NO_PREAD = YesPlease
NO_OPENSSL = YesPlease
NO_CURL = YesPlease
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\"
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
ifdef NO_EXTERNAL_GREP
BASIC_CFLAGS += -DNO_EXTERNAL_GREP
endif
+ifdef UNRELIABLE_FSTAT
+ BASIC_CFLAGS += -DUNRELIABLE_FSTAT
+endif
ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
- -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
$@.sh >$@+ && \
sed -e '1{' \
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
-e ' h' \
- -e ' s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \
+ -e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \
-e ' H' \
-e ' x' \
-e '}' \
chmod +x $@+ && \
mv $@+ $@
+OTHER_PROGRAMS += gitweb/gitweb.cgi
gitweb/gitweb.cgi: gitweb/gitweb.perl
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
$(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) && \
{ $(RM) "$$execdir/git-add$X" && \
+ test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
{ for p in $(filter-out git-add$X,$(BUILT_INS)); do \
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:
-Documentation/RelNotes-1.6.3.txt
\ No newline at end of file
+Documentation/RelNotes-1.6.4.txt
\ No newline at end of file
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;
while (cmdline[++src]
&& isspace(cmdline[src]))
; /* skip */
- if (count >= size) {
- size += 16;
- *argv = xrealloc(*argv, sizeof(char*) * size);
- }
+ ALLOC_GROW(*argv, count+1, size);
(*argv)[count++] = cmdline + dst;
} else if (!quoted && (c == '\'' || c == '"')) {
quoted = c;
return error("unclosed quote");
}
+ ALLOC_GROW(*argv, count+1, size);
+ (*argv)[count] = NULL;
+
return count;
}
#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);
}
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);
#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...]",
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] == '/') {
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)
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"),
"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),
args->verbose = verbose;
args->base = base;
args->baselen = strlen(base);
+ args->worktree_attributes = worktree_attributes;
return argc;
}
time_t time;
const char **pathspec;
unsigned int verbose : 1;
+ unsigned int worktree_attributes : 1;
int compression_level;
};
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;
}
setto == ATTR__UNKNOWN)
;
else
- free((char*) setto);
+ free((char *) setto);
}
free(a);
}
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)
/*
*/
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;
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;
/*
* Read from parent directories and push them down
*/
- if (!is_bare_repository()) {
+ if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
while (1) {
char *cp;
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();
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 *);
#include "list-objects.h"
#include "quote.h"
#include "sha1-lookup.h"
+#include "run-command.h"
#include "bisect.h"
-static unsigned char (*skipped_sha1)[20];
-static int skipped_sha1_nr;
-static int skipped_sha1_alloc;
+struct sha1_array {
+ unsigned char (*sha1)[20];
+ int sha1_nr;
+ int sha1_alloc;
+ int sorted;
+};
+
+static struct sha1_array good_revs;
+static struct sha1_array skipped_revs;
+
+static const unsigned char *current_bad_sha1;
+
+struct argv_array {
+ const char **argv;
+ int argv_nr;
+ int argv_alloc;
+};
-static const char **rev_argv;
-static int rev_argv_nr;
-static int rev_argv_alloc;
+static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL};
+static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
+static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
/* bits #0-15 in revision.h */
return best;
}
+static void argv_array_push(struct argv_array *array, const char *string)
+{
+ ALLOC_GROW(array->argv, array->argv_nr + 1, array->argv_alloc);
+ array->argv[array->argv_nr++] = string;
+}
+
+static void argv_array_push_sha1(struct argv_array *array,
+ const unsigned char *sha1,
+ const char *format)
+{
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addf(&buf, format, sha1_to_hex(sha1));
+ argv_array_push(array, strbuf_detach(&buf, NULL));
+}
+
+static void sha1_array_push(struct sha1_array *array,
+ const unsigned char *sha1)
+{
+ ALLOC_GROW(array->sha1, array->sha1_nr + 1, array->sha1_alloc);
+ hashcpy(array->sha1[array->sha1_nr++], sha1);
+}
+
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));
+ current_bad_sha1 = 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;
+ sha1_array_push(&good_revs, sha1);
} else if (!prefixcmp(refname, "skip-")) {
- ALLOC_GROW(skipped_sha1, skipped_sha1_nr + 1,
- skipped_sha1_alloc);
- hashcpy(skipped_sha1[skipped_sha1_nr++], sha1);
+ sha1_array_push(&skipped_revs, sha1);
}
return 0;
return for_each_ref_in("refs/bisect/", register_ref, NULL);
}
-void read_bisect_paths(void)
+void read_bisect_paths(struct argv_array *array)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path("BISECT_NAMES");
strbuf_trim(&str);
quoted = strbuf_detach(&str, NULL);
- res = sq_dequote_to_argv(quoted, &rev_argv,
- &rev_argv_nr, &rev_argv_alloc);
+ res = sq_dequote_to_argv(quoted, &array->argv,
+ &array->argv_nr, &array->argv_alloc);
if (res)
die("Badly quoted content in file '%s': %s",
filename, quoted);
fclose(fp);
}
-static int skipcmp(const void *a, const void *b)
+static int array_cmp(const void *a, const void *b)
{
return hashcmp(a, b);
}
-static void prepare_skipped(void)
+static void sort_sha1_array(struct sha1_array *array)
{
- qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp);
+ qsort(array->sha1, array->sha1_nr, sizeof(*array->sha1), array_cmp);
+
+ array->sorted = 1;
}
-static const unsigned char *skipped_sha1_access(size_t index, void *table)
+static const unsigned char *sha1_access(size_t index, void *table)
{
- unsigned char (*skipped)[20] = table;
- return skipped[index];
+ unsigned char (*array)[20] = table;
+ return array[index];
}
-static int lookup_skipped(unsigned char *sha1)
+static int lookup_sha1_array(struct sha1_array *array,
+ const unsigned char *sha1)
{
- return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr,
- skipped_sha1_access);
+ if (!array->sorted)
+ sort_sha1_array(array);
+
+ return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access);
+}
+
+static char *join_sha1_array_hex(struct sha1_array *array, char delim)
+{
+ struct strbuf joined_hexs = STRBUF_INIT;
+ int i;
+
+ for (i = 0; i < array->sha1_nr; i++) {
+ strbuf_addstr(&joined_hexs, sha1_to_hex(array->sha1[i]));
+ if (i + 1 < array->sha1_nr)
+ strbuf_addch(&joined_hexs, delim);
+ }
+
+ return strbuf_detach(&joined_hexs, NULL);
}
struct commit_list *filter_skipped(struct commit_list *list,
*tried = NULL;
- if (!skipped_sha1_nr)
+ if (!skipped_revs.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)) {
+ if (0 <= lookup_sha1_array(&skipped_revs,
+ list->item->object.sha1)) {
/* Move current to tried list */
*tried = list;
tried = &list->next;
return filtered;
}
-static void bisect_rev_setup(struct rev_info *revs, const char *prefix)
+static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
+ const char *bad_format, const char *good_format,
+ int read_paths)
{
+ struct argv_array rev_argv = { NULL, 0, 0 };
+ int i;
+
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");
+ /* rev_argv.argv[0] will be ignored by setup_revisions */
+ argv_array_push(&rev_argv, xstrdup("bisect_rev_setup"));
+ argv_array_push_sha1(&rev_argv, current_bad_sha1, bad_format);
+ for (i = 0; i < good_revs.sha1_nr; i++)
+ argv_array_push_sha1(&rev_argv, good_revs.sha1[i],
+ good_format);
+ argv_array_push(&rev_argv, xstrdup("--"));
+ if (read_paths)
+ read_bisect_paths(&rev_argv);
+ argv_array_push(&rev_argv, NULL);
+
+ setup_revisions(rev_argv.argv_nr, rev_argv.argv, revs, NULL);
+}
- if (read_bisect_refs())
- die("reading bisect refs failed");
+static void bisect_common(struct rev_info *revs)
+{
+ if (prepare_revision_walk(revs))
+ die("revision walk setup failed");
+ if (revs->tree_objects)
+ mark_edges_uninteresting(revs->commits, revs, NULL);
+}
+
+static void exit_if_skipped_commits(struct commit_list *tried,
+ const unsigned char *bad)
+{
+ if (!tried)
+ return;
+
+ printf("There are only 'skip'ped commits left to test.\n"
+ "The first bad commit could be any of:\n");
+ print_commit_list(tried, "%s\n", "%s\n");
+ if (bad)
+ printf("%s\n", sha1_to_hex(bad));
+ printf("We cannot bisect more!\n");
+ exit(2);
+}
+
+static int is_expected_rev(const unsigned char *sha1)
+{
+ const char *filename = git_path("BISECT_EXPECTED_REV");
+ struct stat st;
+ struct strbuf str = STRBUF_INIT;
+ FILE *fp;
+ int res = 0;
+
+ if (stat(filename, &st) || !S_ISREG(st.st_mode))
+ return 0;
+
+ fp = fopen(filename, "r");
+ if (!fp)
+ return 0;
+
+ if (strbuf_getline(&str, fp, '\n') != EOF)
+ res = !strcmp(str.buf, sha1_to_hex(sha1));
+
+ strbuf_release(&str);
+ fclose(fp);
+
+ return res;
+}
+
+static void mark_expected_rev(char *bisect_rev_hex)
+{
+ int len = strlen(bisect_rev_hex);
+ const char *filename = git_path("BISECT_EXPECTED_REV");
+ int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+
+ if (fd < 0)
+ die("could not create file '%s': %s",
+ filename, strerror(errno));
- ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
- rev_argv[rev_argv_nr++] = xstrdup("--");
+ bisect_rev_hex[len] = '\n';
+ write_or_die(fd, bisect_rev_hex, len + 1);
+ bisect_rev_hex[len] = '\0';
- read_bisect_paths();
+ if (close(fd) < 0)
+ die("closing file %s: %s", filename, strerror(errno));
+}
+
+static int bisect_checkout(char *bisect_rev_hex)
+{
+ int res;
- ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
- rev_argv[rev_argv_nr++] = NULL;
+ mark_expected_rev(bisect_rev_hex);
- setup_revisions(rev_argv_nr, rev_argv, revs, NULL);
+ argv_checkout[2] = bisect_rev_hex;
+ res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
+ if (res)
+ exit(res);
- revs->limited = 1;
+ argv_show_branch[1] = bisect_rev_hex;
+ return run_command_v_opt(argv_show_branch, RUN_GIT_CMD);
}
-int bisect_next_vars(const char *prefix)
+static struct commit *get_commit_reference(const unsigned char *sha1)
+{
+ struct commit *r = lookup_commit_reference(sha1);
+ if (!r)
+ die("Not a valid commit name %s", sha1_to_hex(sha1));
+ return r;
+}
+
+static struct commit **get_bad_and_good_commits(int *rev_nr)
+{
+ int len = 1 + good_revs.sha1_nr;
+ struct commit **rev = xmalloc(len * sizeof(*rev));
+ int i, n = 0;
+
+ rev[n++] = get_commit_reference(current_bad_sha1);
+ for (i = 0; i < good_revs.sha1_nr; i++)
+ rev[n++] = get_commit_reference(good_revs.sha1[i]);
+ *rev_nr = n;
+
+ return rev;
+}
+
+static void handle_bad_merge_base(void)
+{
+ if (is_expected_rev(current_bad_sha1)) {
+ char *bad_hex = sha1_to_hex(current_bad_sha1);
+ char *good_hex = join_sha1_array_hex(&good_revs, ' ');
+
+ fprintf(stderr, "The merge base %s is bad.\n"
+ "This means the bug has been fixed "
+ "between %s and [%s].\n",
+ bad_hex, bad_hex, good_hex);
+
+ exit(3);
+ }
+
+ fprintf(stderr, "Some good revs are not ancestor of the bad rev.\n"
+ "git bisect cannot work properly in this case.\n"
+ "Maybe you mistake good and bad revs?\n");
+ exit(1);
+}
+
+void handle_skipped_merge_base(const unsigned char *mb)
+{
+ char *mb_hex = sha1_to_hex(mb);
+ char *bad_hex = sha1_to_hex(current_bad_sha1);
+ char *good_hex = join_sha1_array_hex(&good_revs, ' ');
+
+ fprintf(stderr, "Warning: the merge base between %s and [%s] "
+ "must be skipped.\n"
+ "So we cannot be sure the first bad commit is "
+ "between %s and %s.\n"
+ "We continue anyway.\n",
+ bad_hex, good_hex, mb_hex, bad_hex);
+ free(good_hex);
+}
+
+/*
+ * "check_merge_bases" checks that merge bases are not "bad".
+ *
+ * - If one is "bad", it means the user assumed something wrong
+ * and we must exit with a non 0 error code.
+ * - If one is "good", that's good, we have nothing to do.
+ * - If one is "skipped", we can't know but we should warn.
+ * - If we don't know, we should check it out and ask the user to test.
+ */
+static void check_merge_bases(void)
+{
+ struct commit_list *result;
+ int rev_nr;
+ struct commit **rev = get_bad_and_good_commits(&rev_nr);
+
+ result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
+
+ for (; result; result = result->next) {
+ const unsigned char *mb = result->item->object.sha1;
+ if (!hashcmp(mb, current_bad_sha1)) {
+ handle_bad_merge_base();
+ } else if (0 <= lookup_sha1_array(&good_revs, mb)) {
+ continue;
+ } else if (0 <= lookup_sha1_array(&skipped_revs, mb)) {
+ handle_skipped_merge_base(mb);
+ } else {
+ printf("Bisecting: a merge base must be tested\n");
+ exit(bisect_checkout(sha1_to_hex(mb)));
+ }
+ }
+
+ free(rev);
+ free_commit_list(result);
+}
+
+static int check_ancestors(const char *prefix)
{
struct rev_info revs;
- struct rev_list_info info;
- int reaches = 0, all = 0;
+ struct object_array pending_copy;
+ int i, res;
- memset(&info, 0, sizeof(info));
- info.revs = &revs;
- info.bisect_show_flags = BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED;
+ bisect_rev_setup(&revs, prefix, "^%s", "%s", 0);
- bisect_rev_setup(&revs, prefix);
+ /* Save pending objects, so they can be cleaned up later. */
+ memset(&pending_copy, 0, sizeof(pending_copy));
+ for (i = 0; i < revs.pending.nr; i++)
+ add_object_array(revs.pending.objects[i].item,
+ revs.pending.objects[i].name,
+ &pending_copy);
- if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
- if (revs.tree_objects)
- mark_edges_uninteresting(revs.commits, &revs, NULL);
+ bisect_common(&revs);
+ res = (revs.commits != NULL);
+
+ /* Clean up objects used, as they will be reused. */
+ for (i = 0; i < pending_copy.nr; i++) {
+ struct object *o = pending_copy.objects[i].item;
+ unparse_commit((struct commit *)o);
+ }
+
+ return res;
+}
+
+/*
+ * "check_good_are_ancestors_of_bad" checks that all "good" revs are
+ * ancestor of the "bad" rev.
+ *
+ * If that's not the case, we need to check the merge bases.
+ * If a merge base must be tested by the user, its source code will be
+ * checked out to be tested by the user and we will exit.
+ */
+static void check_good_are_ancestors_of_bad(const char *prefix)
+{
+ const char *filename = git_path("BISECT_ANCESTORS_OK");
+ struct stat st;
+ int fd;
+
+ if (!current_bad_sha1)
+ die("a bad revision is needed");
+
+ /* Check if file BISECT_ANCESTORS_OK exists. */
+ if (!stat(filename, &st) && S_ISREG(st.st_mode))
+ return;
+
+ /* Bisecting with no good rev is ok. */
+ if (good_revs.sha1_nr == 0)
+ return;
+
+ /* Check if all good revs are ancestor of the bad rev. */
+ if (check_ancestors(prefix))
+ check_merge_bases();
+
+ /* Create file BISECT_ANCESTORS_OK. */
+ fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ if (fd < 0)
+ warning("could not create file '%s': %s",
+ filename, strerror(errno));
+ else
+ close(fd);
+}
+
+/*
+ * We use the convention that exiting with an exit code 10 means that
+ * the bisection process finished successfully.
+ * In this case the calling shell script should exit 0.
+ */
+int bisect_next_all(const char *prefix)
+{
+ struct rev_info revs;
+ struct commit_list *tried;
+ int reaches = 0, all = 0, nr;
+ const unsigned char *bisect_rev;
+ char bisect_rev_hex[41];
+
+ if (read_bisect_refs())
+ die("reading bisect refs failed");
+
+ check_good_are_ancestors_of_bad(prefix);
+
+ bisect_rev_setup(&revs, prefix, "%s", "^%s", 1);
+ revs.limited = 1;
+
+ bisect_common(&revs);
revs.commits = find_bisection(revs.commits, &reaches, &all,
- !!skipped_sha1_nr);
+ !!skipped_revs.sha1_nr);
+ revs.commits = filter_skipped(revs.commits, &tried, 0);
+
+ if (!revs.commits) {
+ /*
+ * We should exit here only if the "bad"
+ * commit is also a "skip" commit.
+ */
+ exit_if_skipped_commits(tried, NULL);
+
+ printf("%s was both good and bad\n",
+ sha1_to_hex(current_bad_sha1));
+ exit(1);
+ }
- return show_bisect_vars(&info, reaches, all);
+ bisect_rev = revs.commits->item->object.sha1;
+ memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), 41);
+
+ if (!hashcmp(bisect_rev, current_bad_sha1)) {
+ exit_if_skipped_commits(tried, current_bad_sha1);
+ printf("%s is first bad commit\n", bisect_rev_hex);
+ argv_diff_tree[2] = bisect_rev_hex;
+ run_command_v_opt(argv_diff_tree, RUN_GIT_CMD);
+ /* This means the bisection process succeeded. */
+ exit(10);
+ }
+
+ nr = all - reaches - 1;
+ printf("Bisecting: %d revisions left to test after this "
+ "(roughly %d steps)\n", nr, estimate_bisect_steps(all));
+
+ return bisect_checkout(bisect_rev_hex);
}
+
struct commit_list **tried,
int show_all);
+extern void print_commit_list(struct commit_list *list,
+ const char *format_cur,
+ const char *format_last);
+
/* 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;
extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all);
-extern int bisect_next_vars(const char *prefix);
+extern int bisect_next_all(const char *prefix);
+
+extern int estimate_bisect_steps(int all);
#endif
#include "cache-tree.h"
#include "run-command.h"
#include "parse-options.h"
+#include "diff.h"
+#include "revision.h"
static const char * const builtin_add_usage[] = {
"git add [options] [--] <filepattern>...",
NULL
};
-static int patch_interactive, add_interactive;
+static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
fill_pathspec_matches(pathspec, seen, specs);
for (i = 0; i < specs; i++) {
- if (!seen[i] && !file_exists(pathspec[i]))
+ if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))
die("pathspec '%s' did not match any files",
pathspec[i]);
}
return status;
}
+int edit_patch(int argc, const char **argv, const char *prefix)
+{
+ char *file = xstrdup(git_path("ADD_EDIT.patch"));
+ const char *apply_argv[] = { "apply", "--recount", "--cached",
+ file, NULL };
+ struct child_process child;
+ struct rev_info rev;
+ int out;
+ struct stat st;
+
+ git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+ if (read_cache() < 0)
+ die ("Could not read the index");
+
+ init_revisions(&rev, prefix);
+ rev.diffopt.context = 7;
+
+ argc = setup_revisions(argc, argv, &rev, NULL);
+ rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+ out = open(file, O_CREAT | O_WRONLY, 0644);
+ if (out < 0)
+ die ("Could not open '%s' for writing.", file);
+ rev.diffopt.file = fdopen(out, "w");
+ rev.diffopt.close_file = 1;
+ if (run_diff_files(&rev, 0))
+ die ("Could not write patch");
+
+ launch_editor(file, NULL, NULL);
+
+ if (stat(file, &st))
+ die("Could not stat '%s'", file);
+ if (!st.st_size)
+ die("Empty patch. Aborted.");
+
+ memset(&child, 0, sizeof(child));
+ child.git_cmd = 1;
+ child.argv = apply_argv;
+ if (run_command(&child))
+ die ("Could not apply '%s'", file);
+
+ unlink(file);
+ return 0;
+}
+
static struct lock_file lock_file;
static const char ignore_error[] =
OPT_GROUP(""),
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
+ OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
int require_pathspec;
argc = parse_options(argc, argv, builtin_add_options,
- builtin_add_usage, 0);
+ builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive)
add_interactive = 1;
if (add_interactive)
- exit(interactive_add(argc, argv, prefix));
+ exit(interactive_add(argc - 1, argv + 1, prefix));
git_config(add_config, NULL);
+ if (edit_interactive)
+ return(edit_patch(argc, argv, prefix));
+ argc--;
+ argv++;
+
if (addremove && take_worktree_changes)
die("-A and -u are mutually incompatible");
if ((addremove || take_worktree_changes) && !argc) {
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;
*/
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;
}
}
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);
}
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);
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) {
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;
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
{
int err = 0;
+ prepare_fn_table(patch);
while (patch) {
if (apply_verbosely)
say_patch_name(stderr,
if (rmdir(patch->old_name))
warning("unable to remove submodule %s",
patch->old_name);
- } else if (!unlink(patch->old_name) && rmdir_empty) {
+ } else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
remove_path(patch->old_name);
}
}
if (!try_create_file(newpath, mode, buf, size)) {
if (!rename(newpath, path))
return;
- unlink(newpath);
+ unlink_or_warn(newpath);
break;
}
if (errno != EEXIST)
argc = parse_options(argc, argv, builtin_apply_options,
apply_usage, 0);
+ fake_ancestor = parse_options_fix_filename(prefix, fake_ancestor);
+ if (fake_ancestor)
+ fake_ancestor = xstrdup(fake_ancestor);
+
if (apply_with_reject)
apply = apply_verbosely = 1;
if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
#include "bisect.h"
static const char * const git_bisect_helper_usage[] = {
- "git bisect--helper --next-vars",
+ "git bisect--helper --next-all",
NULL
};
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
- int next_vars = 0;
+ int next_all = 0;
struct option options[] = {
- OPT_BOOLEAN(0, "next-vars", &next_vars,
- "output next bisect step variables"),
+ OPT_BOOLEAN(0, "next-all", &next_all,
+ "perform 'git bisect next'"),
OPT_END()
};
argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0);
- if (!next_vars)
+ if (!next_all)
usage_with_options(git_bisect_helper_usage, options);
- /* next-vars */
- return bisect_next_vars(prefix);
+ /* next-all */
+ return bisect_next_all(prefix);
}
* 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) {
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;
}
}
}
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;
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++;
}
if (branch && branch->merge && branch->merge[0]->dst &&
show_upstream_ref)
strbuf_addf(stat, "[%s] ",
- shorten_unambiguous_ref(branch->merge[0]->dst));
+ 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));
+ shorten_unambiguous_ref(branch->merge[0]->dst, 0));
if (!ours)
strbuf_addf(stat, "behind %d] ", theirs);
else if (!theirs)
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",
}
static const char * const cat_file_usage[] = {
- "git cat-file [-t|-s|-e|-p|<type>] <sha1>",
- "git cat-file [--batch|--batch-check] < <list_of_sha1s>",
+ "git cat-file (-t|-s|-e|-p|<type>) <object>",
+ "git cat-file (--batch|--batch-check) < <list_of_objects>",
NULL
};
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];
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) {
#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"
/*
* 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
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_locked_index(lock_file, 1);
- if (read_cache() < 0)
+ if (read_cache_preload(pathspec) < 0)
return error("corrupt index file");
if (source_tree)
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
int newfd = hold_locked_index(lock_file, 1);
- if (read_cache() < 0)
+ if (read_cache_preload(NULL) < 0)
return error("corrupt index file");
if (opts->force) {
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.");
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);
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)) {
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)
}
if (unlink(dest->buf) && errno != ENOENT)
- die("failed to unlink %s", dest->buf);
+ die("failed to unlink %s: %s",
+ dest->buf, strerror(errno));
if (!option_no_hardlinks) {
if (!link(src->buf, dest->buf))
continue;
argc = parse_options(argc, argv, builtin_commit_options, usage, 0);
logfile = parse_options_fix_filename(prefix, logfile);
+ if (logfile)
+ logfile = xstrdup(logfile);
template_file = parse_options_fix_filename(prefix, template_file);
+ if (template_file)
+ template_file = xstrdup(template_file);
if (force_author && !strchr(force_author, '>'))
force_author = find_author_by_nickname(force_author);
}
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"),
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";
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);
}
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",
};
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;
(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++;
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;
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);
}
fd = hold_lock_file_for_update(&lock, shallow,
LOCK_DIE_ON_ERROR);
if (!write_shallow_commits(fd, 0)) {
- unlink(shallow);
+ unlink_or_warn(shallow);
rollback_lock_file(&lock);
} else {
commit_lock_file(&lock);
return ref_map;
}
+#define STORE_REF_ERROR_OTHER 1
+#define STORE_REF_ERROR_DF_CONFLICT 2
+
static int s_update_ref(const char *action,
struct ref *ref,
int check_old)
lock = lock_any_ref_for_update(ref->name,
check_old ? ref->old_sha1 : NULL, 0);
if (!lock)
- return 2;
+ return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
+ STORE_REF_ERROR_OTHER;
if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
- return 2;
+ return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
+ STORE_REF_ERROR_OTHER;
return 0;
}
struct commit *current = NULL, *updated;
enum object_type type;
struct branch *current_branch = branch_get(NULL);
- const char *pretty_ref = prettify_ref(ref);
+ const char *pretty_ref = prettify_refname(ref->name);
*display = 0;
type = sha1_object_info(ref->new_sha1, NULL);
}
}
-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;
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;
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);
fprintf(stderr, " %s\n", note);
}
}
+ free(url);
fclose(fp);
- if (rc & 2)
+ if (rc & STORE_REF_ERROR_DF_CONFLICT)
error("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting "
"branches", remote_name);
argc = parse_options(argc, argv, options, fmt_merge_msg_usage, 0);
if (argc > 0)
usage_with_options(fmt_merge_msg_usage, options);
+ inpath = parse_options_fix_filename(prefix, inpath);
if (inpath && strcmp(inpath, "-")) {
in = fopen(inpath, "r");
static const char *copy_email(const char *buf)
{
const char *email = strchr(buf, '<');
- const char *eoemail = strchr(email, '>');
- if (!email || !eoemail)
+ const char *eoemail;
+ if (!email)
+ return "";
+ eoemail = strchr(email, '>');
+ if (!eoemail)
return "";
return xmemdupz(email, eoemail + 1 - email);
}
if (formatp) {
formatp++;
if (!strcmp(formatp, "short"))
- refname = shorten_unambiguous_ref(refname);
+ refname = shorten_unambiguous_ref(refname,
+ warn_ambiguous_refs);
else
die("unknown %.*s format %s",
(int)(formatp - name), name, formatp);
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);
#include "tag.h"
#include "tree-walk.h"
#include "builtin.h"
+#include "parse-options.h"
#include "grep.h"
#ifndef NO_EXTERNAL_GREP
#endif
#endif
-static int builtin_grep;
+static char const * const grep_usage[] = {
+ "git grep [options] [-e] <pattern> [<rev>...] [[--] path...]",
+ NULL
+};
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);
}
#endif
-static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
+static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
+ int external_grep_allowed)
{
int hit = 0;
int nr;
* we grep through the checked-out files. It tends to
* be a lot more optimized
*/
- if (!cached && !builtin_grep) {
+ if (!cached && external_grep_allowed) {
hit = external_grep(opt, paths, cached);
if (hit >= 0)
return hit;
die("unable to grep from object of type %s", typename(obj->type));
}
-static const char builtin_grep_usage[] =
-"git grep <option>* [-e] <pattern> <rev>* [[--] <path>...]";
+static int context_callback(const struct option *opt, const char *arg,
+ int unset)
+{
+ struct grep_opt *grep_opt = opt->value;
+ int value;
+ const char *endp;
+
+ if (unset) {
+ grep_opt->pre_context = grep_opt->post_context = 0;
+ return 0;
+ }
+ value = strtol(arg, (char **)&endp, 10);
+ if (*endp) {
+ return error("switch `%c' expects a numerical value",
+ opt->short_name);
+ }
+ grep_opt->pre_context = grep_opt->post_context = value;
+ return 0;
+}
+
+static int file_callback(const struct option *opt, const char *arg, int unset)
+{
+ struct grep_opt *grep_opt = opt->value;
+ FILE *patterns;
+ int lno = 0;
+ struct strbuf sb;
+
+ patterns = fopen(arg, "r");
+ if (!patterns)
+ die("'%s': %s", arg, strerror(errno));
+ while (strbuf_getline(&sb, patterns, '\n') == 0) {
+ /* ignore empty line like grep does */
+ if (sb.len == 0)
+ continue;
+ append_grep_pattern(grep_opt, strbuf_detach(&sb, NULL), arg,
+ ++lno, GREP_PATTERN);
+ }
+ fclose(patterns);
+ strbuf_release(&sb);
+ return 0;
+}
-static const char emsg_invalid_context_len[] =
-"%s: invalid context length argument";
-static const char emsg_missing_context_len[] =
-"missing context length argument";
-static const char emsg_missing_argument[] =
-"option requires an argument -%s";
+static int not_callback(const struct option *opt, const char *arg, int unset)
+{
+ struct grep_opt *grep_opt = opt->value;
+ append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT);
+ return 0;
+}
+
+static int and_callback(const struct option *opt, const char *arg, int unset)
+{
+ struct grep_opt *grep_opt = opt->value;
+ append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND);
+ return 0;
+}
+
+static int open_callback(const struct option *opt, const char *arg, int unset)
+{
+ struct grep_opt *grep_opt = opt->value;
+ append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN);
+ return 0;
+}
+
+static int close_callback(const struct option *opt, const char *arg, int unset)
+{
+ struct grep_opt *grep_opt = opt->value;
+ append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN);
+ return 0;
+}
+
+static int pattern_callback(const struct option *opt, const char *arg,
+ int unset)
+{
+ struct grep_opt *grep_opt = opt->value;
+ append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN);
+ return 0;
+}
+
+static int help_callback(const struct option *opt, const char *arg, int unset)
+{
+ return -1;
+}
int cmd_grep(int argc, const char **argv, const char *prefix)
{
int hit = 0;
int cached = 0;
+ int external_grep_allowed = 1;
int seen_dashdash = 0;
struct grep_opt opt;
struct object_array list = { 0, 0, NULL };
const char **paths = NULL;
int i;
+ int dummy;
+ struct option options[] = {
+ OPT_BOOLEAN(0, "cached", &cached,
+ "search in index instead of in the work tree"),
+ OPT_GROUP(""),
+ OPT_BOOLEAN('v', "invert-match", &opt.invert,
+ "show non-matching lines"),
+ OPT_BIT('i', "ignore-case", &opt.regflags,
+ "case insensitive matching", REG_ICASE),
+ OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
+ "match patterns only at word boundaries"),
+ OPT_SET_INT('a', "text", &opt.binary,
+ "process binary files as text", GREP_BINARY_TEXT),
+ OPT_SET_INT('I', NULL, &opt.binary,
+ "don't match patterns in binary files",
+ GREP_BINARY_NOMATCH),
+ OPT_GROUP(""),
+ OPT_BIT('E', "extended-regexp", &opt.regflags,
+ "use extended POSIX regular expressions", REG_EXTENDED),
+ OPT_NEGBIT('G', "basic-regexp", &opt.regflags,
+ "use basic POSIX regular expressions (default)",
+ REG_EXTENDED),
+ OPT_BOOLEAN('F', "fixed-strings", &opt.fixed,
+ "interpret patterns as fixed strings"),
+ OPT_GROUP(""),
+ OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"),
+ OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
+ OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
+ OPT_NEGBIT(0, "full-name", &opt.relative,
+ "show filenames relative to top directory", 1),
+ OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
+ "show only filenames instead of matching lines"),
+ OPT_BOOLEAN(0, "name-only", &opt.name_only,
+ "synonym for --files-with-matches"),
+ OPT_BOOLEAN('L', "files-without-match",
+ &opt.unmatch_name_only,
+ "show only the names of files without match"),
+ OPT_BOOLEAN('z', "null", &opt.null_following_name,
+ "print NUL after filenames"),
+ OPT_BOOLEAN('c', "count", &opt.count,
+ "show the number of matches instead of matching lines"),
+ OPT_SET_INT(0, "color", &opt.color, "highlight matches", 1),
+ OPT_GROUP(""),
+ OPT_CALLBACK('C', NULL, &opt, "n",
+ "show <n> context lines before and after matches",
+ context_callback),
+ OPT_INTEGER('B', NULL, &opt.pre_context,
+ "show <n> context lines before matches"),
+ OPT_INTEGER('A', NULL, &opt.post_context,
+ "show <n> context lines after matches"),
+ OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
+ context_callback),
+ OPT_GROUP(""),
+ OPT_CALLBACK('f', NULL, &opt, "file",
+ "read patterns from file", file_callback),
+ { OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
+ "match <pattern>", PARSE_OPT_NONEG, pattern_callback },
+ { OPTION_CALLBACK, 0, "and", &opt, NULL,
+ "combine patterns specified with -e",
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
+ OPT_BOOLEAN(0, "or", &dummy, ""),
+ { OPTION_CALLBACK, 0, "not", &opt, NULL, "",
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
+ { OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
+ open_callback },
+ { OPTION_CALLBACK, ')', NULL, &opt, NULL, "",
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
+ close_callback },
+ OPT_BOOLEAN(0, "all-match", &opt.all_match,
+ "show only matches from files that match all patterns"),
+ OPT_GROUP(""),
+#if NO_EXTERNAL_GREP
+ OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
+ "allow calling of grep(1) (ignored by this build)"),
+#else
+ OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
+ "allow calling of grep(1) (default)"),
+#endif
+ { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
+ PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
+ OPT_END()
+ };
memset(&opt, 0, sizeof(opt));
opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
* unrecognized non option is the beginning of the refs list
* that continues up to the -- (if exists), and then paths.
*/
+ argc = parse_options(argc, argv, options, grep_usage,
+ PARSE_OPT_KEEP_DASHDASH |
+ PARSE_OPT_STOP_AT_NON_OPTION |
+ PARSE_OPT_NO_INTERNAL_HELP);
- while (1 < argc) {
- const char *arg = argv[1];
- argc--; argv++;
- if (!strcmp("--cached", arg)) {
- cached = 1;
- continue;
- }
- if (!strcmp("--no-ext-grep", arg)) {
- builtin_grep = 1;
- continue;
- }
- if (!strcmp("-a", arg) ||
- !strcmp("--text", arg)) {
- opt.binary = GREP_BINARY_TEXT;
- continue;
- }
- if (!strcmp("-i", arg) ||
- !strcmp("--ignore-case", arg)) {
- opt.regflags |= REG_ICASE;
- continue;
- }
- if (!strcmp("-I", arg)) {
- opt.binary = GREP_BINARY_NOMATCH;
- continue;
- }
- if (!strcmp("-v", arg) ||
- !strcmp("--invert-match", arg)) {
- opt.invert = 1;
- continue;
- }
- if (!strcmp("-E", arg) ||
- !strcmp("--extended-regexp", arg)) {
- opt.regflags |= REG_EXTENDED;
- continue;
- }
- if (!strcmp("-F", arg) ||
- !strcmp("--fixed-strings", arg)) {
- opt.fixed = 1;
- continue;
- }
- if (!strcmp("-G", arg) ||
- !strcmp("--basic-regexp", arg)) {
- opt.regflags &= ~REG_EXTENDED;
- continue;
- }
- if (!strcmp("-n", arg)) {
- opt.linenum = 1;
- continue;
- }
- if (!strcmp("-h", arg)) {
- opt.pathname = 0;
- continue;
- }
- if (!strcmp("-H", arg)) {
- opt.pathname = 1;
- continue;
- }
- if (!strcmp("-l", arg) ||
- !strcmp("--name-only", arg) ||
- !strcmp("--files-with-matches", arg)) {
- opt.name_only = 1;
- continue;
- }
- if (!strcmp("-L", arg) ||
- !strcmp("--files-without-match", arg)) {
- opt.unmatch_name_only = 1;
- continue;
- }
- if (!strcmp("-z", arg) ||
- !strcmp("--null", arg)) {
- opt.null_following_name = 1;
- continue;
- }
- if (!strcmp("-c", arg) ||
- !strcmp("--count", arg)) {
- opt.count = 1;
- continue;
- }
- if (!strcmp("-w", arg) ||
- !strcmp("--word-regexp", arg)) {
- opt.word_regexp = 1;
- continue;
- }
- if (!prefixcmp(arg, "-A") ||
- !prefixcmp(arg, "-B") ||
- !prefixcmp(arg, "-C") ||
- (arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) {
- unsigned num;
- const char *scan;
- switch (arg[1]) {
- case 'A': case 'B': case 'C':
- if (!arg[2]) {
- if (argc <= 1)
- die(emsg_missing_context_len);
- scan = *++argv;
- argc--;
- }
- else
- scan = arg + 2;
- break;
- default:
- scan = arg + 1;
- break;
- }
- if (strtoul_ui(scan, 10, &num))
- die(emsg_invalid_context_len, scan);
- switch (arg[1]) {
- case 'A':
- opt.post_context = num;
- break;
- default:
- case 'C':
- opt.post_context = num;
- case 'B':
- opt.pre_context = num;
- break;
- }
- continue;
- }
- if (!strcmp("-f", arg)) {
- FILE *patterns;
- int lno = 0;
- char buf[1024];
- if (argc <= 1)
- die(emsg_missing_argument, arg);
- patterns = fopen(argv[1], "r");
- if (!patterns)
- die("'%s': %s", argv[1], strerror(errno));
- while (fgets(buf, sizeof(buf), patterns)) {
- int len = strlen(buf);
- if (len && buf[len-1] == '\n')
- buf[len-1] = 0;
- /* ignore empty line like grep does */
- if (!buf[0])
- continue;
- append_grep_pattern(&opt, xstrdup(buf),
- argv[1], ++lno,
- GREP_PATTERN);
- }
- fclose(patterns);
- argv++;
- argc--;
- continue;
- }
- if (!strcmp("--not", arg)) {
- append_grep_pattern(&opt, arg, "command line", 0,
- GREP_NOT);
- continue;
- }
- if (!strcmp("--and", arg)) {
- append_grep_pattern(&opt, arg, "command line", 0,
- GREP_AND);
- continue;
- }
- if (!strcmp("--or", arg))
- continue; /* no-op */
- if (!strcmp("(", arg)) {
- append_grep_pattern(&opt, arg, "command line", 0,
- GREP_OPEN_PAREN);
- continue;
- }
- if (!strcmp(")", arg)) {
- append_grep_pattern(&opt, arg, "command line", 0,
- GREP_CLOSE_PAREN);
- continue;
- }
- if (!strcmp("--all-match", arg)) {
- opt.all_match = 1;
- continue;
- }
- if (!strcmp("-e", arg)) {
- if (1 < argc) {
- append_grep_pattern(&opt, argv[1],
- "-e option", 0,
- GREP_PATTERN);
- argv++;
- argc--;
- continue;
- }
- die(emsg_missing_argument, arg);
- }
- if (!strcmp("--full-name", arg)) {
- opt.relative = 0;
- continue;
- }
- if (!strcmp("--color", arg)) {
- opt.color = 1;
- continue;
- }
- if (!strcmp("--no-color", arg)) {
- opt.color = 0;
- continue;
- }
- if (!strcmp("--", arg)) {
- /* later processing wants to have this at argv[1] */
- argv--;
- argc++;
- break;
- }
- if (*arg == '-')
- usage(builtin_grep_usage);
-
- /* First unrecognized non-option token */
- if (!opt.pattern_list) {
- append_grep_pattern(&opt, arg, "command line", 0,
- GREP_PATTERN);
- break;
- }
- else {
- /* We are looking at the first path or rev;
- * it is found at argv[1] after leaving the
- * loop.
- */
- argc++; argv--;
- break;
- }
+ /* First unrecognized non-option token */
+ if (argc > 0 && !opt.pattern_list) {
+ append_grep_pattern(&opt, argv[0], "command line", 0,
+ GREP_PATTERN);
+ argv++;
+ argc--;
}
if (opt.color && !opt.color_external)
- builtin_grep = 1;
+ external_grep_allowed = 0;
if (!opt.pattern_list)
die("no pattern given.");
if ((opt.regflags != REG_NEWLINE) && opt.fixed)
compile_grep_patterns(&opt);
/* Check revs and then paths */
- for (i = 1; i < argc; i++) {
+ for (i = 0; i < argc; i++) {
const char *arg = argv[i];
unsigned char sha1[20];
/* Is it a rev? */
if (!list.nr) {
if (!cached)
setup_work_tree();
- return !grep_cache(&opt, paths, cached);
+ return !grep_cache(&opt, paths, cached, external_grep_allowed);
}
if (cached)
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. */
}
}
-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) {
}
}
-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";
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)
return add_man_viewer_cmd(name, subkey - name, value);
}
- warning("'%s': unsupported man viewer sub key.", subkey);
return 0;
}
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;
int cover_letter = 0;
int boundary_count = 0;
int no_binary_diff = 0;
+ int numbered_cmdline_opt = 0;
struct commit *origin = NULL, *head = NULL;
const char *in_reply_to = NULL;
struct patch_ids ids;
if (!strcmp(argv[i], "--stdout"))
use_stdout = 1;
else if (!strcmp(argv[i], "-n") ||
- !strcmp(argv[i], "--numbered"))
+ !strcmp(argv[i], "--numbered")) {
numbered = 1;
+ numbered_cmdline_opt = 1;
+ }
else if (!strcmp(argv[i], "-N") ||
!strcmp(argv[i], "--no-numbered")) {
numbered = 0;
if (start_number < 0)
start_number = 1;
+
+ /*
+ * If numbered is set solely due to format.numbered in config,
+ * and it would conflict with --keep-subject (-k) from the
+ * command line, reset "numbered".
+ */
+ if (numbered && keep_subject && !numbered_cmdline_opt)
+ numbered = 0;
+
if (numbered && keep_subject)
die ("-n and -k are mutually exclusive.");
if (keep_subject && subject_prefix)
OPT_BIT(0, "directory", &dir.flags,
"show 'other' directories' name only",
DIR_SHOW_OTHER_DIRECTORIES),
- OPT_BIT(0, "no-empty-directory", &dir.flags,
+ OPT_NEGBIT(0, "empty-directory", &dir.flags,
"don't show empty directories",
DIR_HIDE_EMPTY_DIRECTORIES),
OPT_BOOLEAN('u', "unmerged", &show_unmerged,
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();
bases[bases_count++] = sha;
}
else
- warning("Cannot handle more than %zu bases. "
- "Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]);
+ warning("Cannot handle more than %d bases. "
+ "Ignoring %s.",
+ (int)ARRAY_SIZE(bases)-1, argv[i]);
}
if (argc - i != 3) /* "--" "<head>" "<remote>" */
die("Not handling anything other than two heads merge.");
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];
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;
commit->object.flags |= OBJECT_ADDED;
}
-static void show_object(struct object_array_entry *p, void *data)
+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;
- free((char *)p->name);
- p->name = NULL;
+ 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)
memcpy(pathname + len, de->d_name, 38);
if (opts & DRY_RUN)
printf("rm -f %s\n", pathname);
- else if (unlink(pathname) < 0)
- error("unable to unlink %s", pathname);
+ else
+ unlink_or_warn(pathname);
display_progress(progress, i + 1);
}
pathname[len] = 0;
for (i = 0; i < 256; i++) {
DIR *d;
+ display_progress(progress, i + 1);
sprintf(pathname + len, "%02x/", i);
d = opendir(pathname);
if (!d)
}
printf("Removing stale temporary file %s\n", fullpath);
if (!show_only)
- unlink(fullpath);
+ unlink_or_warn(fullpath);
return 0;
}
(type > 0) ? typename(type) : "unknown");
}
if (!show_only)
- unlink(fullpath);
+ unlink_or_warn(fullpath);
return 0;
}
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;
case 3:
default:
opts.fn = threeway_merge;
- cache_tree_free(&active_cache_tree);
break;
}
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);
* "-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))
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
static int report_status;
+static int prefer_ofs_delta = 1;
static const char *head_name;
-
-static char capabilities[] = " report-status delete-refs ";
-static int capabilities_sent;
+static char *capabilities_to_send;
static enum deny_action parse_deny_action(const char *var, const char *value)
{
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);
}
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
- if (capabilities_sent)
+ if (!capabilities_to_send)
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
else
packet_write(1, "%s %s%c%s\n",
- sha1_to_hex(sha1), path, 0, capabilities);
- capabilities_sent = 1;
+ sha1_to_hex(sha1), path, 0, capabilities_to_send);
+ capabilities_to_send = NULL;
return 0;
}
static void write_head_info(void)
{
for_each_ref(show_ref, NULL);
- if (!capabilities_sent)
+ if (capabilities_to_send)
show_ref("capabilities^{}", null_sha1, 0, NULL);
}
else if (0 <= receive_unpack_limit)
unpack_limit = receive_unpack_limit;
+ capabilities_to_send = (prefer_ofs_delta) ?
+ " report-status delete-refs ofs-delta " :
+ " report-status delete-refs ";
+
add_alternate_refs();
write_head_info();
clear_extra_refs();
unpack_status = unpack();
execute_commands(unpack_status);
if (pack_lockfile)
- unlink(pack_lockfile);
+ unlink_or_warn(pack_lockfile);
if (report_status)
report(unpack_status);
run_receive_hook(post_receive_hook);
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.
*/
return 0;
local_refs = get_local_heads();
- ref = push_map = copy_ref_list(remote_refs);
- while (ref->next)
- ref = ref->next;
- push_tail = &ref->next;
+ push_map = copy_ref_list(remote_refs);
+ push_tail = &push_map;
+ while (*push_tail)
+ push_tail = &((*push_tail)->next);
match_refs(local_refs, push_map, &push_tail, remote->push_refspec_nr,
remote->push_refspec, MATCH_REFS_NONE);
path = git_path("remotes/%s", remote->name);
else if (remote->origin == REMOTE_BRANCHES)
path = git_path("branches/%s", remote->name);
- if (path && unlink(path))
- warning("failed to remove '%s'", path);
+ if (path)
+ unlink_or_warn(path);
return 0;
}
struct option options[] = {
OPT_GROUP("update specific options"),
OPT_BOOLEAN('p', "prune", &prune,
- "prune remotes after fecthing"),
+ "prune remotes after fetching"),
OPT_END()
};
if (!has_rerere_resolution(name))
unlink_rr_item(name);
}
- unlink(git_path("rr-cache/MERGE_RR"));
+ unlink_or_warn(git_path("rr-cache/MERGE_RR"));
} else if (!strcmp(argv[1], "gc"))
garbage_collect(&merge_rr);
else if (!strcmp(argv[1], "status"))
}
/*
* 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)) {
/*
commit->buffer = NULL;
}
-static void finish_object(struct object_array_entry *p, void *data)
+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, void *data)
+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, data);
+ 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)
*
* and P(2^n + x) < 0.5 means 2^n < 3x
*/
-static int estimate_bisect_steps(int all)
+int estimate_bisect_steps(int all)
{
int n, x, e;
return (e < 3 * x) ? n : n - 1;
}
-static void show_tried_revs(struct commit_list *tried, int stringed)
+void print_commit_list(struct commit_list *list,
+ const char *format_cur,
+ const char *format_last)
{
- printf("bisect_tried='");
- for (;tried; tried = tried->next) {
- char *format = tried->next ? "%s|" : "%s";
- printf(format, sha1_to_hex(tried->item->object.sha1));
+ for ( ; list; list = list->next) {
+ const char *format = list->next ? format_cur : format_last;
+ printf(format, sha1_to_hex(list->item->object.sha1));
}
- printf(stringed ? "' &&\n" : "'\n");
+}
+
+static void show_tried_revs(struct commit_list *tried)
+{
+ printf("bisect_tried='");
+ print_commit_list(tried, "%s|", "%s");
+ printf("'\n");
+}
+
+static void print_var_str(const char *var, const char *val)
+{
+ printf("%s='%s'\n", var, val);
+}
+
+static void print_var_int(const char *var, int val)
+{
+ printf("%s=%d\n", var, val);
}
int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
{
int cnt, flags = info->bisect_show_flags;
- char hex[41] = "", *format;
+ char hex[41] = "";
struct commit_list *tried;
struct rev_info *revs = info->revs;
}
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));
+ show_tried_revs(tried);
+
+ print_var_str("bisect_rev", hex);
+ print_var_int("bisect_nr", cnt - 1);
+ print_var_int("bisect_good", all - reaches - 1);
+ print_var_int("bisect_bad", reaches - 1);
+ print_var_int("bisect_all", all);
+ print_var_int("bisect_steps", estimate_bisect_steps(all));
return 0;
}
#define SHOW_SYMBOLIC_FULL 2
static int symbolic;
static int abbrev;
+static int abbrev_ref;
+static int abbrev_ref_strict;
static int output_sq;
/*
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;
*/
break;
case 1: /* happy */
+ if (abbrev_ref)
+ full = shorten_unambiguous_ref(full,
+ abbrev_ref_strict);
show_with_type(type, full);
break;
default: /* ambiguous */
return 0;
}
+static int cmd_sq_quote(int argc, const char **argv)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ if (argc)
+ sq_quote_argv(&buf, argv, 0);
+ printf("%s\n", buf.buf);
+ strbuf_release(&buf);
+
+ return 0;
+}
+
static void die_no_single_rev(int quiet)
{
if (quiet)
if (argc > 1 && !strcmp("--parseopt", argv[1]))
return cmd_parseopt(argc - 1, argv + 1, prefix);
+ if (argc > 1 && !strcmp("--sq-quote", argv[1]))
+ return cmd_sq_quote(argc - 2, argv + 2);
+
prefix = setup_git_directory();
git_config(git_default_config, NULL);
for (i = 1; i < argc; i++) {
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;
"--stdout",
NULL,
NULL,
+ NULL,
};
struct child_process po;
int i;
+ i = 4;
if (args->use_thin_pack)
- argv[4] = "--thin";
+ argv[i++] = "--thin";
+ if (args->use_ofs_delta)
+ argv[i++] = "--delta-base-offset";
memset(&po, 0, sizeof(po));
po.argv = argv;
po.in = -1;
{
fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
if (from)
- fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
+ fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
else
- fputs(prettify_ref(to), stderr);
+ fputs(prettify_refname(to->name), stderr);
if (msg) {
fputs(" (", stderr);
fputs(msg, stderr);
ask_for_status_report = 1;
if (server_supports("delete-refs"))
allow_deleting_refs = 1;
+ if (server_supports("ofs-delta"))
+ args->use_ofs_delta = 1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
#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;
#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) {
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)
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)
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;
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++;
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) {
mark = '*';
else
mark = '+';
- putchar(mark);
+ printf("%s%c%s",
+ get_color_code(i % COLUMN_COLORS_MAX),
+ mark, get_color_reset_code());
}
putchar(' ');
}
exit(128);
}
if (path) {
- unlink(path);
+ unlink_or_warn(path);
free(path);
}
}
* 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;
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);
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)
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;
}
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;
close(gpg.in);
ret = finish_command(&gpg);
- unlink(path);
+ unlink_or_warn(path);
return ret;
}
*/
struct ref_list *p = &header->prerequisites;
struct rev_info revs;
- const char *argv[] = {NULL, "--all"};
+ const char *argv[] = {NULL, "--all", NULL};
struct object_array refs;
struct commit *commit;
int i, ret = 0, req_nr;
#include "cache.h"
#include "tree.h"
+#include "tree-walk.h"
#include "cache-tree.h"
#ifndef DEBUG
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);
+}
#ifndef CACHE_TREE_H
#define CACHE_TREE_H
+#include "tree.h"
+
struct cache_tree;
struct cache_tree_sub {
struct cache_tree *cache_tree;
#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
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);
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 *);
#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"
#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)
{
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;
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;
}
}
}
-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)
{
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;
/* 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;
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;
}
}
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;
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);
}
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
return ret;
}
+static void unparse_commit_list(struct commit_list *list)
+{
+ for (; list; list = list->next)
+ unparse_commit(list->item);
+}
+
+void unparse_commit(struct commit *item)
+{
+ item->object.flags = 0;
+ item->object.used = 0;
+ if (item->object.parsed) {
+ item->object.parsed = 0;
+ if (item->parents) {
+ unparse_commit_list(item->parents);
+ free_commit_list(item->parents);
+ item->parents = NULL;
+ }
+ }
+}
+
struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p)
{
struct commit_list *new_list = xmalloc(sizeof(struct commit_list));
int parse_commit(struct commit *item);
+void unparse_commit(struct commit *item);
+
struct commit_list * commit_list_insert(struct commit *item, struct commit_list **list_p);
unsigned commit_list_count(const struct commit_list *l);
struct commit_list * insert_by_date(struct commit *item, struct commit_list **list);
/*
* 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
# 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>. */
# 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
* 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;
if (buf[0] != '#' || buf[1] != '!')
return NULL;
buf[n] = '\0';
- p = strchr(buf, '\n');
- if (!p)
+ p = buf + strcspn(buf, "\r\n");
+ if (!*p)
return NULL;
*p = '\0';
if (!n)
return NULL;
- path = xmalloc((n+1)*sizeof(char*));
+ path = xmalloc((n+1)*sizeof(char *));
p = envpath;
i = 0;
do {
#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.
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;
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;
}
}
return 0;
}
+
+char *getpass(const char *prompt)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ fputs(prompt, stderr);
+ for (;;) {
+ char c = _getch();
+ if (c == '\r' || c == '\n')
+ break;
+ strbuf_addch(&buf, c);
+ }
+ fputs("\n", stderr);
+ return strbuf_detach(&buf, NULL);
+}
char *pw_dir;
};
+extern char *getpass(const char *prompt);
+
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
}
#define unlink mingw_unlink
-static inline int waitpid(pid_t pid, unsigned *status, unsigned options)
+static inline int waitpid(pid_t pid, int *status, unsigned options)
{
if (options == 0)
return _cwait(status, pid, 0);
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. */
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
for (;;) {
int c = get_next_char();
- if (len >= sizeof(value))
+ if (len >= sizeof(value) - 1)
return NULL;
if (c == '\n') {
if (quote)
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);
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;
}
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 ||
!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;
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;
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);
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;
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);
}
* - 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);
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;
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;
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;
}
if [ -n "$g" ]; then
local r
local b
- if [ -d "$g/rebase-apply" ]; then
- if [ -f "$g/rebase-apply/rebasing" ]; then
- r="|REBASE"
- elif [ -f "$g/rebase-apply/applying" ]; then
- r="|AM"
- else
- r="|AM/REBASE"
- fi
- b="$(git symbolic-ref HEAD 2>/dev/null)"
- elif [ -f "$g/rebase-merge/interactive" ]; then
+ if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
b="$(cat "$g/rebase-merge/head-name")"
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/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
+ if [ -d "$g/rebase-apply" ]; then
+ if [ -f "$g/rebase-apply/rebasing" ]; then
+ r="|REBASE"
+ elif [ -f "$g/rebase-apply/applying" ]; then
+ r="|AM"
+ else
+ r="|AM/REBASE"
fi
+ elif [ -f "$g/MERGE_HEAD" ]; then
+ r="|MERGING"
+ elif [ -f "$g/BISECT_LOG" ]; then
+ r="|BISECTING"
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
local c
if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
- if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then
+ if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
c="BARE:"
else
b="GIT_DIR!"
fi
fi
- if [ -n "$b" ]; then
- if [ -n "${1-}" ]; then
- printf "$1" "$c${b##refs/heads/}$w$i$r"
- else
- printf " (%s)" "$c${b##refs/heads/}$w$i$r"
- fi
+ if [ -n "${1-}" ]; then
+ printf "$1" "$c${b##refs/heads/}$w$i$r"
+ else
+ printf " (%s)" "$c${b##refs/heads/}$w$i$r"
fi
fi
}
__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
"
__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 ()
{
return
;;
--date=*)
- __gitcomp "
- relative iso8601 rfc2822 short local default
- " "" "${cur##--date=}"
+ __gitcomp "$__git_log_date_formats" "" "${cur##--date=}"
return
;;
--*)
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
;;
--*)
__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
;;
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]}"
__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
;;
"
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
__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##*.}"
__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
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
core.autocrlf
core.bare
core.compression
+ core.createObject
core.deltaBaseCacheLimit
core.editor
core.excludesfile
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
gc.rerereresolved
gc.rerereunresolved
gitcvs.allbinary
+ gitcvs.commitmsgannotation
gitcvs.dbTableNamePrefix
gitcvs.dbdriver
gitcvs.dbname
gitcvs.enabled
gitcvs.logfile
gitcvs.usecrlfattr
+ guitool.
gui.blamehistoryctx
gui.commitmsgwidth
gui.copyblamethreshold
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
merge.stat
merge.tool
merge.verbosity
+ mergetool.
mergetool.keepBackup
+ mergetool.prompt
pack.compression
pack.deltaCacheLimit
pack.deltaCacheSize
pack.threads
pack.window
pack.windowMemory
+ pager.
pull.octopus
pull.twohead
+ push.default
+ rebase.stat
receive.denyCurrentBranch
receive.denyDeletes
receive.denyNonFastForwards
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
return
;;
--*)
- __gitcomp "--pretty= --format=
+ __gitcomp "--pretty= --format= --abbrev-commit --oneline
$__git_diff_common_options
"
return
__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
;;
config) _git_config ;;
describe) _git_describe ;;
diff) _git_diff ;;
+ difftool) _git_difftool ;;
fetch) _git_fetch ;;
format-patch) _git_format_patch ;;
fsck) _git_fsck ;;
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);
}
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;
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)) {
+++ /dev/null
-#!/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());
+++ /dev/null
-#!/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
# --pretty %s", displaying the commit id, author, date and log
# message. To list full patches separated by a blank line, you
# could set this to "git show -C %s; echo".
+# To list a gitweb/cgit URL *and* a full patch for each change set, use this:
+# "t=%s; printf 'http://.../?id=%%s' \$t; echo;echo; git show -C \$t; echo"
+# Be careful if "..." contains things that will be expanded by shell "eval"
+# or printf.
#
# Notes
# -----
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
A = GIT_ALPHA,
D = GIT_DIGIT,
G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */
- R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */
+ R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | */
};
unsigned char sane_ctype[256] = {
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;
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;
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;
}
{
int size = n->size;
struct object_decoration *hash = n->hash;
- int j = hash_obj(base, size);
+ unsigned int j = hash_obj(base, size);
while (hash[j].base) {
if (hash[j].base == base) {
/* Lookup a decoration pointer */
void *lookup_decoration(struct decoration *n, const struct object *obj)
{
- int j;
+ unsigned int j;
/* nothing to lookup */
if (!n->size)
const unsigned char *sha1 = ce->sha1;
unsigned int mode = ce->ce_mode;
- if (!cached) {
+ if (!cached && !ce_uptodate(ce)) {
int changed;
struct stat st;
changed = check_removed(ce, &st);
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];
/*
int i;
for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
if (diff_temp[i].name == diff_temp[i].tmp_path)
- unlink(diff_temp[i].name);
+ unlink_or_warn(diff_temp[i].name);
diff_temp[i].name = NULL;
}
}
}
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)
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;
}
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, " -> ");
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;
}
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);
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)
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;
die("stat(%s): %s", name, strerror(errno));
}
if (S_ISLNK(st.st_mode)) {
- int ret;
- char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
- ret = readlink(name, buf, sizeof(buf));
- if (ret < 0)
+ struct strbuf sb = STRBUF_INIT;
+ if (strbuf_readlink(&sb, name, st.st_size) < 0)
die("readlink(%s)", name);
- if (ret == sizeof(buf))
- die("symlink too long: %s", name);
- prep_temp_blob(name, temp, buf, ret,
+ prep_temp_blob(name, temp, sb.buf, sb.len,
(one->sha1_valid ?
one->sha1 : null_sha1),
(one->sha1_valid ?
one->mode : S_IFLNK));
+ strbuf_release(&sb);
}
else {
/* we can borrow from the file in the work tree */
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! */
}
/*
- * 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
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;
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,
static struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
{
- if (cache_name_pos(pathname, len) >= 0)
+ if (!cache_name_is_other(pathname, len))
return NULL;
ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
*/
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) {
*/
if (mkdir(buf, 0777)) {
if (errno == EEXIST && state->force &&
- !unlink(buf) && !mkdir(buf, 0777))
+ !unlink_or_warn(buf) && !mkdir(buf, 0777))
continue;
die("cannot create directory at %s", buf);
}
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;
}
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;
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;
# 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);
struct tree_entry
{
struct tree_content *tree;
- struct atom_str* name;
+ struct atom_str *name;
struct tree_entry_ms
{
uint16_t mode;
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 };
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);
struct packed_git *p = all_packs[k];
snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
get_object_directory(), sha1_to_hex(p->sha1));
- unlink(name);
+ unlink_or_warn(name);
}
}
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);
}
else {
close(old_p->pack_fd);
- unlink(old_p->pack_name);
+ unlink_or_warn(old_p->pack_name);
}
free(old_p);
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);
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;
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);
* 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);
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}},
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+)$/ ?
my $this = +{
TEXT => [],
DISPLAY => [],
+ TYPE => 'hunk',
OLD => $o_ofs,
NEW => $n_ofs,
OCNT => 0,
return @split;
}
+sub find_last_o_ctx {
+ my ($it) = @_;
+ my $text = $it->{TEXT};
+ my ($o_ofs, $o_cnt) = parse_hunk_header($text->[0]);
+ my $i = @{$text};
+ my $last_o_ctx = $o_ofs + $o_cnt;
+ while (0 < --$i) {
+ my $line = $text->[$i];
+ if ($line =~ /^ /) {
+ $last_o_ctx--;
+ next;
+ }
+ last;
+ }
+ return $last_o_ctx;
+}
+
+sub merge_hunk {
+ my ($prev, $this) = @_;
+ my ($o0_ofs, $o0_cnt, $n0_ofs, $n0_cnt) =
+ parse_hunk_header($prev->{TEXT}[0]);
+ my ($o1_ofs, $o1_cnt, $n1_ofs, $n1_cnt) =
+ parse_hunk_header($this->{TEXT}[0]);
+
+ my (@line, $i, $ofs, $o_cnt, $n_cnt);
+ $ofs = $o0_ofs;
+ $o_cnt = $n_cnt = 0;
+ for ($i = 1; $i < @{$prev->{TEXT}}; $i++) {
+ my $line = $prev->{TEXT}[$i];
+ if ($line =~ /^\+/) {
+ $n_cnt++;
+ push @line, $line;
+ next;
+ }
+
+ last if ($o1_ofs <= $ofs);
+
+ $o_cnt++;
+ $ofs++;
+ if ($line =~ /^ /) {
+ $n_cnt++;
+ }
+ push @line, $line;
+ }
+
+ for ($i = 1; $i < @{$this->{TEXT}}; $i++) {
+ my $line = $this->{TEXT}[$i];
+ if ($line =~ /^\+/) {
+ $n_cnt++;
+ push @line, $line;
+ next;
+ }
+ $ofs++;
+ $o_cnt++;
+ if ($line =~ /^ /) {
+ $n_cnt++;
+ }
+ push @line, $line;
+ }
+ my $head = ("@@ -$o0_ofs" .
+ (($o_cnt != 1) ? ",$o_cnt" : '') .
+ " +$n0_ofs" .
+ (($n_cnt != 1) ? ",$n_cnt" : '') .
+ " @@\n");
+ @{$prev->{TEXT}} = ($head, @line);
+}
+
+sub coalesce_overlapping_hunks {
+ my (@in) = @_;
+ my @out = ();
+
+ my ($last_o_ctx, $last_was_dirty);
+
+ for (grep { $_->{USE} } @in) {
+ my $text = $_->{TEXT};
+ my ($o_ofs) = parse_hunk_header($text->[0]);
+ if (defined $last_o_ctx &&
+ $o_ofs <= $last_o_ctx &&
+ !$_->{DIRTY} &&
+ !$last_was_dirty) {
+ merge_hunk($out[-1], $_);
+ }
+ else {
+ push @out, $_;
+ }
+ $last_o_ctx = find_last_o_ctx($out[-1]);
+ $last_was_dirty = $_->{DIRTY};
+ }
+ return @out;
+}
sub color_diff {
return map {
if (!defined $text) {
return undef;
}
- my $newhunk = { TEXT => $text, USE => 1 };
+ my $newhunk = {
+ TEXT => $text,
+ TYPE => $hunk->[$ix]->{TYPE},
+ USE => 1,
+ DIRTY => 1,
+ };
if (diff_applies($head,
@{$hunk}[0..$ix-1],
$newhunk,
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
@mods);
}
for (@them) {
- patch_update_file($_->{VALUE});
+ return 0 if patch_update_file($_->{VALUE});
}
}
}
sub patch_update_file {
+ my $quit = 0;
my ($ix, $num);
my $path = shift;
my ($head, @hunk) = parse_diff($path);
}
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;
}
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) {
}
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 "") {
$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;
}
}
+ @hunk = coalesce_overlapping_hunks(@hunk);
+
my $n_lofs = 0;
my @result = ();
- if ($mode->{USE}) {
- push @result, @{$mode->{TEXT}};
- }
for (@hunk) {
if ($_->{USE}) {
push @result, @{$_->{TEXT}};
open $fh, '| git apply --cached --recount';
for (@{$head->{TEXT}}, @result) {
print $fh $_;
+ print STDERR $_;
}
if (!close $fh) {
for (@{$head->{TEXT}}, @result) {
}
print "\n";
+ return $quit;
}
sub diff_cmd {
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
- printf "%s" "$sqarg" |
- sed -e 's/'\''/'\''\\'\'''\''/g' -e 's/.*/ '\''&'\''/'
- done
+ git rev-parse --sq-quote "$@"
}
stop_here () {
: >"$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
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
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
-sq() {
- @@PERL@@ -e '
- for (@ARGV) {
- s/'\''/'\'\\\\\'\''/g;
- print " '\''$_'\''";
- }
- print "\n";
- ' "$@"
-}
-
bisect_autostart() {
test -s "$GIT_DIR/BISECT_START" || {
echo >&2 'You need to start by "git bisect start"'
for arg; do
case "$arg" in --) has_double_dash=1; break ;; esac
done
- orig_args=$(sq "$@")
+ orig_args=$(git rev-parse --sq-quote "$@")
bad_seen=0
eval=''
while [ $# -gt 0 ]; do
# Write new start state.
#
echo "$start_head" >"$GIT_DIR/BISECT_START" &&
- sq "$@" >"$GIT_DIR/BISECT_NAMES" &&
+ git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
eval "$eval" &&
echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
#
test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
}
-mark_expected_rev() {
- echo "$1" > "$GIT_DIR/BISECT_EXPECTED_REV"
-}
-
check_expected_revs() {
for _rev in "$@"; do
if ! is_expected_rev "$_rev"; then
*..*)
revs=$(git rev-list "$arg") || die "Bad rev input: $arg" ;;
*)
- revs=$(sq "$arg") ;;
+ revs=$(git rev-parse --sq-quote "$arg") ;;
esac
all="$all $revs"
done
bisect_next_check && bisect_next || :
}
-exit_if_skipped_commits () {
- _tried=$1
- _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
-}
-
-bisect_checkout() {
- _rev="$1"
- _msg="$2"
- echo "Bisecting: $_msg"
- mark_expected_rev "$_rev"
- git checkout -q "$_rev" -- || exit
- git show-branch "$_rev"
-}
-
-is_among() {
- _rev="$1"
- _list="$2"
- case "$_list" in *$_rev*) return 0 ;; esac
- return 1
-}
-
-handle_bad_merge_base() {
- _badmb="$1"
- _good="$2"
- if is_expected_rev "$_badmb"; then
- cat >&2 <<EOF
-The merge base $_badmb is bad.
-This means the bug has been fixed between $_badmb and [$_good].
-EOF
- exit 3
- else
- cat >&2 <<EOF
-Some good revs are not ancestor of the bad rev.
-git bisect cannot work properly in this case.
-Maybe you mistake good and bad revs?
-EOF
- exit 1
- fi
-}
-
-handle_skipped_merge_base() {
- _mb="$1"
- _bad="$2"
- _good="$3"
- cat >&2 <<EOF
-Warning: the merge base between $_bad and [$_good] must be skipped.
-So we cannot be sure the first bad commit is between $_mb and $_bad.
-We continue anyway.
-EOF
-}
-
-#
-# "check_merge_bases" checks that merge bases are not "bad".
-#
-# - If one is "good", that's good, we have nothing to do.
-# - If one is "bad", it means the user assumed something wrong
-# and we must exit.
-# - If one is "skipped", we can't know but we should warn.
-# - If we don't know, we should check it out and ask the user to test.
-#
-# In the last case we will return 1, and otherwise 0.
-#
-check_merge_bases() {
- _bad="$1"
- _good="$2"
- _skip="$3"
- for _mb in $(git merge-base --all $_bad $_good)
- do
- if is_among "$_mb" "$_good"; then
- continue
- elif test "$_mb" = "$_bad"; then
- handle_bad_merge_base "$_bad" "$_good"
- elif is_among "$_mb" "$_skip"; then
- handle_skipped_merge_base "$_mb" "$_bad" "$_good"
- else
- bisect_checkout "$_mb" "a merge base must be tested"
- return 1
- fi
- done
- return 0
-}
-
-#
-# "check_good_are_ancestors_of_bad" checks that all "good" revs are
-# ancestor of the "bad" rev.
-#
-# If that's not the case, we need to check the merge bases.
-# If a merge base must be tested by the user we return 1 and
-# otherwise 0.
-#
-check_good_are_ancestors_of_bad() {
- test -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
- return
-
- _bad="$1"
- _good=$(echo $2 | sed -e 's/\^//g')
- _skip="$3"
-
- # Bisecting with no good rev is ok
- test -z "$_good" && return
-
- _side=$(git rev-list $_good ^$_bad)
- if test -n "$_side"; then
- # Return if a checkout was done
- check_merge_bases "$_bad" "$_good" "$_skip" || return
- fi
-
- : > "$GIT_DIR/BISECT_ANCESTORS_OK"
-
- return 0
-}
-
bisect_next() {
case "$#" in 0) ;; *) usage ;; esac
bisect_autostart
bisect_next_check good
- # Get bad, good and skipped revs
- bad=$(git rev-parse --verify refs/bisect/bad) &&
- good=$(git for-each-ref --format='^%(objectname)' \
- "refs/bisect/good-*" | tr '\012' ' ') &&
- skip=$(git for-each-ref --format='%(objectname)' \
- "refs/bisect/skip-*" | tr '\012' ' ') || exit
-
- # Maybe some merge bases must be tested first
- check_good_are_ancestors_of_bad "$bad" "$good" "$skip"
- # Return now if a checkout has already been done
- test "$?" -eq "1" && return
-
- # Get bisection information
- 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" "$bad"
- echo "$bisect_rev is first bad commit"
- git diff-tree --pretty $bisect_rev
- exit 0
- fi
+ # Perform all bisection computation, display and checkout
+ git bisect--helper --next-all
+ res=$?
+
+ # Check if we should exit because bisection is finished
+ test $res -eq 10 && exit 0
- bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)"
+ # Check for an error in the bisection process
+ test $res -ne 0 && exit $res
+
+ return 0
}
bisect_visualize() {
#define _ALL_SOURCE 1
#define _GNU_SOURCE 1
#define _BSD_SOURCE 1
+#define _NETBSD_SOURCE 1
#include <unistd.h>
#include <stdio.h>
#endif
#endif
+#ifdef UNRELIABLE_FSTAT
+#define fstat_is_reliable() 0
+#else
+#define fstat_is_reliable() 1
+#endif
+
+/*
+ * Preserves errno, prints a message, but gives no warning for ENOENT.
+ * Always returns the return value of unlink(2).
+ */
+int unlink_or_warn(const char *path);
+
#endif
--- /dev/null
+#!/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
--- /dev/null
+#!/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));
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
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
set _appname {Git Gui}
set _gitdir {}
set _gitexec {}
+set _githtmldir {}
set _reponame {}
set _iscygwin {}
set _search_path {}
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
}
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]} {
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
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 .}
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"
# 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
# -- 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]} {
if {[is_enabled multicommit] || [is_enabled singlecommit]} {
.mbar add cascade -label [mc Tools] -menu .mbar.tools
}
-. configure -menu .mbar
# -- Repository Menu
#
}
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
#
.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]} {
-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"] \
$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] {
}
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 \
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
# -- 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.
return
}
- if {$curHEAD eq $new_hash} {
+ if {$old_hash eq $new_hash} {
_after_readtree $this
} elseif {[is_config_true gui.trustmtime]} {
_readtree $this
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
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
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
}
######################################################################
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
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
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
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
#
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]
}
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
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.
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} {
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
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]
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"
}
-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
}
$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]} {
}
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]
}
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 ""
#: 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
"\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:"
#: 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 ..."
#: git-gui.sh:2281
msgid "Edit"
-msgstr "Edition"
+msgstr "Édition"
#: git-gui.sh:2283 lib/choose_rev.tcl:561
msgid "Branch"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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
#: git-gui.sh:3078
msgid "Refresh"
-msgstr "Rafraichir"
+msgstr "Rafraîchir"
#: git-gui.sh:3099
msgid "Decrease Font Size"
#: 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"
#: 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"
"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
#: 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"
#: lib/blame.tcl:1232
msgid "Originally By:"
-msgstr "A l'origine par :"
+msgstr "À l'origine par :"
#: lib/blame.tcl:1238
msgid "In File:"
#: 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"
#: 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"
#: 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"
#: 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.)"
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
#: 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 ""
"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 "
"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
"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"
"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"
#: 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..."
#: 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..."
#: 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:"
#: 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:"
#: 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"
#: 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"
#: 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."
#: lib/choose_rev.tcl:531
msgid "Updated"
-msgstr "Mise-à-jour:"
+msgstr "Mise à jour:"
#: lib/choose_rev.tcl:559
msgid "URL"
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
#: 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..."
#: 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..."
"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
"* 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
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."
#: 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"
#: 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."
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
#: 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
"\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
#: 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
"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
"\n"
"%s"
msgstr ""
-"Impossible de lancer l'outil de fusion:\n"
+"Impossible de lancer l'outil de fusion :\n"
"\n"
"%s"
#: 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"
#: 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)"
#: 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"
#: 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"
#: 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"
#: lib/remote_add.tcl:50
msgid "Location:"
-msgstr "Emplacement:"
+msgstr "Emplacement :"
#: lib/remote_add.tcl:62
msgid "Further Action"
#: 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"
#: 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"
"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."
"\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."
#: lib/search.tcl:24
msgid "Prev"
-msgstr "Précédant"
+msgstr "Précédent"
#: lib/search.tcl:25
msgid "Case-Sensitive"
#: 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:"
#: 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"
#: 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..."
"\n"
"%s"
msgstr ""
-"Impossible de lancer ssh-keygen:\n"
+"Impossible de lancer ssh-keygen :\n"
"\n"
"%s"
#: 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
#: 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
#: 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"
#: 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:"
#: 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."
"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
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 ""
#: lib/tools.tcl:149
#, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
msgstr ""
#: lib/tools.tcl:151
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 ""
#: 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
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 ""
#: 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
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 ""
#: lib/tools.tcl:149
#, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
msgstr "ツールが完了しました: %s"
#: lib/tools.tcl:151
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 ""
#: 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
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"
"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"
"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 "Ð\97апÑ\83Ñ\81каеÑ\82Ñ\81Ñ\8f gitk... пожалÑ\83йÑ\81Ñ\82а, ждиÑ\82е..."
+msgstr "Ð\97апÑ\83Ñ\81каеÑ\82Ñ\81Ñ\8f gitk... Ð\9fодождиÑ\82е, пожалÑ\83йÑ\81Ñ\82а..."
-#: 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 "Ð\9eбÑ\8aединиÑ\82Ñ\8c"
+msgstr "СлиÑ\8fние"
-#: 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 "Ð\98Ñ\81Ñ\82оÑ\80иÑ\8f Ñ\82екÑ\83Ñ\89ей веÑ\82ви наглÑ\8fдно"
+msgstr "Ð\9fоказаÑ\82Ñ\8c иÑ\81Ñ\82оÑ\80иÑ\8e Ñ\82екÑ\83Ñ\89ей веÑ\82ви"
-#: git-gui.sh:1892
+#: git-gui.sh:2320
msgid "Visualize All Branch History"
-msgstr "Ð\98Ñ\81Ñ\82оÑ\80иÑ\8f вÑ\81еÑ\85 веÑ\82вей наглÑ\8fдно"
+msgstr "Ð\9fоказаÑ\82Ñ\8c иÑ\81Ñ\82оÑ\80иÑ\8e вÑ\81еÑ\85 веÑ\82вей"
-#: 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 "Ð\98Ñ\81Ñ\82оÑ\80иÑ\8f веÑ\82ви %s наглÑ\8fдно"
+msgstr "Ð\9fоказаÑ\82Ñ\8c иÑ\81Ñ\82оÑ\80иÑ\8e веÑ\82ви %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 "Ð\9fодпиÑ\81аÑ\82Ñ\8c"
+#: git-gui.sh:2491 git-gui.sh:3083
+msgid "Show Less Context"
+msgstr "Ð\9cенÑ\8cÑ\88е конÑ\82екÑ\81Ñ\82а"
-#: 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"
"запущенными из %s\n"
"\n"
-#: git-gui.sh:2792
+#: git-gui.sh:3345
msgid ""
"\n"
"This is due to a known issue with the\n"
"Это известная проблема с Tcl,\n"
"распространяемым Cygwin."
-#: git-gui.sh:2797
+#: git-gui.sh:3350
#, tcl-format
msgid ""
"\n"
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 "Скопировано/перемещено в:"
#: 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 "Ð\9eÑ\82мениÑ\82Ñ\8c"
+msgstr "Ð\9eÑ\82мена"
-#: 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 "Настройки"
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 "Создать"
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 "Название:"
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 "Сброс"
#: 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
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' уже существует."
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"
"Ветвь '%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 "СÑ\82Ñ\80аÑ\82егиÑ\8f обÑ\8aединениÑ\8f '%s' не поддеÑ\80живаеÑ\82Ñ\81Ñ\8f."
+msgstr "Ð\9dеизвеÑ\81Ñ\82наÑ\8f Ñ\81Ñ\82Ñ\80аÑ\82егиÑ\8f Ñ\81лиÑ\8fниÑ\8f: '%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"
"\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"
"Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, "
"начиная с 'Текущего отсоединенного состояния'."
-#: 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"
#: 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:"
#: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538
msgid "Tag"
-msgstr "Таг"
+msgstr "Ð\9cеÑ\82ка"
#: lib/choose_rev.tcl:317
#, tcl-format
"completed. You cannot amend the prior commit unless you first abort the "
"current merge activity.\n"
msgstr ""
-"Ð\9dевозможно иÑ\81пÑ\80авиÑ\82Ñ\8c Ñ\81оÑ\81Ñ\82оÑ\8fние во вÑ\80емÑ\8f обÑ\8aединения.\n"
+"Ð\9dевозможно иÑ\81пÑ\80авиÑ\82Ñ\8c Ñ\81оÑ\81Ñ\82оÑ\8fние во вÑ\80емÑ\8f опеÑ\80аÑ\86ии Ñ\81лиÑ\8fния.\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"
"\n"
"Это будет сделано сейчас автоматически.\n"
-#: lib/commit.tcl:154
+#: lib/commit.tcl:155
#, tcl-format
msgid ""
"Unmerged files cannot be committed.\n"
"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"
"\n"
"Файл %s не может быть сохранен данной программой.\n"
-#: lib/commit.tcl:170
+#: lib/commit.tcl:171
msgid ""
"No changes to commit.\n"
"\n"
"\n"
"Подготовьте хотя бы один файл до создания сохраненного состояния.\n"
-#: lib/commit.tcl:183
+#: lib/commit.tcl:186
msgid ""
"Please supply a commit message.\n"
"\n"
"- вторая строка пустая\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"
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 "
msgid "Invalid date from Git: %s"
msgstr "Неправильная дата в репозитории: %s"
-#: lib/diff.tcl:42
+#: lib/diff.tcl:59
#, tcl-format
msgid ""
"No differences detected.\n"
"\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 "ошибка"
#: lib/index.tcl:15
msgid "Index Error"
-msgstr "Ð\9eÑ\88ибка индекÑ\81а"
+msgstr "Ð\9eÑ\88ибка в индекÑ\81е"
#: lib/index.tcl:21
msgid ""
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 ""
"\n"
"Это будет сделано сейчас автоматически.\n"
-#: lib/merge.tcl:44
+#: lib/merge.tcl:45
#, tcl-format
msgid ""
"You are in the middle of a conflicted merge.\n"
"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"
"\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 "Ð\9eбÑ\8aединение %s и %s..."
+msgstr "СлиÑ\8fние %s и %s..."
-#: lib/merge.tcl:130
+#: lib/merge.tcl:131
msgid "Merge completed successfully."
-msgstr "Ð\9eбÑ\8aединение успешно завершено."
+msgstr "СлиÑ\8fние успешно завершено."
-#: 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 "Ð\9eбÑ\8aединиÑ\82Ñ\8c с %s"
+msgstr "СлиÑ\8fние с %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"
"\n"
"Завершите текущее исправление сохраненного состояния.\n"
-#: lib/merge.tcl:221
+#: lib/merge.tcl:222
msgid ""
"Abort merge?\n"
"\n"
"\n"
"Continue with aborting the current merge?"
msgstr ""
-"Ð\9fÑ\80еÑ\80ваÑ\82Ñ\8c обÑ\8aединение?\n"
+"Ð\9fÑ\80еÑ\80ваÑ\82Ñ\8c опеÑ\80аÑ\86иÑ\8e Ñ\81лиÑ\8fниÑ\8f?\n"
"\n"
-"Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n"
+"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n"
"\n"
"Продолжить?"
-#: lib/merge.tcl:227
+#: lib/merge.tcl:228
msgid ""
"Reset changes?\n"
"\n"
"\n"
"Continue with resetting the current changes?"
msgstr ""
-"Ð\9fÑ\80еÑ\80ваÑ\82Ñ\8c обÑ\8aединение?\n"
+"Ð\9fÑ\80еÑ\80ваÑ\82Ñ\8c опеÑ\80аÑ\86иÑ\8e Ñ\81лиÑ\8fниÑ\8f?\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 "Ð\94ля репозитория %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 "УдалиÑ\82Ñ\8c внеÑ\88нÑ\8eÑ\8e веÑ\82вÑ\8c"
+msgid "Delete Branch Remotely"
+msgstr "Удаление веÑ\82ви во внеÑ\88нем Ñ\80епозиÑ\82оÑ\80ии"
#: 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 "по Ñ\83казанномÑ\83 URL:"
+#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149
+msgid "Arbitrary Location:"
+msgstr "Указаное положение:"
#: lib/remote_branch_delete.tcl:84
msgid "Branches"
#: lib/remote_branch_delete.tcl:111
msgid "Merged Into:"
-msgstr "Ð\9eбÑ\8aединено с:"
+msgstr "СлиÑ\8fние с:"
#: lib/remote_branch_delete.tcl:119
msgid "Always (Do not perform merge checks)"
-msgstr "Ð\92Ñ\81егда (не вÑ\8bполнÑ\8fÑ\82Ñ\8c пÑ\80овеÑ\80кÑ\83 обÑ\8aединений)"
+msgstr "Ð\92Ñ\81егда (не вÑ\8bполнÑ\8fÑ\82Ñ\8c пÑ\80овеÑ\80кÑ\83 на Ñ\81лиÑ\8fние)"
#: lib/remote_branch_delete.tcl:152
msgid "A branch is required for 'Merged Into'."
-msgstr "Ð\94лÑ\8f опÑ\86ии 'Ð\9eбÑ\8aединено с' требуется указать ветвь."
+msgstr "Ð\94лÑ\8f опÑ\86ии 'СлиÑ\8fние с' требуется указать ветвь."
#: lib/remote_branch_delete.tcl:184
#, tcl-format
"\n"
" - %s"
msgstr ""
-"Следующие ветви объединены с %s не полностью:\n"
+"Следующие ветви могут быть объединены с %s при помощи операции слияния:\n"
+"\n"
" - %s"
#: lib/remote_branch_delete.tcl:189
"One or more of the merge tests failed because you have not fetched the "
"necessary commits. Try fetching from %s first."
msgstr ""
-"Ð\9eдин или неÑ\81колÑ\8cко Ñ\82еÑ\81Ñ\82ов на обÑ\8aединение не прошли, потому что Вы не "
+"Ð\9dекоÑ\82оÑ\80Ñ\8bе Ñ\82еÑ\81Ñ\82Ñ\8b на Ñ\81лиÑ\8fние не прошли, потому что Вы не "
"получили необходимые состояния. Попытайтесь получить их из %s."
#: lib/remote_branch_delete.tcl:207
msgid "Scanning %s..."
msgstr "Перечитывание %s... "
-#: lib/remote.tcl:165
-msgid "Prune from"
-msgstr "ЧиÑ\81Ñ\82ка"
+#: lib/search.tcl:21
+msgid "Find:"
+msgstr "Ð\9fоиÑ\81к:"
-#: lib/remote.tcl:170
-msgid "Fetch from"
-msgstr "Ð\9fолÑ\83Ñ\87ение из"
+#: lib/search.tcl:23
+msgid "Next"
+msgstr "Ð\94алÑ\8cÑ\88е"
-#: 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:"
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
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 "Дальше >"
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 ""
#: 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
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 ""
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
}
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.
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
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"
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
--- /dev/null
+# 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" --default --mode=diff2 \
+ "$LOCAL" "$REMOTE"
+ 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"
+ 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"
+}
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
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")" : '\([^ ]*\) ')
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"
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"
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"
-t|--tool*)
case "$#,$1" in
*,*=*)
- merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+ merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)')
;;
1,*)
usage ;;
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) ? "
}
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
# 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
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
"envelopesender" => \$envelope_sender,
"multiedit" => \$multiedit,
"confirm" => \$confirm,
+ "from" => \$sender,
);
# Handle Uncouth Termination
mailrc => sub { my $fh = shift; while (<$fh>) {
if (/^alias\s+(\S+)\s+(.*)$/) {
# spaces delimit multiple addresses
- $aliases{$1} = [ split(/\s+/, $2) ];
+ $aliases{$1} = [ quotewords('\s+', 0, $2) ];
}}},
pine => sub { my $fh = shift; my $f='\t[^\t]*';
for (my $x = ''; defined($x); $x = $_) {
$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 ];
command=
branch=
quiet=
+reference=
cached=
nofetch=
{
path=$1
url=$2
+ reference="$3"
# If there already is a directory at the submodule path,
# expect it to be empty (since that is the default checkout
test -e "$path" &&
die "A file already exist at path '$path'"
- git-clone -n "$url" "$path" ||
+ if test -n "$reference"
+ then
+ git-clone "$reference" -n "$url" "$path"
+ else
+ git-clone -n "$url" "$path"
+ fi ||
die "Clone of '$url' into submodule path '$path' failed"
}
-q|--quiet)
quiet=1
;;
+ --reference)
+ case "$2" in '') usage ;; esac
+ reference="--reference=$2"
+ shift
+ ;;
+ --reference=*)
+ reference="$1"
+ shift
+ ;;
--)
shift
break
git config submodule."$path".url "$url"
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'"
+ module_clone "$path" "$realrepo" "$reference" || exit
+ (
+ 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" ||
quiet=1
;;
-i|--init)
+ init=1
shift
- cmd_init "$@" || return
;;
-N|--no-fetch)
shift
nofetch=1
;;
+ --reference)
+ case "$2" in '') usage ;; esac
+ reference="--reference=$2"
+ shift 2
+ ;;
+ --reference=*)
+ reference="$1"
+ shift
+ ;;
--)
shift
break
esac
done
+ if test -n "$init"
+ then
+ cmd_init "--" "$@" || return
+ fi
+
module_list "$@" |
while read mode sha1 stage path
do
if ! test -d "$path"/.git -o -f "$path"/.git
then
- module_clone "$path" "$url" || exit
+ module_clone "$path" "$url" "$reference"|| exit
subsha1=
else
subsha1=$(unset GIT_DIR; cd "$path" &&
use strict;
use vars qw/ $AUTHOR $VERSION
$sha1 $sha1_short $_revision $_repository
- $_q $_authors %users/;
+ $_q $_authors $_authors_prog %users/;
$AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
$VERSION = '@@GIT_VERSION@@';
use IO::File qw//;
use File::Basename qw/dirname basename/;
use File::Path qw/mkpath/;
+use File::Spec;
use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
use IPC::Open3;
use Git;
'ignore-paths=s' => \$SVN::Git::Fetcher::_ignore_regex );
my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
'authors-file|A=s' => \$_authors,
+ 'authors-prog=s' => \$_authors_prog,
'repack:i' => \$Git::SVN::_repack,
'noMetadata' => \$Git::SVN::_no_metadata,
'useSvmProps' => \$Git::SVN::_use_svm_props,
'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
version() if $_version;
usage(1) unless defined $cmd;
load_authors() if $_authors;
+if (defined $_authors_prog) {
+ $_authors_prog = "'" . File::Spec->rel2abs($_authors_prog) . "'";
+}
unless ($cmd =~ /^(?:clone|init|multi-init|commit-diff)$/) {
Git::SVN::Migration::migration_check();
$path = basename($url) if !defined $path || !length $path;
cmd_init($url, $path);
Git::SVN::fetch_all($Git::SVN::default_repo_id);
+ command_oneline('config', 'svn.authorsfile', $_authors) if $_authors;
}
sub cmd_init {
}
rename $commit_editmsg, $commit_msg or croak $!;
{
+ require Encode;
# SVN requires messages to be UTF-8 when entering the repo
local $/;
open $log_fh, '<', $commit_msg or croak $!;
binmode $log_fh;
chomp($log_entry{log} = <$log_fh>);
- if (my $enc = Git::config('i18n.commitencoding')) {
- require Encode;
- Encode::from_to($log_entry{log}, $enc, 'UTF-8');
+ my $enc = Git::config('i18n.commitencoding') || 'UTF-8';
+ my $msg = $log_entry{log};
+
+ eval { $msg = Encode::decode($enc, $msg, 1) };
+ if ($@) {
+ die "Could not decode as $enc:\n", $msg,
+ "\nPerhaps you need to set i18n.commitencoding\n";
}
+
+ eval { $msg = Encode::encode('UTF-8', $msg, 1) };
+ die "Could not encode as UTF-8:\n$msg\n" if $@;
+
+ $log_entry{log} = $msg;
+
close $log_fh or croak $!;
}
unlink $commit_msg;
$gs
}
+sub call_authors_prog {
+ my ($orig_author) = @_;
+ my $author = `$::_authors_prog $orig_author`;
+ if ($? != 0) {
+ die "$::_authors_prog failed with exit code $?\n"
+ }
+ if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) {
+ my ($name, $email) = ($1, $2);
+ $email = undef if length $2 == 0;
+ return [$name, $email];
+ } else {
+ die "Author: $orig_author: $::_authors_prog returned "
+ . "invalid author format: $author\n";
+ }
+}
+
sub check_author {
my ($author) = @_;
if (!defined $author || length $author == 0) {
$author = '(no author)';
- } elsif (defined $::_authors && ! defined $::users{$author}) {
- die "Author: $author not defined in $::_authors file\n";
+ }
+ if (!defined $::users{$author}) {
+ if (defined $::_authors_prog) {
+ $::users{$author} = call_authors_prog($author);
+ } elsif (defined $::_authors) {
+ die "Author: $author not defined in $::_authors file\n";
+ }
}
$author;
}
my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
my $longest_path = longest_common_path($gsv, $globs);
my $ra_url = $self->{url};
+ my $find_trailing_edge;
while (1) {
my %revs;
my $err;
sub { $revs{$_[1]} = _cb(@_) });
if ($err) {
print "Checked through r$max\r";
+ } else {
+ $find_trailing_edge = 1;
}
- if ($err && $max >= $head) {
+ if ($err and $find_trailing_edge) {
print STDERR "Path '$longest_path' ",
"was probably deleted:\n",
$err->expanded_message,
my $ok;
$self->get_log([$longest_path], $min, $hi,
0, 1, 1, sub {
- $ok ||= $_[1];
+ $ok = $_[1];
$revs{$_[1]} = _cb(@_) });
if ($ok) {
print STDERR "r$min .. r$ok OK\n";
last;
}
}
+ $find_trailing_edge = 0;
}
$SVN::Error::handler = $err_handler;
}
}
-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;
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;
"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;
/*
* 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.
*/
incr viewactive($view)
set viewcomplete($view) 0
reset_pending_select {}
- nowbusy $view "Reading"
+ nowbusy $view [mc "Reading"]
if {$showneartags} {
getallcommits
}
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
# 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}
{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.
}
}
+ 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}
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"
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
{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
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]
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]\""
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 {
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} {
}
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
-fill [$canv cget -selectbackground]]
$canv lower $t
}
+ if {[info exists markedid] && $id eq $markedid} {
+ make_idmark $id
+ }
}
proc bolden_name {id font} {
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
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
}
}
+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
}
}
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 {}
$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
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]
}
$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"}]
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
} 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
}
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
}
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
if {[info exists currentid] && $currentid == $id} {
make_secsel $id
}
+ if {[info exists markedid] && $markedid eq $id} {
+ make_idmark $id
+ }
}
proc mktagcan {} {
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
}
}
allcanvs itemconf text -fill $c
$canv itemconf circle -outline $c
+ $canv itemconf markid -outline $c
}
proc prefscan {} {
}
}
-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
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
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 {}} {
--- /dev/null
+#
+# 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 "Командная строка"
+
* $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
@fmts = map {
exists $known_snapshot_format_aliases{$_} ?
$known_snapshot_format_aliases{$_} : $_} @fmts;
- @fmts = grep(exists $known_snapshot_formats{$_}, @fmts);
-
+ @fmts = grep {
+ exists $known_snapshot_formats{$_} } @fmts;
}
our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
# 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)$//;
- next unless $sfx = $1;
+ unless ($hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//) {
+ next;
+ }
+ my $sfx = $1;
# a valid suffix was found, so set the snapshot format
# and reset the hash parameter
$input_params{'snapshot_format'} = $fmt;
if (!defined($actions{$action})) {
die_error(400, "Unknown action");
}
-if ($action !~ m/^(opml|project_list|project_index)$/ &&
+if ($action !~ m/^(?:opml|project_list|project_index)$/ &&
!$project) {
die_error(400, "Project needed");
}
## ======================================================================
## 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;
}
# replace invalid utf8 character with SUBSTITUTION sequence
-sub esc_html ($;%) {
+sub esc_html {
my $str = shift;
my %opts = @_;
if ($chopped eq $str) {
return esc_html($chopped);
} else {
- $str =~ s/([[:cntrl:]])/?/g;
+ $str =~ s/[[:cntrl:]]/?/g;
return $cgi->span({-title=>$str}, esc_html($chopped));
}
}
};
# submodule/subproject, a commit object reference
-sub S_ISGITLINK($) {
+sub S_ISGITLINK {
my $mode = shift;
return (($mode & S_IFMT) == S_IFGITLINK)
$extra = '' unless defined($extra);
if (length($short) < length($long)) {
+ $long =~ s/[[:cntrl:]]/?/g;
return $cgi->a({-href => $href, -class => "list subject",
-title => to_utf8($long)},
esc_html($short) . $extra);
# Try to avoid using this function wherever possible.
sub quote_command {
return join(' ',
- map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ ));
+ map { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ );
}
# get HEAD ref of given project as hash
my $path = shift;
$git_dir = "$projectroot/$path";
- open my $fd, "$git_dir/description"
+ open my $fd, '<', "$git_dir/description"
or return git_get_project_config('description');
my $descr = <$fd>;
close $fd;
my $ctags = {};
$git_dir = "$projectroot/$path";
- unless (opendir D, "$git_dir/ctags") {
- return $ctags;
- }
- foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir(D)) {
- open CT, $_ or next;
- my $val = <CT>;
+ opendir my $dh, "$git_dir/ctags"
+ or return $ctags;
+ foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) {
+ open my $ct, '<', $_ or next;
+ my $val = <$ct>;
chomp $val;
- close CT;
+ close $ct;
my $ctag = $_; $ctag =~ s#.*/##;
$ctags->{$ctag} = $val;
}
- closedir D;
+ closedir $dh;
$ctags;
}
my $path = shift;
$git_dir = "$projectroot/$path";
- open my $fd, "$git_dir/cloneurl"
+ open my $fd, '<', "$git_dir/cloneurl"
or return wantarray ?
@{ config_to_multi(git_get_project_config('url')) } :
config_to_multi(git_get_project_config('url'));
# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
my %paths;
- open my ($fd), $projects_list or return;
+ open my $fd, '<', $projects_list or return;
PROJECT:
while (my $line = <$fd>) {
chomp $line;
# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
if (-f $projects_list) {
- open (my $fd , $projects_list);
+ open(my $fd, '<', $projects_list);
while (my $line = <$fd>) {
chomp $line;
my ($pr, $ow) = split ' ', $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;
-r $mimemap or return undef;
my %mimemap;
- open(MIME, $mimemap) or return undef;
- while (<MIME>) {
+ open(my $mh, '<', $mimemap) or return undef;
+ while (<$mh>) {
next if m/^#/; # skip comments
- my ($mime, $exts) = split(/\t+/);
+ my ($mimetype, $exts) = split(/\t+/);
if (defined $exts) {
my @exts = split(/\s+/, $exts);
foreach my $ext (@exts) {
- $mimemap{$ext} = $mime;
+ $mimemap{$ext} = $mimetype;
}
}
}
- close(MIME);
+ close($mh);
$filename =~ /\.([^.]*)$/;
return $mimemap{$1};
"\n</div>\n";
}
-#sub git_print_authorship (\%) {
sub git_print_authorship {
my $co = shift;
print "<br/></div>\n";
}
-# sub git_print_log (\@;%) {
-sub git_print_log ($;%) {
+sub git_print_log {
my $log = shift;
my %opts = @_;
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
or return;
{
- local $/;
+ local $/ = undef;
$link_target = <$fd>;
}
close $fd
# return target of link relative to top directory (top tree);
# return undef if it is not possible (including absolute links).
sub normalize_link_target {
- my ($link_target, $basedir, $hash_base) = @_;
-
- # we can normalize symlink target only if $hash_base is provided
- return unless $hash_base;
+ my ($link_target, $basedir) = @_;
# absolute symlinks (beginning with '/') cannot be normalized
return if (substr($link_target, 0, 1) eq '/');
if (S_ISLNK(oct $t->{'mode'})) {
my $link_target = git_get_link_target($t->{'hash'});
if ($link_target) {
- my $norm_target = normalize_link_target($link_target, $basedir, $hash_base);
+ my $norm_target = normalize_link_target($link_target, $basedir);
if (defined $norm_target) {
print " -> " .
$cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
($pname !~ /\/$/) &&
(-d "$projectroot/$pname")) {
$pr->{'forks'} = "-d $projectroot/$pname";
- } else {
+ } else {
$pr->{'forks'} = 0;
}
}
-content_disposition =>
($sandbox ? 'attachment' : 'inline')
. '; filename="' . $save_as . '"');
- undef $/;
+ local $/ = undef;
binmode STDOUT, ':raw';
print <$fd>;
binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
- $/ = "\n";
close $fd;
}
}
}
die_error(404, "No such tree") unless defined($hash);
- $/ = "\0";
- open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash
- or die_error(500, "Open git-ls-tree failed");
- my @entries = map { chomp; $_ } <$fd>;
- close $fd or die_error(404, "Reading tree failed");
- $/ = "\n";
+
+ my @entries = ();
+ {
+ local $/ = "\0";
+ open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash
+ or die_error(500, "Open git-ls-tree failed");
+ @entries = map { chomp; $_ } <$fd>;
+ close $fd
+ or die_error(404, "Reading tree failed");
+ }
my $refs = git_get_references();
my $ref = format_ref_marker($refs, $hash_base);
print "<table class=\"pickaxe search\">\n";
my $alternate = 1;
- $/ = "\n";
+ local $/ = "\n";
open my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,
'--pretty=format:%H', '--no-abbrev', '--raw', "-S$searchtext",
($search_use_regexp ? '--pickaxe-regex' : ());
print "<table class=\"grep_search\">\n";
my $alternate = 1;
my $matches = 0;
- $/ = "\n";
+ local $/ = "\n";
open my $fd, "-|", git_cmd(), 'grep', '-n',
$search_use_regexp ? ('-E', '-i') : '-F',
$searchtext, $co{'tree'};
# end of feed
if ($format eq 'rss') {
print "</channel>\n</rss>\n";
- } elsif ($format eq 'atom') {
+ } elsif ($format eq 'atom') {
print "</feed>\n";
}
}
#include "cache.h"
#include "commit.h"
+#include "color.h"
#include "graph.h"
#include "diff.h"
#include "revision.h"
* 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().
/*
* 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 {
*/
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 {
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
* 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)
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
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)
* 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++;
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);
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
* 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, "");
}
* 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)
* 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))
{
int num_expansion_rows;
int i, seen_this;
+ int chars_written;
/*
* This function formats a row that increases the space around a commit
* 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.
*/
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,
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
* 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)
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.
*/
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
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
{
int i;
int *tmp_mapping;
+ short used_horizontal = 0;
+ int horizontal_edge = -1;
+ int horizontal_edge_target = -1;
/*
* Clear out the new_mapping array
* 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
*
* 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;
}
}
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
* 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, ' ');
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
struct grep_expr *x;
p = *list;
+ if (!p)
+ return NULL;
switch (p->token) {
case GREP_PATTERN: /* atom */
case GREP_PATTERN_HEAD:
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;
struct grep_expr *x;
p = *list;
+ if (!p)
+ return NULL;
switch (p->token) {
case GREP_NOT:
if (!p->next)
{
int hit = 0;
int saved_ch = 0;
+ const char *start = bol;
if ((p->token != GREP_PATTERN) &&
((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
bol = pmatch[0].rm_so + bol + 1;
while (word_char(bol[-1]) && bol < eol)
bol++;
+ eflags |= REG_NOTBOL;
if (bol < eol)
goto again;
}
}
if (p->token == GREP_PATTERN_HEAD && saved_ch)
*eol = saved_ch;
+ if (hit) {
+ pmatch[0].rm_so += bol - start;
+ pmatch[0].rm_eo += bol - start;
+ }
return hit;
}
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);
struct grep_expr *pattern_expression;
int prefix_length;
regex_t regexp;
- unsigned linenum:1;
- unsigned invert:1;
- unsigned status_only:1;
- unsigned name_only:1;
- unsigned unmatch_name_only:1;
- unsigned count:1;
- unsigned word_regexp:1;
- unsigned fixed:1;
- unsigned all_match:1;
+ int linenum;
+ int invert;
+ int status_only;
+ int name_only;
+ int unmatch_name_only;
+ int count;
+ int word_regexp;
+ int fixed;
+ int all_match;
#define GREP_BINARY_DEFAULT 0
#define GREP_BINARY_NOMATCH 1
#define GREP_BINARY_TEXT 2
- unsigned binary:2;
- unsigned extended:1;
- unsigned relative:1;
- unsigned pathname:1;
- unsigned null_following_name:1;
+ int binary;
+ int extended;
+ int relative;
+ int pathname;
+ int null_following_name;
int color;
char color_match[COLOR_MAXLEN];
const char *color_external;
"%s.temp", filename);
snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename);
- unlink(prevfile);
+ unlink_or_warn(prevfile);
rename(request->tmpfile, prevfile);
- unlink(request->tmpfile);
+ unlink_or_warn(request->tmpfile);
if (request->local_fileno != -1)
error("fd leakage in start: %d", request->local_fileno);
} while (prev_read > 0);
close(prevlocal);
}
- unlink(prevfile);
+ unlink_or_warn(prevfile);
/* Reset inflate/SHA1 if there was an error reading the previous temp
file; also rewind to the beginning of the local file. */
request->http_code != 416) {
if (stat(request->tmpfile, &st) == 0) {
if (st.st_size == 0)
- unlink(request->tmpfile);
+ unlink_or_warn(request->tmpfile);
}
} else {
if (request->http_code == 416)
git_inflate_end(&request->stream);
git_SHA1_Final(request->real_sha1, &request->c);
if (request->zret != Z_STREAM_END) {
- unlink(request->tmpfile);
+ unlink_or_warn(request->tmpfile);
} else if (hashcmp(request->obj->sha1, request->real_sha1)) {
- unlink(request->tmpfile);
+ unlink_or_warn(request->tmpfile);
} else {
request->rename =
move_temp_to_file(
fprintf(stderr, "Removing remote locks...\n");
while (lock) {
+ struct remote_lock *next = lock->next;
unlock_remote(lock);
- lock = lock->next;
+ lock = next;
}
}
remote_ls("refs/", (PROCESS_FILES | PROCESS_DIRS | RECURSIVE), process_ls_ref, NULL);
}
-static int is_zero_sha1(const unsigned char *sha1)
-{
- int i;
-
- for (i = 0; i < 20; i++) {
- if (*sha1++)
- return 0;
- }
- return 1;
-}
-
static void add_remote_info_ref(struct remote_ls_ctx *ls)
{
struct strbuf *buf = (struct strbuf *)ls->userData;
/* Remote HEAD must resolve to a known object */
if (symref)
return error("Remote HEAD symrefs too deep");
- if (is_zero_sha1(head_sha1))
+ if (is_null_sha1(head_sha1))
return error("Unable to resolve remote HEAD");
if (!has_sha1_file(head_sha1))
return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", sha1_to_hex(head_sha1));
/* Remote branch must resolve to a known object */
- if (is_zero_sha1(remote_ref->old_sha1))
+ if (is_null_sha1(remote_ref->old_sha1))
return error("Unable to resolve remote branch %s",
remote_ref->name);
if (!has_sha1_file(remote_ref->old_sha1))
new_refs = 0;
for (ref = remote_refs; ref; ref = ref->next) {
char old_hex[60], *new_hex;
- const char *commit_argv[4];
+ const char *commit_argv[5];
int commit_argc;
char *new_sha1_hex, *old_sha1_hex;
if (!ref->peer_ref)
continue;
- if (is_zero_sha1(ref->peer_ref->new_sha1)) {
+ if (is_null_sha1(ref->peer_ref->new_sha1)) {
if (delete_remote_branch(ref->name, 1) == -1) {
error("Could not remove %s", ref->name);
rc = -4;
}
if (!force_all &&
- !is_zero_sha1(ref->old_sha1) &&
+ !is_null_sha1(ref->old_sha1) &&
!ref->force) {
if (!has_sha1_file(ref->old_sha1) ||
!ref_newer(ref->peer_ref->new_sha1,
old_sha1_hex = NULL;
commit_argv[1] = "--objects";
commit_argv[2] = new_sha1_hex;
- if (!push_all && !is_zero_sha1(ref->old_sha1)) {
+ if (!push_all && !is_null_sha1(ref->old_sha1)) {
old_sha1_hex = xmalloc(42);
sprintf(old_sha1_hex, "^%s",
sha1_to_hex(ref->old_sha1));
commit_argv[3] = old_sha1_hex;
commit_argc++;
}
+ commit_argv[commit_argc] = NULL;
init_revisions(&revs, setup_git_directory());
setup_revisions(commit_argc, commit_argv, &revs, NULL);
revs.edge_hint = 0; /* just in case */
struct walker_data *data = walker->data;
snprintf(prevfile, sizeof(prevfile), "%s.prev", obj_req->filename);
- unlink(prevfile);
+ unlink_or_warn(prevfile);
rename(obj_req->tmpfile, prevfile);
- unlink(obj_req->tmpfile);
+ unlink_or_warn(obj_req->tmpfile);
if (obj_req->local != -1)
error("fd leakage in start: %d", obj_req->local);
} while (prev_read > 0);
close(prevlocal);
}
- unlink(prevfile);
+ unlink_or_warn(prevfile);
/* Reset inflate/SHA1 if there was an error reading the previous temp
file; also rewind to the beginning of the local file. */
} else if (obj_req->curl_result != CURLE_OK) {
if (stat(obj_req->tmpfile, &st) == 0)
if (st.st_size == 0)
- unlink(obj_req->tmpfile);
+ unlink_or_warn(obj_req->tmpfile);
return;
}
git_inflate_end(&obj_req->stream);
git_SHA1_Final(obj_req->real_sha1, &obj_req->c);
if (obj_req->zret != Z_STREAM_END) {
- unlink(obj_req->tmpfile);
+ unlink_or_warn(obj_req->tmpfile);
return;
}
if (hashcmp(obj_req->sha1, obj_req->real_sha1)) {
- unlink(obj_req->tmpfile);
+ unlink_or_warn(obj_req->tmpfile);
return;
}
obj_req->rename =
close(obj_req->local);
obj_req->local = -1;
}
- unlink(obj_req->tmpfile);
+ unlink_or_warn(obj_req->tmpfile);
if (obj_req->slot) {
release_active_slot(obj_req->slot);
obj_req->slot = NULL;
struct imap_store *ctx;
struct imap *imap;
char *arg, *rsp;
- struct hostent *he;
- struct sockaddr_in addr;
- int s, a[2], preauth;
+ int s = -1, a[2], preauth;
pid_t pid;
ctx = xcalloc(sizeof(*ctx), 1);
imap_info("ok\n");
} else {
+#ifndef NO_IPV6
+ struct addrinfo hints, *ai0, *ai;
+ int gai;
+ char portstr[6];
+
+ snprintf(portstr, sizeof(portstr), "%hu", srvc->port);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ imap_info("Resolving %s... ", srvc->host);
+ gai = getaddrinfo(srvc->host, portstr, &hints, &ai);
+ if (gai) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai));
+ goto bail;
+ }
+ imap_info("ok\n");
+
+ for (ai0 = ai; ai; ai = ai->ai_next) {
+ char addr[NI_MAXHOST];
+
+ s = socket(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol);
+ if (s < 0)
+ continue;
+
+ getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
+ sizeof(addr), NULL, 0, NI_NUMERICHOST);
+ imap_info("Connecting to [%s]:%s... ", addr, portstr);
+
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+ close(s);
+ s = -1;
+ perror("connect");
+ continue;
+ }
+
+ break;
+ }
+ freeaddrinfo(ai0);
+#else /* NO_IPV6 */
+ struct hostent *he;
+ struct sockaddr_in addr;
+
memset(&addr, 0, sizeof(addr));
addr.sin_port = htons(srvc->port);
addr.sin_family = AF_INET;
imap_info("Connecting to %s:%hu... ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if (connect(s, (struct sockaddr *)&addr, sizeof(addr))) {
close(s);
+ s = -1;
perror("connect");
+ }
+#endif
+ if (s < 0) {
+ fputs("Error: unable to connect to server.\n", stderr);
goto bail;
}
*
* 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:
*
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)
{
if (obj->flags & (UNINTERESTING | SEEN))
return;
obj->flags |= SEEN;
- add_object(obj, p, path, name);
+ show(obj, path, name);
}
/*
*/
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)
{
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)
{
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);
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;
}
}
+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,
show_commit_fn show_commit,
show_object_fn show_object,
{
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, "");
+ add_pending_tree(revs, commit->tree);
show_commit(commit, data);
}
for (i = 0; i < revs->pending.nr; i++) {
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], data);
- free(objects.objects);
if (revs->pending.nr) {
free(revs->pending.objects);
revs->pending.nr = 0;
#define LIST_OBJECTS_H
typedef void (*show_commit_fn)(struct commit *, void *);
-typedef void (*show_object_fn)(struct object_array_entry *, 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 *, show_commit_fn, show_object_fn, void *);
close(fd);
bad:
for (i = 0; i < 3; i++)
- unlink(temp[i]);
+ unlink_or_warn(temp[i]);
strbuf_release(&cmd);
return status;
}
lock_file_list->filename[0]) {
if (lock_file_list->fd >= 0)
close(lock_file_list->fd);
- unlink(lock_file_list->filename);
+ unlink_or_warn(lock_file_list->filename);
}
lock_file_list = lock_file_list->next;
}
* 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 {
if (lk->filename[0]) {
if (lk->fd >= 0)
close(lk->fd);
- unlink(lk->filename);
+ unlink_or_warn(lk->filename);
}
lk->filename[0] = 0;
}
struct object *obj = parse_object(sha1);
if (!obj)
return 0;
+ refname = prettify_refname(refname);
add_name_decoration("", refname, obj);
while (obj->type == OBJ_TAG) {
obj = ((struct tag *)obj)->tagged;
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)
ren1_src, ren1_dst, branch1,
branch2);
update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
- update_stages(ren1_dst, NULL,
- branch1 == o->branch1 ?
- ren1->pair->two : NULL,
- branch1 == o->branch1 ?
- NULL : ren1->pair->two, 1);
+ if (!o->call_depth)
+ update_stages(ren1_dst, NULL,
+ branch1 == o->branch1 ?
+ ren1->pair->two : NULL,
+ branch1 == o->branch1 ?
+ NULL : ren1->pair->two, 1);
} else if (!sha_eq(dst_other.sha1, null_sha1)) {
const char *new_path;
clean_merge = 0;
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;
}
static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size)
{
- int j = hash_obj(obj, size);
+ unsigned int j = hash_obj(obj, size);
while (hash[j]) {
j++;
hash[j] = obj;
}
-static int hashtable_index(const unsigned char *sha1)
+static unsigned int hashtable_index(const unsigned char *sha1)
{
unsigned int i;
memcpy(&i, sha1, sizeof(unsigned int));
- return (int)(i % obj_hash_size);
+ return i % obj_hash_size;
}
struct object *lookup_object(const unsigned char *sha1)
{
- int i;
+ unsigned int i;
struct object *obj;
if (!obj_hash)
struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
if (lock) {
- unlink(git_path("%s", r->name));
+ unlink_or_warn(git_path("%s", r->name));
unlock_ref(lock);
}
}
/* FALLTHROUGH */
case OPTION_BOOLEAN:
case OPTION_BIT:
+ case OPTION_NEGBIT:
case OPTION_SET_INT:
case OPTION_SET_PTR:
return opterror(opt, "takes no value", flags);
*(int *)opt->value |= opt->defval;
return 0;
+ case OPTION_NEGBIT:
+ if (unset)
+ *(int *)opt->value |= opt->defval;
+ else
+ *(int *)opt->value &= ~opt->defval;
+ return 0;
+
case OPTION_BOOLEAN:
*(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
return 0;
static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
{
+ const struct option *numopt = NULL;
+
for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
return get_value(p, options, OPT_SHORT);
}
+
+ /*
+ * Handle the numerical option later, explicit one-digit
+ * options take precedence over it.
+ */
+ if (options->type == OPTION_NUMBER)
+ numopt = options;
+ }
+ if (numopt && isdigit(*p->opt)) {
+ size_t len = 1;
+ char *arg;
+ int rc;
+
+ while (isdigit(p->opt[len]))
+ len++;
+ arg = xmemdupz(p->opt, len);
+ p->opt = p->opt[len] ? p->opt + len : NULL;
+ rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0;
+ free(arg);
+ return rc;
}
return -2;
}
return -2;
}
+static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
+ const struct option *options)
+{
+ for (; options->type != OPTION_END; options++) {
+ if (!(options->flags & PARSE_OPT_NODASH))
+ continue;
+ if ((options->flags & PARSE_OPT_OPTARG) ||
+ !(options->flags & PARSE_OPT_NOARG))
+ die("BUG: dashless options don't support arguments");
+ if (!(options->flags & PARSE_OPT_NONEG))
+ die("BUG: dashless options don't support negation");
+ if (options->long_name)
+ die("BUG: dashless options can't be long");
+ if (options->short_name == arg[0] && arg[1] == '\0')
+ return get_value(p, options, OPT_SHORT);
+ }
+ return -2;
+}
+
static void check_typos(const char *arg, const struct option *options)
{
if (strlen(arg) < 3)
const char *arg = ctx->argv[0];
if (*arg != '-' || !arg[1]) {
+ if (parse_nodash_opt(ctx, arg, options) == 0)
+ continue;
if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
break;
ctx->out[ctx->cpidx++] = ctx->argv[0];
continue;
pos = fprintf(stderr, " ");
- if (opts->short_name)
- pos += fprintf(stderr, "-%c", opts->short_name);
+ if (opts->short_name) {
+ if (opts->flags & PARSE_OPT_NODASH)
+ pos += fprintf(stderr, "%c", opts->short_name);
+ else
+ pos += fprintf(stderr, "-%c", opts->short_name);
+ }
if (opts->long_name && opts->short_name)
pos += fprintf(stderr, ", ");
if (opts->long_name)
pos += fprintf(stderr, "--%s", opts->long_name);
+ if (opts->type == OPTION_NUMBER)
+ pos += fprintf(stderr, "-NUM");
switch (opts->type) {
case OPTION_ARGUMENT:
pos += fprintf(stderr, " ...");
}
break;
- default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
+ default: /* OPTION_{BIT,BOOLEAN,NUMBER,SET_INT,SET_PTR} */
break;
}
OPTION_END,
OPTION_ARGUMENT,
OPTION_GROUP,
+ OPTION_NUMBER,
/* options with no arguments */
OPTION_BIT,
+ OPTION_NEGBIT,
OPTION_BOOLEAN, /* _INCR would have been a better name */
OPTION_SET_INT,
OPTION_SET_PTR,
PARSE_OPT_NONEG = 4,
PARSE_OPT_HIDDEN = 8,
PARSE_OPT_LASTARG_DEFAULT = 16,
+ PARSE_OPT_NODASH = 32,
};
struct option;
*
* `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.
*
* `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
- * the long one.
+ * PARSE_OPT_HIDDEN: this option is skipped in the default usage, and
+ * shown only in the full usage.
+ * PARSE_OPT_LASTARG_DEFAULT: if no argument is given, the default value
+ * is used.
+ * PARSE_OPT_NODASH: this option doesn't start with a dash.
*
* `callback`::
* pointer to the callback to use for OPTION_CALLBACK.
#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) }
#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
#define OPT_BIT(s, l, v, h, b) { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
+#define OPT_NEGBIT(s, l, v, h, b) { OPTION_NEGBIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) }
#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
parse_opt_approxidate_cb }
#define OPT_CALLBACK(s, l, v, a, h, f) \
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
+#define OPT_NUMBER_CALLBACK(v, h, f) \
+ { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, (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,
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,
if ($dir) {
$dir =~ m#^/# or $dir = $opts{Directory} . '/' . $dir;
- $opts{Repository} = $dir;
+ $opts{Repository} = abs_path($dir);
# If --git-dir went ok, this shouldn't die either.
my $prefix = $search->command_oneline('rev-parse', '--show-prefix');
my ($self, @args) = @_;
if ($self) {
$self->repo_path() and $ENV{'GIT_DIR'} = $self->repo_path();
+ $self->repo_path() and $self->wc_path()
+ and $ENV{'GIT_WORK_TREE'} = $self->wc_path();
$self->wc_path() and chdir($self->wc_path());
$self->wc_subdir() and chdir($self->wc_subdir());
}
(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);
}
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) {
* - it has ASCII control character, "~", "^", ":" or SP, anywhere, or
* - it ends with a "/".
* - it ends with ".lock"
+ * - it contains a "\" (backslash)
*/
static inline int bad_ref_char(int ch)
{
if (((unsigned) ch) <= ' ' ||
- ch == '~' || ch == '^' || ch == ':')
+ ch == '~' || ch == '^' || ch == ':' || ch == '\\')
return 1;
/* 2.13 Pattern Matching Notation */
if (ch == '?' || ch == '[') /* Unsupported */
}
}
-const char *prettify_ref(const struct ref *ref)
+const char *prettify_refname(const char *name)
{
- const char *name = ref->name;
return name + (
!prefixcmp(name, "refs/heads/") ? 11 :
!prefixcmp(name, "refs/tags/") ? 10 :
* name is a proper prefix of our refname.
*/
if (missing &&
- !is_refname_available(ref, NULL, get_packed_refs(), 0))
+ !is_refname_available(ref, NULL, get_packed_refs(), 0)) {
+ last_errno = ENOTDIR;
goto error_return;
+ }
lock->lk = xcalloc(1, sizeof(struct lock_file));
} else {
path = git_path("%s", refname);
}
- err = unlink(path);
- if (err && errno != ENOENT) {
+ err = unlink_or_warn(path);
+ if (err && errno != ENOENT)
ret = 1;
- error("unlink(%s) failed: %s",
- path, strerror(errno));
- }
+
if (!(delopt & REF_NODEREF))
lock->lk->filename[i] = '.';
}
*/
ret |= repack_without_ref(refname);
- err = unlink(git_path("logs/%s", lock->ref_name));
- if (err && errno != ENOENT)
- warning("unlink(%s) failed: %s",
- git_path("logs/%s", lock->ref_name), strerror(errno));
+ unlink_or_warn(git_path("logs/%s", lock->ref_name));
invalidate_cached_refs();
unlock_ref(lock);
return ret;
if (adjust_shared_perm(git_HEAD)) {
error("Unable to fix permissions on %s", lockpath);
error_unlink_return:
- unlink(lockpath);
+ unlink_or_warn(lockpath);
error_free_return:
free(git_HEAD);
return -1;
return;
}
-char *shorten_unambiguous_ref(const char *ref)
+char *shorten_unambiguous_ref(const char *ref, int strict)
{
int i;
static char **scanf_fmts;
/* 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))
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 < i; j++) {
+ 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
* short name is non-ambiguous if all previous rules
* haven't resolved to a valid ref
*/
- if (j == i)
+ if (j == rules_to_fail)
return short_name;
}
#define CHECK_REF_FORMAT_WILDCARD (-3)
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);
+extern const char *prettify_refname(const char *refname);
+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);
}
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"))
base = branch->merge[0]->dst;
if (!resolve_ref(base, sha1, 1, NULL))
return 0;
- theirs = lookup_commit(sha1);
+ theirs = lookup_commit_reference(sha1);
if (!theirs)
return 0;
if (!resolve_ref(branch->refname, sha1, 1, NULL))
return 0;
- ours = lookup_commit(sha1);
+ ours = lookup_commit_reference(sha1);
if (!ours)
return 0;
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++] = "--";
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",
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;
}
git_SHA1_Final(sha1, &ctx);
if (hunk != RR_CONTEXT) {
if (output)
- unlink(output);
+ unlink_or_warn(output);
return error("Could not parse conflict hunks in %s", path);
}
if (wrerror)
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;
}
/*
- * 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) {
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,
if (cmd->env) {
for (; *cmd->env; cmd->env++) {
if (strchr(*cmd->env, '='))
- putenv((char*)*cmd->env);
+ putenv((char *)*cmd->env);
else
unsetenv(*cmd->env);
}
send_mirror:1,
force_update:1,
use_thin_pack:1,
+ use_ofs_delta:1,
dry_run:1;
};
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 */
errs = errs | update_info_packs(force);
/* remove leftover rev-cache file if there is any */
- unlink(git_path("info/rev-cache"));
+ unlink_or_warn(git_path("info/rev-cache"));
return errs;
}
return error("packfile %s index unavailable", p->pack_name);
p->pack_fd = open(p->pack_name, O_RDONLY);
+ while (p->pack_fd < 0 && errno == EMFILE && unuse_one_window(p, -1))
+ p->pack_fd = open(p->pack_name, O_RDONLY);
if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
return -1;
&& (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)
sprintf(path, "%s/pack", objdir);
len = strlen(path);
dir = opendir(path);
+ while (!dir && errno == EMFILE && unuse_one_window(packed_git, -1))
+ dir = opendir(path);
if (!dir) {
if (errno != ENOENT)
error("unable to open object pack directory: %s: %s",
{
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;
/*
* left to unlink.
*/
if (ret && ret != EEXIST) {
+ try_rename:
if (!rename(tmpfile, filename))
goto out;
ret = errno;
}
- unlink(tmpfile);
+ unlink_or_warn(tmpfile);
if (ret) {
if (ret != EEXIST) {
return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret));
filename = sha1_file_name(sha1);
fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
+ while (fd < 0 && errno == EMFILE && unuse_one_window(packed_git, -1))
+ fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
if (fd < 0) {
if (errno == EACCES)
return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
} 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 },
};
* 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
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"'
svnrepo=$PWD/svnrepo
export svnrepo
+svnconf=$PWD/svnconf
+export svnconf
perl -w -e "
use SVN::Core;
test-chmtime +1 "$1"
}
+# We need this, because we should pass empty configuration directory to
+# the 'svn commit' to avoid automated property changes and other stuff
+# that could be set from user's configuration files in ~/.subversion.
+svn_cmd () {
+ [ -d "$svnconf" ] || mkdir "$svnconf"
+ orig_svncmd="$1"; shift
+ if [ -z "$orig_svncmd" ]; then
+ svn
+ return
+ fi
+ svn "$orig_svncmd" --config-dir "$svnconf" "$@"
+}
+
for d in \
"$SVN_HTTPD_PATH" \
/usr/sbin/apache2 \
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
-b, --boolean get a boolean
-4, --or4 bitwise-or boolean with ...0100
+ --neg-or4 same as --no-or4
-i, --integer <n> get a integer
-j <n> get a integer, too
Magic arguments
--quux means --quux
+ -NUM set integer to NUM
+ + same as -b
Standard options
--abbrev[=<n>] use <n> digits to display SHA-1s
test_cmp expect output
'
-# --or4
-# --no-or4
+test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' '
+ test-parse-options --set23 -bbbbb --neg-or4 > output 2> output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+'
+
+cat > expect <<EOF
+boolean: 6
+integer: 0
+timestamp: 0
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_BIT() works' '
+ test-parse-options -bb --or4 > output 2> output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+'
+
+test_expect_success 'OPT_NEGBIT() works' '
+ test-parse-options -bb --no-neg-or4 > output 2> output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+'
+
+test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' '
+ test-parse-options + + + + + + > output 2> output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+'
+
+cat > expect <<EOF
+boolean: 0
+integer: 12345
+timestamp: 0
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_NUMBER_CALLBACK() works' '
+ test-parse-options -12345 > output 2> output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+'
test_done
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 &&
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)" &&
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)"
'
check() {
echo "$2" >expected
- git config --get "$1" >actual
+ git config --get "$1" >actual 2>&1
test_cmp actual expected
}
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
--- /dev/null
+#!/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
--- /dev/null
+#!/bin/sh
+
+test_description='merge-recursive backend test'
+
+. ./test-lib.sh
+
+# A <- create some files
+# / \
+# B C <- cause rename/delete conflicts between B and C
+# / \
+# |\ /|
+# | D E |
+# | \ / |
+# | X |
+# | / \ |
+# | / \ |
+# |/ \|
+# F G <- merge E into B, D into C
+# \ /
+# \ /
+# \ /
+# H <- recursive merge crashes
+#
+
+# initialize
+test_expect_success 'setup repo with criss-cross history' '
+ mkdir data &&
+
+ # create a bunch of files
+ n=1 &&
+ while test $n -le 10
+ do
+ echo $n > data/$n &&
+ n=$(($n+1)) ||
+ break
+ done &&
+
+ # check them in
+ git add data &&
+ git commit -m A &&
+ git branch A &&
+
+ # a file in one branch
+ git checkout -b B A &&
+ git rm data/9 &&
+ git add data &&
+ git commit -m B &&
+
+ # with a branch off of it
+ git branch D &&
+
+ # put some commits on D
+ git checkout D &&
+ echo testD > data/testD &&
+ git add data &&
+ git commit -m D &&
+
+ # back up to the top, create another branch and cause
+ # a rename conflict with the file we deleted earlier
+ git checkout -b C A &&
+ git mv data/9 data/new-9 &&
+ git add data &&
+ git commit -m C &&
+
+ # with a branch off of it
+ git branch E &&
+
+ # put a commit on E
+ git checkout E &&
+ echo testE > data/testE &&
+ git add data &&
+ git commit -m E &&
+
+ # now, merge E into B
+ git checkout B &&
+ test_must_fail git merge E &&
+ # force-resolve
+ git add data &&
+ git commit -m F &&
+ git branch F &&
+
+ # and merge D into C
+ git checkout C &&
+ test_must_fail git merge D &&
+ # force-resolve
+ git add data &&
+ git commit -m G &&
+ git branch G
+'
+
+test_expect_success 'recursive merge between F and G, causes segfault' '
+ git merge F
+'
+
+test_done
git tag topic
'
+test_expect_success 'rebase on dirty worktree' '
+ echo dirty >> A &&
+ test_must_fail git rebase master'
+
+test_expect_success 'rebase on dirty cache' '
+ git add A &&
+ test_must_fail git rebase master'
+
test_expect_success 'rebase against master' '
+ git reset --hard HEAD &&
git rebase master'
+test_expect_success 'rebase against master twice' '
+ git rebase master 2>err &&
+ grep "Current branch my-topic-branch is up to date" err
+'
+
+test_expect_success 'rebase against master twice with --force' '
+ git rebase --force-rebase master >out &&
+ grep "Current branch my-topic-branch is up to date, rebase forced" out
+'
+
+test_expect_success 'rebase against master twice from another branch' '
+ git checkout my-topic-branch^ &&
+ git rebase master my-topic-branch 2>err &&
+ grep "Current branch my-topic-branch is up to date" err
+'
+
+test_expect_success 'rebase fast-forward to master' '
+ git checkout my-topic-branch^ &&
+ git rebase my-topic-branch 2>err &&
+ grep "Fast-forwarded HEAD to my-topic-branch" err
+'
+
test_expect_success \
'the rebase operation should not have destroyed author information' \
'! (git log | grep "Author:" | grep "<>")'
! ( git ls-files foobar | grep foobar )
'
+test_expect_success 'git add to resolve conflicts on otherwise ignored path' '
+ git reset --hard &&
+ H=$(git rev-parse :1/2/a) &&
+ (
+ echo "100644 $H 1 track-this"
+ echo "100644 $H 3 track-this"
+ ) | git update-index --index-info &&
+ echo track-this >>.gitignore &&
+ echo resolved >track-this &&
+ git add track-this
+'
+
test_done
# end of tests disabled when filemode is not usable
+test_expect_success 'setup again' '
+ git reset --hard &&
+ test_chmod +x file &&
+ echo content >>file
+'
+
+# Write the patch file with a new line at the top and bottom
+cat >patch <<EOF
+index 180b47c..b6f2c08 100644
+--- a/file
++++ b/file
+@@ -1,2 +1,4 @@
++firstline
+ baseline
+ content
++lastline
+EOF
+# Expected output, similar to the patch but w/ diff at the top
+cat >expected <<EOF
+diff --git a/file b/file
+index b6f2c08..61b9053 100755
+--- a/file
++++ b/file
+@@ -1,2 +1,4 @@
++firstline
+ baseline
+ content
++lastline
+EOF
+# Test splitting the first patch, then adding both
+test_expect_success 'add first line works' '
+ git commit -am "clear local changes" &&
+ git apply patch &&
+ (echo s; echo y; echo y) | git add -p file &&
+ git diff --cached > diff &&
+ test_cmp expected diff
+'
+
test_done
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='add -e basic tests'
+. ./test-lib.sh
+
+
+cat > file << EOF
+LO, praise of the prowess of people-kings
+of spear-armed Danes, in days long sped,
+we have heard, and what honor the athelings won!
+Oft Scyld the Scefing from squadroned foes,
+from many a tribe, the mead-bench tore,
+awing the earls. Since erst he lay
+friendless, a foundling, fate repaid him:
+for he waxed under welkin, in wealth he throve,
+till before him the folk, both far and near,
+who house by the whale-path, heard his mandate,
+gave him gifts: a good king he!
+EOF
+
+cat > second-part << EOF
+To him an heir was afterward born,
+a son in his halls, whom heaven sent
+to favor the folk, feeling their woe
+that erst they had lacked an earl for leader
+so long a while; the Lord endowed him,
+the Wielder of Wonder, with world's renown.
+EOF
+
+test_expect_success 'setup' '
+
+ git add file &&
+ test_tick &&
+ git commit -m initial file
+
+'
+
+cat > expected-patch << EOF
+diff --git a/file b/file
+index b9834b5..9020acb 100644
+--- a/file
++++ b/file
+@@ -1,11 +1,6 @@
+-LO, praise of the prowess of people-kings
+-of spear-armed Danes, in days long sped,
+-we have heard, and what honor the athelings won!
+-Oft Scyld the Scefing from squadroned foes,
+-from many a tribe, the mead-bench tore,
+-awing the earls. Since erst he lay
+-friendless, a foundling, fate repaid him:
+-for he waxed under welkin, in wealth he throve,
+-till before him the folk, both far and near,
+-who house by the whale-path, heard his mandate,
+-gave him gifts: a good king he!
++To him an heir was afterward born,
++a son in his halls, whom heaven sent
++to favor the folk, feeling their woe
++that erst they had lacked an earl for leader
++so long a while; the Lord endowed him,
++the Wielder of Wonder, with world's renown.
+EOF
+
+cat > patch << EOF
+diff --git a/file b/file
+index b9834b5..ef6e94c 100644
+--- a/file
++++ b/file
+@@ -3,1 +3,333 @@ of spear-armed Danes, in days long sped,
+ we have heard, and what honor the athelings won!
++
+ Oft Scyld the Scefing from squadroned foes,
+@@ -2,7 +1,5 @@ awing the earls. Since erst he lay
+ friendless, a foundling, fate repaid him:
++
+ for he waxed under welkin, in wealth he throve,
+EOF
+
+cat > expected << EOF
+diff --git a/file b/file
+index b9834b5..ef6e94c 100644
+--- a/file
++++ b/file
+@@ -1,10 +1,12 @@
+ LO, praise of the prowess of people-kings
+ of spear-armed Danes, in days long sped,
+ we have heard, and what honor the athelings won!
++
+ Oft Scyld the Scefing from squadroned foes,
+ from many a tribe, the mead-bench tore,
+ awing the earls. Since erst he lay
+ friendless, a foundling, fate repaid him:
++
+ for he waxed under welkin, in wealth he throve,
+ till before him the folk, both far and near,
+ who house by the whale-path, heard his mandate,
+EOF
+
+echo "#!$SHELL_PATH" >fake-editor.sh
+cat >> fake-editor.sh <<\EOF
+mv -f "$1" orig-patch &&
+mv -f patch "$1"
+EOF
+
+test_set_editor "$(pwd)/fake-editor.sh"
+chmod a+x fake-editor.sh
+
+test_expect_success 'add -e' '
+
+ cp second-part file &&
+ git add -e &&
+ test_cmp second-part file &&
+ test_cmp orig-patch expected-patch &&
+ git diff --cached > out &&
+ test_cmp out expected
+
+'
+
+test_done
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 '
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
$ git log --decorate --all
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (master)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:04:00 2006 +0000
Merge branch 'side'
-commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:03:00 2006 +0000
This is the second commit.
-commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial)
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (initial)
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:00:00 2006 +0000
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
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" '
'
+test_expect_success 'format.numbered && --keep-subject' '
+
+ git format-patch --keep-subject --stdout HEAD^ >patch4a &&
+ grep "^Subject: Third" patch4a
+
+'
+
test_expect_success 'format.numbered = auto' '
git config format.numbered auto
'
+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
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
-#!/bin/bash
+#!/bin/sh
#
# Copyright (c) Jim Meyering
#
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 &&
--- /dev/null
+#!/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
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2009 Stephen Boyd
+#
+
+test_description='git apply --build-fake-ancestor handling.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit 1 &&
+ test_commit 2 &&
+ mkdir sub &&
+ test_commit 3 sub/3 &&
+ test_commit 4
+'
+
+test_expect_success 'apply --build-fake-ancestor' '
+ git checkout 2 &&
+ echo "A" > 1.t &&
+ git diff > 1.patch &&
+ git reset --hard &&
+ git checkout 1 &&
+ git apply --build-fake-ancestor 1.ancestor 1.patch
+'
+
+test_expect_success 'apply --build-fake-ancestor in a subdirectory' '
+ git checkout 3 &&
+ echo "C" > sub/3.t &&
+ git diff > 3.patch &&
+ git reset --hard &&
+ git checkout 4 &&
+ (
+ cd sub &&
+ git apply --build-fake-ancestor 3.ancestor ../3.patch &&
+ test -f 3.ancestor
+ ) &&
+ git apply --build-fake-ancestor 3.ancestor 3.patch &&
+ test_cmp sub/3.ancestor 3.ancestor
+'
+
+test_done
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
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"
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
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
* | | | Merge branch 'side'
|\ \ \ \
| * | | | side-2
-| | | |/
-| | |/|
+| | |_|/
| |/| |
| * | | side-1
* | | | Second
* | | | sixth
-| | |/
-| |/|
+| |_|/
|/| |
* | | fifth
* | | fourth
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' \
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' \
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' \
--- /dev/null
+#!/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
# Copyright (c) 2005 Johannes Schindelin
#
-test_description='Testing multi_ack pack fetching
+test_description='Testing multi_ack pack fetching'
-'
. ./test-lib.sh
# Test fetch-pack/upload-pack pair.
# Some convenience functions
add () {
- name=$1
- text="$@"
- branch=`echo $name | sed -e 's/^\(.\).*$/\1/'`
- parents=""
+ name=$1 &&
+ text="$@" &&
+ branch=`echo $name | sed -e 's/^\(.\).*$/\1/'` &&
+ parents="" &&
- shift
+ shift &&
while test $1; do
- parents="$parents -p $1"
+ parents="$parents -p $1" &&
shift
- done
+ done &&
- echo "$text" > test.txt
- git update-index --add test.txt
- tree=$(git write-tree)
+ echo "$text" > test.txt &&
+ git update-index --add test.txt &&
+ tree=$(git write-tree) &&
# make sure timestamps are in correct order
- sec=$(($sec+1))
- commit=$(echo "$text" | GIT_AUTHOR_DATE=$sec \
- git commit-tree $tree $parents 2>>log2.txt)
- eval "$name=$commit; export $name"
- echo $commit > .git/refs/heads/$branch
+ test_tick &&
+ commit=$(echo "$text" | git commit-tree $tree $parents) &&
+ eval "$name=$commit; export $name" &&
+ echo $commit > .git/refs/heads/$branch &&
eval ${branch}TIP=$commit
}
-count_objects () {
- ls .git/objects/??/* 2>>log2.txt | wc -l | tr -d " "
-}
-
-test_expect_object_count () {
- message=$1
- count=$2
-
- output="$(count_objects)"
- test_expect_success \
- "new object count $message" \
- "test $count = $output"
-}
-
pull_to_client () {
- number=$1
- heads=$2
- count=$3
- no_strict_count_check=$4
-
- cd client
- test_expect_success "$number pull" \
- "git fetch-pack -k -v .. $heads"
- case "$heads" in *A*) echo $ATIP > .git/refs/heads/A;; esac
- case "$heads" in *B*) echo $BTIP > .git/refs/heads/B;; esac
- git symbolic-ref HEAD refs/heads/`echo $heads | sed -e 's/^\(.\).*$/\1/'`
-
- test_expect_success "fsck" 'git fsck --full > fsck.txt 2>&1'
-
- test_expect_success 'check downloaded results' \
- 'mv .git/objects/pack/pack-* . &&
- p=`ls -1 pack-*.pack` &&
- git unpack-objects <$p &&
- git fsck --full'
-
- test_expect_success "new object count after $number pull" \
- 'idx=`echo pack-*.idx` &&
- pack_count=`git show-index <$idx | wc -l` &&
- test $pack_count = $count'
- test -z "$pack_count" && pack_count=0
- if [ -z "$no_strict_count_check" ]; then
- test_expect_success "minimal count" "test $count = $pack_count"
- else
- test $count != $pack_count && \
- echo "WARNING: $pack_count objects transmitted, only $count of which were needed"
- fi
- rm -f pack-*
- cd ..
+ number=$1 &&
+ heads=$2 &&
+ count=$3 &&
+ test_expect_success "$number pull" '
+ (
+ cd client &&
+ git fetch-pack -k -v .. $heads &&
+
+ case "$heads" in
+ *A*)
+ echo $ATIP > .git/refs/heads/A;;
+ esac &&
+ case "$heads" in *B*)
+ echo $BTIP > .git/refs/heads/B;;
+ esac &&
+ git symbolic-ref HEAD refs/heads/`echo $heads \
+ | sed -e "s/^\(.\).*$/\1/"` &&
+
+ git fsck --full &&
+
+ mv .git/objects/pack/pack-* . &&
+ p=`ls -1 pack-*.pack` &&
+ git unpack-objects <$p &&
+ git fsck --full &&
+
+ idx=`echo pack-*.idx` &&
+ pack_count=`git show-index <$idx | wc -l` &&
+ test $pack_count = $count &&
+ rm -f pack-*
+ )
+ '
}
# Here begins the actual testing
# client pulls A20, B1. Then tracks only B. Then pulls A.
-(
+test_expect_success 'setup' '
mkdir client &&
- cd client &&
- git init 2>> log2.txt &&
- git config transfer.unpacklimit 0
-)
-
-add A1
-
-prev=1; cur=2; while [ $cur -le 10 ]; do
- add A$cur $(eval echo \$A$prev)
- prev=$cur
- cur=$(($cur+1))
-done
-
-add B1 $A1
-
-echo $ATIP > .git/refs/heads/A
-echo $BTIP > .git/refs/heads/B
-git symbolic-ref HEAD refs/heads/B
+ (
+ cd client &&
+ git init &&
+ git config transfer.unpacklimit 0
+ ) &&
+ add A1 &&
+ prev=1 &&
+ cur=2 &&
+ while [ $cur -le 10 ]; do
+ add A$cur $(eval echo \$A$prev) &&
+ prev=$cur &&
+ cur=$(($cur+1))
+ done &&
+ add B1 $A1
+ echo $ATIP > .git/refs/heads/A &&
+ echo $BTIP > .git/refs/heads/B &&
+ git symbolic-ref HEAD refs/heads/B
+'
pull_to_client 1st "B A" $((11*3))
-add A11 $A10
-
-prev=1; cur=2; while [ $cur -le 65 ]; do
- add B$cur $(eval echo \$B$prev)
- prev=$cur
- cur=$(($cur+1))
-done
+test_expect_success 'post 1st pull setup' '
+ add A11 $A10 &&
+ prev=1 &&
+ cur=2 &&
+ while [ $cur -le 65 ]; do
+ add B$cur $(eval echo \$B$prev) &&
+ prev=$cur &&
+ cur=$(($cur+1))
+ done
+'
pull_to_client 2nd "B" $((64*3))
-pull_to_client 3rd "A" $((1*3)) # old fails
-
-test_expect_success "clone shallow" 'git clone --depth 2 "file://$(pwd)/." shallow'
+pull_to_client 3rd "A" $((1*3))
-(cd shallow; git count-objects -v) > count.shallow
-
-test_expect_success "clone shallow object count" \
- "test \"in-pack: 18\" = \"$(grep in-pack count.shallow)\""
-
-count_output () {
- sed -e '/^in-pack:/d' -e '/^packs:/d' -e '/^size-pack:/d' -e '/: 0$/d' "$1"
-}
+test_expect_success 'clone shallow' '
+ git clone --depth 2 "file://$(pwd)/." shallow
+'
-test_expect_success "clone shallow object count (part 2)" '
- test -z "$(count_output count.shallow)"
+test_expect_success 'clone shallow object count' '
+ (
+ cd shallow &&
+ git count-objects -v
+ ) > count.shallow &&
+ grep "^in-pack: 18" count.shallow
'
-test_expect_success "fsck in shallow repo" \
- "(cd shallow; git fsck --full)"
+test_expect_success 'clone shallow object count (part 2)' '
+ sed -e "/^in-pack:/d" -e "/^packs:/d" -e "/^size-pack:/d" \
+ -e "/: 0$/d" count.shallow > count_output &&
+ ! test -s count_output
+'
-#test_done; exit
+test_expect_success 'fsck in shallow repo' '
+ (
+ cd shallow &&
+ git fsck --full
+ )
+'
-add B66 $B65
-add B67 $B66
+test_expect_success 'add two more' '
+ add B66 $B65 &&
+ add B67 $B66
+'
-test_expect_success "pull in shallow repo" \
- "(cd shallow; git pull .. B)"
+test_expect_success 'pull in shallow repo' '
+ (
+ cd shallow &&
+ git pull .. B
+ )
+'
-(cd shallow; git count-objects -v) > count.shallow
-test_expect_success "clone shallow object count" \
- "test \"count: 6\" = \"$(grep count count.shallow)\""
+test_expect_success 'clone shallow object count' '
+ (
+ cd shallow &&
+ git count-objects -v
+ ) > count.shallow &&
+ grep "^count: 6" count.shallow
+'
-add B68 $B67
-add B69 $B68
+test_expect_success 'add two more (part 2)' '
+ add B68 $B67 &&
+ add B69 $B68
+'
-test_expect_success "deepening pull in shallow repo" \
- "(cd shallow; git pull --depth 4 .. B)"
+test_expect_success 'deepening pull in shallow repo' '
+ (
+ cd shallow &&
+ git pull --depth 4 .. B
+ )
+'
-(cd shallow; git count-objects -v) > count.shallow
-test_expect_success "clone shallow object count" \
- "test \"count: 12\" = \"$(grep count count.shallow)\""
+test_expect_success 'clone shallow object count' '
+ (
+ cd shallow &&
+ git count-objects -v
+ ) > count.shallow &&
+ grep "^count: 12" count.shallow
+'
-test_expect_success "deepening fetch in shallow repo" \
- "(cd shallow; git fetch --depth 4 .. A:A)"
+test_expect_success 'deepening fetch in shallow repo' '
+ (
+ cd shallow &&
+ git fetch --depth 4 .. A:A
+ )
+'
-(cd shallow; git count-objects -v) > count.shallow
-test_expect_success "clone shallow object count" \
- "test \"count: 18\" = \"$(grep count count.shallow)\""
+test_expect_success 'clone shallow object count' '
+ (
+ cd shallow &&
+ git count-objects -v
+ ) > count.shallow &&
+ grep "^count: 18" count.shallow
+'
-test_expect_success "pull in shallow repo with missing merge base" \
- "(cd shallow && test_must_fail git pull --depth 4 .. A)"
+test_expect_success 'pull in shallow repo with missing merge base' '
+ (
+ cd shallow &&
+ test_must_fail git pull --depth 4 .. A
+ )
+'
test_done
grep "dangling symref" err
'
+test_expect_success 'show empty remote' '
+
+ test_create_repo empty &&
+ git clone empty empty-clone &&
+ (
+ cd empty-clone &&
+ git remote show origin
+ )
+'
+
test_done
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
git bisect reset
'
-check_trace() {
- grep "$1" "$GIT_TRACE" | grep "\^$2" | grep "$3" >/dev/null
-}
-
test_expect_success 'optimized merge base checks' '
- GIT_TRACE="$(pwd)/trace.log" &&
- export GIT_TRACE &&
git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt &&
grep "merge base must be tested" my_bisect_log.txt &&
grep "$HASH4" my_bisect_log.txt &&
- check_trace "rev-list" "$HASH7" "$SIDE_HASH7" &&
git bisect good > my_bisect_log2.txt &&
test -f ".git/BISECT_ANCESTORS_OK" &&
test "$HASH6" = $(git rev-parse --verify HEAD) &&
- : > "$GIT_TRACE" &&
git bisect bad > my_bisect_log3.txt &&
- test_must_fail check_trace "rev-list" "$HASH6" "$SIDE_HASH7" &&
git bisect good "$A_HASH" > my_bisect_log4.txt &&
grep "merge base must be tested" my_bisect_log4.txt &&
- test_must_fail test -f ".git/BISECT_ANCESTORS_OK" &&
- check_trace "rev-list" "$HASH6" "$A_HASH" &&
- unset GIT_TRACE
+ test_must_fail test -f ".git/BISECT_ANCESTORS_OK"
'
# This creates another side branch called "parallel" with some files
grep "have 1 and 1 different" actual
'
+test_expect_success 'status when tracking lightweight tags' '
+ git checkout master &&
+ git tag light &&
+ git branch --track lighttrack light >actual &&
+ grep "set up to track" actual &&
+ git checkout lighttrack
+'
+test_expect_success 'status when tracking annotated tags' '
+ git checkout master &&
+ git tag -m heavy heavy &&
+ git branch --track heavytrack heavy >actual &&
+ grep "set up to track" actual &&
+ git checkout heavytrack
+'
test_done
test_cmp expected actual
'
+test_expect_success 'merge-msg -F' '
+
+ git config --unset-all merge.log
+ git config --unset-all merge.summary
+ git config merge.summary yes &&
+
+ git checkout master &&
+ setdate &&
+ git fetch . left right &&
+
+ git fmt-merge-msg -F .git/FETCH_HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'merge-msg -F in subdirectory' '
+
+ git config --unset-all merge.log
+ git config --unset-all merge.summary
+ git config merge.summary yes &&
+
+ git checkout master &&
+ setdate &&
+ git fetch . left right &&
+ mkdir sub &&
+ cp .git/FETCH_HEAD sub/FETCH_HEAD &&
+ (
+ cd sub &&
+ git fmt-merge-msg -F FETCH_HEAD >../actual
+ ) &&
+ test_cmp expected actual
+'
+
test_done
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 &&
test_cmp expected actual
'
+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 &&
echo foo mmap bar_mmap
echo foo_mmap bar mmap baz
} >file &&
+ echo ww w >w &&
echo x x xx x >x &&
echo y yy >y &&
echo zzz > z &&
mkdir t &&
echo test >t/t &&
- git add file x y z t/t &&
+ git add file w x y z t/t &&
test_tick &&
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 expected actual
'
+ test_expect_success "grep -w $L (w)" '
+ : >expected &&
+ ! git grep -n -w -e "^w" >actual &&
+ test_cmp expected actual
+ '
+
test_expect_success "grep -w $L (x)" '
{
echo ${HC}x:1:x x xx x
'
+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
)
'
+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 &&
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' '
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2009, Red Hat Inc, Author: Michael S. Tsirkin (mst@redhat.com)
+#
+
+test_description='test clone --reference'
+. ./test-lib.sh
+
+base_dir=`pwd`
+
+U=$base_dir/UPLOAD_LOG
+
+test_expect_success 'preparing first repository' \
+'test_create_repo A && cd A &&
+echo first > file1 &&
+git add file1 &&
+git commit -m A-initial'
+
+cd "$base_dir"
+
+test_expect_success 'preparing second repository' \
+'git clone A B && cd B &&
+echo second > file2 &&
+git add file2 &&
+git commit -m B-addition &&
+git repack -a -d &&
+git prune'
+
+cd "$base_dir"
+
+test_expect_success 'preparing supermodule' \
+'test_create_repo super && cd super &&
+echo file > file &&
+git add file &&
+git commit -m B-super-initial'
+
+cd "$base_dir"
+
+test_expect_success 'submodule add --reference' \
+'cd super && git submodule add --reference ../B "file://$base_dir/A" sub &&
+git commit -m B-super-added'
+
+cd "$base_dir"
+
+test_expect_success 'after add: existence of info/alternates' \
+'test `wc -l <super/sub/.git/objects/info/alternates` = 1'
+
+cd "$base_dir"
+
+test_expect_success 'that reference gets used with add' \
+'cd super/sub &&
+echo "0 objects, 0 kilobytes" > expected &&
+git count-objects > current &&
+diff expected current'
+
+cd "$base_dir"
+
+test_expect_success 'cloning supermodule' \
+'git clone super super-clone'
+
+cd "$base_dir"
+
+test_expect_success 'update with reference' \
+'cd super-clone && git submodule update --init --reference ../B'
+
+cd "$base_dir"
+
+test_expect_success 'after update: existence of info/alternates' \
+'test `wc -l <super-clone/sub/.git/objects/info/alternates` = 1'
+
+cd "$base_dir"
+
+test_expect_success 'that reference gets used with update' \
+'cd super-clone/sub &&
+echo "0 objects, 0 kilobytes" > expected &&
+git count-objects > current &&
+diff expected current'
+
+cd "$base_dir"
+
+test_done
commit_msg_is "Log with foo word"
'
+test_expect_success 'commit -F overrides -t' '
+ (
+ cd subdir &&
+ echo "-F log" > f.log &&
+ echo "-t template" > t.template &&
+ git commit --allow-empty -F f.log -t t.template
+ ) &&
+ commit_msg_is "-F log"
+'
+
test_done
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 &&
--- /dev/null
+#!/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
test_expect_success \
'blame respects i18n.commitencoding' '
git blame --incremental file | \
- grep "^\(author\|summary\) " > actual &&
+ egrep "^(author|summary) " > actual &&
test_cmp actual expected
'
'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
'
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
'
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
'
--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>"
'
echo "zzz" > bar/zzz &&
echo "#!/bin/sh" > exec.sh &&
chmod +x exec.sh &&
- svn import -m "import for git svn" . "$svnrepo" >/dev/null &&
+ svn_cmd import -m "import for git svn" . "$svnrepo" >/dev/null &&
cd .. &&
rm -rf import &&
git svn init "$svnrepo"'
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch &&
- svn up "$SVN_TREE" &&
+ svn_cmd up "$SVN_TREE" &&
test -d "$SVN_TREE"/dir && test ! -d "$SVN_TREE"/dir/a'
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
- svn up "$SVN_TREE" &&
+ svn_cmd up "$SVN_TREE" &&
test ! -x "$SVN_TREE"/exec.sh'
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
- svn up "$SVN_TREE" &&
+ svn_cmd up "$SVN_TREE" &&
test -x "$SVN_TREE"/exec.sh'
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
- svn up "$SVN_TREE" &&
+ svn_cmd up "$SVN_TREE" &&
test -L "$SVN_TREE"/exec.sh'
name='new symlink is added to a file that was also just made executable'
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
- svn up "$SVN_TREE" &&
+ svn_cmd up "$SVN_TREE" &&
test -x "$SVN_TREE"/bar/zzz &&
test -L "$SVN_TREE"/exec-2.sh'
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
- svn up "$SVN_TREE" &&
+ svn_cmd up "$SVN_TREE" &&
test -f "$SVN_TREE"/exec-2.sh &&
test ! -L "$SVN_TREE"/exec-2.sh &&
test_cmp help "$SVN_TREE"/exec-2.sh'
printf "\r\n" > empty_crlf
a_empty_crlf=`git hash-object -w empty_crlf`
- svn import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null
+ svn_cmd import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null
cd ..
rm -rf import
'cd test_wc &&
echo Greetings >> kw.c &&
poke kw.c &&
- svn commit -m "Not yet an Id" &&
+ svn_cmd commit -m "Not yet an Id" &&
echo Hello world >> kw.c &&
poke kw.c &&
- svn commit -m "Modified file, but still not yet an Id" &&
- svn propset svn:keywords Id kw.c &&
+ svn_cmd commit -m "Modified file, but still not yet an Id" &&
+ svn_cmd propset svn:keywords Id kw.c &&
poke kw.c &&
- svn commit -m "Propset Id" &&
+ svn_cmd commit -m "Propset Id" &&
cd ..'
test_expect_success 'initialize git svn' 'git svn init "$svnrepo"'
test_expect_success "propset CR on crlf files" \
'cd test_wc &&
- svn propset svn:eol-style CR empty &&
- svn propset svn:eol-style CR crlf &&
- svn propset svn:eol-style CR ne_crlf &&
- svn commit -m "propset CR on crlf files" &&
+ svn_cmd propset svn:eol-style CR empty &&
+ svn_cmd propset svn:eol-style CR crlf &&
+ svn_cmd propset svn:eol-style CR ne_crlf &&
+ svn_cmd commit -m "propset CR on crlf files" &&
cd ..'
test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
'git svn fetch &&
git pull . ${remotes_git_svn} &&
- svn co "$svnrepo" new_wc'
+ svn_cmd co "$svnrepo" new_wc'
for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
do
a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git hash-object --stdin`
a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git hash-object --stdin`
test_expect_success 'Set CRLF on cr files' \
- 'svn propset svn:eol-style CRLF cr &&
- svn propset svn:eol-style CRLF ne_cr &&
- svn propset svn:keywords Id cr &&
- svn propset svn:keywords Id ne_cr &&
- svn commit -m "propset CRLF on cr files"'
+ 'svn_cmd propset svn:eol-style CRLF cr &&
+ svn_cmd propset svn:eol-style CRLF ne_cr &&
+ svn_cmd propset svn:keywords Id cr &&
+ svn_cmd propset svn:keywords Id ne_cr &&
+ svn_cmd commit -m "propset CRLF on cr files"'
cd ..
test_expect_success 'fetch and pull latest from svn' \
'git svn fetch && git pull . ${remotes_git_svn}'
cd test_wc &&
mkdir -p deeply/nested/directory &&
touch deeply/nested/directory/.keep &&
- svn add deeply &&
- svn up &&
- svn propset -R svn:ignore 'no-such-file*' .
- svn commit -m 'propset svn:ignore'
+ svn_cmd add deeply &&
+ svn_cmd up &&
+ svn_cmd propset -R svn:ignore 'no-such-file*' .
+ svn_cmd commit -m 'propset svn:ignore'
cd .. &&
git svn show-ignore > show-ignore.got &&
cmp show-ignore.expect show-ignore.got
mkdir -p deeply/nested/directory/number/2 &&
echo foo > deeply/nested/directory/number/1/file &&
echo foo > deeply/nested/directory/number/2/another &&
- svn import -m "import for git svn" . "$svnrepo" &&
+ svn_cmd import -m "import for git svn" . "$svnrepo" &&
cd ..
'
git rm -f deeply/nested/directory/number/2/another &&
git commit -a -m "remove another" &&
git svn set-tree --rmdir HEAD &&
- svn ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1
+ svn_cmd ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1
'
mkdir import &&
mkdir import/trunk &&
echo hello >> import/trunk/README &&
- svn import -m initial import "$svnrepo" &&
+ svn_cmd import -m initial import "$svnrepo" &&
rm -rf import &&
- svn co "$svnrepo"/trunk trunk &&
+ svn_cmd co "$svnrepo"/trunk trunk &&
echo bye bye >> trunk/README &&
- svn rm -m "gone" "$svnrepo"/trunk &&
+ svn_cmd rm -m "gone" "$svnrepo"/trunk &&
rm -rf trunk &&
mkdir trunk &&
echo "new" > trunk/FOLLOWME &&
- svn import -m "new trunk" trunk "$svnrepo"/trunk
+ svn_cmd import -m "new trunk" trunk "$svnrepo"/trunk
'
test_expect_success 'clone repo with git' '
cd import &&
mkdir -p trunk &&
echo hello > trunk/readme &&
- svn import -m "initial" . "$svnrepo" &&
+ svn_cmd import -m "initial" . "$svnrepo" &&
cd .. &&
- svn co "$svnrepo" wc &&
+ svn_cmd co "$svnrepo" wc &&
cd wc &&
echo world >> trunk/readme &&
poke trunk/readme &&
- svn commit -m "another commit" &&
- svn up &&
- svn mv trunk thunk &&
+ svn_cmd commit -m "another commit" &&
+ svn_cmd up &&
+ svn_cmd mv trunk thunk &&
echo goodbye >> thunk/readme &&
poke thunk/readme &&
- svn commit -m "bye now" &&
+ svn_cmd commit -m "bye now" &&
cd ..
'
'
test_expect_success 'follow deleted parent' '
- (svn cp -m "resurrecting trunk as junk" \
+ (svn_cmd cp -m "resurrecting trunk as junk" \
"$svnrepo"/trunk@2 "$svnrepo"/junk ||
svn cp -m "resurrecting trunk as junk" \
-r2 "$svnrepo"/trunk "$svnrepo"/junk) &&
'
test_expect_success 'follow deleted directory' '
- svn mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye &&
- svn rm -m "remove glob" "$svnrepo"/glob &&
+ svn_cmd mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye &&
+ svn_cmd rm -m "remove glob" "$svnrepo"/glob &&
git svn init --minimize-url -i glob "$svnrepo"/glob &&
git svn fetch -i glob &&
test "`git cat-file blob refs/remotes/glob:blob/bye`" = hi &&
cd import &&
svn import -m "r9270 test" . "$svnrepo"/r9270 &&
cd .. &&
- svn co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+ svn_cmd co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
cd r9270 &&
svn mkdir native &&
svn mv t native/t &&
'
test_expect_success "track initial change if it was only made to parent" '
- svn cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk &&
+ svn_cmd cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk &&
git svn init --minimize-url -i r9270-d \
"$svnrepo"/r9270/drunk/subversion/bindings/swig/perl/native/t &&
git svn fetch -i r9270-d &&
test_expect_success "follow-parent is atomic" '
(
cd wc &&
- svn up &&
- svn mkdir stunk &&
+ svn_cmd up &&
+ svn_cmd mkdir stunk &&
echo "trunk stunk" > stunk/readme &&
- svn add stunk/readme &&
- svn ci -m "trunk stunk" &&
+ svn_cmd add stunk/readme &&
+ svn_cmd ci -m "trunk stunk" &&
echo "stunk like junk" >> stunk/readme &&
- svn ci -m "really stunk" &&
+ svn_cmd ci -m "really stunk" &&
echo "stink stank stunk" >> stunk/readme &&
- svn ci -m "even the grinch agrees"
+ svn_cmd ci -m "even the grinch agrees"
) &&
- svn copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk &&
+ svn_cmd copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk &&
{ svn cp -m "early stunk flunked too" \
"$svnrepo"/stunk@17 "$svnrepo"/flunked ||
- svn cp -m "early stunk flunked too" \
+ svn_cmd cp -m "early stunk flunked too" \
-r17 "$svnrepo"/stunk "$svnrepo"/flunked; } &&
git svn init --minimize-url -i stunk "$svnrepo"/stunk &&
git svn fetch -i stunk &&
'
test_expect_success "track multi-parent paths" '
- svn cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
+ svn_cmd cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
git svn multi-fetch &&
test `git cat-file commit refs/remotes/glob | \
grep "^parent " | wc -l` -eq 2
mkdir import &&
cd import &&
echo hello > readme &&
- svn import -m "initial" . "$svnrepo" &&
+ svn_cmd import -m "initial" . "$svnrepo" &&
cd .. &&
echo hello > readme &&
git update-index --add readme &&
test_expect_success 'test the commit-diff command' '
test -n "$prev" && test -n "$head" &&
git svn commit-diff -r1 "$prev" "$head" "$svnrepo" &&
- svn co "$svnrepo" wc &&
+ svn_cmd co "$svnrepo" wc &&
cmp readme wc/readme
'
test_expect_success 'commit-diff to a sub-directory (with git svn config)' '
- svn import -m "sub-directory" import "$svnrepo"/subdir &&
+ svn_cmd import -m "sub-directory" import "$svnrepo"/subdir &&
git svn init --minimize-url "$svnrepo"/subdir &&
git svn fetch &&
git svn commit-diff -r3 "$prev" "$head" &&
- svn cat "$svnrepo"/subdir/readme > readme.2 &&
+ svn_cmd cat "$svnrepo"/subdir/readme > readme.2 &&
cmp readme readme.2
'
mkdir import &&
cd import &&
echo initial > file &&
- svn import -m "initial" . "$svnrepo" &&
+ svn_cmd import -m "initial" . "$svnrepo" &&
cd .. &&
echo initial > file &&
git update-index --add file &&
git commit -a -m "initial"
'
test_expect_success 'commit change from svn side' '
- svn co "$svnrepo" t.svn &&
+ svn_cmd co "$svnrepo" t.svn &&
cd t.svn &&
echo second line from svn >> file &&
poke file &&
- svn commit -m "second line from svn" &&
+ svn_cmd commit -m "second line from svn" &&
cd .. &&
rm -rf t.svn
'
git svn init "$svnrepo" &&
git svn fetch &&
git reset --hard refs/${remotes_git_svn} &&
- svn co "$svnrepo" t.svn &&
+ svn_cmd co "$svnrepo" t.svn &&
cd t.svn &&
echo fourth line from svn >> file &&
poke file &&
- svn commit -m "fourth line from svn" &&
+ svn_cmd commit -m "fourth line from svn" &&
cd .. &&
rm -rf t.svn &&
echo "fourth line from git" >> file &&
"
test_expect_success 'commit another change from svn side' '
- svn co "$svnrepo" t.svn &&
+ svn_cmd co "$svnrepo" t.svn &&
cd t.svn &&
echo third line from svn >> file &&
poke file &&
- svn commit -m "third line from svn" &&
+ svn_cmd commit -m "third line from svn" &&
cd .. &&
rm -rf t.svn
'
mkdir -p $i && \
echo hello >> $i/README || exit 1
done && \
- svn import -m test . "$svnrepo"
+ svn_cmd import -m test . "$svnrepo"
cd .. &&
git svn init "$svnrepo" &&
git svn fetch &&
mkdir -p trunk/src/a trunk/src/b trunk/doc &&
echo "hello world" > trunk/src/a/readme &&
echo "goodbye world" > trunk/src/b/readme &&
- svn import -m "initial" trunk "$svnrepo"/trunk &&
- svn co "$svnrepo" tmp &&
+ svn_cmd import -m "initial" trunk "$svnrepo"/trunk &&
+ svn_cmd co "$svnrepo" tmp &&
(
cd tmp &&
mkdir branches tags &&
- svn add branches tags &&
- svn cp trunk branches/start &&
- svn commit -m "start a new branch" &&
- svn up &&
+ svn_cmd add branches tags &&
+ svn_cmd cp trunk branches/start &&
+ svn_cmd commit -m "start a new branch" &&
+ svn_cmd up &&
echo "hi" >> branches/start/src/b/readme &&
poke branches/start/src/b/readme &&
echo "hey" >> branches/start/src/a/readme &&
poke branches/start/src/a/readme &&
- svn commit -m "hi" &&
- svn up &&
- svn cp branches/start tags/end &&
+ svn_cmd commit -m "hi" &&
+ svn_cmd up &&
+ svn_cmd cp branches/start tags/end &&
echo "bye" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
echo "aye" >> tags/end/src/a/readme &&
poke tags/end/src/a/readme &&
- svn commit -m "the end" &&
+ svn_cmd commit -m "the end" &&
echo "byebye" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
- svn commit -m "nothing to see here"
+ svn_cmd commit -m "nothing to see here"
) &&
git config --add svn-remote.svn.url "$svnrepo" &&
git config --add svn-remote.svn.fetch \
cd tmp &&
echo "try try" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
- svn commit -m "try to try"
+ svn_cmd commit -m "try to try"
) &&
git svn fetch two &&
test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
cd tmp &&
echo "try try" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
- svn commit -m "try to try"
+ svn_cmd commit -m "try to try"
) &&
test_must_fail git svn fetch three 2> stderr.three &&
test_cmp expect.three stderr.three
mkdir -p trunk/src/a trunk/src/b trunk/doc &&
echo "hello world" > trunk/src/a/readme &&
echo "goodbye world" > trunk/src/b/readme &&
- svn import -m "initial" trunk "$svnrepo"/trunk &&
- svn co "$svnrepo" tmp &&
+ svn_cmd import -m "initial" trunk "$svnrepo"/trunk &&
+ svn_cmd co "$svnrepo" tmp &&
(
cd tmp &&
mkdir branches branches/v1 tags &&
- svn add branches tags &&
- svn cp trunk branches/v1/start &&
- svn commit -m "start a new branch" &&
- svn up &&
+ svn_cmd add branches tags &&
+ svn_cmd cp trunk branches/v1/start &&
+ svn_cmd commit -m "start a new branch" &&
+ svn_cmd up &&
echo "hi" >> branches/v1/start/src/b/readme &&
poke branches/v1/start/src/b/readme &&
echo "hey" >> branches/v1/start/src/a/readme &&
poke branches/v1/start/src/a/readme &&
- svn commit -m "hi" &&
- svn up &&
- svn cp branches/v1/start tags/end &&
+ svn_cmd commit -m "hi" &&
+ svn_cmd up &&
+ svn_cmd cp branches/v1/start tags/end &&
echo "bye" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
echo "aye" >> tags/end/src/a/readme &&
poke tags/end/src/a/readme &&
- svn commit -m "the end" &&
+ svn_cmd commit -m "the end" &&
echo "byebye" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
- svn commit -m "nothing to see here"
+ svn_cmd commit -m "nothing to see here"
) &&
git config --add svn-remote.svn.url "$svnrepo" &&
git config --add svn-remote.svn.fetch \
cd tmp &&
echo "try try" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
- svn commit -m "try to try"
+ svn_cmd commit -m "try to try"
) &&
git svn fetch two &&
test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
(
cd tmp &&
mkdir branches/v2 &&
- svn add branches/v2 &&
- svn cp trunk branches/v2/start &&
- svn commit -m "Another versioned branch" &&
- svn up &&
+ svn_cmd add branches/v2 &&
+ svn_cmd cp trunk branches/v2/start &&
+ svn_cmd commit -m "Another versioned branch" &&
+ svn_cmd up &&
echo "hello" >> branches/v2/start/src/b/readme &&
poke branches/v2/start/src/b/readme &&
echo "howdy" >> branches/v2/start/src/a/readme &&
poke branches/v2/start/src/a/readme &&
- svn commit -m "Changed 2 in v2/start" &&
- svn up &&
- svn cp branches/v2/start tags/next &&
+ svn_cmd commit -m "Changed 2 in v2/start" &&
+ svn_cmd up &&
+ svn_cmd cp branches/v2/start tags/next &&
echo "bye" >> tags/next/src/b/readme &&
poke tags/next/src/b/readme &&
echo "aye" >> tags/next/src/a/readme &&
poke tags/next/src/a/readme &&
- svn commit -m "adding more" &&
+ svn_cmd commit -m "adding more" &&
echo "byebye" >> tags/next/src/b/readme &&
poke tags/next/src/b/readme &&
- svn commit -m "adios"
+ svn_cmd commit -m "adios"
) &&
git config --add svn-remote.four.url "$svnrepo" &&
git config --add svn-remote.four.fetch trunk:refs/remotes/four/trunk &&
cd tmp &&
echo "try try" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
- svn commit -m "try to try"
+ svn_cmd commit -m "try to try"
) &&
test_must_fail git svn fetch three 2> stderr.three &&
test_cmp expect.three stderr.three
require_svnserve
test_expect_success 'start tracking an empty repo' '
- svn mkdir -m "empty dir" "$svnrepo"/empty-dir &&
+ svn_cmd mkdir -m "empty dir" "$svnrepo"/empty-dir &&
echo "[general]" > "$rawsvnrepo"/conf/svnserve.conf &&
echo anon-access = write >> "$rawsvnrepo"/conf/svnserve.conf &&
start_svnserve &&
}
test_expect_success 'setup svn repository' '
- svn co "$svnrepo" mysvnwork &&
+ svn_cmd co "$svnrepo" mysvnwork &&
mkdir -p mysvnwork/trunk &&
cd mysvnwork &&
big_text_block >> trunk/README &&
- svn add trunk &&
- svn ci -m "first commit" trunk &&
+ svn_cmd add trunk &&
+ svn_cmd ci -m "first commit" trunk &&
cd ..
'
mkdir -p $i && \
echo hello >> $i/README || exit 1
done && \
- svn import -m test . "$svnrepo"
+ svn_cmd import -m test . "$svnrepo"
cd .. &&
git svn init "$svnrepo" -T trunk -b branches -t tags &&
git svn fetch &&
test_expect_success 'setup svnrepo' '
mkdir project project/trunk project/branches project/tags &&
echo foo > project/trunk/foo &&
- svn import -m "$test_description" project "$svnrepo"/project &&
+ svn_cmd import -m "$test_description" project "$svnrepo"/project &&
rm -rf project
'
test_expect_success 'setup svnrepo' '
mkdir project project/trunk project/branches project/tags &&
echo foo > project/trunk/foo &&
- svn import -m "$test_description" project "$svnrepo/pr ject" &&
+ svn_cmd import -m "$test_description" project "$svnrepo/pr ject" &&
rm -rf project &&
- svn cp -m "fun" "$svnrepo/pr ject/trunk" \
+ svn_cmd cp -m "fun" "$svnrepo/pr ject/trunk" \
"$svnrepo/pr ject/branches/fun plugin" &&
- svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \
+ svn_cmd cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \
"$svnrepo/pr ject/branches/more fun plugin!" &&
- svn cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \
+ svn_cmd cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \
"$svnrepo/pr ject/branches/$scary_uri" &&
start_httpd
'
. ./lib-git-svn.sh
# Tested with: svn, version 1.4.4 (r25188)
-v=`svn --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'`
+v=`svn_cmd --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'`
case $v in
1.[45].*)
;;
my $atime = $mtime;
utime $atime, $mtime, $git_file;
}
- ' "`svn info $2 | grep '^Text Last Updated:'`" "$1"
+ ' "`svn_cmd info $2 | grep '^Text Last Updated:'`" "$1"
}
quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')"
mkdir directory &&
touch directory/.placeholder &&
ln -s directory symlink-directory &&
- svn import -m "initial" . "$svnrepo" &&
+ svn_cmd import -m "initial" . "$svnrepo" &&
cd .. &&
- svn co "$svnrepo" svnwc &&
+ svn_cmd co "$svnrepo" svnwc &&
cd svnwc &&
echo foo > foo &&
- svn add foo &&
- svn commit -m "change outside directory" &&
- svn update &&
+ svn_cmd add foo &&
+ svn_cmd commit -m "change outside directory" &&
+ svn_cmd update &&
cd .. &&
mkdir gitwc &&
cd gitwc &&
cp gitwc/added-file svnwc/added-file &&
ptouch gitwc/added-file svnwc/added-file &&
cd svnwc &&
- svn add added-file > /dev/null &&
+ svn_cmd add added-file > /dev/null &&
cd .. &&
(cd svnwc; svn info added-file) > expected.info-added-file &&
(cd gitwc; git svn info added-file) > actual.info-added-file &&
ptouch gitwc/added-directory svnwc/added-directory &&
touch gitwc/added-directory/.placeholder &&
cd svnwc &&
- svn add added-directory > /dev/null &&
+ svn_cmd add added-directory > /dev/null &&
cd .. &&
cd gitwc &&
git add added-directory &&
cd .. &&
cd svnwc &&
ln -s added-file added-symlink-file &&
- svn add added-symlink-file > /dev/null &&
+ svn_cmd add added-symlink-file > /dev/null &&
cd .. &&
ptouch gitwc/added-symlink-file svnwc/added-symlink-file &&
(cd svnwc; svn info added-symlink-file) \
cd .. &&
cd svnwc &&
ln -s added-directory added-symlink-directory &&
- svn add added-symlink-directory > /dev/null &&
+ svn_cmd add added-symlink-directory > /dev/null &&
cd .. &&
ptouch gitwc/added-symlink-directory svnwc/added-symlink-directory &&
(cd svnwc; svn info added-symlink-directory) \
git rm -f file > /dev/null &&
cd .. &&
cd svnwc &&
- svn rm --force file > /dev/null &&
+ svn_cmd rm --force file > /dev/null &&
cd .. &&
(cd svnwc; svn info file) |
sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
git rm -r -f directory > /dev/null &&
cd .. &&
cd svnwc &&
- svn rm --force directory > /dev/null &&
+ svn_cmd rm --force directory > /dev/null &&
cd .. &&
(cd svnwc; svn info directory) |
sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
git rm -f symlink-file > /dev/null &&
cd .. &&
cd svnwc &&
- svn rm --force symlink-file > /dev/null &&
+ svn_cmd rm --force symlink-file > /dev/null &&
cd .. &&
(cd svnwc; svn info symlink-file) |
sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
git rm -f symlink-directory > /dev/null &&
cd .. &&
cd svnwc &&
- svn rm --force symlink-directory > /dev/null &&
+ svn_cmd rm --force symlink-directory > /dev/null &&
cd .. &&
(cd svnwc; svn info symlink-directory) |
sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
test_expect_success 'setup svnrepo' '
mkdir project project/trunk project/branches project/tags &&
echo foo > project/trunk/foo &&
- svn import -m "$test_description" project "$svnrepo/pr ject" &&
+ svn_cmd import -m "$test_description" project "$svnrepo/pr ject" &&
rm -rf project &&
start_httpd
'
-if test "$SVN_HTTPD_PORT" = ""
-then
- test_expect_failure 'test clone with percent escapes - needs SVN_HTTPD_PORT set' 'false'
-else
- test_expect_success 'test clone with percent escapes' '
- git svn clone "$svnrepo/pr%20ject" clone &&
- cd clone &&
- git rev-parse refs/${remotes_git_svn} &&
- cd ..
- '
-fi
+test_expect_success 'test clone with percent escapes' '
+ git svn clone "$svnrepo/pr%20ject" clone &&
+ cd clone &&
+ git rev-parse refs/${remotes_git_svn} &&
+ cd ..
+'
stop_httpd
. ./lib-git-svn.sh
test_expect_success 'setup svn repository' '
- svn checkout "$svnrepo" work.svn &&
+ svn_cmd checkout "$svnrepo" work.svn &&
(
cd work.svn &&
echo >file
- svn add file
- svn commit -m "first commit" file
+ svn_cmd add file
+ svn_cmd commit -m "first commit" file
)
'
# Make sure there are no svn commit messages with excess blank lines
(
cd work.svn &&
- svn up &&
+ svn_cmd up &&
- test $(svn log -r2:2 | wc -l) = 5 &&
- test $(svn log -r4:4 | wc -l) = 7
+ test $(svn_cmd log -r2:2 | wc -l) = 5 &&
+ test $(svn_cmd log -r4:4 | wc -l) = 7
)
'
mkdir import
cd import
touch foo
- svn import -m 'import for git svn' . "$svnrepo" >/dev/null
+ svn_cmd import -m 'import for git svn' . "$svnrepo" >/dev/null
cd ..
rm -rf import
(
cd import &&
echo foo >foo &&
- svn import -m "import for git svn" . "$svnrepo"
+ svn_cmd import -m "import for git svn" . "$svnrepo"
) &&
rm -rf import &&
git svn init "$svnrepo"
(
mkdir work &&
cd work &&
- svn co "$svnrepo" &&
+ svn_cmd co "$svnrepo" &&
cd svnrepo &&
# Check properties from first commit.
- test "x$(svn propget svn:executable exec1.sh)" = "x*" &&
- test "x$(svn propget svn:mime-type exec1.sh)" = \
+ test "x$(svn_cmd propget svn:executable exec1.sh)" = "x*" &&
+ test "x$(svn_cmd propget svn:mime-type exec1.sh)" = \
"xapplication/x-shellscript" &&
- test "x$(svn propget svn:mime-type hello.txt)" = "xtext/plain" &&
- test "x$(svn propget svn:eol-style hello.txt)" = "xnative" &&
- test "x$(svn propget svn:mime-type bar)" = "x" &&
+ test "x$(svn_cmd propget svn:mime-type hello.txt)" = "xtext/plain" &&
+ test "x$(svn_cmd propget svn:eol-style hello.txt)" = "xnative" &&
+ test "x$(svn_cmd propget svn:mime-type bar)" = "x" &&
# Check properties from second commit.
- test "x$(svn propget svn:executable exec2.sh)" = "x*" &&
- test "x$(svn propget svn:mime-type exec2.sh)" = "x" &&
- test "x$(svn propget svn:mime-type world.txt)" = "x" &&
- test "x$(svn propget svn:eol-style world.txt)" = "x" &&
- test "x$(svn propget svn:mime-type zot)" = "x"
+ test "x$(svn_cmd propget svn:executable exec2.sh)" = "x*" &&
+ test "x$(svn_cmd propget svn:mime-type exec2.sh)" = "x" &&
+ test "x$(svn_cmd propget svn:mime-type world.txt)" = "x" &&
+ test "x$(svn_cmd propget svn:eol-style world.txt)" = "x" &&
+ test "x$(svn_cmd propget svn:mime-type zot)" = "x"
)
'
git svn dcommit --config-dir=user &&
(
cd work/svnrepo &&
- svn up &&
+ svn_cmd up &&
test ! -e foo &&
test -e foo.sh &&
- test "x$(svn propget svn:mime-type foo.sh)" = \
+ test "x$(svn_cmd propget svn:mime-type foo.sh)" = \
"xapplication/x-shellscript" &&
- test "x$(svn propget svn:eol-style foo.sh)" = "xLF"
+ test "x$(svn_cmd propget svn:eol-style foo.sh)" = "xLF"
)
'
mkdir project project/trunk project/branches \
project/branches/v14.1 project/tags &&
echo foo > project/trunk/foo &&
- svn import -m "$test_description" project "$svnrepo/project" &&
+ svn_cmd import -m "$test_description" project "$svnrepo/project" &&
rm -rf project &&
- svn cp -m "fun" "$svnrepo/project/trunk" \
+ svn_cmd cp -m "fun" "$svnrepo/project/trunk" \
"$svnrepo/project/branches/v14.1/beta" &&
- svn cp -m "more fun!" "$svnrepo/project/branches/v14.1/beta" \
+ svn_cmd cp -m "more fun!" "$svnrepo/project/branches/v14.1/beta" \
"$svnrepo/project/branches/v14.1/gold"
'
cd trunk &&
echo foo > foo &&
cd .. &&
- svn import -m "import for git-svn" . "$svnrepo" >/dev/null &&
- svn copy "$svnrepo"/trunk "$svnrepo"/branches/a \
+ svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null &&
+ svn_cmd copy "$svnrepo"/trunk "$svnrepo"/branches/a \
-m "created branch a" &&
cd .. &&
rm -rf import &&
- svn co "$svnrepo"/trunk trunk &&
+ svn_cmd co "$svnrepo"/trunk trunk &&
cd trunk &&
echo bar >> foo &&
- svn ci -m "updated trunk" &&
+ svn_cmd ci -m "updated trunk" &&
cd .. &&
- svn co "$svnrepo"/branches/a a &&
+ svn_cmd co "$svnrepo"/branches/a a &&
cd a &&
echo baz >> a &&
- svn add a &&
- svn ci -m "updated a" &&
+ svn_cmd add a &&
+ svn_cmd ci -m "updated a" &&
cd .. &&
git svn init --stdlayout "$svnrepo"
)
cd trunk &&
echo foo > foo &&
cd .. &&
- svn import -m "import for git-svn" . "$svnrepo" >/dev/null &&
+ svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null &&
cd .. &&
rm -rf import &&
- svn co "$svnrepo"/trunk trunk &&
+ svn_cmd co "$svnrepo"/trunk trunk &&
cd trunk &&
echo bar >> foo &&
- svn ci -m "updated trunk" &&
+ svn_cmd ci -m "updated trunk" &&
cd .. &&
rm -rf trunk
)
'
test_expect_success 'branch uses correct svn-remote' '
- (svn co "$svnrepo" svn &&
+ (svn_cmd co "$svnrepo" svn &&
cd svn &&
mkdir mirror &&
- svn add mirror &&
- svn copy trunk mirror/ &&
- svn copy tags mirror/ &&
- svn copy branches mirror/ &&
- svn ci -m "made mirror" ) &&
+ svn_cmd add mirror &&
+ svn_cmd copy trunk mirror/ &&
+ svn_cmd copy tags mirror/ &&
+ svn_cmd copy branches mirror/ &&
+ svn_cmd ci -m "made mirror" ) &&
rm -rf svn &&
git svn init -s -R mirror --prefix=mirror/ "$svnrepo"/mirror &&
git svn fetch -R mirror &&
do
test_expect_success "$H setup" '
mkdir $H &&
- svn import -m "$H test" $H "$svnrepo"/$H &&
+ svn_cmd import -m "$H test" $H "$svnrepo"/$H &&
git svn clone "$svnrepo"/$H $H
'
done
test_expect_success 'setup svnrepo' '
for i in aa bb cc dd
do
- svn mkdir -m $i --username $i "$svnrepo"/$i
+ svn_cmd mkdir -m $i --username $i "$svnrepo"/$i
done
'
'
test_expect_success 'authors-file against globs' '
- svn mkdir -m globs --username aa \
+ svn_cmd mkdir -m globs --username aa \
"$svnrepo"/aa/trunk "$svnrepo"/aa/branches "$svnrepo"/aa/tags &&
git svn clone --authors-file=svn-authors -s "$svnrepo"/aa aa-work &&
for i in bb ee cc
do
branch="aa/branches/$i"
- svn mkdir -m "$branch" --username $i "$svnrepo/$branch"
+ svn_cmd mkdir -m "$branch" --username $i "$svnrepo/$branch"
done
'
. ./lib-git-svn.sh
test_expect_success 'setup repo with a git repo inside it' '
- svn co "$svnrepo" s &&
+ svn_cmd co "$svnrepo" s &&
(
cd s &&
git init &&
test -f .git/HEAD &&
> .git/a &&
echo a > a &&
- svn add .git a &&
- svn commit -m "create a nested git repo" &&
- svn up &&
+ svn_cmd add .git a &&
+ svn_cmd commit -m "create a nested git repo" &&
+ svn_cmd up &&
echo hi >> .git/a &&
- svn commit -m "modify .git/a" &&
- svn up
+ svn_cmd commit -m "modify .git/a" &&
+ svn_cmd up
)
'
(
cd s &&
echo b >> a &&
- svn commit -m "SVN-side change outside of .git" &&
- svn up &&
- svn log -v | fgrep "SVN-side change outside of .git"
+ svn_cmd commit -m "SVN-side change outside of .git" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change outside of .git"
)
'
git add a &&
git commit -m "add a inside an SVN repo" &&
git log &&
- svn add --force .git &&
- svn commit -m "SVN-side change inside of .git" &&
- svn up &&
- svn log -v | fgrep "SVN-side change inside of .git"
+ svn_cmd add --force .git &&
+ svn_cmd commit -m "SVN-side change inside of .git" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change inside of .git"
)
'
echo c >> a &&
git add a &&
git commit -m "add a inside an SVN repo" &&
- svn commit -m "SVN-side change in and out of .git" &&
- svn up &&
- svn log -v | fgrep "SVN-side change in and out of .git"
+ svn_cmd commit -m "SVN-side change in and out of .git" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change in and out of .git"
)
'
. ./lib-git-svn.sh
test_expect_success 'setup test repository' '
- svn co "$svnrepo" s &&
+ svn_cmd co "$svnrepo" s &&
(
cd s &&
mkdir qqq www &&
echo test_qqq > qqq/test_qqq.txt &&
echo test_www > www/test_www.txt &&
- svn add qqq &&
- svn add www &&
- svn commit -m "create some files" &&
- svn up &&
+ svn_cmd add qqq &&
+ svn_cmd add www &&
+ svn_cmd commit -m "create some files" &&
+ svn_cmd up &&
echo hi >> www/test_www.txt &&
- svn commit -m "modify www/test_www.txt" &&
- svn up
+ svn_cmd commit -m "modify www/test_www.txt" &&
+ svn_cmd up
)
'
(
cd s &&
echo b >> qqq/test_qqq.txt &&
- svn commit -m "SVN-side change outside of www" &&
- svn up &&
- svn log -v | fgrep "SVN-side change outside of www"
+ svn_cmd commit -m "SVN-side change outside of www" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change outside of www"
)
'
(
cd s &&
echo zaq >> www/test_www.txt
- svn commit -m "SVN-side change inside of www/test_www.txt" &&
- svn up &&
- svn log -v | fgrep "SVN-side change inside of www/test_www.txt"
+ svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
)
'
cd s &&
echo cvf >> www/test_www.txt
echo ygg >> qqq/test_qqq.txt
- svn commit -m "SVN-side change in and out of ignored www" &&
- svn up &&
- svn log -v | fgrep "SVN-side change in and out of ignored www"
+ svn_cmd commit -m "SVN-side change in and out of ignored www" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
)
'
mkdir import &&
cd import &&
awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file
- svn import -m "initial" . "$svnrepo" &&
+ svn_cmd import -m "initial" . "$svnrepo" &&
cd .. &&
git svn init "$svnrepo" &&
git svn fetch &&
test_expect_success '(supposedly) non-conflicting change from SVN' '
test x"`sed -n -e 58p < file`" = x58 &&
test x"`sed -n -e 61p < file`" = x61 &&
- svn co "$svnrepo" tmp &&
+ svn_cmd co "$svnrepo" tmp &&
cd tmp &&
perl -i.bak -p -e "s/^58$/5588/" file &&
perl -i.bak -p -e "s/^61$/6611/" file &&
poke file &&
test x"`sed -n -e 58p < file`" = x5588 &&
test x"`sed -n -e 61p < file`" = x6611 &&
- svn commit -m "58 => 5588, 61 => 6611" &&
+ svn_cmd commit -m "58 => 5588, 61 => 6611" &&
cd ..
'
test x\"\`sed -n -e 7p < file\`\" = x7777 &&
git commit -m '4 => 4444, 7 => 7777' file &&
git svn dcommit &&
- svn up tmp &&
+ svn_cmd up tmp &&
cd tmp &&
test x\"\`sed -n -e 4p < file\`\" = x4444 &&
test x\"\`sed -n -e 7p < file\`\" = x7777 &&
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2009 Eric Wong, Mark Lodato
+#
+
+test_description='git svn authors prog tests'
+
+. ./lib-git-svn.sh
+
+cat > svn-authors-prog <<'EOF'
+#!/usr/bin/perl
+$_ = shift;
+if (s/-sub$//) {
+ print "$_ <$_\@sub.example.com>\n";
+}
+else {
+ print "$_ <$_\@example.com>\n";
+}
+EOF
+chmod +x svn-authors-prog
+
+cat > svn-authors <<'EOF'
+ff = FFFFFFF FFFFFFF <fFf@other.example.com>
+EOF
+
+test_expect_success 'setup svnrepo' '
+ for i in aa bb cc-sub dd-sub ee-foo ff
+ do
+ svn mkdir -m $i --username $i "$svnrepo"/$i
+ done
+ '
+
+test_expect_success 'import authors with prog and file' '
+ git svn clone --authors-prog=./svn-authors-prog \
+ --authors-file=svn-authors "$svnrepo" x
+ '
+
+test_expect_success 'imported 6 revisions successfully' '
+ (
+ cd x
+ test "`git rev-list refs/remotes/git-svn | wc -l`" -eq 6
+ )
+ '
+
+test_expect_success 'authors-prog ran correctly' '
+ (
+ cd x
+ git rev-list -1 --pretty=raw refs/remotes/git-svn~1 | \
+ grep "^author ee-foo <ee-foo@example\.com> " &&
+ git rev-list -1 --pretty=raw refs/remotes/git-svn~2 | \
+ grep "^author dd <dd@sub\.example\.com> " &&
+ git rev-list -1 --pretty=raw refs/remotes/git-svn~3 | \
+ grep "^author cc <cc@sub\.example\.com> " &&
+ git rev-list -1 --pretty=raw refs/remotes/git-svn~4 | \
+ grep "^author bb <bb@example\.com> " &&
+ git rev-list -1 --pretty=raw refs/remotes/git-svn~5 | \
+ grep "^author aa <aa@example\.com> "
+ )
+ '
+
+test_expect_success 'authors-file overrode authors-prog' '
+ (
+ cd x
+ git rev-list -1 --pretty=raw refs/remotes/git-svn | \
+ grep "^author FFFFFFF FFFFFFF <fFf@other\.example\.com> "
+ )
+ '
+
+test_done
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2009 Eric Wong
+
+test_description='git svn refuses to dcommit non-UTF8 messages'
+
+. ./lib-git-svn.sh
+
+# ISO-2022-JP can pass for valid UTF-8, so skipping that in this test
+
+for H in ISO-8859-1 EUCJP
+do
+ test_expect_success "$H setup" '
+ mkdir $H &&
+ svn_cmd import -m "$H test" $H "$svnrepo"/$H &&
+ git svn clone "$svnrepo"/$H $H
+ '
+done
+
+for H in ISO-8859-1 EUCJP
+do
+ test_expect_success "$H commit on git side" '
+ (
+ cd $H &&
+ git config i18n.commitencoding $H &&
+ git checkout -b t refs/remotes/git-svn &&
+ echo $H >F &&
+ git add F &&
+ git commit -a -F "$TEST_DIRECTORY"/t3900/$H.txt &&
+ E=$(git cat-file commit HEAD | sed -ne "s/^encoding //p") &&
+ test "z$E" = "z$H"
+ )
+ '
+done
+
+for H in ISO-8859-1 EUCJP
+do
+ test_expect_success "$H dcommit to svn" '
+ (
+ cd $H &&
+ git config --unset i18n.commitencoding &&
+ ! git svn dcommit
+ )
+ '
+done
+
+test_done
git add . &&
git commit -m "first commit" &&
+ echo "new file in subdir 2" > directory2/file2 &&
+ git add . &&
+ git commit -m "commit in directory2" &&
+
echo "changed file 1" > file1 &&
git commit -a -m "second commit" &&
unlink $tmpfile;
# paths
-is($r->repo_path, "./.git", "repo_path");
+is($r->repo_path, $abs_repo_dir . "/.git", "repo_path");
is($r->wc_path, $abs_repo_dir . "/", "wc_path");
is($r->wc_subdir, "", "wc_subdir initial");
$r->wc_chdir("directory1");
is($r->wc_subdir, "directory1", "wc_subdir after wc_chdir");
-TODO: {
- local $TODO = "commands do not work after wc_chdir";
- # Failure output is active even in non-verbose mode and thus
- # annoying. Hence we skip these tests as long as they fail.
- todo_skip 'config after wc_chdir', 1;
- is($r->config("color.string"), "value", "config after wc_chdir");
-}
+is($r->config("test.string"), "value", "config after wc_chdir");
+
+# Object generation in sub directory
+chdir("directory2");
+my $r2 = Git->repository();
+is($r2->repo_path, $abs_repo_dir . "/.git", "repo_path (2)");
+is($r2->wc_path, $abs_repo_dir . "/", "wc_path (2)");
+is($r2->wc_subdir, "directory2/", "wc_subdir initial (2)");
+
+# commands in sub directory
+my $last_commit = $r2->command_oneline(qw(rev-parse --verify HEAD));
+like($last_commit, qr/^[0-9a-fA-F]{40}$/, 'rev-parse returned hash');
+my $dir_commit = $r2->command_oneline('log', '-n1', '--pretty=format:%H', '.');
+isnt($last_commit, $dir_commit, 'log . does not show last commit');
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"
#
# To enable this hook, rename this file to "pre-commit".
-if git-rev-parse --verify HEAD 2>/dev/null
+# If you want to allow non-ascii filenames set this variable to true.
+allownonascii=$(git config hooks.allownonascii)
+
+# Cross platform projects tend to avoid non-ascii filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+ test "$(git diff --cached --name-only --diff-filter=A -z |
+ LC_ALL=C tr -d '[ -~]\0')"
+then
+ echo "Error: Attempt to add a non-ascii filename."
+ echo
+ echo "This can cause problems if you want to work together"
+ echo "with people on other platforms than you."
+ echo
+ echo "To be portable it is adviseable to rename the file ..."
+ echo
+ echo "If you know what you are doing you can disable this"
+ echo "check using:"
+ echo
+ echo " git config hooks.allownonascii true"
+ echo
+ exit 1
+fi
+
+if git-rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
+# hooks.allowmodifytag
+# This boolean sets whether a tag may be modified after creation. By default
+# it won't be.
# 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
# --- 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)
+allowmodifytag=$(git config --bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
# --- 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)
;;
refs/tags/*,tag)
# annotated tag
+ if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
+ then
+ echo "*** Tag '$refname' already exists." >&2
+ echo "*** Modifying a tag is not allowed in this repository." >&2
+ exit 1
+ fi
;;
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
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;
}
return 0;
}
+int number_callback(const struct option *opt, const char *arg, int unset)
+{
+ *(int *)opt->value = strtol(arg, NULL, 10);
+ return 0;
+}
+
int main(int argc, const char **argv)
{
const char *usage[] = {
OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
OPT_BIT('4', "or4", &boolean,
"bitwise-or boolean with ...0100", 4),
+ OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4),
OPT_GROUP(""),
OPT_INTEGER('i', "integer", &integer, "get a integer"),
OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
"set string to default", (unsigned long)"default"),
OPT_GROUP("Magic arguments"),
OPT_ARGUMENT("quux", "means --quux"),
+ OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
+ number_callback),
+ { OPTION_BOOLEAN, '+', NULL, &boolean, NULL, "same as -b",
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH },
OPT_GROUP("Standard options"),
OPT__ABBREV(&abbrev),
OPT__VERBOSE(&verbose),
{
fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
if (from)
- fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
+ fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
else
- fputs(prettify_ref(to), stderr);
+ fputs(prettify_refname(to->name), stderr);
if (msg) {
fputs(" (", stderr);
fputs(msg, stderr);
void transport_unlock_pack(struct transport *transport)
{
if (transport->pack_lockfile) {
- unlink(transport->pack_lockfile);
+ unlink_or_warn(transport->pack_lockfile);
free(transport->pack_lockfile);
transport->pack_lockfile = NULL;
}
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);
+}
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
}
/*
- * 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];
continue;
/* pathspecs match only at the directory boundaries */
if (!matchlen ||
+ baselen == matchlen ||
base[matchlen] == '/' ||
match[matchlen - 1] == '/')
return 1;
{
if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
return;
- if (unlink(ce->name))
+ if (unlink_or_warn(ce->name))
return;
schedule_dir_for_removal(ce->name, ce_namelen(ce));
}
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];
}
}
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;
}
commit->buffer = NULL;
}
-static void show_object(struct object_array_entry *p, void *data)
+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)
safe_create_leading_directories(name);
return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
}
+
+int unlink_or_warn(const char *file)
+{
+ int rc = unlink(file);
+
+ if (rc < 0) {
+ int err = errno;
+ if (ENOENT != err) {
+ warning("unable to unlink %s: %s",
+ file, strerror(errno));
+ errno = err;
+ }
+ }
+ return rc;
+}
+
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] : "";
}
/*
* 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;