Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.mailmap2
-rw-r--r--Documentation/RelNotes-1.5.4.1.txt17
-rw-r--r--Documentation/RelNotes-1.5.4.2.txt43
-rw-r--r--Documentation/RelNotes-1.5.5.txt78
-rw-r--r--Documentation/SubmittingPatches65
-rw-r--r--Documentation/config.txt45
-rw-r--r--Documentation/git-add.txt4
-rw-r--r--Documentation/git-clone.txt13
-rw-r--r--Documentation/git-commit.txt4
-rw-r--r--Documentation/git-cvsimport.txt4
-rw-r--r--Documentation/git-fast-import.txt87
-rw-r--r--Documentation/git-help.txt26
-rw-r--r--Documentation/git-instaweb.txt12
-rw-r--r--Documentation/git-pull.txt20
-rw-r--r--Documentation/git-push.txt55
-rw-r--r--Documentation/git-reset.txt23
-rw-r--r--Documentation/git-stash.txt5
-rw-r--r--Documentation/git-web--browse.txt78
-rw-r--r--Documentation/git.txt4
-rw-r--r--Documentation/gitattributes.txt20
-rw-r--r--Documentation/gitignore.txt7
-rw-r--r--Documentation/hooks.txt29
-rw-r--r--Documentation/technical/api-remote.txt123
-rw-r--r--Documentation/technical/api-run-command.txt171
-rwxr-xr-xGIT-VERSION-GEN11
-rw-r--r--Makefile12
l---------RelNotes2
-rw-r--r--builtin-add.c12
-rw-r--r--builtin-apply.c2
-rw-r--r--builtin-blame.c9
-rw-r--r--builtin-commit.c257
-rw-r--r--builtin-config.c5
-rwxr-xr-xbuiltin-fast-export.c3
-rw-r--r--builtin-fmt-merge-msg.c3
-rw-r--r--builtin-log.c12
-rw-r--r--builtin-ls-files.c17
-rw-r--r--builtin-mailinfo.c1
-rw-r--r--builtin-mv.c10
-rw-r--r--builtin-pack-objects.c16
-rw-r--r--builtin-push.c2
-rw-r--r--builtin-rev-list.c3
-rw-r--r--builtin-shortlog.c3
-rw-r--r--builtin-show-ref.c3
-rw-r--r--bundle.c3
-rw-r--r--cache.h33
-rw-r--r--commit.c14
-rw-r--r--compat/qsort.c62
-rw-r--r--config.c78
-rw-r--r--contrib/emacs/git.el7
-rwxr-xr-xcontrib/hg-to-git/hg-to-git.py2
-rw-r--r--convert.c47
-rw-r--r--diff.c22
-rw-r--r--dir.c49
-rw-r--r--dir.h3
-rw-r--r--environment.c7
-rw-r--r--fast-import.c32
-rwxr-xr-xgit-bisect.sh6
-rwxr-xr-xgit-clone.sh18
-rw-r--r--git-compat-util.h6
-rwxr-xr-xgit-cvsexportcommit.perl11
-rwxr-xr-xgit-cvsimport.perl2
-rwxr-xr-xgit-filter-branch.sh9
-rw-r--r--git-gui/Makefile17
-rwxr-xr-xgit-gui/git-gui.sh34
-rw-r--r--git-gui/lib/about.tcl5
-rw-r--r--git-gui/lib/checkout_op.tcl6
-rw-r--r--git-gui/lib/commit.tcl16
-rw-r--r--git-gui/lib/index.tcl2
-rw-r--r--git-gui/lib/merge.tcl5
-rw-r--r--git-gui/lib/option.tcl39
-rw-r--r--git-gui/lib/spellcheck.tcl363
-rw-r--r--git-gui/macosx/Info.plist2
-rw-r--r--git-gui/po/de.po129
-rw-r--r--git-gui/po/git-gui.pot82
-rwxr-xr-xgit-instaweb.sh20
-rwxr-xr-xgit-send-email.perl2
-rwxr-xr-xgit-sh-setup.sh10
-rwxr-xr-xgit-web--browse.sh (renamed from git-help--browse.sh)57
-rw-r--r--git.spec.in69
-rw-r--r--gitk-git/gitk115
-rw-r--r--gitweb/README4
-rwxr-xr-xgitweb/gitweb.perl51
-rw-r--r--help.c26
-rw-r--r--http-push.c3
-rw-r--r--list-objects.c4
-rw-r--r--merge-recursive.c2
-rw-r--r--pager.c1
-rw-r--r--reachable.c13
-rw-r--r--remote.c12
-rw-r--r--revision.c8
-rw-r--r--setup.c158
-rw-r--r--sha1_file.c6
-rw-r--r--sha1_name.c13
-rw-r--r--shallow.c5
-rwxr-xr-xt/t0020-crlf.sh58
-rwxr-xr-xt/t1500-rev-parse.sh4
-rwxr-xr-xt/t3001-ls-files-others-exclude.sh41
-rwxr-xr-xt/t3404-rebase-interactive.sh22
-rwxr-xr-xt/t4015-diff-whitespace.sh9
-rwxr-xr-xt/t5100-mailinfo.sh2
-rw-r--r--t/t5100/info00095
-rw-r--r--t/t5100/msg00092
-rw-r--r--t/t5100/patch000913
-rw-r--r--t/t5100/sample.mbox23
-rwxr-xr-xt/t5701-clone-local.sh8
-rwxr-xr-xt/t7001-mv.sh38
-rwxr-xr-xt/t7003-filter-branch.sh14
-rwxr-xr-xt/t7010-setup.sh164
-rwxr-xr-xt/t7502-commit.sh29
-rwxr-xr-xt/t7502-status.sh32
-rwxr-xr-xt/t7505-prepare-commit-msg-hook.sh155
-rwxr-xr-xt/t9200-git-cvsexportcommit.sh18
-rw-r--r--t/test-lib.sh7
-rw-r--r--tag.c5
-rw-r--r--templates/hooks--commit-msg3
-rw-r--r--templates/hooks--prepare-commit-msg36
-rw-r--r--unpack-trees.c3
-rw-r--r--upload-pack.c12
-rw-r--r--wt-status.c2
120 files changed, 3084 insertions, 631 deletions
diff --git a/.gitignore b/.gitignore
index 7f8421dcd0..165b256e2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,7 +50,6 @@ git-gc
git-get-tar-commit-id
git-grep
git-hash-object
-git-help--browse
git-http-fetch
git-http-push
git-imap-send
@@ -136,6 +135,7 @@ git-upload-pack
git-var
git-verify-pack
git-verify-tag
+git-web--browse
git-whatchanged
git-write-tree
git-core-*/?*
diff --git a/.mailmap b/.mailmap
index 695739ea70..f88ae77a1f 100644
--- a/.mailmap
+++ b/.mailmap
@@ -17,6 +17,7 @@ H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
H. Peter Anvin <hpa@trantor.hos.anvin.org>
Horst H. von Brand <vonbrand@inf.utfsm.cl>
+Jay Soffian <jaysoffian+git@gmail.com>
Joachim Berdal Haga <cjhaga@fys.uio.no>
Jon Loeliger <jdl@freescale.com>
Jon Seymour <jon@blackcubes.dyndns.org>
@@ -43,6 +44,7 @@ Steven Grimm <koreth@midwinter.com>
Theodore Ts'o <tytso@mit.edu>
Tony Luck <tony.luck@intel.com>
Uwe Kleine-König <Uwe_Zeisberger@digi.com>
+Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
Uwe Kleine-König <uzeisberger@io.fsforth.de>
Uwe Kleine-König <zeisberg@informatik.uni-freiburg.de>
diff --git a/Documentation/RelNotes-1.5.4.1.txt b/Documentation/RelNotes-1.5.4.1.txt
new file mode 100644
index 0000000000..d4e44b8b09
--- /dev/null
+++ b/Documentation/RelNotes-1.5.4.1.txt
@@ -0,0 +1,17 @@
+GIT v1.5.4.1 Release Notes
+==========================
+
+Fixes since v1.5.4
+------------------
+
+ * "git-commit -C $tag" used to work but rewrite in C done in
+ 1.5.4 broke it.
+
+ * An entry in the .gitattributes file that names a pattern in a
+ subdirectory of the directory it is in did not match
+ correctly (e.g. pattern "b/*.c" in "a/.gitattributes" should
+ match "a/b/foo.c" but it didn't).
+
+ * Customized color specification was parsed incorrectly when
+ numeric color values are used. This was fixed in 1.5.4.1.
+
diff --git a/Documentation/RelNotes-1.5.4.2.txt b/Documentation/RelNotes-1.5.4.2.txt
new file mode 100644
index 0000000000..21d0df59fb
--- /dev/null
+++ b/Documentation/RelNotes-1.5.4.2.txt
@@ -0,0 +1,43 @@
+GIT v1.5.4.2 Release Notes
+==========================
+
+Fixes since v1.5.4
+------------------
+
+ * The configuration parser was not prepared to see string
+ valued variables misspelled as boolean and segfaulted.
+
+ * Temporary files left behind due to interrupted object
+ transfers were not cleaned up with "git prune".
+
+ * "git config --unset" was confused when the unset variables
+ were spelled with continuation lines in the config file.
+
+ * The merge message detection in "git cvsimport" did not catch
+ a message that began with "Merge...".
+
+ * "git status" suggests "git rm --cached" for unstaging the
+ earlier "git add" before the initial commit.
+
+ * "git status" output was incorrect during a partial commit.
+
+ * "git bisect" refused to start when the HEAD was detached.
+
+ * "git bisect" allowed a wildcard character in the commit
+ message expanded while writing its log file.
+
+ * Manual pages were not formatted correctly with docbook xsl
+ 1.72; added a workaround.
+
+ * "git-commit -C $tag" used to work but rewrite in C done in
+ 1.5.4 broke it. This was fixed in 1.5.4.1.
+
+ * An entry in the .gitattributes file that names a pattern in a
+ subdirectory of the directory it is in did not match
+ correctly (e.g. pattern "b/*.c" in "a/.gitattributes" should
+ match "a/b/foo.c" but it didn't). This was fixed in 1.5.4.1.
+
+ * Customized color specification was parsed incorrectly when
+ numeric color values are used. This was fixed in 1.5.4.1.
+
+ * http transport misbehaved when linked with curl-gnutls.
diff --git a/Documentation/RelNotes-1.5.5.txt b/Documentation/RelNotes-1.5.5.txt
new file mode 100644
index 0000000000..c8b4f72c23
--- /dev/null
+++ b/Documentation/RelNotes-1.5.5.txt
@@ -0,0 +1,78 @@
+GIT v1.5.5 Release Notes
+========================
+
+Updates since v1.5.4
+--------------------
+
+(performance)
+
+ * On platforms with suboptimal qsort(3) implementation, there
+ is an option to use more reasonable substitute we ship with
+ our software.
+
+ * New configuration variable "pack.packsizelimit" can be used
+ in place of command line option --max-pack-size.
+
+ * "git fetch" over the native git protocol used to make a
+ connection to find out the set of current remote refs and
+ another to actually download the pack data. We now use only
+ one connection for these tasks.
+
+ * "git commit" does not run lstat(2) more than necessary
+ anymore.
+
+(usability, bells and whistles)
+
+ * You can be warned when core.autocrlf conversion is applied in
+ such a way that results in an irreversible conversion.
+
+ * A pattern "foo/" in .gitignore file now matches a directory
+ "foo". Pattern "foo" also matches as before.
+
+ * "git describe" learned to limit the tags to be used for
+ naming with --match option.
+
+ * "git describe --contains" now barfs when the named commit
+ cannot be described.
+
+ * bash completion's prompt helper function can talk about
+ operation in-progress (e.g. merge, rebase, etc.).
+
+ * "git commit" learned a new hook "prepare-commit-msg" that can
+ inspect what is going to be committed and prepare the commit
+ log message template to be edited.
+
+ * "git gui" learned an auto-spell checking.
+
+ * "git send-email" learned to prompt for passwords
+ interactively.
+
+ * "git send-email" learned an easier way to suppress CC
+ recipients.
+
+ * Various "git cvsimport", "git cvsexportcommit", "git svn" and
+ "git p4" improvements.
+
+(internal)
+
+ * Duplicated code between git-help and git-instaweb that
+ launches user's preferred browser has been refactored.
+
+ * It is now easier to write test scripts that records known
+ breakages.
+
+
+Fixes since v1.5.4
+------------------
+
+All of the fixes in v1.5.4 maintenance series are included in
+this release, unless otherwise noted.
+
+
+---
+exec >/var/tmp/1
+O=v1.5.4
+O=v1.5.4.2-122-g7cb97da
+echo O=`git describe refs/heads/master`
+git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
+
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index de08d094e3..0e155c936c 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -34,9 +34,9 @@ Checklist (and a short version for the impatient):
- if your name is not writable in ASCII, make sure that
you send off a message in the correct encoding.
- send the patch to the list (git@vger.kernel.org) and the
- maintainer (gitster@pobox.com). If you use
- git-send-email(1), please test it first by sending
- email to yourself.
+ maintainer (gitster@pobox.com) if (and only if) the patch
+ is ready for inclusion. If you use git-send-email(1),
+ please test it first by sending email to yourself.
Long version:
@@ -112,7 +112,12 @@ lose tabs that way if you are not careful.
It is a common convention to prefix your subject line with
[PATCH]. This lets people easily distinguish patches from other
-e-mail discussions.
+e-mail discussions. Use of additional markers after PATCH and
+the closing bracket to mark the nature of the patch is also
+encouraged. E.g. [PATCH/RFC] is often used when the patch is
+not ready to be applied but it is for discussion, [PATCH v2],
+[PATCH v3] etc. are often seen when you are sending an update to
+what you have previously sent.
"git format-patch" command follows the best current practice to
format the body of an e-mail message. At the beginning of the
@@ -157,7 +162,8 @@ Note that your maintainer does not necessarily read everything
on the git mailing list. If your patch is for discussion first,
send it "To:" the mailing list, and optionally "cc:" him. If it
is trivially correct or after the list reached a consensus, send
-it "To:" the maintainer and optionally "cc:" the list.
+it "To:" the maintainer and optionally "cc:" the list for
+inclusion.
Also note that your maintainer does not actively involve himself in
maintaining what are in contrib/ hierarchy. When you send fixes and
@@ -210,10 +216,53 @@ then you just add a line saying
This line can be automatically added by git if you run the git-commit
command with the -s option.
-Some people also put extra tags at the end. They'll just be ignored for
-now, but you can do this to mark internal company procedures or just
-point out some special detail about the sign-off.
+Notice that you can place your own Signed-off-by: line when
+forwarding somebody else's patch with the above rules for
+D-C-O. Indeed you are encouraged to do so. Do not forget to
+place an in-body "From: " line at the beginning to properly attribute
+the change to its true author (see (2) above).
+Some people also put extra tags at the end.
+
+"Acked-by:" says that the patch was reviewed by the person who
+is more familiar with the issues and the area the patch attempts
+to modify. "Tested-by:" says the patch was tested by the person
+and found to have the desired effect.
+
+------------------------------------------------
+An ideal patch flow
+
+Here is an ideal patch flow for this project the current maintainer
+suggests to the contributors:
+
+ (0) You come up with an itch. You code it up.
+
+ (1) Send it to the list and cc people who may need to know about
+ the change.
+
+ The people who may need to know are the ones whose code you
+ are butchering. These people happen to be the ones who are
+ most likely to be knowledgeable enough to help you, but
+ they have no obligation to help you (i.e. you ask for help,
+ don't demand). "git log -p -- $area_you_are_modifying" would
+ help you find out who they are.
+
+ (2) You get comments and suggestions for improvements. You may
+ even get them in a "on top of your change" patch form.
+
+ (3) Polish, refine, and re-send to the list and the people who
+ spend their time to improve your patch. Go back to step (2).
+
+ (4) The list forms consensus that the last round of your patch is
+ good. Send it to the list and cc the maintainer.
+
+ (5) A topic branch is created with the patch and is merged to 'next',
+ and cooked further and eventually graduates to 'master'.
+
+In any time between the (2)-(3) cycle, the maintainer may pick it up
+from the list and queue it to 'pu', in order to make it easier for
+people play with it without having to pick up and apply the patch to
+their trees themselves.
------------------------------------------------
MUA specific hints
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f9bdb164e0..f2f6a774e0 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -139,6 +139,51 @@ core.autocrlf::
"text" (i.e. be subjected to the autocrlf mechanism) is
decided purely based on the contents.
+core.safecrlf::
+ If true, makes git check if converting `CRLF` as controlled by
+ `core.autocrlf` is reversible. Git will verify if a command
+ modifies a file in the work tree either directly or indirectly.
+ For example, committing a file followed by checking out the
+ same file should yield the original file in the work tree. If
+ this is not the case for the current setting of
+ `core.autocrlf`, git will reject the file. The variable can
+ be set to "warn", in which case git will only warn about an
+ irreversible conversion but continue the operation.
++
+CRLF conversion bears a slight chance of corrupting data.
+autocrlf=true will convert CRLF to LF during commit and LF to
+CRLF during checkout. A file that contains a mixture of LF and
+CRLF before the commit cannot be recreated by git. For text
+files this is the right thing to do: it corrects line endings
+such that we have only LF line endings in the repository.
+But for binary files that are accidentally classified as text the
+conversion can corrupt data.
++
+If you recognize such corruption early you can easily fix it by
+setting the conversion type explicitly in .gitattributes. Right
+after committing you still have the original file in your work
+tree and this file is not yet corrupted. You can explicitly tell
+git that this file is binary and git will handle the file
+appropriately.
++
+Unfortunately, the desired effect of cleaning up text files with
+mixed line endings and the undesired effect of corrupting binary
+files cannot be distinguished. In both cases CRLFs are removed
+in an irreversible way. For text files this is the right thing
+to do because CRLFs are line endings, while for binary files
+converting CRLFs corrupts data.
++
+Note, this safety check does not mean that a checkout will generate a
+file identical to the original file for a different setting of
+`core.autocrlf`, but only for the current one. For example, a text
+file with `LF` would be accepted with `core.autocrlf=input` and could
+later be checked out with `core.autocrlf=true`, in which case the
+resulting file would contain `CRLF`, although the original file
+contained `LF`. However, in both work trees the line endings would be
+consistent, that is either all `LF` or all `CRLF`, but never mixed. A
+file with mixed line endings would be reported by the `core.safecrlf`
+mechanism.
+
core.symlinks::
If false, symbolic links are checked out as small plain files that
contain the link text. linkgit:git-update-index[1] and
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 9d2ac865d2..47799097ce 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -74,8 +74,8 @@ OPTIONS
Update only files that git already knows about. This is similar
to what "git commit -a" does in preparation for making a commit,
except that the update is limited to paths specified on the
- command line. If no paths are specified, all tracked files are
- updated.
+ command line. If no paths are specified, all tracked files in the
+ current directory and its subdirectories are updated.
\--refresh::
Don't add the file(s), but only refresh their stat()
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 2341881614..975824301a 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -62,12 +62,13 @@ OPTIONS
.git/objects/info/alternates to share the objects
with the source repository. The resulting repository
starts out without any object of its own.
- *NOTE*: this is a possibly dangerous operation; do *not* use
- it unless you understand what it does. If you clone your
- repository using this option, then delete branches in the
- source repository and then run linkgit:git-gc[1] using the
- '--prune' option in the source repository, it may remove
- objects which are referenced by the cloned repository.
++
+*NOTE*: this is a possibly dangerous operation; do *not* use
+it unless you understand what it does. If you clone your
+repository using this option, then delete branches in the
+source repository and then run linkgit:git-gc[1] using the
+'--prune' option in the source repository, it may remove
+objects which are referenced by the cloned repository.
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index c3725b2ed9..b4ae61ff46 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -280,8 +280,8 @@ order).
HOOKS
-----
-This command can run `commit-msg`, `pre-commit`, and
-`post-commit` hooks. See link:hooks.html[hooks] for more
+This command can run `commit-msg`, `prepare-commit-msg`, `pre-commit`,
+and `post-commit` hooks. See link:hooks.html[hooks] for more
information.
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index dbce503694..6f91b9ea2a 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -107,8 +107,8 @@ If you need to pass multiple options, separate them with a comma.
-M <regex>::
Attempt to detect merges based on the commit message with a custom
- regex. It can be used with '-m' to also see the default regexes.
- You must escape forward slashes.
+ regex. It can be used with '-m' to enable the default regexes
+ as well. You must escape forward slashes.
-S <regex>::
Skip paths matching the regex.
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index bd625ababf..96f6767075 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -805,6 +805,93 @@ Placing a `progress` command immediately after a `checkpoint` will
inform the reader when the `checkpoint` has been completed and it
can safely access the refs that fast-import updated.
+Crash Reports
+-------------
+If fast-import is supplied invalid input it will terminate with a
+non-zero exit status and create a crash report in the top level of
+the Git repository it was importing into. Crash reports contain
+a snapshot of the internal fast-import state as well as the most
+recent commands that lead up to the crash.
+
+All recent commands (including stream comments, file changes and
+progress commands) are shown in the command history within the crash
+report, but raw file data and commit messages are excluded from the
+crash report. This exclusion saves space within the report file
+and reduces the amount of buffering that fast-import must perform
+during execution.
+
+After writing a crash report fast-import will close the current
+packfile and export the marks table. This allows the frontend
+developer to inspect the repository state and resume the import from
+the point where it crashed. The modified branches and tags are not
+updated during a crash, as the import did not complete successfully.
+Branch and tag information can be found in the crash report and
+must be applied manually if the update is needed.
+
+An example crash:
+
+====
+ $ cat >in <<END_OF_INPUT
+ # my very first test commit
+ commit refs/heads/master
+ committer Shawn O. Pearce <spearce> 19283 -0400
+ # who is that guy anyway?
+ data <<EOF
+ this is my commit
+ EOF
+ M 644 inline .gitignore
+ data <<EOF
+ .gitignore
+ EOF
+ M 777 inline bob
+ END_OF_INPUT
+
+ $ git-fast-import <in
+ fatal: Corrupt mode: M 777 inline bob
+ fast-import: dumping crash report to .git/fast_import_crash_8434
+
+ $ cat .git/fast_import_crash_8434
+ fast-import crash report:
+ fast-import process: 8434
+ parent process : 1391
+ at Sat Sep 1 00:58:12 2007
+
+ fatal: Corrupt mode: M 777 inline bob
+
+ Most Recent Commands Before Crash
+ ---------------------------------
+ # my very first test commit
+ commit refs/heads/master
+ committer Shawn O. Pearce <spearce> 19283 -0400
+ # who is that guy anyway?
+ data <<EOF
+ M 644 inline .gitignore
+ data <<EOF
+ * M 777 inline bob
+
+ Active Branch LRU
+ -----------------
+ active_branches = 1 cur, 5 max
+
+ pos clock name
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 1) 0 refs/heads/master
+
+ Inactive Branches
+ -----------------
+ refs/heads/master:
+ status : active loaded dirty
+ tip commit : 0000000000000000000000000000000000000000
+ old tree : 0000000000000000000000000000000000000000
+ cur tree : 0000000000000000000000000000000000000000
+ commit clock: 0
+ last pack :
+
+
+ -------------------
+ END OF CRASH REPORT
+====
+
Tips and Tricks
---------------
The following tips and tricks have been collected from various
diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt
index fb77ca3a57..0926dc12ba 100644
--- a/Documentation/git-help.txt
+++ b/Documentation/git-help.txt
@@ -47,27 +47,9 @@ OPTIONS
+
The web browser can be specified using the configuration variable
'help.browser', or 'web.browser' if the former is not set. If none of
-these config variables is set, the 'git-help--browse' helper script
-(called by 'git-help') will pick a suitable default.
-+
-You can explicitly provide a full path to your preferred browser by
-setting the configuration variable 'browser.<tool>.path'. For example,
-you can configure the absolute path to firefox by setting
-'browser.firefox.path'. Otherwise, 'git-help--browse' assumes the tool
-is available in PATH.
-+
-Note that the script tries, as much as possible, to display the HTML
-page in a new tab on an already opened browser.
-+
-The following browsers are currently supported by 'git-help--browse':
-+
-* firefox (this is the default under X Window when not using KDE)
-* iceweasel
-* konqueror (this is the default under KDE)
-* w3m (this is the default outside X Window)
-* links
-* lynx
-* dillo
+these config variables is set, the 'git-web--browse' helper script
+(called by 'git-help') will pick a suitable default. See
+linkgit:git-web--browse[1] for more information about this.
CONFIGURATION VARIABLES
-----------------------
@@ -84,7 +66,7 @@ line option:
The 'help.browser', 'web.browser' and 'browser.<tool>.path' will also
be checked if the 'web' format is chosen (either by command line
option or configuration variable). See '-w|--web' in the OPTIONS
-section above.
+section above and linkgit:git-web--browse[1].
Note that these configuration variables should probably be set using
the '--global' flag, for example like this:
diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt
index 841e8fac7f..51f1532ef7 100644
--- a/Documentation/git-instaweb.txt
+++ b/Documentation/git-instaweb.txt
@@ -38,10 +38,11 @@ OPTIONS
The port number to bind the httpd to. (Default: 1234)
-b|--browser::
-
- The web browser command-line to execute to view the gitweb page.
- If blank, the URL of the gitweb instance will be printed to
- stdout. (Default: 'firefox')
+ The web browser that should be used to view the gitweb
+ page. This will be passed to the 'git-web--browse' helper
+ script along with the URL of the gitweb instance. See
+ linkgit:git-web--browse[1] for more information about this. If
+ the script fails, the URL will be printed to stdout.
--start::
Start the httpd instance and exit. This does not generate
@@ -72,7 +73,8 @@ You may specify configuration in your .git/config
-----------------------------------------------------------------------
If the configuration variable 'instaweb.browser' is not set,
-'web.browser' will be used instead if it is defined.
+'web.browser' will be used instead if it is defined. See
+linkgit:git-web--browse[1] for more information about this.
Author
------
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 179bdfc69d..737894390d 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -15,6 +15,7 @@ DESCRIPTION
-----------
Runs `git-fetch` with the given parameters, and calls `git-merge`
to merge the retrieved head(s) into the current branch.
+With `--rebase`, calls `git-rebase` instead of `git-merge`.
Note that you can use `.` (current directory) as the
<repository> to pull from the local repository -- this is useful
@@ -26,19 +27,14 @@ OPTIONS
include::merge-options.txt[]
:git-pull: 1
-include::fetch-options.txt[]
-
-include::pull-fetch-param.txt[]
-
-include::urls-remotes.txt[]
-
-include::merge-strategies.txt[]
\--rebase::
Instead of a merge, perform a rebase after fetching. If
there is a remote ref for the upstream branch, and this branch
was rebased since last fetched, the rebase uses that information
- to avoid rebasing non-local changes.
+ to avoid rebasing non-local changes. To make this the default
+ for branch `<name>`, set configuration `branch.<name>.rebase`
+ to `true`.
+
*NOTE:* This is a potentially _dangerous_ mode of operation.
It rewrites history, which does not bode well when you
@@ -48,6 +44,14 @@ unless you have read linkgit:git-rebase[1] carefully.
\--no-rebase::
Override earlier \--rebase.
+include::fetch-options.txt[]
+
+include::pull-fetch-param.txt[]
+
+include::urls-remotes.txt[]
+
+include::merge-strategies.txt[]
+
DEFAULT BEHAVIOUR
-----------------
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 5f2494495b..3128170bcd 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -47,9 +47,9 @@ even if it does not result in a fast forward update.
+
Note: If no explicit refspec is found, (that is neither
on the command line nor in any Push line of the
-corresponding remotes file---see below), then all the
-heads that exist both on the local side and on the remote
-side are updated.
+corresponding remotes file---see below), then "matching" heads are
+pushed: for every head that exists on the local side, the remote side is
+updated if a head of the same name already exists on the remote side.
+
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
+
@@ -108,6 +108,55 @@ the remote repository.
include::urls-remotes.txt[]
+OUTPUT
+------
+
+The output of "git push" depends on the transport method used; this
+section describes the output when pushing over the git protocol (either
+locally or via ssh).
+
+The status of the push is output in tabular form, with each line
+representing the status of a single ref. Each line is of the form:
+
+-------------------------------
+ <flag> <summary> <from> -> <to> (<reason>)
+-------------------------------
+
+flag::
+ A single character indicating the status of the ref. This is
+ blank for a successfully pushed ref, `!` for a ref that was
+ rejected or failed to push, and '=' for a ref that was up to
+ date and did not need pushing (note that the status of up to
+ date refs is shown only when `git push` is running verbosely).
+
+summary::
+ For a successfully pushed ref, the summary shows the old and new
+ values of the ref in a form suitable for using as an argument to
+ `git log` (this is `<old>..<new>` in most cases, and
+ `<old>...<new>` for forced non-fast forward updates). For a
+ failed update, more details are given for the failure.
+ The string `rejected` indicates that git did not try to send the
+ ref at all (typically because it is not a fast forward). The
+ string `remote rejected` indicates that the remote end refused
+ the update; this rejection is typically caused by a hook on the
+ remote side. The string `remote failure` indicates that the
+ remote end did not report the successful update of the ref
+ (perhaps because of a temporary error on the remote side, a
+ break in the network connection, or other transient error).
+
+from::
+ The name of the local ref being pushed, minus its
+ `refs/<type>/` prefix. In the case of deletion, the
+ name of the local ref is omitted.
+
+to::
+ The name of the remote ref being updated, minus its
+ `refs/<type>/` prefix.
+
+reason::
+ A human-readable explanation. In the case of successfully pushed
+ refs, no explanation is needed. For a failed ref, the reason for
+ failure is described.
Examples
--------
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index a4e0a779de..fac59c9726 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -8,8 +8,8 @@ git-reset - Reset current HEAD to the specified state
SYNOPSIS
--------
[verse]
-'git-reset' [--mixed | --soft | --hard] [-q] [<commit>]
-'git-reset' [--mixed] [-q] [<commit>] [--] <paths>...
+'git reset' [--mixed | --soft | --hard] [-q] [<commit>]
+'git reset' [-q] [<commit>] [--] <paths>...
DESCRIPTION
-----------
@@ -37,7 +37,7 @@ OPTIONS
--soft::
Does not touch the index file nor the working tree at all, but
requires them to be in a good order. This leaves all your changed
- files "Added but not yet committed", as linkgit:git-status[1] would
+ files "Changes to be committed", as linkgit:git-status[1] would
put it.
--hard::
@@ -176,6 +176,23 @@ $ git reset <3>
committed as 'snapshot WIP'. This updates the index to show your
WIP files as uncommitted.
+Reset a single file in the index::
++
+Suppose you have added a file to your index, but later decide you do not
+want to add it to your commit. You can remove the file from the index
+while keeping your changes with git reset.
++
+------------
+$ git reset -- frotz.c <1>
+$ git commit -m "Commit files in index" <2>
+$ git add frotz.c <3>
+------------
++
+<1> This removes the file from the index while keeping it in the working
+ directory.
+<2> This commits all other changes in the index.
+<3> Adds the file to the index again.
+
Author
------
Written by Junio C Hamano <junkio@cox.net> and Linus Torvalds <torvalds@osdl.org>
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index cd0dc1bd9d..48e6f5a3f7 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -43,7 +43,7 @@ save [<message>]::
subcommand is given. The <message> part is optional and gives
the description along with the stashed state.
-list::
+list [<options>]::
List the stashes that you currently have. Each 'stash' is listed
with its name (e.g. `stash@\{0}` is the latest stash, `stash@\{1}` is
@@ -55,6 +55,9 @@ list::
stash@{0}: WIP on submit: 6ebd0e2... Update git-stash documentation
stash@{1}: On master: 9cc0589... Add git-stash
----------------------------------------------------------------
++
+The command takes options applicable to the linkgit:git-log[1]
+command to control what is shown and how.
show [<stash>]::
diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt
new file mode 100644
index 0000000000..df57d010e5
--- /dev/null
+++ b/Documentation/git-web--browse.txt
@@ -0,0 +1,78 @@
+git-web--browse(1)
+==================
+
+NAME
+----
+git-web--browse - git helper script to launch a web browser
+
+SYNOPSIS
+--------
+'git-web--browse' [OPTIONS] URL/FILE ...
+
+DESCRIPTION
+-----------
+
+This script tries, as much as possible, to display the URLs and FILEs
+that are passed as arguments, as HTML pages in new tabs on an already
+opened web browser.
+
+The following browsers (or commands) are currently supported:
+
+* firefox (this is the default under X Window when not using KDE)
+* iceweasel
+* konqueror (this is the default under KDE)
+* w3m (this is the default outside graphical environments)
+* links
+* lynx
+* dillo
+* open (this is the default under Mac OS X GUI)
+
+OPTIONS
+-------
+-b BROWSER|--browser=BROWSER::
+ Use the specified BROWSER. It must be in the list of supported
+ browsers.
+
+-t BROWSER|--tool=BROWSER::
+ Same as above.
+
+-c CONF.VAR|--config=CONF.VAR::
+ CONF.VAR is looked up in the git config files. If it's set,
+ then its value specify the browser that should be used.
+
+CONFIGURATION VARIABLES
+-----------------------
+
+The web browser can be specified using a configuration variable passed
+with the -c (or --config) command line option, or the 'web.browser'
+configuration variable if the former is not used.
+
+You can explicitly provide a full path to your preferred browser by
+setting the configuration variable 'browser.<tool>.path'. For example,
+you can configure the absolute path to firefox by setting
+'browser.firefox.path'. Otherwise, 'git-web--browse' assumes the tool
+is available in PATH.
+
+Note that these configuration variables should probably be set using
+the '--global' flag, for example like this:
+
+------------------------------------------------
+$ git config --global web.browser firefox
+------------------------------------------------
+
+as they are probably more user specific than repository specific.
+See linkgit:git-config[1] for more information about this.
+
+Author
+------
+Written by Christian Couder <chriscool@tuxfamily.org> and the git-list
+<git@vger.kernel.org>, based on git-mergetool by Theodore Y. Ts'o.
+
+Documentation
+-------------
+Documentation by Christian Couder <chriscool@tuxfamily.org> and the
+git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the linkgit:git[7] suite
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 17aee93ec5..d57bed618f 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,11 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.5.4/git.html[documentation for release 1.5.4]
+* link:v1.5.4.2/git.html[documentation for release 1.5.4.2]
* release notes for
+ link:RelNotes-1.5.4.2.txt[1.5.4.2],
+ link:RelNotes-1.5.4.1.txt[1.5.4.1],
link:RelNotes-1.5.4.txt[1.5.4].
* link:v1.5.3.8/git.html[documentation for release 1.5.3.8]
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 35a29fd60c..84ec9623a2 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -133,6 +133,26 @@ When `core.autocrlf` is set to "input", line endings are
converted to LF upon checkin, but there is no conversion done
upon checkout.
+If `core.safecrlf` is set to "true" or "warn", git verifies if
+the conversion is reversible for the current setting of
+`core.autocrlf`. For "true", git rejects irreversible
+conversions; for "warn", git only prints a warning but accepts
+an irreversible conversion. The safety triggers to prevent such
+a conversion done to the files in the work tree, but there are a
+few exceptions. Even though...
+
+- "git add" itself does not touch the files in the work tree, the
+ next checkout would, so the safety triggers;
+
+- "git apply" to update a text file with a patch does touch the files
+ in the work tree, but the operation is about text files and CRLF
+ conversion is about fixing the line ending inconsistencies, so the
+ safety does not trigger;
+
+- "git diff" itself does not touch the files in the work tree, it is
+ often run to inspect the changes you intend to next "git add". To
+ catch potential problems early, safety triggers.
+
`ident`
^^^^^^^
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 08373f52bb..e847b3ba63 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -57,6 +57,13 @@ Patterns have the following format:
included again. If a negated pattern matches, this will
override lower precedence patterns sources.
+ - If the pattern ends with a slash, it is removed for the
+ purpose of the following description, but it would only find
+ a match with a directory. In other words, `foo/` will match a
+ directory `foo` and paths underneath it, but will not match a
+ regular file or a symbolic link `foo` (this is consistent
+ with the way how pathspec works in general in git).
+
- If the pattern does not contain a slash '/', git treats it as
a shell glob pattern and checks for a match against the
pathname without leading directories.
diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt
index f110162b01..76b8d77460 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/hooks.txt
@@ -61,6 +61,35 @@ The default 'pre-commit' hook, when enabled, catches introduction
of lines with trailing whitespaces and aborts the commit when
such a line is found.
+All the `git-commit` hooks are invoked with the environment
+variable `GIT_EDITOR=:` if the command will not bring up an editor
+to modify the commit message.
+
+prepare-commit-msg
+------------------
+
+This hook is invoked by `git-commit` right after preparing the
+default log message, and before the editor is started.
+
+It takes one to three parameters. The first is the name of the file
+that the commit log message. The second is the source of the commit
+message, and can be: `message` (if a `\-m` or `\-F` option was
+given); `template` (if a `\-t` option was given or the
+configuration option `commit.template` is set); `merge` (if the
+commit is a merge or a `.git/MERGE_MSG` file exists); `squash`
+(if a `.git/SQUASH_MSG` file exists); or `commit`, followed by
+a commit SHA1 (if a `\-c`, `\-C` or `\--amend` option was given).
+
+If the exit status is non-zero, `git-commit` will abort.
+
+The purpose of the hook is to edit the message file in place, and
+it is not suppressed by the `\--no-verify` option. A non-zero exit
+means a failure of the hook and aborts the commit. It should not
+be used as replacement for pre-commit hook.
+
+The sample `prepare-commit-msg` hook that comes with git comments
+out the `Conflicts:` part of a merge's commit message.
+
commit-msg
----------
diff --git a/Documentation/technical/api-remote.txt b/Documentation/technical/api-remote.txt
new file mode 100644
index 0000000000..073b22bd83
--- /dev/null
+++ b/Documentation/technical/api-remote.txt
@@ -0,0 +1,123 @@
+Remotes configuration API
+=========================
+
+The API in remote.h gives access to the configuration related to
+remotes. It handles all three configuration mechanisms historically
+and currently used by git, and presents the information in a uniform
+fashion. Note that the code also handles plain URLs without any
+configuration, giving them just the default information.
+
+struct remote
+-------------
+
+`name`::
+
+ The user's nickname for the remote
+
+`url`::
+
+ An array of all of the url_nr URLs configured for the remote
+
+`push`::
+
+ An array of refspecs configured for pushing, with
+ push_refspec being the literal strings, and push_refspec_nr
+ being the quantity.
+
+`fetch`::
+
+ An array of refspecs configured for fetching, with
+ fetch_refspec being the literal strings, and fetch_refspec_nr
+ being the quantity.
+
+`fetch_tags`::
+
+ The setting for whether to fetch tags (as a separate rule from
+ the configured refspecs); -1 means never to fetch tags, 0
+ means to auto-follow tags based on the default heuristic, 1
+ means to always auto-follow tags, and 2 means to fetch all
+ tags.
+
+`receivepack`, `uploadpack`::
+
+ The configured helper programs to run on the remote side, for
+ git-native protocols.
+
+`http_proxy`::
+
+ The proxy to use for curl (http, https, ftp, etc.) URLs.
+
+struct remotes can be found by name with remote_get(), and iterated
+through with for_each_remote(). remote_get(NULL) will return the
+default remote, given the current branch and configuration.
+
+struct refspec
+--------------
+
+A struct refspec holds the parsed interpretation of a refspec. If it
+will force updates (starts with a '+'), force is true. If it is a
+pattern (sides end with '*') pattern is true. src and dest are the two
+sides (if a pattern, only the part outside of the wildcards); if there
+is only one side, it is src, and dst is NULL; if sides exist but are
+empty (i.e., the refspec either starts or ends with ':'), the
+corresponding side is "".
+
+This parsing can be done to an array of strings to give an array of
+struct refpsecs with parse_ref_spec().
+
+remote_find_tracking(), given a remote and a struct refspec with
+either src or dst filled out, will fill out the other such that the
+result is in the "fetch" specification for the remote (note that this
+evaluates patterns and returns a single result).
+
+struct branch
+-------------
+
+Note that this may end up moving to branch.h
+
+struct branch holds the configuration for a branch. It can be looked
+up with branch_get(name) for "refs/heads/{name}", or with
+branch_get(NULL) for HEAD.
+
+It contains:
+
+`name`::
+
+ The short name of the branch.
+
+`refname`::
+
+ The full path for the branch ref.
+
+`remote_name`::
+
+ The name of the remote listed in the configuration.
+
+`remote`::
+
+ The struct remote for that remote.
+
+`merge_name`::
+
+ An array of the "merge" lines in the configuration.
+
+`merge`::
+
+ An array of the struct refspecs used for the merge lines. That
+ is, merge[i]->dst is a local tracking ref which should be
+ merged into this branch by default.
+
+`merge_nr`::
+
+ The number of merge configurations
+
+branch_has_merge_config() returns true if the given branch has merge
+configuration given.
+
+Other stuff
+-----------
+
+There is other stuff in remote.h that is related, in general, to the
+process of interacting with remotes.
+
+(Daniel Barkalow)
diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt
index 19d2f64f73..dfbf9ac5d0 100644
--- a/Documentation/technical/api-run-command.txt
+++ b/Documentation/technical/api-run-command.txt
@@ -1,10 +1,171 @@
run-command API
===============
-Talk about <run-command.h>, and things like:
+The run-command API offers a versatile tool to run sub-processes with
+redirected input and output as well as with a modified environment
+and an alternate current directory.
-* Environment the command runs with (e.g. GIT_DIR);
-* File descriptors and pipes;
-* Exit status;
+A similar API offers the capability to run a function asynchronously,
+which is primarily used to capture the output that the function
+produces in the caller in order to process it.
-(Hannes, Dscho, Shawn)
+
+Functions
+---------
+
+`start_command`::
+
+ Start a sub-process. Takes a pointer to a `struct child_process`
+ that specifies the details and returns pipe FDs (if requested).
+ See below for details.
+
+`finish_command`::
+
+ Wait for the completion of a sub-process that was started with
+ start_command().
+
+`run_command`::
+
+ A convenience function that encapsulates a sequence of
+ start_command() followed by finish_command(). Takes a pointer
+ to a `struct child_process` that specifies the details.
+
+`run_command_v_opt`, `run_command_v_opt_dir`, `run_command_v_opt_cd_env`::
+
+ Convenience functions that encapsulate a sequence of
+ start_command() followed by finish_command(). The argument argv
+ specifies the program and its arguments. The argument opt is zero
+ or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`, or
+ `RUN_COMMAND_STDOUT_TO_STDERR` that correspond to the members
+ .no_stdin, .git_cmd, .stdout_to_stderr of `struct child_process`.
+ The argument dir corresponds the member .dir. The argument env
+ corresponds to the member .env.
+
+`start_async`::
+
+ Run a function asynchronously. Takes a pointer to a `struct
+ async` that specifies the details and returns a pipe FD
+ from which the caller reads. See below for details.
+
+`finish_async`::
+
+ Wait for the completeion of an asynchronous function that was
+ started with start_async().
+
+
+Data structures
+---------------
+
+* `struct child_process`
+
+This describes the arguments, redirections, and environment of a
+command to run in a sub-process.
+
+The caller:
+
+1. allocates and clears (memset(&chld, '0', sizeof(chld));) a
+ struct child_process variable;
+2. initializes the members;
+3. calls start_command();
+4. processes the data;
+5. closes file descriptors (if necessary; see below);
+6. calls finish_command().
+
+The .argv member is set up as an array of string pointers (NULL
+terminated), of which .argv[0] is the program name to run (usually
+without a path). If the command to run is a git command, set argv[0] to
+the command name without the 'git-' prefix and set .git_cmd = 1.
+
+The members .in, .out, .err are used to redirect stdin, stdout,
+stderr as follows:
+
+. Specify 0 to request no special redirection. No new file descriptor
+ is allocated. The child process simply inherits the channel from the
+ parent.
+
+. Specify -1 to have a pipe allocated; start_command() replaces -1
+ by the pipe FD in the following way:
+
+ .in: Returns the writable pipe end into which the caller writes;
+ the readable end of the pipe becomes the child's stdin.
+
+ .out, .err: Returns the readable pipe end from which the caller
+ reads; the writable end of the pipe end becomes child's
+ stdout/stderr.
+
+ The caller of start_command() must close the so returned FDs
+ after it has completed reading from/writing to it!
+
+. Specify a file descriptor > 0 to be used by the child:
+
+ .in: The FD must be readable; it becomes child's stdin.
+ .out: The FD must be writable; it becomes child's stdout.
+ .err > 0 is not supported.
+
+ The specified FD is closed by start_command(), even if it fails to
+ run the sub-process!
+
+. Special forms of redirection are available by setting these members
+ to 1:
+
+ .no_stdin, .no_stdout, .no_stderr: The respective channel is
+ redirected to /dev/null.
+
+ .stdout_to_stderr: stdout of the child is redirected to the
+ parent's stderr (i.e. *not* to what .err or
+ .no_stderr specify).
+
+To modify the environment of the sub-process, specify an array of
+string pointers (NULL terminated) in .env:
+
+. If the string is of the form "VAR=value", i.e. it contains '='
+ the variable is added to the child process's environment.
+
+. If the string does not contain '=', it names an environement
+ variable that will be removed from the child process's envionment.
+
+To specify a new initial working directory for the sub-process,
+specify it in the .dir member.
+
+
+* `struct async`
+
+This describes a function to run asynchronously, whose purpose is
+to produce output that the caller reads.
+
+The caller:
+
+1. allocates and clears (memset(&asy, '0', sizeof(asy));) a
+ struct async variable;
+2. initializes .proc and .data;
+3. calls start_async();
+4. processes the data by reading from the fd in .out;
+5. closes .out;
+6. calls finish_async().
+
+The function pointer in .proc has the following signature:
+
+ int proc(int fd, void *data);
+
+. fd specifies a writable file descriptor to which the function must
+ write the data that it produces. The function *must* close this
+ descriptor before it returns.
+
+. data is the value that the caller has specified in the .data member
+ of struct async.
+
+. The return value of the function is 0 on success and non-zero
+ on failure. If the function indicates failure, finish_async() will
+ report failure as well.
+
+
+There are serious restrictions on what the asynchronous function can do
+because this facility is implemented by a pipe to a forked process on
+UNIX, but by a thread in the same address space on Windows:
+
+. It cannot change the program's state (global variables, environment,
+ etc.) in a way that the caller notices; in other words, .out is the
+ only communication channel to the caller.
+
+. It must not change the program's state that the caller of the
+ facility also uses.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 38a3273974..1ad324e236 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -15,7 +15,8 @@ elif test -d .git &&
VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
- v[0-9]*) : happy ;;
+ v[0-9]*)
+ git diff-index --quiet HEAD || VN="$VN-dirty" ;;
esac
then
VN=$(echo "$VN" | sed -e 's/-/./g');
@@ -25,14 +26,6 @@ fi
VN=$(expr "$VN" : v*'\(.*\)')
-dirty=$(sh -c 'git diff-index --name-only HEAD' 2>/dev/null) || dirty=
-case "$dirty" in
-'')
- ;;
-*)
- VN="$VN-dirty" ;;
-esac
-
if test -r $GVF
then
VC=$(sed -e 's/^GIT_VERSION = //' <$GVF)
diff --git a/Makefile b/Makefile
index debfc236d2..d33a556ffe 100644
--- a/Makefile
+++ b/Makefile
@@ -140,6 +140,10 @@ all::
# Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit
# parallel delta searching when packing objects.
#
+# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
+# is a simplified version of the merge sort used in glibc. This is
+# recommended if Git triggers O(n^2) behavior in your platform's qsort().
+#
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -234,7 +238,7 @@ SCRIPT_SH = \
git-lost-found.sh git-quiltimport.sh git-submodule.sh \
git-filter-branch.sh \
git-stash.sh \
- git-help--browse.sh
+ git-web--browse.sh
SCRIPT_PERL = \
git-add--interactive.perl \
@@ -729,6 +733,10 @@ ifdef NO_MEMMEM
COMPAT_CFLAGS += -DNO_MEMMEM
COMPAT_OBJS += compat/memmem.o
endif
+ifdef INTERNAL_QSORT
+ COMPAT_CFLAGS += -DINTERNAL_QSORT
+ COMPAT_OBJS += compat/qsort.o
+endif
ifdef THREADED_DELTA_SEARCH
BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
@@ -826,6 +834,7 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
help.o: help.c common-cmds.h GIT-CFLAGS
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
+ '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
'-DGIT_INFO_PATH="$(infodir_SQ)"' $<
@@ -846,7 +855,6 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
- -e 's|@@HTMLDIR@@|$(htmldir_SQ)|g' \
$@.sh >$@+ && \
chmod +x $@+ && \
mv $@+ $@
diff --git a/RelNotes b/RelNotes
index 46308cee0b..3e77358f70 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.5.4.txt \ No newline at end of file
+Documentation/RelNotes-1.5.5.txt \ No newline at end of file
diff --git a/builtin-add.c b/builtin-add.c
index 4a91e3eb11..820110e085 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -228,6 +228,18 @@ int cmd_add(int argc, const char **argv, const char *prefix)
goto finish;
}
+ if (*argv) {
+ /* Was there an invalid path? */
+ if (pathspec) {
+ int num;
+ for (num = 0; pathspec[num]; num++)
+ ; /* just counting */
+ if (argc != num)
+ exit(1); /* error message already given */
+ } else
+ exit(1); /* error message already given */
+ }
+
fill_directory(&dir, pathspec, ignored_too);
if (show_only) {
diff --git a/builtin-apply.c b/builtin-apply.c
index 46dad5b2a1..6a88ff018d 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -1430,7 +1430,7 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
case S_IFREG:
if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
return error("unable to open or read %s", path);
- convert_to_git(path, buf->buf, buf->len, buf);
+ convert_to_git(path, buf->buf, buf->len, buf, 0);
return 0;
default:
return -1;
diff --git a/builtin-blame.c b/builtin-blame.c
index c7e68874e7..59d7237f21 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1894,9 +1894,7 @@ static unsigned parse_score(const char *arg)
static const char *add_prefix(const char *prefix, const char *path)
{
- if (!prefix || !prefix[0])
- return path;
- return prefix_path(prefix, strlen(prefix), path);
+ return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
}
/*
@@ -2073,7 +2071,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
if (strbuf_read(&buf, 0, 0) < 0)
die("read error %s from stdin", strerror(errno));
}
- convert_to_git(path, buf.buf, buf.len, &buf);
+ convert_to_git(path, buf.buf, buf.len, &buf, 0);
origin->file.ptr = buf.buf;
origin->file.size = buf.len;
pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
@@ -2369,7 +2367,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
* bottom commits we would reach while traversing as
* uninteresting.
*/
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
if (is_null_sha1(sb.final->object.sha1)) {
char *buf;
diff --git a/builtin-commit.c b/builtin-commit.c
index 717eb18da0..6612b4f405 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -317,6 +317,10 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
if (write_cache(fd, active_cache, active_nr) ||
close_lock_file(&false_lock))
die("unable to write temporary index file");
+
+ discard_cache();
+ read_cache_from(false_lock.filename);
+
return false_lock.filename;
}
@@ -343,45 +347,107 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
return s.commitable;
}
+static int run_hook(const char *index_file, const char *name, ...)
+{
+ struct child_process hook;
+ const char *argv[10], *env[2];
+ char index[PATH_MAX];
+ va_list args;
+ int i;
+
+ va_start(args, name);
+ argv[0] = git_path("hooks/%s", name);
+ i = 0;
+ do {
+ if (++i >= ARRAY_SIZE(argv))
+ die ("run_hook(): too many arguments");
+ argv[i] = va_arg(args, const char *);
+ } while (argv[i]);
+ va_end(args);
+
+ snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+ env[0] = index;
+ env[1] = NULL;
+
+ if (access(argv[0], X_OK) < 0)
+ return 0;
+
+ memset(&hook, 0, sizeof(hook));
+ hook.argv = argv;
+ hook.no_stdin = 1;
+ hook.stdout_to_stderr = 1;
+ hook.env = env;
+
+ return run_command(&hook);
+}
+
+static int is_a_merge(const unsigned char *sha1)
+{
+ struct commit *commit = lookup_commit(sha1);
+ if (!commit || parse_commit(commit))
+ die("could not parse HEAD commit");
+ return !!(commit->parents && commit->parents->next);
+}
+
static const char sign_off_header[] = "Signed-off-by: ";
-static int prepare_log_message(const char *index_file, const char *prefix)
+static int prepare_to_commit(const char *index_file, const char *prefix)
{
struct stat statbuf;
int commitable, saved_color_setting;
struct strbuf sb;
char *buffer;
FILE *fp;
+ const char *hook_arg1 = NULL;
+ const char *hook_arg2 = NULL;
+
+ if (!no_verify && run_hook(index_file, "pre-commit", NULL))
+ return 0;
strbuf_init(&sb, 0);
if (message.len) {
strbuf_addbuf(&sb, &message);
+ hook_arg1 = "message";
} else if (logfile && !strcmp(logfile, "-")) {
if (isatty(0))
fprintf(stderr, "(reading log message from standard input)\n");
if (strbuf_read(&sb, 0, 0) < 0)
die("could not read log from standard input");
+ hook_arg1 = "message";
} else if (logfile) {
if (strbuf_read_file(&sb, logfile, 0) < 0)
die("could not read log file '%s': %s",
logfile, strerror(errno));
+ hook_arg1 = "message";
} else if (use_message) {
buffer = strstr(use_message_buffer, "\n\n");
if (!buffer || buffer[2] == '\0')
die("commit has empty message");
strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
+ hook_arg1 = "commit";
+ hook_arg2 = use_message;
} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
die("could not read MERGE_MSG: %s", strerror(errno));
+ hook_arg1 = "merge";
} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
die("could not read SQUASH_MSG: %s", strerror(errno));
+ hook_arg1 = "squash";
} else if (template_file && !stat(template_file, &statbuf)) {
if (strbuf_read_file(&sb, template_file, 0) < 0)
die("could not read %s: %s",
template_file, strerror(errno));
+ hook_arg1 = "template";
}
+ /*
+ * This final case does not modify the template message,
+ * it just sets the argument to the prepare-commit-msg hook.
+ */
+ else if (in_merge)
+ hook_arg1 = "merge";
+
fp = fopen(git_path(commit_editmsg), "w");
if (fp == NULL)
die("could not open %s", git_path(commit_editmsg));
@@ -413,13 +479,38 @@ static int prepare_log_message(const char *index_file, const char *prefix)
strbuf_release(&sb);
- if (!use_editor) {
+ if (use_editor) {
+ if (in_merge)
+ fprintf(fp,
+ "#\n"
+ "# It looks like you may be committing a MERGE.\n"
+ "# If this is not correct, please remove the file\n"
+ "# %s\n"
+ "# and try again.\n"
+ "#\n",
+ git_path("MERGE_HEAD"));
+
+ fprintf(fp,
+ "\n"
+ "# Please enter the commit message for your changes.\n"
+ "# (Comment lines starting with '#' will ");
+ if (cleanup_mode == CLEANUP_ALL)
+ fprintf(fp, "not be included)\n");
+ else /* CLEANUP_SPACE, that is. */
+ fprintf(fp, "be kept.\n"
+ "# You can remove them yourself if you want to)\n");
+ if (only_include_assumed)
+ fprintf(fp, "# %s\n", only_include_assumed);
+
+ saved_color_setting = wt_status_use_color;
+ wt_status_use_color = 0;
+ commitable = run_status(fp, index_file, prefix, 1);
+ wt_status_use_color = saved_color_setting;
+ } else {
struct rev_info rev;
unsigned char sha1[20];
const char *parent = "HEAD";
- fclose(fp);
-
if (!active_nr && read_cache() < 0)
die("Cannot read index");
@@ -427,48 +518,60 @@ static int prepare_log_message(const char *index_file, const char *prefix)
parent = "HEAD^1";
if (get_sha1(parent, sha1))
- return !!active_nr;
+ commitable = !!active_nr;
+ else {
+ init_revisions(&rev, "");
+ rev.abbrev = 0;
+ setup_revisions(0, NULL, &rev, parent);
+ DIFF_OPT_SET(&rev.diffopt, QUIET);
+ DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
+ run_diff_index(&rev, 1 /* cached */);
+
+ commitable = !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
+ }
+ }
- init_revisions(&rev, "");
- rev.abbrev = 0;
- setup_revisions(0, NULL, &rev, parent);
- DIFF_OPT_SET(&rev.diffopt, QUIET);
- DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
- run_diff_index(&rev, 1 /* cached */);
+ fclose(fp);
- return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
+ if (!commitable && !in_merge && !allow_empty &&
+ !(amend && is_a_merge(head_sha1))) {
+ run_status(stdout, index_file, prefix, 0);
+ unlink(commit_editmsg);
+ return 0;
}
- if (in_merge)
- fprintf(fp,
- "#\n"
- "# It looks like you may be committing a MERGE.\n"
- "# If this is not correct, please remove the file\n"
- "# %s\n"
- "# and try again.\n"
- "#\n",
- git_path("MERGE_HEAD"));
-
- fprintf(fp,
- "\n"
- "# Please enter the commit message for your changes.\n"
- "# (Comment lines starting with '#' will ");
- if (cleanup_mode == CLEANUP_ALL)
- fprintf(fp, "not be included)\n");
- else /* CLEANUP_SPACE, that is. */
- fprintf(fp, "be kept.\n"
- "# You can remove them yourself if you want to)\n");
- if (only_include_assumed)
- fprintf(fp, "# %s\n", only_include_assumed);
-
- saved_color_setting = wt_status_use_color;
- wt_status_use_color = 0;
- commitable = run_status(fp, index_file, prefix, 1);
- wt_status_use_color = saved_color_setting;
+ /*
+ * Re-read the index as pre-commit hook could have updated it,
+ * and write it out as a tree. We must do this before we invoke
+ * the editor and after we invoke run_status above.
+ */
+ discard_cache();
+ read_cache_from(index_file);
+ if (!active_cache_tree)
+ active_cache_tree = cache_tree();
+ if (cache_tree_update(active_cache_tree,
+ active_cache, active_nr, 0, 0) < 0) {
+ error("Error building trees");
+ return 0;
+ }
- fclose(fp);
+ if (run_hook(index_file, "prepare-commit-msg",
+ git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
+ return 0;
+
+ if (use_editor) {
+ char index[PATH_MAX];
+ const char *env[2] = { index, NULL };
+ snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+ launch_editor(git_path(commit_editmsg), NULL, env);
+ }
+
+ if (!no_verify &&
+ run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
+ return 0;
+ }
- return commitable;
+ return 1;
}
/*
@@ -565,6 +668,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
use_editor = 0;
if (edit_flag)
use_editor = 1;
+ if (!use_editor)
+ setenv("GIT_EDITOR", ":", 1);
if (get_sha1("HEAD", head_sha1))
initial_commit = 1;
@@ -677,31 +782,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)
return commitable ? 0 : 1;
}
-static int run_hook(const char *index_file, const char *name, const char *arg)
-{
- struct child_process hook;
- const char *argv[3], *env[2];
- char index[PATH_MAX];
-
- argv[0] = git_path("hooks/%s", name);
- argv[1] = arg;
- argv[2] = NULL;
- snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
- env[0] = index;
- env[1] = NULL;
-
- if (access(argv[0], X_OK) < 0)
- return 0;
-
- memset(&hook, 0, sizeof(hook));
- hook.argv = argv;
- hook.no_stdin = 1;
- hook.stdout_to_stderr = 1;
- hook.env = env;
-
- return run_command(&hook);
-}
-
static void print_summary(const char *prefix, const unsigned char *sha1)
{
struct rev_info rev;
@@ -752,14 +832,6 @@ int git_commit_config(const char *k, const char *v)
return git_status_config(k, v);
}
-static int is_a_merge(const unsigned char *sha1)
-{
- struct commit *commit = lookup_commit(sha1);
- if (!commit || parse_commit(commit))
- die("could not parse HEAD commit");
- return !!(commit->parents && commit->parents->next);
-}
-
static const char commit_utf8_warn[] =
"Warning: commit message does not conform to UTF-8.\n"
"You may want to amend it after fixing the message, or set the config\n"
@@ -791,33 +863,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
index_file = prepare_index(argc, argv, prefix);
- if (!no_verify && run_hook(index_file, "pre-commit", NULL)) {
+ /* Set up everything for writing the commit object. This includes
+ running hooks, writing the trees, and interacting with the user. */
+ if (!prepare_to_commit(index_file, prefix)) {
rollback_index_files();
return 1;
}
- if (!prepare_log_message(index_file, prefix) && !in_merge &&
- !allow_empty && !(amend && is_a_merge(head_sha1))) {
- run_status(stdout, index_file, prefix, 0);
- rollback_index_files();
- unlink(commit_editmsg);
- return 1;
- }
-
- /*
- * Re-read the index as pre-commit hook could have updated it,
- * and write it out as a tree.
- */
- discard_cache();
- read_cache_from(index_file);
- if (!active_cache_tree)
- active_cache_tree = cache_tree();
- if (cache_tree_update(active_cache_tree,
- active_cache, active_nr, 0, 0) < 0) {
- rollback_index_files();
- die("Error building trees");
- }
-
/*
* The commit object
*/
@@ -869,19 +921,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
strbuf_addch(&sb, '\n');
- /* Get the commit message and validate it */
+ /* Finally, get the commit message */
header_len = sb.len;
- if (use_editor) {
- char index[PATH_MAX];
- const char *env[2] = { index, NULL };
- snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
- launch_editor(git_path(commit_editmsg), NULL, env);
- }
- if (!no_verify &&
- run_hook(index_file, "commit-msg", git_path(commit_editmsg))) {
- rollback_index_files();
- exit(1);
- }
if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
rollback_index_files();
die("could not read commit message");
diff --git a/builtin-config.c b/builtin-config.c
index 077d8ef2df..2b9a4261d4 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -79,9 +79,10 @@ static int get_value(const char* key_, const char* regex_)
local = getenv(CONFIG_LOCAL_ENVIRONMENT);
if (!local)
local = repo_config = xstrdup(git_path("config"));
- if (home)
+ if (git_config_global() && home)
global = xstrdup(mkpath("%s/.gitconfig", home));
- system_wide = git_etc_gitconfig();
+ if (git_config_system())
+ system_wide = git_etc_gitconfig();
}
key = xstrdup(key_);
diff --git a/builtin-fast-export.c b/builtin-fast-export.c
index ef27eee71b..f741df5220 100755
--- a/builtin-fast-export.c
+++ b/builtin-fast-export.c
@@ -383,7 +383,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
get_tags_and_duplicates(&revs.pending, &extra_refs);
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
revs.diffopt.format_callback = show_filemodify;
DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
while ((commit = get_revision(&revs))) {
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index 6163bd4975..ebb3f37cf1 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -187,7 +187,8 @@ static void shortlog(const char *name, unsigned char *sha1,
add_pending_object(rev, branch, name);
add_pending_object(rev, &head->object, "^HEAD");
head->object.flags |= UNINTERESTING;
- prepare_revision_walk(rev);
+ if (prepare_revision_walk(rev))
+ die("revision walk setup failed");
while ((commit = get_revision(rev)) != NULL) {
char *oneline, *bol, *eol;
diff --git a/builtin-log.c b/builtin-log.c
index 99d69f0791..5fea64abad 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -197,7 +197,8 @@ static int cmd_log_walk(struct rev_info *rev)
if (rev->early_output)
setup_early_output(rev);
- prepare_revision_walk(rev);
+ if (prepare_revision_walk(rev))
+ die("revision walk setup failed");
if (rev->early_output)
finish_early_output(rev);
@@ -556,7 +557,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha
o2->flags ^= UNINTERESTING;
add_pending_object(&check_rev, o1, "o1");
add_pending_object(&check_rev, o2, "o2");
- prepare_revision_walk(&check_rev);
+ if (prepare_revision_walk(&check_rev))
+ die("revision walk setup failed");
while ((commit = get_revision(&check_rev)) != NULL) {
/* ignore merges */
@@ -781,7 +783,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (!use_stdout)
realstdout = xfdopen(xdup(1), "w");
- prepare_revision_walk(&rev);
+ if (prepare_revision_walk(&rev))
+ die("revision walk setup failed");
while ((commit = get_revision(&rev)) != NULL) {
/* ignore merges */
if (commit->parents && commit->parents->next)
@@ -923,7 +926,8 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
die("Unknown commit %s", limit);
/* reverse the list of commits */
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
while ((commit = get_revision(&revs)) != NULL) {
/* ignore merges */
if (commit->parents && commit->parents->next)
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index d56e33e251..25dbfb4499 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -238,7 +238,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
if (show_cached | show_stage) {
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
- if (excluded(dir, ce->name) != dir->show_ignored)
+ int dtype = ce_to_dtype(ce);
+ if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
continue;
if (show_unmerged && !ce_stage(ce))
continue;
@@ -252,7 +253,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
struct cache_entry *ce = active_cache[i];
struct stat st;
int err;
- if (excluded(dir, ce->name) != dir->show_ignored)
+ int dtype = ce_to_dtype(ce);
+ if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
continue;
err = lstat(ce->name, &st);
if (show_deleted && err)
@@ -572,8 +574,17 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
pathspec = get_pathspec(prefix, argv + i);
/* Verify that the pathspec matches the prefix */
- if (pathspec)
+ if (pathspec) {
+ if (argc != i) {
+ int cnt;
+ for (cnt = 0; pathspec[cnt]; cnt++)
+ ;
+ if (cnt != (argc - i))
+ exit(1); /* error message already given */
+ }
prefix = verify_pathspec(prefix);
+ } else if (argc != i)
+ exit(1); /* error message already given */
/* Treat unmatching pathspec elements as errors */
if (pathspec && error_unmatch) {
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index 2600847974..11f154b31f 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -818,6 +818,7 @@ static void handle_body(void)
switch (transfer_encoding) {
case TE_BASE64:
+ case TE_QP:
{
char *op = line;
diff --git a/builtin-mv.c b/builtin-mv.c
index 990e21355d..68aa2a68bb 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -19,6 +19,7 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
int count, int base_name)
{
int i;
+ int len = prefix ? strlen(prefix) : 0;
const char **result = xmalloc((count + 1) * sizeof(const char *));
memcpy(result, pathspec, count * sizeof(const char *));
result[count] = NULL;
@@ -32,8 +33,11 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
if (last_slash)
result[i] = last_slash + 1;
}
+ result[i] = prefix_path(prefix, len, result[i]);
+ if (!result[i])
+ exit(1); /* error already given */
}
- return get_pathspec(prefix, result);
+ return result;
}
static void show_list(const char *label, struct path_list *list)
@@ -164,7 +168,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
}
dst = add_slash(dst);
- dst_len = strlen(dst) - 1;
+ dst_len = strlen(dst);
for (j = 0; j < last - first; j++) {
const char *path =
@@ -172,7 +176,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
source[argc + j] = path;
destination[argc + j] =
prefix_path(dst, dst_len,
- path + length);
+ path + length + 1);
modes[argc + j] = INDEX;
}
argc += last - first;
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index acb05554d4..d2bb12e574 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -1464,7 +1464,7 @@ static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)
return m;
}
-static unsigned long free_unpacked_data(struct unpacked *n)
+static unsigned long free_unpacked(struct unpacked *n)
{
unsigned long freed_mem = sizeof_delta_index(n->index);
free_delta_index(n->index);
@@ -1474,12 +1474,6 @@ static unsigned long free_unpacked_data(struct unpacked *n)
free(n->data);
n->data = NULL;
}
- return freed_mem;
-}
-
-static unsigned long free_unpacked(struct unpacked *n)
-{
- unsigned long freed_mem = free_unpacked_data(n);
n->entry = NULL;
n->depth = 0;
return freed_mem;
@@ -1520,7 +1514,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
mem_usage > window_memory_limit &&
count > 1) {
uint32_t tail = (idx + window - count) % window;
- mem_usage -= free_unpacked_data(array + tail);
+ mem_usage -= free_unpacked(array + tail);
count--;
}
@@ -1553,9 +1547,6 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
if (!m->entry)
break;
ret = try_delta(n, m, max_depth, &mem_usage);
- if (window_memory_limit &&
- mem_usage > window_memory_limit)
- mem_usage -= free_unpacked_data(m);
if (ret < 0)
break;
else if (ret > 0)
@@ -2042,7 +2033,8 @@ static void get_object_list(int ac, const char **av)
die("bad revision '%s'", line);
}
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object);
diff --git a/builtin-push.c b/builtin-push.c
index c8cb63e238..9f727c00f6 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -90,7 +90,7 @@ static int do_push(const char *repo, int flags)
if (!err)
continue;
- error("failed to push to '%s'", remote->url[i]);
+ error("failed to push some refs to '%s'", remote->url[i]);
errs++;
}
return !!errs;
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index de80158fd4..9426081dae 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -609,7 +609,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (bisect_list)
revs.limited = 1;
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
if (revs.tree_objects)
mark_edges_uninteresting(revs.commits, &revs, show_edge);
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index fa8bc7d02a..0055a57aeb 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -136,7 +136,8 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
{
struct commit *commit;
- prepare_revision_walk(rev);
+ if (prepare_revision_walk(rev))
+ die("revision walk setup failed");
while ((commit = get_revision(rev)) != NULL) {
const char *author = NULL, *buffer;
diff --git a/builtin-show-ref.c b/builtin-show-ref.c
index 65051d14fd..a323633e29 100644
--- a/builtin-show-ref.c
+++ b/builtin-show-ref.c
@@ -86,6 +86,9 @@ match:
sha1_to_hex(sha1));
if (obj->type == OBJ_TAG) {
obj = deref_tag(obj, refname, 0);
+ if (!obj)
+ die("git-show-ref: bad tag at ref %s (%s)", refname,
+ sha1_to_hex(sha1));
hex = find_unique_abbrev(obj->sha1, abbrev);
printf("%s %s^{}\n", hex, refname);
}
diff --git a/bundle.c b/bundle.c
index 5c95eca07d..bd12ec8537 100644
--- a/bundle.c
+++ b/bundle.c
@@ -128,7 +128,8 @@ int verify_bundle(struct bundle_header *header, int verbose)
add_object_array(e->item, e->name, &refs);
}
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
i = req_nr;
while (i && (commit = get_revision(&revs)))
diff --git a/cache.h b/cache.h
index 3867ba7ff5..e1000bccb2 100644
--- a/cache.h
+++ b/cache.h
@@ -178,6 +178,18 @@ static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned in
}
return create_ce_mode(mode);
}
+static inline int ce_to_dtype(const struct cache_entry *ce)
+{
+ unsigned ce_mode = ntohl(ce->ce_mode);
+ if (S_ISREG(ce_mode))
+ return DT_REG;
+ else if (S_ISDIR(ce_mode) || S_ISGITLINK(ce_mode))
+ return DT_DIR;
+ else if (S_ISLNK(ce_mode))
+ return DT_LNK;
+ else
+ return DT_UNKNOWN;
+}
#define canon_mode(mode) \
(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
@@ -371,6 +383,14 @@ extern size_t packed_git_limit;
extern size_t delta_base_cache_limit;
extern int auto_crlf;
+enum safe_crlf {
+ SAFE_CRLF_FALSE = 0,
+ SAFE_CRLF_FAIL = 1,
+ SAFE_CRLF_WARN = 2,
+};
+
+extern enum safe_crlf safe_crlf;
+
#define GIT_REPO_VERSION 0
extern int repository_format_version;
extern int check_repository_format(void);
@@ -625,11 +645,15 @@ extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *);
extern int git_config_bool(const char *, const char *);
+extern int git_config_string(const char **, const char *, const char *);
extern int git_config_set(const char *, const char *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
extern int git_config_rename_section(const char *, const char *);
extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value);
+extern int git_env_bool(const char *, int);
+extern int git_config_system(void);
+extern int git_config_global(void);
extern int config_error_nonbool(const char *);
#define MAX_GITNAME (1000)
@@ -650,12 +674,12 @@ extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char
/* pager.c */
extern void setup_pager(void);
-extern char *pager_program;
+extern const char *pager_program;
extern int pager_in_use(void);
extern int pager_use_color;
-extern char *editor_program;
-extern char *excludes_file;
+extern const char *editor_program;
+extern const char *excludes_file;
/* base85 */
int decode_85(char *dst, const char *line, int linelen);
@@ -675,7 +699,8 @@ extern void trace_argv_printf(const char **argv, const char *format, ...);
/* convert.c */
/* returns 1 if *dst was used */
-extern int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst);
+extern int convert_to_git(const char *path, const char *src, size_t len,
+ struct strbuf *dst, enum safe_crlf checksafe);
extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
/* add */
diff --git a/commit.c b/commit.c
index 8b8fb04d1f..22ce776863 100644
--- a/commit.c
+++ b/commit.c
@@ -311,6 +311,8 @@ int parse_commit(struct commit *item)
unsigned long size;
int ret;
+ if (!item)
+ return -1;
if (item->object.parsed)
return 0;
buffer = read_sha1_file(item->object.sha1, &type, &size);
@@ -385,8 +387,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
while (parents) {
struct commit *commit = parents->item;
- parse_commit(commit);
- if (!(commit->object.flags & mark)) {
+ if (!parse_commit(commit) && !(commit->object.flags & mark)) {
commit->object.flags |= mark;
insert_by_date(commit, list);
}
@@ -552,8 +553,10 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two)
*/
return commit_list_insert(one, &result);
- parse_commit(one);
- parse_commit(two);
+ if (parse_commit(one))
+ return NULL;
+ if (parse_commit(two))
+ return NULL;
one->object.flags |= PARENT1;
two->object.flags |= PARENT2;
@@ -586,7 +589,8 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two)
parents = parents->next;
if ((p->object.flags & flags) == flags)
continue;
- parse_commit(p);
+ if (parse_commit(p))
+ return NULL;
p->object.flags |= flags;
insert_by_date(p, &list);
}
diff --git a/compat/qsort.c b/compat/qsort.c
new file mode 100644
index 0000000000..d93dce2cf8
--- /dev/null
+++ b/compat/qsort.c
@@ -0,0 +1,62 @@
+#include "../git-compat-util.h"
+
+/*
+ * A merge sort implementation, simplified from the qsort implementation
+ * by Mike Haertel, which is a part of the GNU C Library.
+ */
+
+static void msort_with_tmp(void *b, size_t n, size_t s,
+ int (*cmp)(const void *, const void *),
+ char *t)
+{
+ char *tmp;
+ char *b1, *b2;
+ size_t n1, n2;
+
+ if (n <= 1)
+ return;
+
+ n1 = n / 2;
+ n2 = n - n1;
+ b1 = b;
+ b2 = (char *)b + (n1 * s);
+
+ msort_with_tmp(b1, n1, s, cmp, t);
+ msort_with_tmp(b2, n2, s, cmp, t);
+
+ tmp = t;
+
+ while (n1 > 0 && n2 > 0) {
+ if (cmp(b1, b2) <= 0) {
+ memcpy(tmp, b1, s);
+ tmp += s;
+ b1 += s;
+ --n1;
+ } else {
+ memcpy(tmp, b2, s);
+ tmp += s;
+ b2 += s;
+ --n2;
+ }
+ }
+ if (n1 > 0)
+ memcpy(tmp, b1, n1 * s);
+ memcpy(b, t, (n - n2) * s);
+}
+
+void git_qsort(void *b, size_t n, size_t s,
+ int (*cmp)(const void *, const void *))
+{
+ const size_t size = n * s;
+ char buf[1024];
+
+ if (size < sizeof(buf)) {
+ /* The temporary array fits on the small on-stack buffer. */
+ msort_with_tmp(b, n, s, cmp, buf);
+ } else {
+ /* It's somewhat large, so malloc it. */
+ char *tmp = malloc(size);
+ msort_with_tmp(b, n, s, cmp, tmp);
+ free(tmp);
+ }
+}
diff --git a/config.c b/config.c
index 3e72778e94..8064cae182 100644
--- a/config.c
+++ b/config.c
@@ -309,6 +309,14 @@ int git_config_bool(const char *name, const char *value)
return git_config_int(name, value) != 0;
}
+int git_config_string(const char **dest, const char *var, const char *value)
+{
+ if (!value)
+ return config_error_nonbool(var);
+ *dest = xstrdup(value);
+ return 0;
+}
+
int git_default_config(const char *var, const char *value)
{
/* This needs a better name */
@@ -407,6 +415,15 @@ int git_default_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.safecrlf")) {
+ if (value && !strcasecmp(value, "warn")) {
+ safe_crlf = SAFE_CRLF_WARN;
+ return 0;
+ }
+ safe_crlf = git_config_bool(var, value);
+ return 0;
+ }
+
if (!strcmp(var, "user.name")) {
if (!value)
return config_error_nonbool(var);
@@ -421,46 +438,25 @@ int git_default_config(const char *var, const char *value)
return 0;
}
- if (!strcmp(var, "i18n.commitencoding")) {
- if (!value)
- return config_error_nonbool(var);
- git_commit_encoding = xstrdup(value);
- return 0;
- }
-
- if (!strcmp(var, "i18n.logoutputencoding")) {
- if (!value)
- return config_error_nonbool(var);
- git_log_output_encoding = xstrdup(value);
- return 0;
- }
+ if (!strcmp(var, "i18n.commitencoding"))
+ return git_config_string(&git_commit_encoding, var, value);
+ if (!strcmp(var, "i18n.logoutputencoding"))
+ return git_config_string(&git_log_output_encoding, var, value);
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
pager_use_color = git_config_bool(var,value);
return 0;
}
- if (!strcmp(var, "core.pager")) {
- if (!value)
- return config_error_nonbool(var);
- pager_program = xstrdup(value);
- return 0;
- }
+ if (!strcmp(var, "core.pager"))
+ return git_config_string(&pager_program, var, value);
- if (!strcmp(var, "core.editor")) {
- if (!value)
- return config_error_nonbool(var);
- editor_program = xstrdup(value);
- return 0;
- }
+ if (!strcmp(var, "core.editor"))
+ return git_config_string(&editor_program, var, value);
- if (!strcmp(var, "core.excludesfile")) {
- if (!value)
- return config_error_nonbool(var);
- excludes_file = xstrdup(value);
- return 0;
- }
+ if (!strcmp(var, "core.excludesfile"))
+ return git_config_string(&excludes_file, var, value);
if (!strcmp(var, "core.whitespace")) {
if (!value)
@@ -506,6 +502,22 @@ const char *git_etc_gitconfig(void)
return system_wide;
}
+int git_env_bool(const char *k, int def)
+{
+ const char *v = getenv(k);
+ return v ? git_config_bool(k, v) : def;
+}
+
+int git_config_system(void)
+{
+ return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
+}
+
+int git_config_global(void)
+{
+ return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
+}
+
int git_config(config_fn_t fn)
{
int ret = 0;
@@ -518,7 +530,7 @@ int git_config(config_fn_t fn)
* config file otherwise. */
filename = getenv(CONFIG_ENVIRONMENT);
if (!filename) {
- if (!access(git_etc_gitconfig(), R_OK))
+ if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
ret += git_config_from_file(fn, git_etc_gitconfig());
home = getenv("HOME");
filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
@@ -526,7 +538,7 @@ int git_config(config_fn_t fn)
filename = repo_config = xstrdup(git_path("config"));
}
- if (home) {
+ if (git_config_global() && home) {
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
if (!access(user_config, R_OK))
ret = git_config_from_file(fn, user_config);
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index a8bf0ef883..f69b697f8d 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -185,9 +185,8 @@ if there is already one that displays the same directory."
(defun git-call-process-env (buffer env &rest args)
"Wrapper for call-process that sets environment strings."
- (if env
- (apply #'call-process "env" nil buffer nil
- (append (git-get-env-strings env) (list "git") args))
+ (let ((process-environment (append (git-get-env-strings env)
+ process-environment)))
(apply #'call-process "git" nil buffer nil args)))
(defun git-call-process-display-error (&rest args)
@@ -204,7 +203,7 @@ if there is already one that displays the same directory."
(defun git-call-process-env-string (env &rest args)
"Wrapper for call-process that sets environment strings,
-and returns the process output as a string."
+and returns the process output as a string, or nil if the git failed."
(with-temp-buffer
(and (eq 0 (apply #' git-call-process-env t env args))
(buffer-string))))
diff --git a/contrib/hg-to-git/hg-to-git.py b/contrib/hg-to-git/hg-to-git.py
index c35b15860d..d72ffbb777 100755
--- a/contrib/hg-to-git/hg-to-git.py
+++ b/contrib/hg-to-git/hg-to-git.py
@@ -111,7 +111,7 @@ hgparents["0"] = (None, None)
hgbranch["0"] = "master"
for cset in range(1, int(tip) + 1):
hgchildren[str(cset)] = ()
- prnts = os.popen('hg log -r %d --template "{parents}"' % cset).read().split(' ')
+ prnts = os.popen('hg log -r %d --template "{parents}"' % cset).read().strip().split(' ')
prnts = map(lambda x: x[:x.find(':')], prnts)
if prnts[0] != '':
parent = prnts[0].strip()
diff --git a/convert.c b/convert.c
index 552707e8e6..d8c94cb3ed 100644
--- a/convert.c
+++ b/convert.c
@@ -85,8 +85,39 @@ static int is_binary(unsigned long size, struct text_stat *stats)
return 0;
}
+static void check_safe_crlf(const char *path, int action,
+ struct text_stat *stats, enum safe_crlf checksafe)
+{
+ if (!checksafe)
+ return;
+
+ if (action == CRLF_INPUT || auto_crlf <= 0) {
+ /*
+ * CRLFs would not be restored by checkout:
+ * check if we'd remove CRLFs
+ */
+ if (stats->crlf) {
+ if (checksafe == SAFE_CRLF_WARN)
+ warning("CRLF will be replaced by LF in %s.", path);
+ else /* i.e. SAFE_CRLF_FAIL */
+ die("CRLF would be replaced by LF in %s.", path);
+ }
+ } else if (auto_crlf > 0) {
+ /*
+ * CRLFs would be added by checkout:
+ * check if we have "naked" LFs
+ */
+ if (stats->lf != stats->crlf) {
+ if (checksafe == SAFE_CRLF_WARN)
+ warning("LF will be replaced by CRLF in %s", path);
+ else /* i.e. SAFE_CRLF_FAIL */
+ die("LF would be replaced by CRLF in %s", path);
+ }
+ }
+}
+
static int crlf_to_git(const char *path, const char *src, size_t len,
- struct strbuf *buf, int action)
+ struct strbuf *buf, int action, enum safe_crlf checksafe)
{
struct text_stat stats;
char *dst;
@@ -95,9 +126,6 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
return 0;
gather_stats(src, len, &stats);
- /* No CR? Nothing to convert, regardless. */
- if (!stats.cr)
- return 0;
if (action == CRLF_GUESS) {
/*
@@ -115,6 +143,12 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
return 0;
}
+ check_safe_crlf(path, action, &stats, checksafe);
+
+ /* Optimization: No CR? Nothing to convert, regardless. */
+ if (!stats.cr)
+ return 0;
+
/* only grow if not in place */
if (strbuf_avail(buf) + buf->len < len)
strbuf_grow(buf, len - buf->len);
@@ -536,7 +570,8 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check)
return !!ATTR_TRUE(value);
}
-int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst)
+int convert_to_git(const char *path, const char *src, size_t len,
+ struct strbuf *dst, enum safe_crlf checksafe)
{
struct git_attr_check check[3];
int crlf = CRLF_GUESS;
@@ -558,7 +593,7 @@ int convert_to_git(const char *path, const char *src, size_t len, struct strbuf
src = dst->buf;
len = dst->len;
}
- ret |= crlf_to_git(path, src, len, dst, crlf);
+ ret |= crlf_to_git(path, src, len, dst, crlf, checksafe);
if (ret) {
src = dst->buf;
len = dst->len;
diff --git a/diff.c b/diff.c
index cd8bc4dcc3..58fe7750f9 100644
--- a/diff.c
+++ b/diff.c
@@ -57,7 +57,7 @@ static int parse_diff_color_slot(const char *var, int ofs)
static struct ll_diff_driver {
const char *name;
struct ll_diff_driver *next;
- char *cmd;
+ const char *cmd;
} *user_diff, **user_diff_tail;
/*
@@ -86,10 +86,7 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
user_diff_tail = &(drv->next);
}
- if (!value)
- return error("%s: lacks value", var);
- drv->cmd = strdup(value);
- return 0;
+ return git_config_string(&(drv->cmd), var, value);
}
/*
@@ -166,13 +163,8 @@ int git_diff_ui_config(const char *var, const char *value)
if (!prefixcmp(var, "diff.")) {
const char *ep = strrchr(var, '.');
- if (ep != var + 4) {
- if (!strcmp(ep, ".command")) {
- if (!value)
- return config_error_nonbool(var);
- return parse_lldiff_command(var, ep, value);
- }
- }
+ if (ep != var + 4 && !strcmp(ep, ".command"))
+ return parse_lldiff_command(var, ep, value);
}
return git_diff_basic_config(var, value);
@@ -1021,6 +1013,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
char *err;
if (line[0] == '+') {
+ data->lineno++;
data->status = check_and_emit_line(line + 1, len - 1,
data->ws_rule, NULL, NULL, NULL, NULL);
if (!data->status)
@@ -1031,13 +1024,12 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
emit_line(set, reset, line, 1);
(void)check_and_emit_line(line + 1, len - 1, data->ws_rule,
stdout, set, reset, ws);
- data->lineno++;
} else if (line[0] == ' ')
data->lineno++;
else if (line[0] == '@') {
char *plus = strchr(line, '+');
if (plus)
- data->lineno = strtol(plus, NULL, 10);
+ data->lineno = strtol(plus, NULL, 10) - 1;
else
die("invalid diff");
}
@@ -1639,7 +1631,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
* Convert from working tree format to canonical git format
*/
strbuf_init(&buf, 0);
- if (convert_to_git(s->path, s->data, s->size, &buf)) {
+ if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) {
size_t size = 0;
munmap(s->data, s->size);
s->should_munmap = 0;
diff --git a/dir.c b/dir.c
index 6543105b96..1f507daff2 100644
--- a/dir.c
+++ b/dir.c
@@ -17,6 +17,7 @@ struct path_simplify {
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);
+static int get_dtype(struct dirent *de, const char *path);
int common_prefix(const char **pathspec)
{
@@ -126,18 +127,34 @@ static int no_wildcard(const char *string)
void add_exclude(const char *string, const char *base,
int baselen, struct exclude_list *which)
{
- struct exclude *x = xmalloc(sizeof (*x));
+ struct exclude *x;
+ size_t len;
+ int to_exclude = 1;
+ int flags = 0;
- x->to_exclude = 1;
if (*string == '!') {
- x->to_exclude = 0;
+ to_exclude = 0;
string++;
}
- x->pattern = string;
+ len = strlen(string);
+ if (len && string[len - 1] == '/') {
+ char *s;
+ x = xmalloc(sizeof(*x) + len);
+ s = (char*)(x+1);
+ memcpy(s, string, len - 1);
+ s[len - 1] = '\0';
+ string = s;
+ x->pattern = s;
+ flags = EXC_FLAG_MUSTBEDIR;
+ } else {
+ x = xmalloc(sizeof(*x));
+ x->pattern = string;
+ }
+ x->to_exclude = to_exclude;
x->patternlen = strlen(string);
x->base = base;
x->baselen = baselen;
- x->flags = 0;
+ x->flags = flags;
if (!strchr(string, '/'))
x->flags |= EXC_FLAG_NODIR;
if (no_wildcard(string))
@@ -261,7 +278,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
* Return 1 for exclude, 0 for include and -1 for undecided.
*/
static int excluded_1(const char *pathname,
- int pathlen, const char *basename,
+ int pathlen, const char *basename, int *dtype,
struct exclude_list *el)
{
int i;
@@ -272,6 +289,13 @@ static int excluded_1(const char *pathname,
const char *exclude = x->pattern;
int to_exclude = x->to_exclude;
+ if (x->flags & EXC_FLAG_MUSTBEDIR) {
+ if (*dtype == DT_UNKNOWN)
+ *dtype = get_dtype(NULL, pathname);
+ if (*dtype != DT_DIR)
+ continue;
+ }
+
if (x->flags & EXC_FLAG_NODIR) {
/* match basename */
if (x->flags & EXC_FLAG_NOWILDCARD) {
@@ -314,7 +338,7 @@ static int excluded_1(const char *pathname,
return -1; /* undecided */
}
-int excluded(struct dir_struct *dir, const char *pathname)
+int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
{
int pathlen = strlen(pathname);
int st;
@@ -323,7 +347,8 @@ int excluded(struct dir_struct *dir, const char *pathname)
prep_exclude(dir, pathname, basename-pathname);
for (st = EXC_CMDL; st <= EXC_FILE; st++) {
- switch (excluded_1(pathname, pathlen, basename, &dir->exclude_list[st])) {
+ switch (excluded_1(pathname, pathlen, basename,
+ dtype_p, &dir->exclude_list[st])) {
case 0:
return 0;
case 1:
@@ -508,7 +533,7 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
static int get_dtype(struct dirent *de, const char *path)
{
- int dtype = DTYPE(de);
+ int dtype = de ? DTYPE(de) : DT_UNKNOWN;
struct stat st;
if (dtype != DT_UNKNOWN)
@@ -560,7 +585,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
if (simplify_away(fullname, baselen + len, simplify))
continue;
- exclude = excluded(dir, fullname);
+ dtype = DTYPE(de);
+ exclude = excluded(dir, fullname, &dtype);
if (exclude && dir->collect_ignored
&& in_pathspec(fullname, baselen + len, simplify))
dir_add_ignored(dir, fullname, baselen + len);
@@ -572,7 +598,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
if (exclude && !dir->show_ignored)
continue;
- dtype = get_dtype(de, fullname);
+ if (dtype == DT_UNKNOWN)
+ dtype = get_dtype(de, fullname);
/*
* Do we want to see just the ignored files?
diff --git a/dir.h b/dir.h
index d8814dccb2..2df15defb6 100644
--- a/dir.h
+++ b/dir.h
@@ -9,6 +9,7 @@ struct dir_entry {
#define EXC_FLAG_NODIR 1
#define EXC_FLAG_NOWILDCARD 2
#define EXC_FLAG_ENDSWITH 4
+#define EXC_FLAG_MUSTBEDIR 8
struct exclude_list {
int nr;
@@ -67,7 +68,7 @@ extern int match_pathspec(const char **pathspec, const char *name, int namelen,
extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec);
-extern int excluded(struct dir_struct *, const char *);
+extern int excluded(struct dir_struct *, const char *, int *);
extern void add_excludes_from_file(struct dir_struct *, const char *fname);
extern void add_exclude(const char *string, const char *base,
int baselen, struct exclude_list *which);
diff --git a/environment.c b/environment.c
index 18a1c4eec4..3527f1663f 100644
--- a/environment.c
+++ b/environment.c
@@ -30,11 +30,12 @@ int core_compression_seen;
size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
size_t delta_base_cache_limit = 16 * 1024 * 1024;
-char *pager_program;
+const char *pager_program;
int pager_use_color = 1;
-char *editor_program;
-char *excludes_file;
+const char *editor_program;
+const char *excludes_file;
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
+enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
/* This is set by setup_git_dir_gently() and/or git_default_config() */
diff --git a/fast-import.c b/fast-import.c
index a523b171e2..0d3449f2ce 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -372,6 +372,8 @@ static void write_branch_report(FILE *rpt, struct branch *b)
fputc('\n', rpt);
}
+static void dump_marks_helper(FILE *, uintmax_t, struct mark_set *);
+
static void write_crash_report(const char *err)
{
char *loc = git_path("fast_import_crash_%d", getpid());
@@ -430,12 +432,37 @@ static void write_crash_report(const char *err)
write_branch_report(rpt, b);
}
+ if (first_tag) {
+ struct tag *tg;
+ fputc('\n', rpt);
+ fputs("Annotated Tags\n", rpt);
+ fputs("--------------\n", rpt);
+ for (tg = first_tag; tg; tg = tg->next_tag) {
+ fputs(sha1_to_hex(tg->sha1), rpt);
+ fputc(' ', rpt);
+ fputs(tg->name, rpt);
+ fputc('\n', rpt);
+ }
+ }
+
+ fputc('\n', rpt);
+ fputs("Marks\n", rpt);
+ fputs("-----\n", rpt);
+ if (mark_file)
+ fprintf(rpt, " exported to %s\n", mark_file);
+ else
+ dump_marks_helper(rpt, 0, marks);
+
fputc('\n', rpt);
fputs("-------------------\n", rpt);
fputs("END OF CRASH REPORT\n", rpt);
fclose(rpt);
}
+static void end_packfile(void);
+static void unkeep_all_packs(void);
+static void dump_marks(void);
+
static NORETURN void die_nicely(const char *err, va_list params)
{
static int zombie;
@@ -449,6 +476,9 @@ static NORETURN void die_nicely(const char *err, va_list params)
if (!zombie) {
zombie = 1;
write_crash_report(message);
+ end_packfile();
+ unkeep_all_packs();
+ dump_marks();
}
exit(128);
}
@@ -1204,6 +1234,8 @@ static void load_tree(struct tree_entry *root)
die("Not a tree: %s", sha1_to_hex(sha1));
t->delta_depth = myoe->depth;
buf = gfi_unpack_entry(myoe, &size);
+ if (!buf)
+ die("Can't load tree %s", sha1_to_hex(sha1));
} else {
enum object_type type;
buf = read_sha1_file(sha1, &type, &size);
diff --git a/git-bisect.sh b/git-bisect.sh
index 393fa35584..74715edf0b 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -135,7 +135,7 @@ bisect_write() {
*) die "Bad bisect_write argument: $state" ;;
esac
git update-ref "refs/bisect/$tag" "$rev"
- echo "# $state: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
+ echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
test -z "$nolog" && echo "git-bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
}
@@ -331,9 +331,9 @@ bisect_visualize() {
if test $# = 0
then
- case "${DISPLAY+set}" in
+ case "${DISPLAY+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in
'') set git log ;;
- set) set gitk ;;
+ set*) set gitk ;;
esac
else
case "$1" in
diff --git a/git-clone.sh b/git-clone.sh
index b4e858c388..0d686c3a03 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -409,11 +409,12 @@ else
cd "$D" || exit
fi
-if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD"
+if test -z "$bare"
then
# a non-bare repository is always in separate-remote layout
remote_top="refs/remotes/$origin"
- head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
+ head_sha1=
+ test ! -r "$GIT_DIR/REMOTE_HEAD" || head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
case "$head_sha1" in
'ref: refs/'*)
# Uh-oh, the remote told us (http transport done against
@@ -470,9 +471,16 @@ then
git config branch."$head_points_at".merge "refs/heads/$head_points_at"
;;
'')
- # Source had detached HEAD pointing nowhere
- git update-ref --no-deref HEAD "$head_sha1" &&
- rm -f "refs/remotes/$origin/HEAD"
+ if test -z "$head_sha1"
+ then
+ # Source had nonexistent ref in HEAD
+ echo >&2 "Warning: Remote HEAD refers to nonexistent ref, unable to checkout."
+ no_checkout=t
+ else
+ # Source had detached HEAD pointing nowhere
+ git update-ref --no-deref HEAD "$head_sha1" &&
+ rm -f "refs/remotes/$origin/HEAD"
+ fi
;;
esac
diff --git a/git-compat-util.h b/git-compat-util.h
index 46d5e93c72..2a40703c85 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -431,4 +431,10 @@ static inline int strtol_i(char const *s, int base, int *result)
return 0;
}
+#ifdef INTERNAL_QSORT
+void git_qsort(void *base, size_t nmemb, size_t size,
+ int(*compar)(const void *, const void *));
+#define qsort git_qsort
+#endif
+
#endif
diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index d2e50c3429..2a8ad1e9f4 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -5,6 +5,7 @@ use Getopt::Std;
use File::Temp qw(tempdir);
use Data::Dumper;
use File::Basename qw(basename dirname);
+use File::Spec;
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w);
@@ -15,17 +16,15 @@ $opt_h && usage();
die "Need at least one commit identifier!" unless @ARGV;
if ($opt_w) {
+ # Remember where GIT_DIR is before changing to CVS checkout
unless ($ENV{GIT_DIR}) {
- # Remember where our GIT_DIR is before changing to CVS checkout
+ # No GIT_DIR set. Figure it out for ourselves
my $gd =`git-rev-parse --git-dir`;
chomp($gd);
- if ($gd eq '.git') {
- my $wd = `pwd`;
- chomp($wd);
- $gd = $wd."/.git" ;
- }
$ENV{GIT_DIR} = $gd;
}
+ # Make sure GIT_DIR is absolute
+ $ENV{GIT_DIR} = File::Spec->rel2abs($ENV{GIT_DIR});
if (! -d $opt_w."/CVS" ) {
die "$opt_w is not a CVS checkout";
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 5694978c46..9516242338 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -164,7 +164,7 @@ if ($#ARGV == 0) {
our @mergerx = ();
if ($opt_m) {
- @mergerx = ( qr/\W(?:from|of|merge|merging|merged) (\w+)/i );
+ @mergerx = ( qr/\b(?:from|of|merge|merging|merged) (\w+)/i );
}
if ($opt_M) {
push (@mergerx, qr/$opt_M/);
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index ff716cabb0..49e13f0bb1 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -276,10 +276,11 @@ while read commit parents; do
eval "$filter_tree" < /dev/null ||
die "tree filter failed: $filter_tree"
- git diff-index -r $commit | cut -f 2- | tr '\012' '\000' | \
- xargs -0 git update-index --add --replace --remove
- git ls-files -z --others | \
- xargs -0 git update-index --add --replace --remove
+ (
+ git diff-index -r --name-only $commit
+ git ls-files --others
+ ) |
+ git update-index --add --replace --remove --stdin
fi
eval "$filter_index" < /dev/null ||
diff --git a/git-gui/Makefile b/git-gui/Makefile
index 34438cdf5c..081d7550a7 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -13,6 +13,7 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
+uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
SCRIPT_SH = git-gui.sh
GITGUI_MAIN := git-gui
@@ -93,7 +94,14 @@ endif
TCL_PATH ?= tclsh
TCLTK_PATH ?= wish
-TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app
+
+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
+ endif
+ TKEXECUTABLE = $(shell basename "$(TKFRAMEWORK)" .app)
+endif
ifeq ($(findstring $(MAKEFLAGS),s),s)
QUIET_GEN =
@@ -147,7 +155,7 @@ git-gui: GIT-VERSION-FILE GIT-GUI-VARS
echo then >>$@+ && \
echo ' 'echo \'git-gui version '$(GITGUI_VERSION)'\' >>$@+ && \
echo else >>$@+ && \
- echo ' 'exec \''$(libdir_SQ)/Git Gui.app/Contents/MacOS/Wish'\' \
+ echo ' 'exec \''$(libdir_SQ)/Git Gui.app/Contents/MacOS/$(subst \,,$(TKEXECUTABLE))'\' \
'"$$0" "$$@"' >>$@+ && \
echo fi >>$@+ && \
chmod +x $@+ && \
@@ -157,14 +165,15 @@ Git\ Gui.app: GIT-VERSION-FILE GIT-GUI-VARS \
macosx/Info.plist \
macosx/git-gui.icns \
macosx/AppMain.tcl \
- $(TKFRAMEWORK)/Contents/MacOS/Wish
+ $(TKFRAMEWORK)/Contents/MacOS/$(TKEXECUTABLE)
$(QUIET_GEN)rm -rf '$@' '$@'+ && \
mkdir -p '$@'+/Contents/MacOS && \
mkdir -p '$@'+/Contents/Resources/Scripts && \
- cp '$(subst ','\'',$(TKFRAMEWORK))/Contents/MacOS/Wish' \
+ cp '$(subst ','\'',$(subst \,,$(TKFRAMEWORK)/Contents/MacOS/$(TKEXECUTABLE)))' \
'$@'+/Contents/MacOS && \
cp macosx/git-gui.icns '$@'+/Contents/Resources && \
sed -e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \
+ -e 's/@@GITGUI_TKEXECUTABLE@@/$(TKEXECUTABLE)/g' \
macosx/Info.plist \
>'$@'+/Contents/Info.plist && \
sed -e 's|@@gitexecdir@@|$(gitexecdir_SQ)|' \
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index f42e461fd4..5d65272e26 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -612,6 +612,7 @@ set default_config(gui.pruneduringfetch) false
set default_config(gui.trustmtime) false
set default_config(gui.diffcontext) 5
set default_config(gui.newbranchtemplate) {}
+set default_config(gui.spellingdictionary) {}
set default_config(gui.fontui) [font configure font_ui]
set default_config(gui.fontdiff) [font configure font_diff]
set font_descs {
@@ -1683,6 +1684,7 @@ set is_quitting 0
proc do_quit {} {
global ui_comm is_quitting repo_config commit_type
global GITGUI_BCK_exists GITGUI_BCK_i
+ global ui_comm_spell
if {$is_quitting} return
set is_quitting 1
@@ -1710,6 +1712,12 @@ proc do_quit {} {
}
}
+ # -- Cancel our spellchecker if its running.
+ #
+ if {[info exists ui_comm_spell]} {
+ $ui_comm_spell stop
+ }
+
# -- Remove our editor backup, its not needed.
#
after cancel $GITGUI_BCK_i
@@ -2454,7 +2462,7 @@ $ctxm add separator
$ctxm add command \
-label [mc "Sign Off"] \
-command do_signoff
-bind_button3 $ui_comm "tk_popup $ctxm %X %Y"
+set ui_comm_ctxm $ctxm
# -- Diff Header
#
@@ -2857,6 +2865,30 @@ if {[winfo exists $ui_comm]} {
}
backup_commit_buffer
+
+ # -- If the user has aspell available we can drive it
+ # in pipe mode to spellcheck the commit message.
+ #
+ set spell_cmd [list |]
+ set spell_dict [get_config gui.spellingdictionary]
+ lappend spell_cmd aspell
+ if {$spell_dict ne {}} {
+ lappend spell_cmd --master=$spell_dict
+ }
+ lappend spell_cmd --mode=none
+ lappend spell_cmd --encoding=utf-8
+ lappend spell_cmd pipe
+ if {$spell_dict eq {none}
+ || [catch {set spell_fd [open $spell_cmd r+]} spell_err]} {
+ bind_button3 $ui_comm [list tk_popup $ui_comm_ctxm %X %Y]
+ } else {
+ set ui_comm_spell [spellcheck::init \
+ $spell_fd \
+ $ui_comm \
+ $ui_comm_ctxm \
+ ]
+ }
+ unset -nocomplain spell_cmd spell_fd spell_err spell_dict
}
lock_index begin-read
diff --git a/git-gui/lib/about.tcl b/git-gui/lib/about.tcl
index 719fc547b3..47be8eb97a 100644
--- a/git-gui/lib/about.tcl
+++ b/git-gui/lib/about.tcl
@@ -4,6 +4,7 @@
proc do_about {} {
global appvers copyright oguilib
global tcl_patchLevel tk_patchLevel
+ global ui_comm_spell
set w .about_dialog
toplevel $w
@@ -40,6 +41,10 @@ proc do_about {} {
append v "Tcl version $tcl_patchLevel"
append v ", Tk version $tk_patchLevel"
}
+ if {[info exists ui_comm_spell]} {
+ append v "\n"
+ append v [$ui_comm_spell version]
+ }
set d {}
append d "git wrapper: $::_git\n"
diff --git a/git-gui/lib/checkout_op.tcl b/git-gui/lib/checkout_op.tcl
index f243966924..6e1411711b 100644
--- a/git-gui/lib/checkout_op.tcl
+++ b/git-gui/lib/checkout_op.tcl
@@ -280,7 +280,7 @@ The rescan will be automatically started now.
} elseif {[is_config_true gui.trustmtime]} {
_readtree $this
} else {
- ui_status {Refreshing file status...}
+ ui_status [mc "Refreshing file status..."]
set fd [git_read update-index \
-q \
--unmerged \
@@ -320,7 +320,7 @@ method _readtree {} {
set readtree_d {}
$::main_status start \
[mc "Updating working directory to '%s'..." [_name $this]] \
- {files checked out}
+ [mc "files checked out"]
set fd [git_read --stderr read-tree \
-m \
@@ -447,7 +447,7 @@ If you wanted to be on a branch, create one now starting from 'This Detached Che
} else {
repository_state commit_type HEAD MERGE_HEAD
set PARENT $HEAD
- ui_status "Checked out '$name'."
+ ui_status [mc "Checked out '%s'." $name]
}
delete_this
}
diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl
index 947b201c32..40a7103557 100644
--- a/git-gui/lib/commit.tcl
+++ b/git-gui/lib/commit.tcl
@@ -218,7 +218,7 @@ A good commit message has the following format:
return
}
- ui_status {Calling pre-commit hook...}
+ ui_status [mc "Calling pre-commit hook..."]
set pch_error {}
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
fileevent $fd_ph readable \
@@ -233,7 +233,7 @@ proc commit_prehook_wait {fd_ph curHEAD msg_p} {
if {[eof $fd_ph]} {
if {[catch {close $fd_ph}]} {
catch {file delete $msg_p}
- ui_status {Commit declined by pre-commit hook.}
+ ui_status [mc "Commit declined by pre-commit hook."]
hook_failed_popup pre-commit $pch_error
unlock_index
} else {
@@ -256,7 +256,7 @@ proc commit_commitmsg {curHEAD msg_p} {
return
}
- ui_status {Calling commit-msg hook...}
+ ui_status [mc "Calling commit-msg hook..."]
set pch_error {}
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
fileevent $fd_ph readable \
@@ -271,7 +271,7 @@ proc commit_commitmsg_wait {fd_ph curHEAD msg_p} {
if {[eof $fd_ph]} {
if {[catch {close $fd_ph}]} {
catch {file delete $msg_p}
- ui_status {Commit declined by commit-msg hook.}
+ ui_status [mc "Commit declined by commit-msg hook."]
hook_failed_popup commit-msg $pch_error
unlock_index
} else {
@@ -284,7 +284,7 @@ proc commit_commitmsg_wait {fd_ph curHEAD msg_p} {
}
proc commit_writetree {curHEAD msg_p} {
- ui_status {Committing changes...}
+ ui_status [mc "Committing changes..."]
set fd_wt [git_read write-tree]
fileevent $fd_wt readable \
[list commit_committree $fd_wt $curHEAD $msg_p]
@@ -301,7 +301,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {
if {[catch {close $fd_wt} err]} {
catch {file delete $msg_p}
error_popup [strcat [mc "write-tree failed:"] "\n\n$err"]
- ui_status {Commit failed.}
+ ui_status [mc "Commit failed."]
unlock_index
return
}
@@ -345,7 +345,7 @@ A rescan will be automatically started now.
if {[catch {set cmt_id [eval git $cmd]} err]} {
catch {file delete $msg_p}
error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"]
- ui_status {Commit failed.}
+ ui_status [mc "Commit failed."]
unlock_index
return
}
@@ -365,7 +365,7 @@ A rescan will be automatically started now.
} err]} {
catch {file delete $msg_p}
error_popup [strcat [mc "update-ref failed:"] "\n\n$err"]
- ui_status {Commit failed.}
+ ui_status [mc "Commit failed."]
unlock_index
return
}
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 30a244cc17..3c1fce7475 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -310,7 +310,7 @@ proc add_helper {txt paths} {
update_index \
$txt \
$pathList \
- [concat $after {ui_status {Ready to commit.}}]
+ [concat $after {ui_status [mc "Ready to commit."]}]
}
}
diff --git a/git-gui/lib/merge.tcl b/git-gui/lib/merge.tcl
index 63e14279c1..cc26b07808 100644
--- a/git-gui/lib/merge.tcl
+++ b/git-gui/lib/merge.tcl
@@ -116,8 +116,7 @@ method _start {} {
lappend cmd HEAD
lappend cmd $name
- set msg [mc "Merging %s and %s" $current_branch $stitle]
- ui_status "$msg..."
+ ui_status [mc "Merging %s and %s..." $current_branch $stitle]
set cons [console::new [mc "Merge"] "merge $stitle"]
console::exec $cons $cmd [cb _finish $cons]
@@ -236,7 +235,7 @@ Continue with resetting the current changes?"]
set fd [git_read --stderr read-tree --reset -u -v HEAD]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [namespace code [list _reset_wait $fd]]
- $::main_status start [mc "Aborting"] {files reset}
+ $::main_status start [mc "Aborting"] [mc "files reset"]
} else {
unlock_index
}
diff --git a/git-gui/lib/option.tcl b/git-gui/lib/option.tcl
index f812e5e89a..ea80df0092 100644
--- a/git-gui/lib/option.tcl
+++ b/git-gui/lib/option.tcl
@@ -5,6 +5,7 @@ proc save_config {} {
global default_config font_descs
global repo_config global_config
global repo_config_new global_config_new
+ global ui_comm_spell
foreach option $font_descs {
set name [lindex $option 0]
@@ -52,11 +53,23 @@ proc save_config {} {
set repo_config($name) $value
}
}
+
+ if {[info exists repo_config(gui.spellingdictionary)]} {
+ set value $repo_config(gui.spellingdictionary)
+ if {$value eq {none}} {
+ if {[info exists ui_comm_spell]} {
+ $ui_comm_spell stop
+ }
+ } elseif {[info exists ui_comm_spell]} {
+ $ui_comm_spell lang $value
+ }
+ }
}
proc do_options {} {
global repo_config global_config font_descs
global repo_config_new global_config_new
+ global ui_comm_spell
array unset repo_config_new
array unset global_config_new
@@ -159,6 +172,32 @@ proc do_options {} {
}
}
+ set all_dicts [linsert \
+ [spellcheck::available_langs] \
+ 0 \
+ none]
+ incr optid
+ foreach f {repo global} {
+ if {![info exists ${f}_config_new(gui.spellingdictionary)]} {
+ if {[info exists ui_comm_spell]} {
+ set value [$ui_comm_spell lang]
+ } else {
+ set value none
+ }
+ set ${f}_config_new(gui.spellingdictionary) $value
+ }
+
+ frame $w.$f.$optid
+ label $w.$f.$optid.l -text [mc "Spelling Dictionary:"]
+ eval tk_optionMenu $w.$f.$optid.v \
+ ${f}_config_new(gui.spellingdictionary) \
+ $all_dicts
+ pack $w.$f.$optid.l -side left -anchor w -fill x
+ pack $w.$f.$optid.v -side right -anchor e -padx 5
+ pack $w.$f.$optid -side top -anchor w -fill x
+ }
+ unset all_dicts
+
set all_fonts [lsort [font families]]
foreach option $font_descs {
set name [lindex $option 0]
diff --git a/git-gui/lib/spellcheck.tcl b/git-gui/lib/spellcheck.tcl
new file mode 100644
index 0000000000..7f018e4009
--- /dev/null
+++ b/git-gui/lib/spellcheck.tcl
@@ -0,0 +1,363 @@
+# git-gui spellchecking support through aspell
+# Copyright (C) 2008 Shawn Pearce
+
+class spellcheck {
+
+field s_fd {} ; # pipe to aspell
+field s_version ; # aspell version string
+field s_lang ; # current language code
+
+field w_text ; # text widget we are spelling
+field w_menu ; # context menu for the widget
+field s_menuidx 0 ; # last index of insertion into $w_menu
+
+field s_i ; # timer registration for _run callbacks
+field s_clear 0 ; # did we erase mispelled tags yet?
+field s_seen [list] ; # lines last seen from $w_text in _run
+field s_checked [list] ; # lines already checked
+field s_pending [list] ; # [$line $data] sent to aspell
+field s_suggest ; # array, list of suggestions, keyed by misspelling
+
+constructor init {pipe_fd ui_text ui_menu} {
+ set w_text $ui_text
+ set w_menu $ui_menu
+
+ _connect $this $pipe_fd
+ return $this
+}
+
+method _connect {pipe_fd} {
+ fconfigure $pipe_fd \
+ -encoding utf-8 \
+ -eofchar {} \
+ -translation lf
+
+ if {[gets $pipe_fd s_version] <= 0} {
+ close $pipe_fd
+ error [mc "Not connected to aspell"]
+ }
+ if {{@(#) } ne [string range $s_version 0 4]} {
+ close $pipe_fd
+ error [strcat [mc "Unrecognized aspell version"] ": $s_version"]
+ }
+ set s_version [string range $s_version 5 end]
+
+ puts $pipe_fd ! ; # enable terse mode
+ puts $pipe_fd {$$cr master} ; # fetch the language
+ flush $pipe_fd
+
+ gets $pipe_fd s_lang
+ regexp {[/\\]([^/\\]+)\.[^\.]+$} $s_lang _ s_lang
+
+ if {$::default_config(gui.spellingdictionary) eq {}
+ && [get_config gui.spellingdictionary] eq {}} {
+ set ::default_config(gui.spellingdictionary) $s_lang
+ }
+
+ if {$s_fd ne {}} {
+ catch {close $s_fd}
+ }
+ set s_fd $pipe_fd
+
+ fconfigure $s_fd -blocking 0
+ fileevent $s_fd readable [cb _read]
+
+ $w_text tag conf misspelled \
+ -foreground red \
+ -underline 1
+ bind_button3 $w_text [cb _popup_suggest %X %Y @%x,%y]
+
+ array unset s_suggest
+ set s_seen [list]
+ set s_checked [list]
+ set s_pending [list]
+ _run $this
+}
+
+method lang {{n {}}} {
+ if {$n ne {} && $s_lang ne $n} {
+ set spell_cmd [list |]
+ lappend spell_cmd aspell
+ lappend spell_cmd --master=$n
+ lappend spell_cmd --mode=none
+ lappend spell_cmd --encoding=UTF-8
+ lappend spell_cmd pipe
+ _connect $this [open $spell_cmd r+]
+ }
+ return $s_lang
+}
+
+method version {} {
+ return "$s_version, $s_lang"
+}
+
+method stop {} {
+ while {$s_menuidx > 0} {
+ $w_menu delete 0
+ incr s_menuidx -1
+ }
+ $w_text tag delete misspelled
+
+ catch {close $s_fd}
+ catch {after cancel $s_i}
+ set s_fd {}
+ set s_i {}
+ set s_lang {}
+}
+
+method _popup_suggest {X Y pos} {
+ while {$s_menuidx > 0} {
+ $w_menu delete 0
+ incr s_menuidx -1
+ }
+
+ set b_loc [$w_text index "$pos wordstart"]
+ set e_loc [_wordend $this $b_loc]
+ set orig [$w_text get $b_loc $e_loc]
+ set tags [$w_text tag names $b_loc]
+
+ if {[lsearch -exact $tags misspelled] >= 0} {
+ if {[info exists s_suggest($orig)]} {
+ set cnt 0
+ foreach s $s_suggest($orig) {
+ if {$cnt < 5} {
+ $w_menu insert $s_menuidx command \
+ -label $s \
+ -command [cb _replace $b_loc $e_loc $s]
+ incr s_menuidx
+ incr cnt
+ } else {
+ break
+ }
+ }
+ } else {
+ $w_menu insert $s_menuidx command \
+ -label [mc "No Suggestions"] \
+ -state disabled
+ incr s_menuidx
+ }
+ $w_menu insert $s_menuidx separator
+ incr s_menuidx
+ }
+
+ $w_text mark set saved-insert insert
+ tk_popup $w_menu $X $Y
+}
+
+method _replace {b_loc e_loc word} {
+ $w_text configure -autoseparators 0
+ $w_text edit separator
+
+ $w_text delete $b_loc $e_loc
+ $w_text insert $b_loc $word
+
+ $w_text edit separator
+ $w_text configure -autoseparators 1
+ $w_text mark set insert saved-insert
+}
+
+method _restart_timer {} {
+ set s_i [after 300 [cb _run]]
+}
+
+proc _match_length {max_line arr_name} {
+ upvar $arr_name a
+
+ if {[llength $a] > $max_line} {
+ set a [lrange $a 0 $max_line]
+ }
+ while {[llength $a] <= $max_line} {
+ lappend a {}
+ }
+}
+
+method _wordend {pos} {
+ set pos [$w_text index "$pos wordend"]
+ set tags [$w_text tag names $pos]
+ while {[lsearch -exact $tags misspelled] >= 0} {
+ set pos [$w_text index "$pos +1c"]
+ set tags [$w_text tag names $pos]
+ }
+ return $pos
+}
+
+method _run {} {
+ set cur_pos [$w_text index {insert -1c}]
+ set cur_line [lindex [split $cur_pos .] 0]
+ set max_line [lindex [split [$w_text index end] .] 0]
+ _match_length $max_line s_seen
+ _match_length $max_line s_checked
+
+ # Nothing in the message buffer? Nothing to spellcheck.
+ #
+ if {$cur_line == 1
+ && $max_line == 2
+ && [$w_text get 1.0 end] eq "\n"} {
+ array unset s_suggest
+ _restart_timer $this
+ return
+ }
+
+ set active 0
+ for {set n 1} {$n <= $max_line} {incr n} {
+ set s [$w_text get "$n.0" "$n.end"]
+
+ # Don't spellcheck the current line unless we are at
+ # a word boundary. The user might be typing on it.
+ #
+ if {$n == $cur_line
+ && ![regexp {^\W$} [$w_text get $cur_pos insert]]} {
+
+ # If the current word is mispelled remove the tag
+ # but force a spellcheck later.
+ #
+ set tags [$w_text tag names $cur_pos]
+ if {[lsearch -exact $tags misspelled] >= 0} {
+ $w_text tag remove misspelled \
+ "$cur_pos wordstart" \
+ [_wordend $this $cur_pos]
+ lset s_seen $n $s
+ lset s_checked $n {}
+ }
+
+ continue
+ }
+
+ if {[lindex $s_seen $n] eq $s
+ && [lindex $s_checked $n] ne $s} {
+ # Don't send empty lines to Aspell it doesn't check them.
+ #
+ if {$s eq {}} {
+ lset s_checked $n $s
+ continue
+ }
+
+ # Don't send typical s-b-o lines as the emails are
+ # almost always misspelled according to Aspell.
+ #
+ if {[regexp -nocase {^[a-z-]+-by:.*<.*@.*>$} $s]} {
+ $w_text tag remove misspelled "$n.0" "$n.end"
+ lset s_checked $n $s
+ continue
+ }
+
+ puts $s_fd ^$s
+ lappend s_pending [list $n $s]
+ set active 1
+ } else {
+ # Delay until another idle loop to make sure we don't
+ # spellcheck lines the user is actively changing.
+ #
+ lset s_seen $n $s
+ }
+ }
+
+ if {$active} {
+ set s_clear 1
+ flush $s_fd
+ } else {
+ _restart_timer $this
+ }
+}
+
+method _read {} {
+ while {[gets $s_fd line] >= 0} {
+ set lineno [lindex $s_pending 0 0]
+
+ if {$s_clear} {
+ $w_text tag remove misspelled "$lineno.0" "$lineno.end"
+ set s_clear 0
+ }
+
+ if {$line eq {}} {
+ lset s_checked $lineno [lindex $s_pending 0 1]
+ set s_pending [lrange $s_pending 1 end]
+ set s_clear 1
+ continue
+ }
+
+ set sugg [list]
+ switch -- [string range $line 0 1] {
+ {& } {
+ set line [split [string range $line 2 end] :]
+ set info [split [lindex $line 0] { }]
+ set orig [lindex $info 0]
+ set offs [lindex $info 2]
+ foreach s [split [lindex $line 1] ,] {
+ lappend sugg [string range $s 1 end]
+ }
+ }
+ {# } {
+ set info [split [string range $line 2 end] { }]
+ set orig [lindex $info 0]
+ set offs [lindex $info 1]
+ }
+ default {
+ puts stderr "<spell> $line"
+ continue
+ }
+ }
+
+ incr offs -1
+ set b_loc "$lineno.$offs"
+ set e_loc [$w_text index "$lineno.$offs wordend"]
+ set curr [$w_text get $b_loc $e_loc]
+
+ # At least for English curr = "bob", orig = "bob's"
+ # so Tk didn't include the 's but Aspell did. We
+ # try to round out the word.
+ #
+ while {$curr ne $orig
+ && [string equal -length [string length $curr] $curr $orig]} {
+ set n_loc [$w_text index "$e_loc +1c"]
+ set n_curr [$w_text get $b_loc $n_loc]
+ if {$n_curr eq $curr} {
+ break
+ }
+ set curr $n_curr
+ set e_loc $n_loc
+ }
+
+ if {$curr eq $orig} {
+ $w_text tag add misspelled $b_loc $e_loc
+ if {[llength $sugg] > 0} {
+ set s_suggest($orig) $sugg
+ } else {
+ unset -nocomplain s_suggest($orig)
+ }
+ } else {
+ unset -nocomplain s_suggest($orig)
+ }
+ }
+
+ fconfigure $s_fd -block 1
+ if {[eof $s_fd]} {
+ if {![catch {close $s_fd} err]} {
+ set err [mc "unexpected eof from aspell"]
+ }
+ catch {after cancel $s_i}
+ $w_text tag remove misspelled 1.0 end
+ error_popup [strcat "Spell Checker Failed" "\n\n" $err]
+ return
+ }
+ fconfigure $s_fd -block 0
+
+ if {[llength $s_pending] == 0} {
+ _restart_timer $this
+ }
+}
+
+proc available_langs {} {
+ set langs [list]
+ catch {
+ set fd [open [list | aspell dump dicts] r]
+ while {[gets $fd line] >= 0} {
+ if {$line eq {}} continue
+ lappend langs $line
+ }
+ close $fd
+ }
+ return $langs
+}
+
+}
diff --git a/git-gui/macosx/Info.plist b/git-gui/macosx/Info.plist
index 99913ec57a..b3bf15fa1c 100644
--- a/git-gui/macosx/Info.plist
+++ b/git-gui/macosx/Info.plist
@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
- <string>Wish</string>
+ <string>@@GITGUI_TKEXECUTABLE@@</string>
<key>CFBundleGetInfoString</key>
<string>Git Gui @@GITGUI_VERSION@@ © 2006-2007 Shawn Pearce, et. al.</string>
<key>CFBundleIconFile</key>
diff --git a/git-gui/po/de.po b/git-gui/po/de.po
index 2dfe07e06f..d7c38f9c73 100644
--- a/git-gui/po/de.po
+++ b/git-gui/po/de.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: git-gui\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-11-24 10:36+0100\n"
-"PO-Revision-Date: 2008-01-15 20:33+0100\n"
+"POT-Creation-Date: 2008-02-02 10:14+0100\n"
+"PO-Revision-Date: 2008-02-02 10:18+0100\n"
"Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"
@@ -343,7 +343,9 @@ msgstr "Online-Dokumentation"
#: git-gui.sh:2201
#, tcl-format
msgid "fatal: cannot stat path %s: No such file or directory"
-msgstr "Fehler: Verzeichnis »%s« kann nicht gelesen werden: Datei oder Verzeichnis nicht gefunden"
+msgstr ""
+"Fehler: Verzeichnis »%s« kann nicht gelesen werden: Datei oder Verzeichnis "
+"nicht gefunden"
#: git-gui.sh:2234
msgid "Current Branch:"
@@ -371,19 +373,19 @@ msgstr "Erste Versionsbeschreibung:"
#: git-gui.sh:2370
msgid "Amended Commit Message:"
-msgstr "Nachgebesserte Versionsbeschreibung:"
+msgstr "Nachgebesserte Beschreibung:"
#: git-gui.sh:2371
msgid "Amended Initial Commit Message:"
-msgstr "Nachgebesserte erste Versionsbeschreibung:"
+msgstr "Nachgebesserte erste Beschreibung:"
#: git-gui.sh:2372
msgid "Amended Merge Commit Message:"
-msgstr "Nachgebesserte Zusammenführungs-Versionsbeschreibung:"
+msgstr "Nachgebesserte Zusammenführungs-Beschreibung:"
#: git-gui.sh:2373
msgid "Merge Commit Message:"
-msgstr "Zusammenführungs-Versionsbeschreibung:"
+msgstr "Zusammenführungs-Beschreibung:"
#: git-gui.sh:2374
msgid "Commit Message:"
@@ -397,31 +399,31 @@ msgstr "Alle kopieren"
msgid "File:"
msgstr "Datei:"
-#: git-gui.sh:2545
-msgid "Refresh"
-msgstr "Aktualisieren"
-
-#: git-gui.sh:2566
+#: git-gui.sh:2573
msgid "Apply/Reverse Hunk"
msgstr "Kontext anwenden/umkehren"
-#: git-gui.sh:2572
-msgid "Decrease Font Size"
-msgstr "Schriftgröße verkleinern"
-
-#: git-gui.sh:2576
-msgid "Increase Font Size"
-msgstr "Schriftgröße vergrößern"
-
-#: git-gui.sh:2581
+#: git-gui.sh:2579
msgid "Show Less Context"
msgstr "Weniger Zeilen anzeigen"
-#: git-gui.sh:2588
+#: git-gui.sh:2586
msgid "Show More Context"
msgstr "Mehr Zeilen anzeigen"
-#: git-gui.sh:2602
+#: git-gui.sh:2594
+msgid "Refresh"
+msgstr "Aktualisieren"
+
+#: git-gui.sh:2615
+msgid "Decrease Font Size"
+msgstr "Schriftgröße verkleinern"
+
+#: git-gui.sh:2619
+msgid "Increase Font Size"
+msgstr "Schriftgröße vergrößern"
+
+#: git-gui.sh:2630
msgid "Unstage Hunk From Commit"
msgstr "Kontext aus Bereitstellung herausnehmen"
@@ -542,7 +544,7 @@ msgstr "Kopiert oder verschoben durch:"
#: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19
msgid "Checkout Branch"
-msgstr "Zweig umstellen"
+msgstr "Auf Zweig umstellen"
#: lib/branch_checkout.tcl:23
msgid "Checkout"
@@ -805,11 +807,15 @@ msgstr ""
msgid "Updating working directory to '%s'..."
msgstr "Arbeitskopie umstellen auf »%s«..."
+#: lib/checkout_op.tcl:323
+msgid "files checked out"
+msgstr "Dateien aktualisiert"
+
#: lib/checkout_op.tcl:353
#, tcl-format
msgid "Aborted checkout of '%s' (file level merging is required)."
msgstr ""
-"Zweig umstellen von »%s« abgebrochen (Zusammenführen der Dateien ist "
+"Auf Zweig »%s« umstellen abgebrochen (Zusammenführen der Dateien ist "
"notwendig)."
#: lib/checkout_op.tcl:354
@@ -1069,15 +1075,21 @@ msgstr "Für Objekt konnte kein Hardlink erstellt werden: %s"
#: lib/choose_repository.tcl:847
msgid "Cannot fetch branches and objects. See console output for details."
-msgstr "Zweige und Objekte konnten nicht angefordert werden. Kontrollieren Sie die Ausgaben auf der Konsole für weitere Angaben."
+msgstr ""
+"Zweige und Objekte konnten nicht angefordert werden. Kontrollieren Sie die "
+"Ausgaben auf der Konsole für weitere Angaben."
#: lib/choose_repository.tcl:858
msgid "Cannot fetch tags. See console output for details."
-msgstr "Markierungen konnten nicht angefordert werden. Kontrollieren Sie die Ausgaben auf der Konsole für weitere Angaben."
+msgstr ""
+"Markierungen konnten nicht angefordert werden. Kontrollieren Sie die "
+"Ausgaben auf der Konsole für weitere Angaben."
#: lib/choose_repository.tcl:882
msgid "Cannot determine HEAD. See console output for details."
-msgstr "Die Zweigspitze (HEAD) konnte nicht gefunden werden. Kontrollieren Sie die Ausgaben auf der Konsole für weitere Angaben."
+msgstr ""
+"Die Zweigspitze (HEAD) konnte nicht gefunden werden. Kontrollieren Sie die "
+"Ausgaben auf der Konsole für weitere Angaben."
#: lib/choose_repository.tcl:891
#, tcl-format
@@ -1273,11 +1285,40 @@ msgstr ""
"\n"
"- Rest: Eine ausführliche Beschreibung, warum diese Änderung hilfreich ist.\n"
-#: lib/commit.tcl:257
+#: lib/commit.tcl:207
+#, tcl-format
+msgid "warning: Tcl does not support encoding '%s'."
+msgstr "Warning: Tcl/Tk unterstützt die Zeichencodierung »%s« nicht."
+
+#: lib/commit.tcl:221
+msgid "Calling pre-commit hook..."
+msgstr ""
+
+#: lib/commit.tcl:236
+msgid "Commit declined by pre-commit hook."
+msgstr ""
+
+#: lib/commit.tcl:259
+msgid "Calling commit-msg hook..."
+msgstr ""
+
+#: lib/commit.tcl:274
+msgid "Commit declined by commit-msg hook."
+msgstr ""
+
+#: lib/commit.tcl:287
+msgid "Committing changes..."
+msgstr "Änderungen eintragen..."
+
+#: lib/commit.tcl:303
msgid "write-tree failed:"
msgstr "write-tree fehlgeschlagen:"
-#: lib/commit.tcl:275
+#: lib/commit.tcl:304 lib/commit.tcl:348 lib/commit.tcl:368
+msgid "Commit failed."
+msgstr "Eintragen fehlgeschlagen."
+
+#: lib/commit.tcl:321
#, tcl-format
msgid "Commit %s appears to be corrupt"
msgstr "Version »%s« scheint beschädigt zu sein"
@@ -1301,12 +1342,7 @@ msgstr ""
msgid "No changes to commit."
msgstr "Keine Änderungen, die eingetragen werden können."
-#: lib/commit.tcl:303
-#, tcl-format
-msgid "warning: Tcl does not support encoding '%s'."
-msgstr "Warning: Tcl/Tk unterstützt die Zeichencodierung »%s« nicht."
-
-#: lib/commit.tcl:317
+#: lib/commit.tcl:347
msgid "commit-tree failed:"
msgstr "commit-tree fehlgeschlagen:"
@@ -1440,7 +1476,8 @@ msgstr "Fehler beim Laden des Vergleichs:"
#: lib/diff.tcl:302
msgid "Failed to unstage selected hunk."
-msgstr "Fehler beim Herausnehmen des gewählten Kontexts aus der Bereitstellung."
+msgstr ""
+"Fehler beim Herausnehmen des gewählten Kontexts aus der Bereitstellung."
#: lib/diff.tcl:309
msgid "Failed to stage selected hunk."
@@ -1471,7 +1508,10 @@ msgstr "Fehler in Bereitstellung"
msgid ""
"Updating the Git index failed. A rescan will be automatically started to "
"resynchronize git-gui."
-msgstr "Das Aktualisieren der Git-Bereitstellung ist fehlgeschlagen. Eine allgemeine Git-Aktualisierung wird jetzt gestartet, um git-gui wieder mit git zu synchronisieren."
+msgstr ""
+"Das Aktualisieren der Git-Bereitstellung ist fehlgeschlagen. Eine allgemeine "
+"Git-Aktualisierung wird jetzt gestartet, um git-gui wieder mit git zu "
+"synchronisieren."
#: lib/index.tcl:27
msgid "Continue"
@@ -1486,6 +1526,10 @@ msgstr "Bereitstellung freigeben"
msgid "Unstaging %s from commit"
msgstr "Datei »%s« aus der Bereitstellung herausnehmen"
+#: lib/index.tcl:313
+msgid "Ready to commit."
+msgstr "Bereit zum Eintragen."
+
#: lib/index.tcl:326
#, tcl-format
msgid "Adding %s"
@@ -1503,7 +1547,8 @@ msgstr "Änderungen in den gewählten %i Dateien verwerfen?"
#: lib/index.tcl:389
msgid "Any unstaged changes will be permanently lost by the revert."
-msgstr "Alle nicht bereitgestellten Änderungen werden beim Verwerfen verloren gehen."
+msgstr ""
+"Alle nicht bereitgestellten Änderungen werden beim Verwerfen verloren gehen."
#: lib/index.tcl:392
msgid "Do Nothing"
@@ -1641,7 +1686,11 @@ msgstr ""
msgid "Aborting"
msgstr "Abbruch"
-#: lib/merge.tcl:266
+#: lib/merge.tcl:238
+msgid "files reset"
+msgstr "Dateien zurückgesetzt"
+
+#: lib/merge.tcl:265
msgid "Abort failed."
msgstr "Abbruch fehlgeschlagen."
diff --git a/git-gui/po/git-gui.pot b/git-gui/po/git-gui.pot
index dfa48ae263..3f139da6c7 100644
--- a/git-gui/po/git-gui.pot
+++ b/git-gui/po/git-gui.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-11-24 10:36+0100\n"
+"POT-Creation-Date: 2008-02-02 10:14+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -386,31 +386,31 @@ msgstr ""
msgid "File:"
msgstr ""
-#: git-gui.sh:2545
-msgid "Refresh"
+#: git-gui.sh:2573
+msgid "Apply/Reverse Hunk"
msgstr ""
-#: git-gui.sh:2566
-msgid "Apply/Reverse Hunk"
+#: git-gui.sh:2579
+msgid "Show Less Context"
msgstr ""
-#: git-gui.sh:2572
-msgid "Decrease Font Size"
+#: git-gui.sh:2586
+msgid "Show More Context"
msgstr ""
-#: git-gui.sh:2576
-msgid "Increase Font Size"
+#: git-gui.sh:2594
+msgid "Refresh"
msgstr ""
-#: git-gui.sh:2581
-msgid "Show Less Context"
+#: git-gui.sh:2615
+msgid "Decrease Font Size"
msgstr ""
-#: git-gui.sh:2588
-msgid "Show More Context"
+#: git-gui.sh:2619
+msgid "Increase Font Size"
msgstr ""
-#: git-gui.sh:2602
+#: git-gui.sh:2630
msgid "Unstage Hunk From Commit"
msgstr ""
@@ -766,6 +766,10 @@ msgstr ""
msgid "Updating working directory to '%s'..."
msgstr ""
+#: lib/checkout_op.tcl:323
+msgid "files checked out"
+msgstr ""
+
#: lib/checkout_op.tcl:353
#, tcl-format
msgid "Aborted checkout of '%s' (file level merging is required)."
@@ -1182,11 +1186,40 @@ msgid ""
"- Remaining lines: Describe why this change is good.\n"
msgstr ""
-#: lib/commit.tcl:257
+#: lib/commit.tcl:207
+#, tcl-format
+msgid "warning: Tcl does not support encoding '%s'."
+msgstr ""
+
+#: lib/commit.tcl:221
+msgid "Calling pre-commit hook..."
+msgstr ""
+
+#: lib/commit.tcl:236
+msgid "Commit declined by pre-commit hook."
+msgstr ""
+
+#: lib/commit.tcl:259
+msgid "Calling commit-msg hook..."
+msgstr ""
+
+#: lib/commit.tcl:274
+msgid "Commit declined by commit-msg hook."
+msgstr ""
+
+#: lib/commit.tcl:287
+msgid "Committing changes..."
+msgstr ""
+
+#: lib/commit.tcl:303
msgid "write-tree failed:"
msgstr ""
-#: lib/commit.tcl:275
+#: lib/commit.tcl:304 lib/commit.tcl:348 lib/commit.tcl:368
+msgid "Commit failed."
+msgstr ""
+
+#: lib/commit.tcl:321
#, tcl-format
msgid "Commit %s appears to be corrupt"
msgstr ""
@@ -1204,12 +1237,7 @@ msgstr ""
msgid "No changes to commit."
msgstr ""
-#: lib/commit.tcl:303
-#, tcl-format
-msgid "warning: Tcl does not support encoding '%s'."
-msgstr ""
-
-#: lib/commit.tcl:317
+#: lib/commit.tcl:347
msgid "commit-tree failed:"
msgstr ""
@@ -1373,6 +1401,10 @@ msgstr ""
msgid "Unstaging %s from commit"
msgstr ""
+#: lib/index.tcl:313
+msgid "Ready to commit."
+msgstr ""
+
#: lib/index.tcl:326
#, tcl-format
msgid "Adding %s"
@@ -1491,7 +1523,11 @@ msgstr ""
msgid "Aborting"
msgstr ""
-#: lib/merge.tcl:266
+#: lib/merge.tcl:238
+msgid "files reset"
+msgstr ""
+
+#: lib/merge.tcl:265
msgid "Abort failed."
msgstr ""
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 3e4452bc4b..6f91c8f845 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -24,8 +24,6 @@ restart restart the web server
fqgitdir="$GIT_DIR"
local="`git config --bool --get instaweb.local`"
httpd="`git config --get instaweb.httpd`"
-browser="`git config --get instaweb.browser`"
-test -z "$browser" && browser="`git config --get web.browser`"
port=`git config --get instaweb.port`
module_path="`git config --get instaweb.modulepath`"
@@ -36,9 +34,6 @@ conf="$GIT_DIR/gitweb/httpd.conf"
# if installed, it doesn't need further configuration (module_path)
test -z "$httpd" && httpd='lighttpd -f'
-# probably the most popular browser among gitweb users
-test -z "$browser" && browser='firefox'
-
# any untaken local port will do...
test -z "$port" && port=1234
@@ -274,14 +269,11 @@ webrick)
;;
esac
-init_browser_path() {
- browser_path="`git config browser.$1.path`"
- test -z "$browser_path" && browser_path="$1"
-}
-
start_httpd
url=http://127.0.0.1:$port
-test -n "$browser" && {
- init_browser_path "$browser"
- "$browser_path" $url
-} || echo $url
+
+if test -n "$browser"; then
+ git web--browse -b "$browser" $url || echo $url
+else
+ git web--browse -c "instaweb.browser" $url || echo $url
+fi
diff --git a/git-send-email.perl b/git-send-email.perl
index 59601e36e8..ccb87a2d55 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -475,7 +475,7 @@ if ($thread && !defined $initial_reply_to && $prompting) {
$initial_reply_to = $_;
}
-if (defined $initial_reply_to && $_ ne "") {
+if (defined $initial_reply_to) {
$initial_reply_to =~ s/^\s*<?/</;
$initial_reply_to =~ s/>?\s*$/>/;
}
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index aae14090bd..a44b1c74a3 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -119,7 +119,7 @@ get_author_ident_from_commit () {
}
'
encoding=$(git config i18n.commitencoding || echo UTF-8)
- git show -s --pretty=raw --encoding="$encoding" "$1" |
+ git show -s --pretty=raw --encoding="$encoding" "$1" -- |
LANG=C LC_ALL=C sed -ne "$pick_author_script"
}
@@ -127,20 +127,14 @@ get_author_ident_from_commit () {
# if we require to be in a git repository.
if test -z "$NONGIT_OK"
then
+ GIT_DIR=$(git rev-parse --git-dir) || exit
if [ -z "$SUBDIRECTORY_OK" ]
then
- : ${GIT_DIR=.git}
test -z "$(git rev-parse --show-cdup)" || {
exit=$?
echo >&2 "You need to run this command from the toplevel of the working tree."
exit $exit
}
- else
- GIT_DIR=$(git rev-parse --git-dir) || {
- exit=$?
- echo >&2 "Failed to find a valid git directory."
- exit $exit
- }
fi
test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {
echo >&2 "Unable to determine absolute path of git directory"
diff --git a/git-help--browse.sh b/git-web--browse.sh
index 10b0a36a3d..1023b90859 100755
--- a/git-help--browse.sh
+++ b/git-web--browse.sh
@@ -16,21 +16,16 @@
# git maintainer.
#
-USAGE='[--browser=browser|--tool=browser] [cmd to display] ...'
+USAGE='[--browser=browser|--tool=browser] [--config=conf.var] url/file ...'
# This must be capable of running outside of git directory, so
# the vanilla git-sh-setup should not be used.
NONGIT_OK=Yes
. git-sh-setup
-# Install data.
-html_dir="@@HTMLDIR@@"
-
-test -f "$html_dir/git.html" || die "No documentation directory found."
-
valid_tool() {
case "$1" in
- firefox | iceweasel | konqueror | w3m | links | lynx | dillo)
+ firefox | iceweasel | konqueror | w3m | links | lynx | dillo | open)
;; # happy
*)
return 1
@@ -39,8 +34,8 @@ valid_tool() {
}
init_browser_path() {
- browser_path=`git config browser.$1.path`
- test -z "$browser_path" && browser_path=$1
+ browser_path=$(git config "browser.$1.path")
+ test -z "$browser_path" && browser_path="$1"
}
while test $# != 0
@@ -58,6 +53,18 @@ do
shift ;;
esac
;;
+ -c|--config*)
+ case "$#,$1" in
+ *,*=*)
+ conf=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+ ;;
+ 1,*)
+ usage ;;
+ *)
+ conf="$2"
+ shift ;;
+ esac
+ ;;
--)
break
;;
@@ -71,17 +78,20 @@ do
shift
done
+test $# = 0 && usage
+
if test -z "$browser"
then
- for opt in "help.browser" "web.browser"
+ for opt in "$conf" "web.browser"
do
+ test -z "$opt" && continue
browser="`git config $opt`"
test -z "$browser" || break
done
if test -n "$browser" && ! valid_tool "$browser"; then
- echo >&2 "git config option $opt set to unknown browser: $browser"
- echo >&2 "Resetting to default..."
- unset browser
+ echo >&2 "git config option $opt set to unknown browser: $browser"
+ echo >&2 "Resetting to default..."
+ unset browser
fi
fi
@@ -94,6 +104,10 @@ if test -z "$browser" ; then
else
browser_candidates="w3m links lynx"
fi
+ # SECURITYSESSIONID indicates an OS X GUI login session
+ if test -n "$SECURITYSESSIONID"; then
+ browser_candidates="open $browser_candidates"
+ fi
for i in $browser_candidates; do
init_browser_path $i
@@ -113,16 +127,13 @@ else
fi
fi
-pages=$(for p in "$@"; do echo "$html_dir/$p.html" ; done)
-test -z "$pages" && pages="$html_dir/git.html"
-
case "$browser" in
firefox|iceweasel)
# Check version because firefox < 2.0 does not support "-new-tab".
vers=$(expr "$($browser_path -version)" : '.* \([0-9][0-9]*\)\..*')
NEWTAB='-new-tab'
test "$vers" -lt 2 && NEWTAB=''
- nohup "$browser_path" $NEWTAB $pages &
+ "$browser_path" $NEWTAB "$@" &
;;
konqueror)
case "$(basename "$browser_path")" in
@@ -130,20 +141,20 @@ case "$browser" in
# It's simpler to use kfmclient to open a new tab in konqueror.
browser_path="$(echo "$browser_path" | sed -e 's/konqueror$/kfmclient/')"
type "$browser_path" > /dev/null 2>&1 || die "No '$browser_path' found."
- eval "$browser_path" newTab $pages
+ eval "$browser_path" newTab "$@"
;;
kfmclient)
- eval "$browser_path" newTab $pages
+ eval "$browser_path" newTab "$@"
;;
*)
- nohup "$browser_path" $pages &
+ "$browser_path" "$@" &
;;
esac
;;
- w3m|links|lynx)
- eval "$browser_path" $pages
+ w3m|links|lynx|open)
+ eval "$browser_path" "$@"
;;
dillo)
- nohup "$browser_path" $pages &
+ "$browser_path" "$@" &
;;
esac
diff --git a/git.spec.in b/git.spec.in
index 3f9f88815b..97a26be29a 100644
--- a/git.spec.in
+++ b/git.spec.in
@@ -3,7 +3,7 @@
Name: git
Version: @@VERSION@@
Release: 1%{?dist}
-Summary: Git core and tools
+Summary: Core git tools
License: GPL
Group: Development/Tools
URL: http://kernel.org/pub/software/scm/git/
@@ -11,80 +11,86 @@ Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel, gettext %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-Requires: git-core = %{version}-%{release}
-Requires: git-svn = %{version}-%{release}
-Requires: git-cvs = %{version}-%{release}
-Requires: git-arch = %{version}-%{release}
-Requires: git-email = %{version}-%{release}
-Requires: gitk = %{version}-%{release}
-Requires: git-gui = %{version}-%{release}
Requires: perl-Git = %{version}-%{release}
+Requires: zlib >= 1.2, rsync, curl, less, openssh-clients, expat
+Provides: git-core = %{version}-%{release}
+Obsoletes: git-core <= 1.5.4.2
+Obsoletes: git-p4
%description
Git is a fast, scalable, distributed revision control system with an
unusually rich command set that provides both high-level operations
and full access to internals.
-This is a dummy package which brings in all subpackages.
+The git rpm installs the core tools with minimal dependencies. To
+install all git packages, including tools for integrating with other
+SCMs, install the git-all meta-package.
-%package core
-Summary: Core git tools
+%package all
+Summary: Meta-package to pull in all git tools
Group: Development/Tools
-Requires: zlib >= 1.2, rsync, curl, less, openssh-clients, expat
-Obsoletes: git-p4
-%description core
+Requires: git = %{version}-%{release}
+Requires: git-svn = %{version}-%{release}
+Requires: git-cvs = %{version}-%{release}
+Requires: git-arch = %{version}-%{release}
+Requires: git-email = %{version}-%{release}
+Requires: gitk = %{version}-%{release}
+Requires: git-gui = %{version}-%{release}
+Obsoletes: git <= 1.5.4.2
+
+%description all
Git is a fast, scalable, distributed revision control system with an
unusually rich command set that provides both high-level operations
and full access to internals.
-These are the core tools with minimal dependencies.
+This is a dummy package which brings in all subpackages.
%package svn
Summary: Git tools for importing Subversion repositories
Group: Development/Tools
-Requires: git-core = %{version}-%{release}, subversion
+Requires: git = %{version}-%{release}, subversion
%description svn
Git tools for importing Subversion repositories.
%package cvs
Summary: Git tools for importing CVS repositories
Group: Development/Tools
-Requires: git-core = %{version}-%{release}, cvs, cvsps
+Requires: git = %{version}-%{release}, cvs, cvsps
%description cvs
Git tools for importing CVS repositories.
%package arch
Summary: Git tools for importing Arch repositories
Group: Development/Tools
-Requires: git-core = %{version}-%{release}, tla
+Requires: git = %{version}-%{release}, tla
%description arch
Git tools for importing Arch repositories.
%package email
Summary: Git tools for sending email
Group: Development/Tools
-Requires: git-core = %{version}-%{release}
+Requires: git = %{version}-%{release}
%description email
Git tools for sending email.
%package gui
Summary: Git GUI tool
Group: Development/Tools
-Requires: git-core = %{version}-%{release}, tk >= 8.4
+Requires: git = %{version}-%{release}, tk >= 8.4
%description gui
Git GUI tool
%package -n gitk
Summary: Git revision tree visualiser ('gitk')
Group: Development/Tools
-Requires: git-core = %{version}-%{release}, tk >= 8.4
+Requires: git = %{version}-%{release}, tk >= 8.4
%description -n gitk
Git revision tree visualiser ('gitk')
%package -n perl-Git
Summary: Perl interface to Git
Group: Development/Libraries
-Requires: git-core = %{version}-%{release}
+Requires: git = %{version}-%{release}
Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
BuildRequires: perl(Error)
@@ -121,8 +127,12 @@ rm -rf $RPM_BUILD_ROOT%{_mandir}
%clean
rm -rf $RPM_BUILD_ROOT
-%files
-# These are no files in the root package
+%files -f bin-man-doc-files
+%defattr(-,root,root)
+%{_datadir}/git-core/
+%doc README COPYING Documentation/*.txt
+%{!?_without_docs: %doc Documentation/*.html Documentation/howto}
+%{!?_without_docs: %doc Documentation/technical}
%files svn
%defattr(-,root,root)
@@ -173,14 +183,13 @@ rm -rf $RPM_BUILD_ROOT
%files -n perl-Git -f perl-files
%defattr(-,root,root)
-%files core -f bin-man-doc-files
-%defattr(-,root,root)
-%{_datadir}/git-core/
-%doc README COPYING Documentation/*.txt
-%{!?_without_docs: %doc Documentation/*.html Documentation/howto}
-%{!?_without_docs: %doc Documentation/technical}
+%files all
+# No files for you!
%changelog
+* Fri Feb 15 2008 Kristian Høgsberg <krh@redhat.com>
+- Rename git-core to just git and rename meta package from git to git-all.
+
* Sun Feb 03 2008 James Bowes <jbowes@dangerouslyinc.com>
- Add a BuildRequires for gettext
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 5560e4dc56..f1f21e97bf 100644
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -240,11 +240,12 @@ proc getcommitlines {fd view} {
set listed 1
if {$j >= 0 && [string match "commit *" $cmit]} {
set ids [string range $cmit 7 [expr {$j - 1}]]
- if {[string match {[-<>]*} $ids]} {
+ if {[string match {[-^<>]*} $ids]} {
switch -- [string index $ids 0] {
"-" {set listed 0}
- "<" {set listed 2}
- ">" {set listed 3}
+ "^" {set listed 2}
+ "<" {set listed 3}
+ ">" {set listed 4}
}
set ids [string range $ids 1 end]
}
@@ -632,6 +633,7 @@ proc makewindow {} {
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
global diffcontextstring diffcontext
+ global ignorespace
global maincursor textcursor curtextcursor
global rowctxmenu fakerowmenu mergemax wrapcomment
global highlight_files gdttype
@@ -849,6 +851,9 @@ proc makewindow {} {
trace add variable diffcontextstring write diffcontextchange
lappend entries .bleft.mid.diffcontext
pack .bleft.mid.labeldiffcontext .bleft.mid.diffcontext -side left
+ checkbutton .bleft.mid.ignspace -text [mc "Ignore space change"] \
+ -command changeignorespace -variable ignorespace
+ pack .bleft.mid.ignspace -side left -padx 5
set ctext .bleft.ctext
text $ctext -background $bgcolor -foreground $fgcolor \
-state disabled -font textfont \
@@ -1307,45 +1312,45 @@ proc keys {} {
}
toplevel $w
wm title $w [mc "Gitk key bindings"]
- message $w.m -text [mc "
-Gitk key bindings:
-
-<$M1T-Q> Quit
-<Home> Move to first commit
-<End> Move to last commit
-<Up>, p, i Move up one commit
-<Down>, n, k Move down one commit
-<Left>, z, j Go back in history list
-<Right>, x, l Go forward in history list
-<PageUp> Move up one page in commit list
-<PageDown> Move down one page in commit list
-<$M1T-Home> Scroll to top of commit list
-<$M1T-End> Scroll to bottom of commit list
-<$M1T-Up> Scroll commit list up one line
-<$M1T-Down> Scroll commit list down one line
-<$M1T-PageUp> Scroll commit list up one page
-<$M1T-PageDown> Scroll commit list down one page
-<Shift-Up> Find backwards (upwards, later commits)
-<Shift-Down> Find forwards (downwards, earlier commits)
-<Delete>, b Scroll diff view up one page
-<Backspace> Scroll diff view up one page
-<Space> Scroll diff view down one page
-u Scroll diff view up 18 lines
-d Scroll diff view down 18 lines
-<$M1T-F> Find
-<$M1T-G> Move to next find hit
-<Return> Move to next find hit
-/ Move to next find hit, or redo find
-? Move to previous find hit
-f Scroll diff view to next file
-<$M1T-S> Search for next hit in diff view
-<$M1T-R> Search for previous hit in diff view
-<$M1T-KP+> Increase font size
-<$M1T-plus> Increase font size
-<$M1T-KP-> Decrease font size
-<$M1T-minus> Decrease font size
-<F5> Update
-"] \
+ message $w.m -text "
+[mc "Gitk key bindings:"]
+
+[mc "<%s-Q> Quit" $M1T]
+[mc "<Home> Move to first commit"]
+[mc "<End> Move to last commit"]
+[mc "<Up>, p, i Move up one commit"]
+[mc "<Down>, n, k Move down one commit"]
+[mc "<Left>, z, j Go back in history list"]
+[mc "<Right>, x, l Go forward in history list"]
+[mc "<PageUp> Move up one page in commit list"]
+[mc "<PageDown> Move down one page in commit list"]
+[mc "<%s-Home> Scroll to top of commit list" $M1T]
+[mc "<%s-End> Scroll to bottom of commit list" $M1T]
+[mc "<%s-Up> Scroll commit list up one line" $M1T]
+[mc "<%s-Down> Scroll commit list down one line" $M1T]
+[mc "<%s-PageUp> Scroll commit list up one page" $M1T]
+[mc "<%s-PageDown> Scroll commit list down one page" $M1T]
+[mc "<Shift-Up> Find backwards (upwards, later commits)"]
+[mc "<Shift-Down> Find forwards (downwards, earlier commits)"]
+[mc "<Delete>, b Scroll diff view up one page"]
+[mc "<Backspace> Scroll diff view up one page"]
+[mc "<Space> Scroll diff view down one page"]
+[mc "u Scroll diff view up 18 lines"]
+[mc "d Scroll diff view down 18 lines"]
+[mc "<%s-F> Find" $M1T]
+[mc "<%s-G> Move to next find hit" $M1T]
+[mc "<Return> Move to next find hit"]
+[mc "/ Move to next find hit, or redo find"]
+[mc "? Move to previous find hit"]
+[mc "f Scroll diff view to next file"]
+[mc "<%s-S> Search for next hit in diff view" $M1T]
+[mc "<%s-R> Search for previous hit in diff view" $M1T]
+[mc "<%s-KP+> Increase font size" $M1T]
+[mc "<%s-plus> Increase font size" $M1T]
+[mc "<%s-KP-> Decrease font size" $M1T]
+[mc "<%s-minus> Decrease font size" $M1T]
+[mc "<F5> Update"]
+" \
-justify left -bg white -border 2 -relief groove
pack $w.m -side top -fill both -padx 2 -pady 2
button $w.ok -text [mc "Close"] -command "destroy $w" -default active
@@ -3627,23 +3632,23 @@ proc drawcmittext {id row col} {
global linehtag linentag linedtag selectedline
global canvxmax boldrows boldnamerows fgcolor nullid nullid2
- # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
+ # listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right
set listed [lindex $commitlisted $row]
if {$id eq $nullid} {
set ofill red
} elseif {$id eq $nullid2} {
set ofill green
} else {
- set ofill [expr {$listed != 0? "blue": "white"}]
+ set ofill [expr {$listed != 0 ? $listed == 2 ? "gray" : "blue" : "white"}]
}
set x [xc $row $col]
set y [yc $row]
set orad [expr {$linespc / 3}]
- if {$listed <= 1} {
+ if {$listed <= 2} {
set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
[expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
-fill $ofill -outline $fgcolor -width 1 -tags circle]
- } elseif {$listed == 2} {
+ } elseif {$listed == 3} {
# triangle pointing left for left-side commits
set t [$canv create polygon \
[expr {$x - $orad}] $y \
@@ -5027,13 +5032,14 @@ proc getblobline {bf id} {
proc mergediff {id l} {
global diffmergeid mdifffd
global diffids
+ global diffcontext
global parentlist
global limitdiffs viewfiles curview
set diffmergeid $id
set diffids $id
# this doesn't seem to actually affect anything...
- set cmd [concat | git diff-tree --no-commit-id --cc $id]
+ set cmd [concat | git diff-tree --no-commit-id --cc -U$diffcontext $id]
if {$limitdiffs && $viewfiles($curview) ne {}} {
set cmd [concat $cmd -- $viewfiles($curview)]
}
@@ -5270,13 +5276,21 @@ proc diffcontextchange {n1 n2 op} {
}
}
+proc changeignorespace {} {
+ reselectline
+}
+
proc getblobdiffs {ids} {
global blobdifffd diffids env
global diffinhdr treediffs
global diffcontext
+ global ignorespace
global limitdiffs viewfiles curview
set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"]
+ if {$ignorespace} {
+ append cmd " -w"
+ }
if {$limitdiffs && $viewfiles($curview) ne {}} {
set cmd [concat $cmd -- $viewfiles($curview)]
}
@@ -6137,11 +6151,7 @@ proc domktag {} {
return
}
if {[catch {
- set dir [gitdir]
- set fname [file join $dir "refs/tags" $tag]
- set f [open $fname w]
- puts $f $id
- close $f
+ exec git tag $tag $id
} err]} {
error_popup "[mc "Error creating tag:"] $err"
return
@@ -8459,6 +8469,7 @@ set bgcolor white
set fgcolor black
set diffcolors {red "#00a000" blue}
set diffcontext 3
+set ignorespace 0
set selectbgcolor gray85
## For msgcat loading, first locate the installation location.
diff --git a/gitweb/README b/gitweb/README
index 4c8bedf744..2163071047 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -233,6 +233,10 @@ You can use the following files in repository:
Displayed in the project summary page. You can use multiple-valued
gitweb.url repository configuration variable for that, but the file
takes precendence.
+ * gitweb.owner
+ You can use the gitweb.owner repository configuration variable to set
+ repository's owner. It is displayed in the project list and summary
+ page. If it's not set, filesystem directory's owner is used.
* various gitweb.* config variables (in config)
Read description of %feature hash for detailed list, and some
descriptions.
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 5e88637b5e..8ed6d04417 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -611,6 +611,8 @@ sub href(%) {
);
my %mapping = @mapping;
+ $params{'project'} = $project unless exists $params{'project'};
+
if ($params{-replay}) {
while (my ($name, $symbol) = each %mapping) {
if (!exists $params{$name}) {
@@ -620,8 +622,6 @@ sub href(%) {
}
}
- $params{'project'} = $project unless exists $params{'project'};
-
my ($use_pathinfo) = gitweb_check_feature('pathinfo');
if ($use_pathinfo) {
# use PATH_INFO for project name
@@ -753,29 +753,40 @@ sub esc_path {
# Make control characters "printable", using character escape codes (CEC)
sub quot_cec {
my $cntrl = shift;
+ my %opts = @_;
my %es = ( # character escape codes, aka escape sequences
- "\t" => '\t', # tab (HT)
- "\n" => '\n', # line feed (LF)
- "\r" => '\r', # carrige return (CR)
- "\f" => '\f', # form feed (FF)
- "\b" => '\b', # backspace (BS)
- "\a" => '\a', # alarm (bell) (BEL)
- "\e" => '\e', # escape (ESC)
- "\013" => '\v', # vertical tab (VT)
- "\000" => '\0', # nul character (NUL)
- );
+ "\t" => '\t', # tab (HT)
+ "\n" => '\n', # line feed (LF)
+ "\r" => '\r', # carrige return (CR)
+ "\f" => '\f', # form feed (FF)
+ "\b" => '\b', # backspace (BS)
+ "\a" => '\a', # alarm (bell) (BEL)
+ "\e" => '\e', # escape (ESC)
+ "\013" => '\v', # vertical tab (VT)
+ "\000" => '\0', # nul character (NUL)
+ );
my $chr = ( (exists $es{$cntrl})
? $es{$cntrl}
: sprintf('\%03o', ord($cntrl)) );
- return "<span class=\"cntrl\">$chr</span>";
+ if ($opts{-nohtml}) {
+ return $chr;
+ } else {
+ return "<span class=\"cntrl\">$chr</span>";
+ }
}
# Alternatively use unicode control pictures codepoints,
# Unicode "printable representation" (PR)
sub quot_upr {
my $cntrl = shift;
+ my %opts = @_;
+
my $chr = sprintf('&#%04d;', 0x2400+ord($cntrl));
- return "<span class=\"cntrl\">$chr</span>";
+ if ($opts{-nohtml}) {
+ return $chr;
+ } else {
+ return "<span class=\"cntrl\">$chr</span>";
+ }
}
# git may return quoted and escaped filenames
@@ -800,7 +811,7 @@ sub unquote {
return chr(oct($seq));
} elsif (exists $es{$seq}) {
# C escape sequence, aka character escape code
- return $es{$seq}
+ return $es{$seq};
}
# quoted ordinary character
return $seq;
@@ -866,8 +877,8 @@ sub chop_and_escape_str {
if ($chopped eq $str) {
return esc_html($chopped);
} else {
- return qq{<span title="} . esc_html($str) . qq{">} .
- esc_html($chopped) . qq{</span>};
+ $str =~ s/([[:cntrl:]])/?/g;
+ return $cgi->span({-title=>$str}, esc_html($chopped));
}
}
@@ -1759,6 +1770,7 @@ sub git_get_project_owner {
my $owner;
return undef unless $project;
+ $git_dir = "$projectroot/$project";
if (!defined $gitweb_project_owner) {
git_get_project_list_from_file();
@@ -1767,8 +1779,11 @@ sub git_get_project_owner {
if (exists $gitweb_project_owner->{$project}) {
$owner = $gitweb_project_owner->{$project};
}
+ if (!defined $owner){
+ $owner = git_get_project_config('owner');
+ }
if (!defined $owner) {
- $owner = get_file_owner("$projectroot/$project");
+ $owner = get_file_owner("$git_dir");
}
return $owner;
diff --git a/help.c b/help.c
index 95e7640fed..8143dcdd38 100644
--- a/help.c
+++ b/help.c
@@ -39,12 +39,8 @@ static void parse_help_format(const char *format)
static int git_help_config(const char *var, const char *value)
{
- if (!strcmp(var, "help.format")) {
- if (!value)
- return config_error_nonbool(var);
- help_default_format = xstrdup(value);
- return 0;
- }
+ if (!strcmp(var, "help.format"))
+ return git_config_string(&help_default_format, var, value);
return git_default_config(var, value);
}
@@ -330,10 +326,26 @@ static void show_info_page(const char *git_cmd)
execlp("info", "info", "gitman", page, NULL);
}
+static void get_html_page_path(struct strbuf *page_path, const char *page)
+{
+ struct stat st;
+
+ /* Check that we have a git documentation directory. */
+ if (stat(GIT_HTML_PATH "/git.html", &st) || !S_ISREG(st.st_mode))
+ die("'%s': not a documentation directory.", GIT_HTML_PATH);
+
+ strbuf_init(page_path, 0);
+ strbuf_addf(page_path, GIT_HTML_PATH "/%s.html", page);
+}
+
static void show_html_page(const char *git_cmd)
{
const char *page = cmd_to_page(git_cmd);
- execl_git_cmd("help--browse", page, NULL);
+ struct strbuf page_path; /* it leaks but we exec bellow */
+
+ get_html_page_path(&page_path, page);
+
+ execl_git_cmd("web--browse", "-c", "help.browser", page_path.buf, NULL);
}
void help_unknown_cmd(const char *cmd)
diff --git a/http-push.c b/http-push.c
index b2b410df90..63ff218b3c 100644
--- a/http-push.c
+++ b/http-push.c
@@ -2383,7 +2383,8 @@ int main(int argc, char **argv)
/* Generate a list of objects that need to be pushed */
pushing = 0;
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
mark_edges_uninteresting(revs.commits);
objects_to_send = get_delta(&revs, ref_lock);
finish_all_active_slots();
diff --git a/list-objects.c b/list-objects.c
index 4ef58e7ec0..c8b8375e49 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -18,6 +18,8 @@ static void process_blob(struct rev_info *revs,
if (!revs->blob_objects)
return;
+ if (!obj)
+ die("bad blob object");
if (obj->flags & (UNINTERESTING | SEEN))
return;
obj->flags |= SEEN;
@@ -69,6 +71,8 @@ static void process_tree(struct rev_info *revs,
if (!revs->tree_objects)
return;
+ if (!obj)
+ die("bad tree object");
if (obj->flags & (UNINTERESTING | SEEN))
return;
if (parse_tree(tree) < 0)
diff --git a/merge-recursive.c b/merge-recursive.c
index dd52342539..55ef76f5a5 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1673,6 +1673,8 @@ static struct commit *get_ref(const char *ref)
if (get_sha1(ref, sha1))
die("Could not resolve ref '%s'", ref);
object = deref_tag(parse_object(sha1), ref, strlen(ref));
+ if (!object)
+ return NULL;
if (object->type == OBJ_TREE)
return make_virtual_commit((struct tree*)object,
better_branch_name(ref));
diff --git a/pager.c b/pager.c
index 0376953cb1..ca002f9f79 100644
--- a/pager.c
+++ b/pager.c
@@ -57,6 +57,7 @@ void setup_pager(void)
/* return in the child */
if (!pid) {
dup2(fd[1], 1);
+ dup2(fd[1], 2);
close(fd[0]);
close(fd[1]);
return;
diff --git a/reachable.c b/reachable.c
index 00f289f2f4..3b1c18ff9b 100644
--- a/reachable.c
+++ b/reachable.c
@@ -15,6 +15,8 @@ static void process_blob(struct blob *blob,
{
struct object *obj = &blob->object;
+ if (!blob)
+ die("bad blob object");
if (obj->flags & SEEN)
return;
obj->flags |= SEEN;
@@ -39,6 +41,8 @@ static void process_tree(struct tree *tree,
struct name_entry entry;
struct name_path me;
+ if (!tree)
+ die("bad tree object");
if (obj->flags & SEEN)
return;
obj->flags |= SEEN;
@@ -79,7 +83,8 @@ static void process_tag(struct tag *tag, struct object_array *p, const char *nam
if (parse_tag(tag) < 0)
die("bad tag object %s", sha1_to_hex(obj->sha1));
- add_object(tag->tagged, p, NULL, name);
+ if (tag->tagged)
+ add_object(tag->tagged, p, NULL, name);
}
static void walk_commit_list(struct rev_info *revs)
@@ -150,7 +155,8 @@ static int add_one_reflog(const char *path, const unsigned char *sha1, int flag,
static void add_one_tree(const unsigned char *sha1, struct rev_info *revs)
{
struct tree *tree = lookup_tree(sha1);
- add_pending_object(revs, &tree->object, "");
+ if (tree)
+ add_pending_object(revs, &tree->object, "");
}
static void add_cache_tree(struct cache_tree *it, struct rev_info *revs)
@@ -215,6 +221,7 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog)
* Set up the revision walk - this will move all commits
* from the pending list to the commit walking list.
*/
- prepare_revision_walk(revs);
+ if (prepare_revision_walk(revs))
+ die("revision walk setup failed");
walk_commit_list(revs);
}
diff --git a/remote.c b/remote.c
index 20abbc07ac..6b56473f5b 100644
--- a/remote.c
+++ b/remote.c
@@ -343,6 +343,16 @@ struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
return rs;
}
+static int valid_remote_nick(const char *name)
+{
+ if (!name[0] || /* not empty */
+ (name[0] == '.' && /* not "." */
+ (!name[1] || /* not ".." */
+ (name[1] == '.' && !name[2]))))
+ return 0;
+ return !strchr(name, '/'); /* no slash */
+}
+
struct remote *remote_get(const char *name)
{
struct remote *ret;
@@ -351,7 +361,7 @@ struct remote *remote_get(const char *name)
if (!name)
name = default_remote_name;
ret = make_remote(name, 0);
- if (name[0] != '/') {
+ if (valid_remote_nick(name)) {
if (!ret->url)
read_remotes_file(ret);
if (!ret->url)
diff --git a/revision.c b/revision.c
index 6e85aaa3fb..b1aebf8999 100644
--- a/revision.c
+++ b/revision.c
@@ -46,6 +46,8 @@ void add_object(struct object *obj,
static void mark_blob_uninteresting(struct blob *blob)
{
+ if (!blob)
+ return;
if (blob->object.flags & UNINTERESTING)
return;
blob->object.flags |= UNINTERESTING;
@@ -57,6 +59,8 @@ void mark_tree_uninteresting(struct tree *tree)
struct name_entry entry;
struct object *obj = &tree->object;
+ if (!tree)
+ return;
if (obj->flags & UNINTERESTING)
return;
obj->flags |= UNINTERESTING;
@@ -173,6 +177,8 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
struct tag *tag = (struct tag *) object;
if (revs->tag_objects && !(flags & UNINTERESTING))
add_pending_object(revs, object, tag->tag);
+ if (!tag->tagged)
+ die("bad tag");
object = parse_object(tag->tagged->sha1);
if (!object)
die("bad object %s", sha1_to_hex(tag->tagged->sha1));
@@ -685,6 +691,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
it = get_reference(revs, arg, sha1, 0);
if (it->type != OBJ_TAG)
break;
+ if (!((struct tag*)it)->tagged)
+ return 0;
hashcpy(sha1, ((struct tag*)it)->tagged->sha1);
}
if (it->type != OBJ_COMMIT)
diff --git a/setup.c b/setup.c
index 4509598d57..bc80301c42 100644
--- a/setup.c
+++ b/setup.c
@@ -4,51 +4,118 @@
static int inside_git_dir = -1;
static int inside_work_tree = -1;
-const char *prefix_path(const char *prefix, int len, const char *path)
+static int sanitary_path_copy(char *dst, const char *src)
{
- const char *orig = path;
+ char *dst0 = dst;
+
+ if (*src == '/') {
+ *dst++ = '/';
+ while (*src == '/')
+ src++;
+ }
+
for (;;) {
- char c;
- if (*path != '.')
- break;
- c = path[1];
- /* "." */
- if (!c) {
- path++;
- break;
+ char c = *src;
+
+ /*
+ * A path component that begins with . could be
+ * special:
+ * (1) "." and ends -- ignore and terminate.
+ * (2) "./" -- ignore them, eat slash and continue.
+ * (3) ".." and ends -- strip one and terminate.
+ * (4) "../" -- strip one, eat slash and continue.
+ */
+ if (c == '.') {
+ switch (src[1]) {
+ case '\0':
+ /* (1) */
+ src++;
+ break;
+ case '/':
+ /* (2) */
+ src += 2;
+ while (*src == '/')
+ src++;
+ continue;
+ case '.':
+ switch (src[2]) {
+ case '\0':
+ /* (3) */
+ src += 2;
+ goto up_one;
+ case '/':
+ /* (4) */
+ src += 3;
+ while (*src == '/')
+ src++;
+ goto up_one;
+ }
+ }
}
- /* "./" */
+
+ /* copy up to the next '/', and eat all '/' */
+ while ((c = *src++) != '\0' && c != '/')
+ *dst++ = c;
if (c == '/') {
- path += 2;
- continue;
- }
- if (c != '.')
+ *dst++ = c;
+ while (c == '/')
+ c = *src++;
+ src--;
+ } else if (!c)
break;
- c = path[2];
- if (!c)
- path += 2;
- else if (c == '/')
- path += 3;
- else
- break;
- /* ".." and "../" */
- /* Remove last component of the prefix */
- do {
- if (!len)
- die("'%s' is outside repository", orig);
- len--;
- } while (len && prefix[len-1] != '/');
continue;
+
+ up_one:
+ /*
+ * dst0..dst is prefix portion, and dst[-1] is '/';
+ * go up one level.
+ */
+ dst -= 2; /* go past trailing '/' if any */
+ if (dst < dst0)
+ return -1;
+ while (1) {
+ if (dst <= dst0)
+ break;
+ c = *dst--;
+ if (c == '/') {
+ dst += 2;
+ break;
+ }
+ }
}
- if (len) {
- int speclen = strlen(path);
- char *n = xmalloc(speclen + len + 1);
+ *dst = '\0';
+ return 0;
+}
- memcpy(n, prefix, len);
- memcpy(n + len, path, speclen+1);
- path = n;
+const char *prefix_path(const char *prefix, int len, const char *path)
+{
+ const char *orig = path;
+ char *sanitized = xmalloc(len + strlen(path) + 1);
+ if (*orig == '/')
+ strcpy(sanitized, path);
+ else {
+ if (len)
+ memcpy(sanitized, prefix, len);
+ strcpy(sanitized + len, path);
}
- return path;
+ if (sanitary_path_copy(sanitized, sanitized))
+ goto error_out;
+ if (*orig == '/') {
+ const char *work_tree = get_git_work_tree();
+ size_t len = strlen(work_tree);
+ size_t total = strlen(sanitized) + 1;
+ if (strncmp(sanitized, work_tree, len) ||
+ (sanitized[len] != '\0' && sanitized[len] != '/')) {
+ error_out:
+ error("'%s' is outside repository", orig);
+ free(sanitized);
+ return NULL;
+ }
+ if (sanitized[len] == '/')
+ len++;
+ memmove(sanitized, sanitized + len, total - len);
+ }
+ return sanitized;
}
/*
@@ -114,7 +181,7 @@ void verify_non_filename(const char *prefix, const char *arg)
const char **get_pathspec(const char *prefix, const char **pathspec)
{
const char *entry = *pathspec;
- const char **p;
+ const char **src, **dst;
int prefixlen;
if (!prefix && !entry)
@@ -128,12 +195,19 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
}
/* Otherwise we have to re-write the entries.. */
- p = pathspec;
+ src = pathspec;
+ dst = pathspec;
prefixlen = prefix ? strlen(prefix) : 0;
- do {
- *p = prefix_path(prefix, prefixlen, entry);
- } while ((entry = *++p) != NULL);
- return (const char **) pathspec;
+ while (*src) {
+ const char *p = prefix_path(prefix, prefixlen, *src);
+ if (p)
+ *(dst++) = p;
+ src++;
+ }
+ *dst = NULL;
+ if (!*pathspec)
+ return NULL;
+ return pathspec;
}
/*
diff --git a/sha1_file.c b/sha1_file.c
index 66a4e00fa8..d9da7c8f75 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1943,7 +1943,8 @@ void *read_object_with_reference(const unsigned char *sha1,
}
ref_length = strlen(ref_type);
- if (memcmp(buffer, ref_type, ref_length) ||
+ if (ref_length + 40 > isize ||
+ memcmp(buffer, ref_type, ref_length) ||
get_sha1_hex((char *) buffer + ref_length, actual_sha1)) {
free(buffer);
return NULL;
@@ -2358,7 +2359,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) {
struct strbuf nbuf;
strbuf_init(&nbuf, 0);
- if (convert_to_git(path, buf, size, &nbuf)) {
+ if (convert_to_git(path, buf, size, &nbuf,
+ write_object ? safe_crlf : 0)) {
munmap(buf, size);
buf = strbuf_detach(&nbuf, &size);
re_allocated = 1;
diff --git a/sha1_name.c b/sha1_name.c
index be8489e4e5..c2805e736b 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -494,8 +494,11 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
return error("%.*s: expected %s type, but the object dereferences to %s type",
len, name, typename(expected_type),
typename(o->type));
+ if (!o)
+ return -1;
if (!o->parsed)
- parse_object(o->sha1);
+ if (!parse_object(o->sha1))
+ return -1;
}
}
return 0;
@@ -578,8 +581,11 @@ static int handle_one_ref(const char *path,
struct object *object = parse_object(sha1);
if (!object)
return 0;
- if (object->type == OBJ_TAG)
+ if (object->type == OBJ_TAG) {
object = deref_tag(object, path, strlen(path));
+ if (!object)
+ return 0;
+ }
if (object->type != OBJ_COMMIT)
return 0;
insert_by_date((struct commit *)object, list);
@@ -617,7 +623,8 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
unsigned long size;
commit = pop_most_recent_commit(&list, ONELINE_SEEN);
- parse_object(commit->object.sha1);
+ if (!parse_object(commit->object.sha1))
+ continue;
if (temp_commit_buffer)
free(temp_commit_buffer);
if (commit->buffer)
diff --git a/shallow.c b/shallow.c
index dbd9f5ad0a..4d90eda19e 100644
--- a/shallow.c
+++ b/shallow.c
@@ -56,7 +56,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
if (i < heads->nr) {
commit = (struct commit *)
deref_tag(heads->objects[i++].item, NULL, 0);
- if (commit->object.type != OBJ_COMMIT) {
+ if (!commit || commit->object.type != OBJ_COMMIT) {
commit = NULL;
continue;
}
@@ -70,7 +70,8 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
cur_depth = *(int *)commit->util;
}
}
- parse_commit(commit);
+ if (parse_commit(commit))
+ die("invalid commit");
commit->object.flags |= not_shallow_flag;
cur_depth++;
for (p = commit->parents, commit = NULL; p; p = p->next) {
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 8b27aa892b..90ea081db6 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -8,6 +8,10 @@ q_to_nul () {
tr Q '\000'
}
+q_to_cr () {
+ tr Q '\015'
+}
+
append_cr () {
sed -e 's/$/Q/' | tr Q '\015'
}
@@ -42,6 +46,60 @@ test_expect_success setup '
echo happy.
'
+test_expect_success 'safecrlf: autocrlf=input, all CRLF' '
+
+ git config core.autocrlf input &&
+ git config core.safecrlf true &&
+
+ for w in I am all CRLF; do echo $w; done | append_cr >allcrlf &&
+ ! git add allcrlf
+'
+
+test_expect_success 'safecrlf: autocrlf=input, mixed LF/CRLF' '
+
+ git config core.autocrlf input &&
+ git config core.safecrlf true &&
+
+ for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >mixed &&
+ ! git add mixed
+'
+
+test_expect_success 'safecrlf: autocrlf=true, all LF' '
+
+ git config core.autocrlf true &&
+ git config core.safecrlf true &&
+
+ for w in I am all LF; do echo $w; done >alllf &&
+ ! git add alllf
+'
+
+test_expect_success 'safecrlf: autocrlf=true mixed LF/CRLF' '
+
+ git config core.autocrlf true &&
+ git config core.safecrlf true &&
+
+ for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >mixed &&
+ ! git add mixed
+'
+
+test_expect_success 'safecrlf: print warning only once' '
+
+ git config core.autocrlf input &&
+ git config core.safecrlf warn &&
+
+ for w in I am all LF; do echo $w; done >doublewarn &&
+ git add doublewarn &&
+ git commit -m "nowarn" &&
+ for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >doublewarn &&
+ test $(git add doublewarn 2>&1 | grep "CRLF will be replaced by LF" | wc -l) = 1
+'
+
+test_expect_success 'switch off autocrlf, safecrlf, reset HEAD' '
+ git config core.autocrlf false &&
+ git config core.safecrlf false &&
+ git reset --hard HEAD^
+'
+
test_expect_success 'update with autocrlf=input' '
rm -f tmp one dir/two three &&
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index e474b3f1d5..38a2bf09af 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -33,9 +33,9 @@ test_rev_parse() {
test_rev_parse toplevel false false true ''
cd .git || exit 1
-test_rev_parse .git/ true true false ''
+test_rev_parse .git/ false true false ''
cd objects || exit 1
-test_rev_parse .git/objects/ true true false ''
+test_rev_parse .git/objects/ false true false ''
cd ../.. || exit 1
mkdir -p sub/dir || exit 1
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index e25b255683..b4297bacf2 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -99,4 +99,45 @@ EOF
test_expect_success 'git-status honours core.excludesfile' \
'diff -u expect output'
+test_expect_success 'trailing slash in exclude allows directory match(1)' '
+
+ git ls-files --others --exclude=one/ >output &&
+ if grep "^one/" output
+ then
+ echo Ooops
+ false
+ else
+ : happy
+ fi
+
+'
+
+test_expect_success 'trailing slash in exclude allows directory match (2)' '
+
+ git ls-files --others --exclude=one/two/ >output &&
+ if grep "^one/two/" output
+ then
+ echo Ooops
+ false
+ else
+ : happy
+ fi
+
+'
+
+test_expect_success 'trailing slash in exclude forces directory match (1)' '
+
+ >two
+ git ls-files --others --exclude=two/ >output &&
+ grep "^two" output
+
+'
+
+test_expect_success 'trailing slash in exclude forces directory match (2)' '
+
+ git ls-files --others --exclude=one/a.1/ >output &&
+ grep "^one/a.1" output
+
+'
+
test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index e33ea4e9f4..e5ed74545b 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -340,4 +340,26 @@ test_expect_success 'rebase a commit violating pre-commit' '
'
+test_expect_success 'rebase with a file named HEAD in worktree' '
+
+ rm -fr .git/hooks &&
+ git reset --hard &&
+ git checkout -b branch3 A &&
+
+ (
+ GIT_AUTHOR_NAME="Squashed Away" &&
+ export GIT_AUTHOR_NAME &&
+ >HEAD &&
+ git add HEAD &&
+ git commit -m "Add head" &&
+ >BODY &&
+ git add BODY &&
+ git commit -m "Add body"
+ ) &&
+
+ FAKE_LINES="1 squash 2" git rebase -i to-be-rebased &&
+ test "$(git show -s --pretty=format:%an)" = "Squashed Away"
+
+'
+
test_done
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index d30169fbdc..83c54b747f 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -326,4 +326,13 @@ test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab:
! git diff --check
'
+
+test_expect_success 'line numbers in --check output are correct' '
+
+ echo "" > x &&
+ echo "foo(); " >> x &&
+ git diff --check | grep "x:2:"
+
+'
+
test_done
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index 9b1a74542a..d6c55c1157 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -11,7 +11,7 @@ test_expect_success 'split sample box' \
'git mailsplit -o. ../t5100/sample.mbox >last &&
last=`cat last` &&
echo total is $last &&
- test `cat last` = 8'
+ test `cat last` = 9'
for mail in `echo 00*`
do
diff --git a/t/t5100/info0009 b/t/t5100/info0009
new file mode 100644
index 0000000000..2a66321c80
--- /dev/null
+++ b/t/t5100/info0009
@@ -0,0 +1,5 @@
+Author: F U Bar
+Email: f.u.bar@example.com
+Subject: updates
+Date: Mon, 17 Sep 2001 00:00:00 +0900
+
diff --git a/t/t5100/msg0009 b/t/t5100/msg0009
new file mode 100644
index 0000000000..9ffe131489
--- /dev/null
+++ b/t/t5100/msg0009
@@ -0,0 +1,2 @@
+This is to fix diff-format documentation.
+
diff --git a/t/t5100/patch0009 b/t/t5100/patch0009
new file mode 100644
index 0000000000..65615c34af
--- /dev/null
+++ b/t/t5100/patch0009
@@ -0,0 +1,13 @@
+diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt
+index b426a14..97756ec 100644
+--- a/Documentation/diff-format.txt
++++ b/Documentation/diff-format.txt
+@@ -81,7 +81,7 @@ The "diff" formatting options can be customized via the
+ environment variable 'GIT_DIFF_OPTS'. For example, if you
+ prefer context diff:
+
+- GIT_DIFF_OPTS=-c git-diff-index -p $(cat .git/HEAD)
++ GIT_DIFF_OPTS=-c git-diff-index -p HEAD
+
+
+ 2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the
diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox
index 070c1661b9..0476b96c33 100644
--- a/t/t5100/sample.mbox
+++ b/t/t5100/sample.mbox
@@ -407,3 +407,26 @@ Subject: [PATCH] another patch
Hey you forgot the patch!
+From nobody Mon Sep 17 00:00:00 2001
+From: A U Thor <a.u.thor@example.com>
+Date: Mon, 17 Sep 2001 00:00:00 +0900
+Mime-Version: 1.0
+Content-Type: Text/Plain; charset=us-ascii
+Content-Transfer-Encoding: Quoted-Printable
+
+=0A=0AFrom: F U Bar <f.u.bar@example.com>
+Subject: [PATCH] updates=0A=0AThis is to fix diff-format documentation.
+
+diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt
+index b426a14..97756ec 100644
+--- a/Documentation/diff-format.txt
++++ b/Documentation/diff-format.txt
+@@ -81,7 +81,7 @@ The "diff" formatting options can be customized via the
+ environment variable 'GIT_DIFF_OPTS'. For example, if you
+ prefer context diff:
+=20
+- GIT_DIFF_OPTS=3D-c git-diff-index -p $(cat .git/HEAD)
++ GIT_DIFF_OPTS=3D-c git-diff-index -p HEAD
+=20
+=20
+ 2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the
diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh
index 822ac8c28e..59a165a6d4 100755
--- a/t/t5701-clone-local.sh
+++ b/t/t5701-clone-local.sh
@@ -63,4 +63,12 @@ test_expect_success 'Even without -l, local will make a hardlink' '
test 0 = $copied
'
+test_expect_success 'local clone of repo with nonexistent ref in HEAD' '
+ cd "$D" &&
+ echo "ref: refs/heads/nonexistent" > a.git/HEAD &&
+ git clone a d &&
+ cd d &&
+ git fetch &&
+ test ! -e .git/refs/remotes/origin/HEAD'
+
test_done
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index b1243b4163..fa382c58da 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -118,4 +118,42 @@ test_expect_success "Sergey Vlasov's test case" '
git mv ab a
'
+test_expect_success 'absolute pathname' '(
+
+ rm -fr mine &&
+ mkdir mine &&
+ cd mine &&
+ test_create_repo one &&
+ cd one &&
+ mkdir sub &&
+ >sub/file &&
+ git add sub/file &&
+
+ git mv sub "$(pwd)/in" &&
+ ! test -d sub &&
+ test -d in &&
+ git ls-files --error-unmatch in/file
+
+
+)'
+
+test_expect_success 'absolute pathname outside should fail' '(
+
+ rm -fr mine &&
+ mkdir mine &&
+ cd mine &&
+ out=$(pwd) &&
+ test_create_repo one &&
+ cd one &&
+ mkdir sub &&
+ >sub/file &&
+ git add sub/file &&
+
+ ! git mv sub "$out/out" &&
+ test -d sub &&
+ ! test -d ../in &&
+ git ls-files --error-unmatch sub/file
+
+)'
+
test_done
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 5f60b22d87..868babc4b2 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -165,4 +165,18 @@ test_expect_success '"map" works in commit filter' '
git rev-parse --verify master
'
+test_expect_success 'Name needing quotes' '
+
+ git checkout -b rerere A &&
+ mkdir foo &&
+ name="れれれ" &&
+ >foo/$name &&
+ git add foo &&
+ git commit -m "Adding a file" &&
+ git filter-branch --tree-filter "rm -fr foo" &&
+ ! git ls-files --error-unmatch "foo/$name" &&
+ test $(git rev-parse --verify rerere) != $(git rev-parse --verify A)
+
+'
+
test_done
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
new file mode 100755
index 0000000000..e809e0e2c9
--- /dev/null
+++ b/t/t7010-setup.sh
@@ -0,0 +1,164 @@
+#!/bin/sh
+
+test_description='setup taking and sanitizing funny paths'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+ mkdir -p a/b/c a/e &&
+ D=$(pwd) &&
+ >a/b/c/d &&
+ >a/e/f
+
+'
+
+test_expect_success 'git add (absolute)' '
+
+ git add "$D/a/b/c/d" &&
+ git ls-files >current &&
+ echo a/b/c/d >expect &&
+ diff -u expect current
+
+'
+
+
+test_expect_success 'git add (funny relative)' '
+
+ rm -f .git/index &&
+ (
+ cd a/b &&
+ git add "../e/./f"
+ ) &&
+ git ls-files >current &&
+ echo a/e/f >expect &&
+ diff -u expect current
+
+'
+
+test_expect_success 'git rm (absolute)' '
+
+ rm -f .git/index &&
+ git add a &&
+ git rm -f --cached "$D/a/b/c/d" &&
+ git ls-files >current &&
+ echo a/e/f >expect &&
+ diff -u expect current
+
+'
+
+test_expect_success 'git rm (funny relative)' '
+
+ rm -f .git/index &&
+ git add a &&
+ (
+ cd a/b &&
+ git rm -f --cached "../e/./f"
+ ) &&
+ git ls-files >current &&
+ echo a/b/c/d >expect &&
+ diff -u expect current
+
+'
+
+test_expect_success 'git ls-files (absolute)' '
+
+ rm -f .git/index &&
+ git add a &&
+ git ls-files "$D/a/e/../b" >current &&
+ echo a/b/c/d >expect &&
+ diff -u expect current
+
+'
+
+test_expect_success 'git ls-files (relative #1)' '
+
+ rm -f .git/index &&
+ git add a &&
+ (
+ cd a/b &&
+ git ls-files "../b/c"
+ ) >current &&
+ echo c/d >expect &&
+ diff -u expect current
+
+'
+
+test_expect_success 'git ls-files (relative #2)' '
+
+ rm -f .git/index &&
+ git add a &&
+ (
+ cd a/b &&
+ git ls-files --full-name "../e/f"
+ ) >current &&
+ echo a/e/f >expect &&
+ diff -u expect current
+
+'
+
+test_expect_success 'git ls-files (relative #3)' '
+
+ rm -f .git/index &&
+ git add a &&
+ (
+ cd a/b &&
+ if git ls-files "../e/f"
+ then
+ echo Gaah, should have failed
+ exit 1
+ else
+ : happy
+ fi
+ )
+
+'
+
+test_expect_success 'commit using absolute path names' '
+ git commit -m "foo" &&
+ echo aa >>a/b/c/d &&
+ git commit -m "aa" "$(pwd)/a/b/c/d"
+'
+
+test_expect_success 'log using absolute path names' '
+ echo bb >>a/b/c/d &&
+ git commit -m "bb" $(pwd)/a/b/c/d &&
+
+ git log a/b/c/d >f1.txt &&
+ git log "$(pwd)/a/b/c/d" >f2.txt &&
+ diff -u f1.txt f2.txt
+'
+
+test_expect_success 'blame using absolute path names' '
+ git blame a/b/c/d >f1.txt &&
+ git blame "$(pwd)/a/b/c/d" >f2.txt &&
+ diff -u f1.txt f2.txt
+'
+
+test_expect_success 'setup deeper work tree' '
+ test_create_repo tester
+'
+
+test_expect_success 'add a directory outside the work tree' '(
+ cd tester &&
+ d1="$(cd .. ; pwd)" &&
+ git add "$d1"
+)'
+
+test_expect_success 'add a file outside the work tree, nasty case 1' '(
+ cd tester &&
+ f="$(pwd)x" &&
+ echo "$f" &&
+ touch "$f" &&
+ git add "$f"
+)'
+
+test_expect_success 'add a file outside the work tree, nasty case 2' '(
+ cd tester &&
+ f="$(pwd | sed "s/.$//")x" &&
+ echo "$f" &&
+ touch "$f" &&
+ git add "$f"
+)'
+
+test_done
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index aaf497e6a5..b780fddc08 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -154,4 +154,33 @@ test_expect_success 'cleanup commit messages (strip,-F,-e)' '
'
+pwd=`pwd`
+cat >> .git/FAKE_EDITOR << EOF
+#! /bin/sh
+echo editor started > "$pwd/.git/result"
+exit 0
+EOF
+chmod +x .git/FAKE_EDITOR
+
+test_expect_success 'do not fire editor in the presence of conflicts' '
+
+ git clean
+ echo f>g
+ git add g
+ git commit -myes
+ git branch second
+ echo master>g
+ echo g>h
+ git add g h
+ git commit -mmaster
+ git checkout second
+ echo second>g
+ git add g
+ git commit -msecond
+ git cherry-pick -n master
+ echo "editor not started" > .git/result
+ GIT_EDITOR=`pwd`/.git/FAKE_EDITOR git commit && exit 1 # should fail
+ test "`cat .git/result`" = "editor not started"
+'
+
test_done
diff --git a/t/t7502-status.sh b/t/t7502-status.sh
index 9ce50cade8..e00607490b 100755
--- a/t/t7502-status.sh
+++ b/t/t7502-status.sh
@@ -17,6 +17,9 @@ test_expect_success 'setup' '
: > dir1/tracked &&
: > dir1/modified &&
git add . &&
+
+ git status >output &&
+
test_tick &&
git commit -m initial &&
: > untracked &&
@@ -28,6 +31,12 @@ test_expect_success 'setup' '
git add dir2/added
'
+test_expect_success 'status (1)' '
+
+ grep -e "use \"git rm --cached <file>\.\.\.\" to unstage" output
+
+'
+
cat > expect << \EOF
# On branch master
# Changes to be committed:
@@ -51,7 +60,7 @@ cat > expect << \EOF
# untracked
EOF
-test_expect_success 'status' '
+test_expect_success 'status (2)' '
git status > output &&
git diff expect output
@@ -119,4 +128,25 @@ test_expect_success 'status without relative paths' '
'
+cat <<EOF >expect
+# On branch master
+# Changes to be committed:
+# (use "git reset HEAD <file>..." to unstage)
+#
+# modified: dir1/modified
+#
+# Untracked files:
+# (use "git add <file>..." to include in what will be committed)
+#
+# dir1/untracked
+# dir2/
+# expect
+# output
+# untracked
+EOF
+test_expect_success 'status of partial commit excluding new file in index' '
+ git status dir1/modified >output &&
+ diff -u expect output
+'
+
test_done
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
new file mode 100755
index 0000000000..7ddec99a64
--- /dev/null
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -0,0 +1,155 @@
+#!/bin/sh
+
+test_description='prepare-commit-msg hook'
+
+. ./test-lib.sh
+
+test_expect_success 'with no hook' '
+
+ echo "foo" > file &&
+ git add file &&
+ git commit -m "first"
+
+'
+
+# set up fake editor for interactive editing
+cat > fake-editor <<'EOF'
+#!/bin/sh
+exit 0
+EOF
+chmod +x fake-editor
+FAKE_EDITOR="$(pwd)/fake-editor"
+export FAKE_EDITOR
+
+# now install hook that always succeeds and adds a message
+HOOKDIR="$(git rev-parse --git-dir)/hooks"
+HOOK="$HOOKDIR/prepare-commit-msg"
+mkdir -p "$HOOKDIR"
+cat > "$HOOK" <<'EOF'
+#!/bin/sh
+if test "$2" = commit; then
+ source=$(git-rev-parse "$3")
+else
+ source=${2-default}
+fi
+if test "$GIT_EDITOR" = :; then
+ sed -e "1s/.*/$source (no editor)/" "$1" > msg.tmp
+else
+ sed -e "1s/.*/$source/" "$1" > msg.tmp
+fi
+mv msg.tmp "$1"
+exit 0
+EOF
+chmod +x "$HOOK"
+
+echo dummy template > "$(git rev-parse --git-dir)/template"
+
+test_expect_success 'with hook (-m)' '
+
+ echo "more" >> file &&
+ git add file &&
+ git commit -m "more" &&
+ test "`git log -1 --pretty=format:%s`" = "message (no editor)"
+
+'
+
+test_expect_success 'with hook (-m editor)' '
+
+ echo "more" >> file &&
+ git add file &&
+ GIT_EDITOR="$FAKE_EDITOR" git commit -e -m "more more" &&
+ test "`git log -1 --pretty=format:%s`" = message
+
+'
+
+test_expect_success 'with hook (-t)' '
+
+ echo "more" >> file &&
+ git add file &&
+ git commit -t "$(git rev-parse --git-dir)/template" &&
+ test "`git log -1 --pretty=format:%s`" = template
+
+'
+
+test_expect_success 'with hook (-F)' '
+
+ echo "more" >> file &&
+ git add file &&
+ (echo more | git commit -F -) &&
+ test "`git log -1 --pretty=format:%s`" = "message (no editor)"
+
+'
+
+test_expect_success 'with hook (-F editor)' '
+
+ echo "more" >> file &&
+ git add file &&
+ (echo more more | GIT_EDITOR="$FAKE_EDITOR" git commit -e -F -) &&
+ test "`git log -1 --pretty=format:%s`" = message
+
+'
+
+test_expect_success 'with hook (-C)' '
+
+ head=`git rev-parse HEAD` &&
+ echo "more" >> file &&
+ git add file &&
+ git commit -C $head &&
+ test "`git log -1 --pretty=format:%s`" = "$head (no editor)"
+
+'
+
+test_expect_success 'with hook (editor)' '
+
+ echo "more more" >> file &&
+ git add file &&
+ GIT_EDITOR="$FAKE_EDITOR" git commit &&
+ test "`git log -1 --pretty=format:%s`" = default
+
+'
+
+test_expect_success 'with hook (--amend)' '
+
+ head=`git rev-parse HEAD` &&
+ echo "more" >> file &&
+ git add file &&
+ GIT_EDITOR="$FAKE_EDITOR" git commit --amend &&
+ test "`git log -1 --pretty=format:%s`" = "$head"
+
+'
+
+test_expect_success 'with hook (-c)' '
+
+ head=`git rev-parse HEAD` &&
+ echo "more" >> file &&
+ git add file &&
+ GIT_EDITOR="$FAKE_EDITOR" git commit -c $head &&
+ test "`git log -1 --pretty=format:%s`" = "$head"
+
+'
+
+cat > "$HOOK" <<'EOF'
+#!/bin/sh
+exit 1
+EOF
+
+test_expect_success 'with failing hook' '
+
+ head=`git rev-parse HEAD` &&
+ echo "more" >> file &&
+ git add file &&
+ ! GIT_EDITOR="$FAKE_EDITOR" git commit -c $head
+
+'
+
+test_expect_success 'with failing hook (--no-verify)' '
+
+ head=`git rev-parse HEAD` &&
+ echo "more" >> file &&
+ git add file &&
+ ! GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify -c $head
+
+'
+
+
+test_done
diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index a15222ced4..49d57a81ec 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -2,7 +2,7 @@
#
# Copyright (c) Robin Rosenberg
#
-test_description='CVS export comit. '
+test_description='Test export of commits to CVS'
. ./test-lib.sh
@@ -246,4 +246,20 @@ test_expect_success \
;;
esac
+test_expect_success '-w option should work with relative GIT_DIR' '
+ mkdir W &&
+ echo foobar >W/file1.txt &&
+ echo bazzle >W/file2.txt &&
+ git add W/file1.txt &&
+ git add W/file2.txt &&
+ git commit -m "More updates" &&
+ id=$(git rev-list --max-count=1 HEAD) &&
+ (cd "$GIT_DIR" &&
+ GIT_DIR=. git cvsexportcommit -w "$CVSWORK" -c $id &&
+ check_entries "$CVSWORK/W" "file1.txt/1.1/|file2.txt/1.1/" &&
+ diff -u "$CVSWORK/W/file1.txt" ../W/file1.txt &&
+ diff -u "$CVSWORK/W/file2.txt" ../W/file2.txt
+ )
+'
+
test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index da47bd7c9e..83889c4f46 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -324,8 +324,11 @@ test_done () {
PATH=$(pwd)/..:$PATH
GIT_EXEC_PATH=$(pwd)/..
GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
-GIT_CONFIG=.git/config
-export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG
+unset GIT_CONFIG
+unset GIT_CONFIG_LOCAL
+GIT_CONFIG_NOSYSTEM=1
+GIT_CONFIG_NOGLOBAL=1
+export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL
GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
export GITPERLLIB
diff --git a/tag.c b/tag.c
index 38bf9134f9..990134fe7a 100644
--- a/tag.c
+++ b/tag.c
@@ -9,7 +9,10 @@ const char *tag_type = "tag";
struct object *deref_tag(struct object *o, const char *warn, int warnlen)
{
while (o && o->type == OBJ_TAG)
- o = parse_object(((struct tag *)o)->tagged->sha1);
+ if (((struct tag *)o)->tagged)
+ o = parse_object(((struct tag *)o)->tagged->sha1);
+ else
+ o = NULL;
if (!o && warn) {
if (!warnlen)
warnlen = strlen(warn);
diff --git a/templates/hooks--commit-msg b/templates/hooks--commit-msg
index c5cdb9d7ee..4ef86eb244 100644
--- a/templates/hooks--commit-msg
+++ b/templates/hooks--commit-msg
@@ -9,6 +9,9 @@
# To enable this hook, make this file executable.
# Uncomment the below to add a Signed-off-by line to the message.
+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
+# hook is more suited to it.
+#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff --git a/templates/hooks--prepare-commit-msg b/templates/hooks--prepare-commit-msg
new file mode 100644
index 0000000000..ff0f42a1d9
--- /dev/null
+++ b/templates/hooks--prepare-commit-msg
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# An example hook script to prepare the commit log message.
+# Called by git-commit with the name of the file that has the
+# commit message, followed by the description of the commit
+# message's source. The hook's purpose is to edit the commit
+# message file. If the hook fails with a non-zero status,
+# the commit is aborted.
+#
+# To enable this hook, make this file executable.
+
+# This hook includes three examples. The first comments out the
+# "Conflicts:" part of a merge commit.
+#
+# The second includes the output of "git diff --name-status -r"
+# into the message, just before the "git status" output. It is
+# commented because it doesn't cope with --amend or with squashed
+# commits.
+#
+# The third example adds a Signed-off-by line to the message, that can
+# still be edited. This is rarely a good idea.
+
+case "$2 $3" in
+ merge)
+ sed -i '/^Conflicts:/,/#/!b;s/^/# &/;s/^# #/#/' "$1" ;;
+
+# ""|template)
+# perl -i -pe '
+# print "\n" . `git diff --cached --name-status -r`
+# if /^#/ && $first++ == 0' "$1" ;;
+
+ *) ;;
+esac
+
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff --git a/unpack-trees.c b/unpack-trees.c
index ff46fd62fd..ec558f9005 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -521,8 +521,9 @@ static void verify_absent(struct cache_entry *ce, const char *action,
if (!lstat(ce->name, &st)) {
int cnt;
+ int dtype = ce_to_dtype(ce);
- if (o->dir && excluded(o->dir, ce->name))
+ if (o->dir && excluded(o->dir, ce->name, &dtype))
/*
* ce->name is explicitly excluded, so it is Ok to
* overwrite it.
diff --git a/upload-pack.c b/upload-pack.c
index 7e04311027..b26d05331d 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -129,7 +129,8 @@ static int do_rev_list(int fd, void *create_full_pack)
}
setup_revisions(0, NULL, &revs, NULL);
}
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object);
return 0;
@@ -533,7 +534,8 @@ static void receive_needs(void)
/* make sure the real parents are parsed */
unregister_shallow(object->sha1);
object->parsed = 0;
- parse_commit((struct commit *)object);
+ if (parse_commit((struct commit *)object))
+ die("invalid commit");
parents = ((struct commit *)object)->parents;
while (parents) {
add_object_array(&parents->item->object,
@@ -575,7 +577,8 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
}
if (o->type == OBJ_TAG) {
o = deref_tag(o, refname, 0);
- packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
+ if (o)
+ packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
}
return 0;
}
@@ -620,6 +623,9 @@ int main(int argc, char **argv)
if (i != argc-1)
usage(upload_pack_usage);
+
+ setup_path(NULL);
+
dir = argv[i];
if (!enter_repo(dir, strict))
diff --git a/wt-status.c b/wt-status.c
index f14022f2a9..0b060934e2 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -60,7 +60,7 @@ static void wt_status_print_cached_header(struct wt_status *s)
{
const char *c = color(WT_STATUS_HEADER);
color_fprintf_ln(s->fp, c, "# Changes to be committed:");
- if (s->reference) {
+ if (!s->is_initial) {
color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference);
} else {
color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)");