summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes-1.6.3.txt104
-rw-r--r--Documentation/SubmittingPatches10
-rw-r--r--Documentation/blame-options.txt8
-rw-r--r--Documentation/config.txt14
-rw-r--r--Documentation/git-archive.txt4
-rw-r--r--Documentation/git-bisect.txt18
-rw-r--r--Documentation/git-checkout.txt33
-rw-r--r--Documentation/git-config.txt6
-rw-r--r--Documentation/git-filter-branch.txt17
-rw-r--r--Documentation/git-format-patch.txt21
-rw-r--r--Documentation/git-imap-send.txt7
-rw-r--r--Documentation/git-rebase.txt17
-rw-r--r--Documentation/git-send-email.txt21
-rw-r--r--Documentation/git.txt3
-rw-r--r--Documentation/pretty-formats.txt9
-rw-r--r--Documentation/pretty-options.txt5
-rw-r--r--Documentation/technical/api-parse-options.txt28
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile24
l---------RelNotes2
-rw-r--r--archive.c5
-rw-r--r--builtin-archive.c103
-rw-r--r--builtin-blame.c174
-rw-r--r--builtin-branch.c149
-rw-r--r--builtin-checkout.c2
-rw-r--r--builtin-clone.c13
-rw-r--r--builtin-config.c16
-rw-r--r--builtin-count-objects.c2
-rw-r--r--builtin-diff-tree.c1
-rw-r--r--builtin-fetch-pack.c3
-rw-r--r--builtin-fmt-merge-msg.c6
-rw-r--r--builtin-for-each-ref.c1
-rw-r--r--builtin-fsck.c2
-rw-r--r--builtin-log.c83
-rw-r--r--builtin-mailinfo.c1
-rw-r--r--builtin-pack-objects.c14
-rw-r--r--builtin-prune-packed.c2
-rw-r--r--builtin-receive-pack.c2
-rw-r--r--builtin-remote.c3
-rw-r--r--builtin-rerere.c25
-rw-r--r--builtin-rev-list.c45
-rw-r--r--builtin-shortlog.c1
-rw-r--r--builtin-upload-archive.c2
-rw-r--r--cache.h4
-rw-r--r--color.c8
-rw-r--r--color.h10
-rw-r--r--combine-diff.c3
-rw-r--r--compat/memmem.c5
-rw-r--r--compat/mingw.c8
-rw-r--r--compat/mingw.h5
-rw-r--r--connect.c11
-rwxr-xr-xcontrib/completion/git-completion.bash292
-rwxr-xr-xcontrib/difftool/git-difftool6
-rwxr-xr-xcontrib/difftool/git-difftool-helper19
-rw-r--r--contrib/difftool/git-difftool.txt30
-rwxr-xr-xcontrib/fast-import/git-p42
-rw-r--r--daemon.c2
-rw-r--r--diff-no-index.c4
-rw-r--r--diff.c39
-rw-r--r--diff.h3
-rw-r--r--diffcore-break.c3
-rw-r--r--diffcore-pickaxe.c18
-rw-r--r--fast-import.c8
-rw-r--r--fsck.c6
-rwxr-xr-xgit-add--interactive.perl4
-rwxr-xr-xgit-bisect.sh2
-rwxr-xr-xgit-filter-branch.sh4
-rwxr-xr-xgit-instaweb.sh69
-rwxr-xr-xgit-pull.sh10
-rwxr-xr-xgit-rebase.sh49
-rwxr-xr-xgit-repack.sh6
-rwxr-xr-xgit-send-email.perl84
-rwxr-xr-xgit-submodule.sh15
-rwxr-xr-xgit-svn.perl5
-rw-r--r--http.c30
-rw-r--r--imap-send.c55
-rw-r--r--log-tree.c17
-rw-r--r--parse-options.c28
-rw-r--r--parse-options.h2
-rw-r--r--pretty.c32
-rw-r--r--remote.c2
-rw-r--r--rerere.c22
-rw-r--r--rerere.h2
-rw-r--r--revision.c31
-rw-r--r--revision.h8
-rw-r--r--sha1_file.c60
-rw-r--r--t/Makefile5
-rw-r--r--t/README18
-rw-r--r--t/lib-httpd/apache.conf3
-rwxr-xr-xt/t1450-fsck.sh67
-rwxr-xr-xt/t3203-branch-output.sh81
-rwxr-xr-xt/t3406-rebase-message.sh23
-rwxr-xr-xt/t3413-rebase-hook.sh (renamed from t/t3409-rebase-hook.sh)0
-rwxr-xr-xt/t4002-diff-basic.sh8
-rwxr-xr-xt/t4012-diff-binary.sh2
-rwxr-xr-xt/t4013-diff-various.sh5
-rw-r--r--t/t4013/diff.diff_--dirstat_master~1_master~23
-rw-r--r--t/t4013/diff.log_--decorate_--all34
-rw-r--r--t/t4013/diff.rev-list_--children_HEAD7
-rw-r--r--t/t4013/diff.rev-list_--parents_HEAD7
-rwxr-xr-xt/t4014-format-patch.sh263
-rwxr-xr-xt/t4035-diff-quiet.sh (renamed from t/t4017-quiet.sh)0
-rwxr-xr-xt/t4036-format-patch-signer-mime.sh (renamed from t/t4021-format-patch-signer-mime.sh)0
-rwxr-xr-xt/t4202-log.sh188
-rwxr-xr-xt/t4204-patch-id.sh38
-rwxr-xr-xt/t5000-tar-tree.sh8
-rwxr-xr-xt/t5403-post-checkout-hook.sh12
-rwxr-xr-xt/t5522-pull-symlink.sh (renamed from t/t5521-pull-symlink.sh)0
-rwxr-xr-xt/t5705-clone-2gb.sh45
-rwxr-xr-xt/t6034-merge-rename-nocruft.sh (renamed from t/t6023-merge-rename-nocruft.sh)0
-rwxr-xr-xt/t7400-submodule-basic.sh49
-rwxr-xr-xt/t7508-status.sh (renamed from t/t7502-status.sh)0
-rwxr-xr-xt/t9001-send-email.sh108
-rwxr-xr-xt/t9109-git-svn-multi-glob.sh (renamed from t/t9108-git-svn-multi-glob.sh)0
-rwxr-xr-xt/t9137-git-svn-dcommit-clobber-series.sh (renamed from t/t9106-git-svn-dcommit-clobber-series.sh)0
-rw-r--r--t/test-lib.sh93
-rw-r--r--t/valgrind/.gitignore2
-rwxr-xr-xt/valgrind/analyze.sh123
-rw-r--r--t/valgrind/default.supp45
-rwxr-xr-xt/valgrind/valgrind.sh22
-rwxr-xr-xtemplates/hooks--update.sample6
-rw-r--r--templates/this--description2
-rw-r--r--upload-pack.c7
-rw-r--r--wt-status.c10
-rw-r--r--xdiff-interface.c3
125 files changed, 2584 insertions, 734 deletions
diff --git a/Documentation/RelNotes-1.6.3.txt b/Documentation/RelNotes-1.6.3.txt
new file mode 100644
index 0000000000..679ad28b9d
--- /dev/null
+++ b/Documentation/RelNotes-1.6.3.txt
@@ -0,0 +1,104 @@
+GIT v1.6.3 Release Notes
+========================
+
+With the next major release, "git push" into a branch that is
+currently checked out will be refused by default. You can choose
+what should happen upon such a push by setting the configuration
+variable receive.denyCurrentBranch in the receiving repository.
+
+To ease the transition plan, the receiving repository of such a
+push running this release will issue a big warning when the
+configuration variable is missing. Please refer to:
+
+ http://git.or.cz/gitwiki/GitFaq#non-bare
+ http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
+
+for more details on the reason why this change is needed and the
+transition plan.
+
+For a similar reason, "git push $there :$killed" to delete the branch
+$killed in a remote repository $there, if $killed branch is the current
+branch pointed at by its HEAD, gets a large warning. You can choose what
+should happen upon such a push by setting the configuration variable
+receive.denyDeleteCurrent in the receiving repository.
+
+
+Updates since v1.6.2
+--------------------
+
+(subsystems)
+
+(performance)
+
+(usability, bells and whistles)
+
+* "--pretty=<style>" option to the log family of commands can now be
+ spelled as "--format=<style>". In addition, --format=%formatstring
+ is a short-hand for --pretty=tformat:%formatstring.
+
+* "--oneline" is a synonym for "--pretty=oneline --abbrev=commit".
+
+* If you realize that you botched the patch when you are editing hunks
+ with the 'edit' action in git-add -i/-p, you can abort the editor to
+ tell git not to apply it.
+
+* git-archive learned --output=<file> option.
+
+* git-bisect shows not just the number of remaining commits whose goodness
+ is unknown, but also shows the estimated number of remaining rounds.
+
+* You can give --date=<format> option to git-blame.
+
+* git-branch -r shows HEAD symref that points at a remote branch in
+ interest of each tracked remote repository.
+
+* git-config learned -e option to open an editor to edit the config file
+ directly.
+
+* git-clone runs post-checkout hook when run without --no-checkout.
+
+* git-format-patch can be told to use attachment with a new configuration,
+ format.attach.
+
+* git-format-patch can be told to produce deep or shallow message threads.
+
+* git-imap-send learned to work around Thunderbird's inability to easily
+ disable format=flowed with a new configuration, imap.preformattedHTML.
+
+* git-rebase can be told to rebase the series even if your branch is a
+ descendant of the commit you are rebasing onto with --force-rebase
+ option.
+
+* git-rebase can be told to report diffstat with the --stat option.
+
+* git-send-email learned --confirm option to review the Cc: list before
+ sending the messages out.
+
+(developers)
+
+* Test scripts can be run under valgrind.
+
+* Makefile learned 'coverage' option to run the test suites with
+ coverage tracking enabled.
+
+Fixes since v1.6.2
+------------------
+
+All of the fixes in v1.6.2.X maintenance series are included in this
+release, unless otherwise noted.
+
+Here are fixes that this release has, but have not been backported to
+v1.6.2.X series.
+
+* 'git-submodule add' did not tolerate extra slashes and ./ in the
+ path it accepted from the command line; it now is more lenient
+ (if needed, backport by merging db75ada).
+
+* git-gc spent excessive amount of time to decide if an object appears
+ in a locally existing pack (if needed, backport by merging 69e020a).
+
+---
+exec >/var/tmp/1
+O=v1.6.2.1-135-g7d65c21
+echo O=$(git describe master)
+git shortlog --no-merges $O..master ^maint
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 9b559adefc..8d818a2160 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -491,6 +491,12 @@ message, complete the addressing and subject fields, and press send.
Gmail
-----
+GMail does not appear to have any way to turn off line wrapping in the web
+interface, so this will mangle any emails that you send. You can however
+use any IMAP email client to connect to the google imap server, and forward
+the emails through that. Just make sure to disable line wrapping in that
+email client. Alternatively, use "git send-email" instead.
+
Submitting properly formatted patches via Gmail is simple now that
IMAP support is available. First, edit your ~/.gitconfig to specify your
account settings:
@@ -503,6 +509,9 @@ account settings:
port = 993
sslverify = false
+You might need to instead use: folder = "[Google Mail]/Drafts" if you get an error
+that the "Folder doesn't exist".
+
Next, ensure that your Gmail settings are correct. In "Settings" the
"Use Unicode (UTF-8) encoding for outgoing messages" should be checked.
@@ -513,3 +522,4 @@ command to send the patch emails to your Gmail Drafts folder.
Go to your Gmail account, open the Drafts folder, find the patch email, fill
in the To: and CC: fields and send away!
+
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index df2a7c1641..63fc197fbe 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -70,6 +70,14 @@ of lines before or after the line given by <start>.
tree copy has the contents of the named file (specify
`-` to make the command read from the standard input).
+--date <format>::
+ The value is one of the following alternatives:
+ {relative,local,default,iso,rfc,short}. If --date is not
+ provided, the value of the blame.date config variable is
+ used. If the blame.date config variable is also not set, the
+ iso format is used. For more information, See the discussion
+ of the --date option at linkgit:git-log[1].
+
-M|<num>|::
Detect moving lines in the file as well. When a commit
moves a block of lines in a file (e.g. the original file
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f5152c5038..56bd781a16 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -677,6 +677,16 @@ format.pretty::
See linkgit:git-log[1], linkgit:git-show[1],
linkgit:git-whatchanged[1].
+format.thread::
+ The default threading style for 'git-format-patch'. Can be
+ either a boolean value, `shallow` or `deep`. 'Shallow'
+ threading makes every mail a reply to the head of the series,
+ where the head is chosen from the cover letter, the
+ `\--in-reply-to`, and the first patch mail, in this order.
+ 'Deep' threading makes every mail a reply to the previous one.
+ A true boolean value is the same as `shallow`, and a false
+ value disables threading.
+
gc.aggressiveWindow::
The window size parameter used in the delta compression
algorithm used by 'git-gc --aggressive'. This defaults
@@ -1160,6 +1170,10 @@ pull.octopus::
pull.twohead::
The default merge strategy to use when pulling a single branch.
+rebase.stat::
+ Whether to show a diffstat of what changed upstream since the last
+ rebase. False by default.
+
receive.fsckObjects::
If it is set to true, git-receive-pack will check all received
objects. It will abort in the case of a malformed object or a
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 5b3eb12c8a..0eeefe0060 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
+ [--output=<file>]
[--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
[path...]
@@ -47,6 +48,9 @@ OPTIONS
--prefix=<prefix>/::
Prepend <prefix>/ to each filename in the archive.
+--output=<file>::
+ Write the archive to <file> instead of stdout.
+
<extra>::
This can be any options that the archiver backend understand.
See next section.
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 147ea38197..e65c1cae8b 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -212,7 +212,7 @@ If you have a script that can tell if the current source code is good
or bad, you can automatically bisect using:
------------
-$ git bisect run my_script
+$ git bisect run my_script arguments
------------
Note that the "run" script (`my_script` in the above example) should
@@ -252,6 +252,13 @@ $ git bisect start HEAD v1.2 -- # HEAD is bad, v1.2 is good
$ git bisect run make # "make" builds the app
------------
+* Automatically bisect a test failure between origin and HEAD:
++
+------------
+$ git bisect start HEAD origin -- # HEAD is bad, origin is good
+$ git bisect run make test # "make test" builds and tests
+------------
+
* Automatically bisect a broken test suite:
+
------------
@@ -291,6 +298,15 @@ It's safer if both "test.sh" and "check_test_case.sh" scripts are
outside the repo to prevent interactions between the bisect, make and
test processes and the scripts.
+* Automatically bisect a broken test suite:
++
+------------
+$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
+$ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
+------------
++
+Does the same as the previous example, but on a single line.
+
Author
------
Written by Linus Torvalds <torvalds@osdl.org>
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 3bccffae62..125d8f3c32 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -8,7 +8,7 @@ git-checkout - Checkout a branch or paths to the working tree
SYNOPSIS
--------
[verse]
-'git checkout' [-q] [-f] [--track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>]
+'git checkout' [-q] [-f] [-t | --track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>]
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
DESCRIPTION
@@ -21,15 +21,15 @@ specified, <new_branch>. Using -b will cause <new_branch> to
be created; in this case you can use the --track or --no-track
options, which will be passed to `git branch`.
-As a convenience, --track will default to create a branch whose
+As a convenience, --track will default to creating a branch whose
name is constructed from the specified branch name by stripping
the first namespace level.
When <paths> are given, this command does *not* switch
branches. It updates the named paths in the working tree from
the index file, or from a named <tree-ish> (most often a commit). In
-this case, the `-b` options is meaningless and giving
-either of them results in an error. <tree-ish> argument can be
+this case, the `-b` and `--track` options are meaningless and giving
+either of them results in an error. The <tree-ish> argument can be
used to specify a specific tree-ish (i.e. commit, tag or tree)
to update the index for the given paths before updating the
working tree.
@@ -75,14 +75,13 @@ entries; instead, unmerged entries are ignored.
<repository> <refspec>" explicitly. This behavior is the default
when the start point is a remote branch. Set the
branch.autosetupmerge configuration variable to `false` if you want
- 'git-checkout' and 'git-branch' to always behave as if '--no-track' were
+ 'git checkout' and 'git branch' to always behave as if '--no-track' were
given. Set it to `always` if you want this behavior when the
- start-point is either a local or remote branch.
+ start point is either a local or remote branch.
+
-If no '-b' option was given, the name of the new branch will be
-derived from the remote branch, by attempting to guess the name
-of the branch on remote system. If "remotes/" or "refs/remotes/"
-are prefixed, it is stripped away, and then the part up to the
+If no '-b' option is given, the name of the new branch will be
+derived from the remote branch. If "remotes/" or "refs/remotes/"
+is prefixed it is stripped away, and then the part up to the
next slash (which would be the nickname of the remote) is removed.
This would tell us to use "hack" as the local branch when branching
off of "origin/hack" (or "remotes/origin/hack", or even
@@ -152,12 +151,12 @@ $ git checkout v2.6.18
------------
Earlier versions of git did not allow this and asked you to
-create a temporary branch using `-b` option, but starting from
+create a temporary branch using the `-b` option, but starting from
version 1.5.0, the above command 'detaches' your HEAD from the
-current branch and directly point at the commit named by the tag
-(`v2.6.18` in the above example).
+current branch and directly points at the commit named by the tag
+(`v2.6.18` in the example above).
-You can use usual git commands while in this state. You can use
+You can use all git commands while in this state. You can use
`git reset --hard $othercommit` to further move around, for
example. You can make changes and create a new commit on top of
a detached HEAD. You can even create a merge by using `git
@@ -191,7 +190,7 @@ $ git checkout hello.c <3>
------------
+
<1> switch branch
-<2> take out a file out of other commit
+<2> take a file out of another commit
<3> restore hello.c from HEAD of current branch
+
If you have an unfortunate branch that is named `hello.c`, this
@@ -202,7 +201,7 @@ You should instead write:
$ git checkout -- hello.c
------------
-. After working in a wrong branch, switching to the correct
+. After working in the wrong branch, switching to the correct
branch would be done using:
+
------------
@@ -210,7 +209,7 @@ $ git checkout mytopic
------------
+
However, your "wrong" branch and correct "mytopic" branch may
-differ in files that you have locally modified, in which case,
+differ in files that you have modified locally, in which case
the above checkout would fail like this:
+
------------
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 6ab2af4b61..82ce89eae8 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -22,6 +22,7 @@ SYNOPSIS
'git config' [<file-option>] [-z|--null] -l | --list
'git config' [<file-option>] --get-color name [default]
'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
+'git config' [<file-option>] -e | --edit
DESCRIPTION
-----------
@@ -161,6 +162,11 @@ See also <<FILES>>.
output. The optional `default` parameter is used instead, if
there is no color configured for `name`.
+-e::
+--edit::
+ Opens an editor to modify the specified config file; either
+ '--system', '--global', or repository (default).
+
[[FILES]]
FILES
-----
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 7ffe03f427..237f85e767 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -91,7 +91,9 @@ OPTIONS
--index-filter <command>::
This is the filter for rewriting the index. It is similar to the
tree filter but does not check out the tree, which makes it much
- faster. For hairy cases, see linkgit:git-update-index[1].
+ faster. Frequently used with `git rm \--cached
+ \--ignore-unmatch ...`, see EXAMPLES below. For hairy
+ cases, see linkgit:git-update-index[1].
--parent-filter <command>::
This is the filter for rewriting the commit's parent list.
@@ -204,19 +206,18 @@ However, if the file is absent from the tree of some commit,
a simple `rm filename` will fail for that tree and commit.
Thus you may instead want to use `rm -f filename` as the script.
-A significantly faster version:
+Using `\--index-filter` with 'git-rm' yields a significantly faster
+version. Like with using `rm filename`, `git rm --cached filename`
+will fail if the file is absent from the tree of a commit. If you
+want to "completely forget" a file, it does not matter when it entered
+history, so we also add `\--ignore-unmatch`:
--------------------------------------------------------------------------
-git filter-branch --index-filter 'git rm --cached filename' HEAD
+git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
--------------------------------------------------------------------------
Now, you will get the rewritten history saved in HEAD.
-As with using `rm filename`, `git rm --cached filename` will fail
-if the file is absent from the tree of a commit. If it is not important
-whether the file is already absent from the tree, you can use
-`git rm --cached --ignore-unmatch filename` instead.
-
To rewrite the repository to look as if `foodir/` had been its project
root, and discard all other history:
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 11a7d77261..c14e3ee395 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -10,7 +10,8 @@ SYNOPSIS
--------
[verse]
'git format-patch' [-k] [-o <dir> | --stdout] [--thread]
- [--attach[=<boundary>] | --inline[=<boundary>]]
+ [--attach[=<boundary>] | --inline[=<boundary>] |
+ [--no-attach]]
[-s | --signoff] [<common diff options>]
[-n | --numbered | -N | --no-numbered]
[--start-number <n>] [--numbered-files]
@@ -117,15 +118,27 @@ include::diff-options.txt[]
which is the commit message and the patch itself in the
second part, with "Content-Disposition: attachment".
+--no-attach::
+ Disable the creation of an attachment, overriding the
+ configuration setting.
+
--inline[=<boundary>]::
Create multipart/mixed attachment, the first part of
which is the commit message and the patch itself in the
second part, with "Content-Disposition: inline".
---thread::
+--thread[=<style>]::
Add In-Reply-To and References headers to make the second and
subsequent mails appear as replies to the first. Also generates
the Message-Id header to reference.
++
+The optional <style> argument can be either `shallow` or `deep`.
+'Shallow' threading makes every mail a reply to the head of the
+series, where the head is chosen from the cover letter, the
+`\--in-reply-to`, and the first patch mail, in this order. 'Deep'
+threading makes every mail a reply to the previous one. If not
+specified, defaults to the 'format.thread' configuration, or `shallow`
+if that is not set.
--in-reply-to=Message-Id::
Make the first mail (or all the mails with --no-thread) appear as a
@@ -174,7 +187,8 @@ CONFIGURATION
-------------
You can specify extra mail header lines to be added to each message
in the repository configuration, new defaults for the subject prefix
-and file suffix, and number patches when outputting more than one.
+and file suffix, control attachements, and number patches when outputting
+more than one.
------------
[format]
@@ -183,6 +197,7 @@ and file suffix, and number patches when outputting more than one.
suffix = .txt
numbered = auto
cc = <email>
+ attach [ = mime-boundary-string ]
------------
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 1685f04efe..024084b8b7 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -64,6 +64,13 @@ imap.sslverify::
used by the SSL/TLS connection. Default is `true`. Ignored when
imap.tunnel is set.
+imap.preformattedHTML::
+ A boolean to enable/disable the use of html encoding when sending
+ a patch. An html encoded patch will be bracketed with <pre>
+ and have a content type of text/html. Ironically, enabling this
+ option causes Thunderbird to send the patch as a plain/text,
+ format=fixed email. Default is `false`.
+
Examples
~~~~~~~~
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index da3c38cd60..57bd333f0b 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -192,6 +192,13 @@ Alternatively, you can undo the 'git-rebase' with
git rebase --abort
+CONFIGURATION
+-------------
+
+rebase.stat::
+ Whether to show a diffstat of what changed upstream since the last
+ rebase. False by default.
+
OPTIONS
-------
<newbase>::
@@ -232,7 +239,15 @@ OPTIONS
-v::
--verbose::
- Display a diffstat of what changed upstream since the last rebase.
+ Be verbose. Implies --stat.
+
+--stat::
+ Show a diffstat of what changed upstream since the last rebase. The
+ diffstat is also controlled by the configuration option rebase.stat.
+
+-n::
+--no-stat::
+ Do not show a diffstat as part of the rebase process.
--no-verify::
This option bypasses the pre-rebase hook. See also linkgit:githooks[5].
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index fc0a4ab441..14dfb501eb 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -212,6 +212,22 @@ specified, as well as 'body' if --no-signed-off-cc is specified.
Administering
~~~~~~~~~~~~~
+--confirm::
+ Confirm just before sending:
++
+--
+- 'always' will always confirm before sending
+- 'never' will never confirm before sending
+- 'cc' will confirm before sending when send-email has automatically
+ added addresses from the patch to the Cc list
+- 'compose' will confirm before sending the first message when using --compose.
+- 'auto' is equivalent to 'cc' + 'compose'
+--
++
+Default is the value of 'sendemail.confirm' configuration value; if that
+is unspecified, default to 'auto' unless any of the suppress options
+have been specified, in which case default to 'compose'.
+
--dry-run::
Do everything except actually send the emails.
@@ -255,6 +271,11 @@ sendemail.multiedit::
summary when '--compose' is used). If false, files will be edited one
after the other, spawning a new editor each time.
+sendemail.confirm::
+ Sets the default for whether to confirm before sending. Must be
+ one of 'always', 'never', 'cc', 'compose', or 'auto'. See '--confirm'
+ in the previous section for the meaning of these values.
+
Author
------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 9a26bde73e..7513c57c6a 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.6.2/git.html[documentation for release 1.6.2]
+* link:v1.6.2.1/git.html[documentation for release 1.6.2.1]
* release notes for
+ link:RelNotes-1.6.2.1.txt[1.6.2.1],
link:RelNotes-1.6.2.txt[1.6.2].
* link:v1.6.1.3/git.html[documentation for release 1.6.1.3]
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 159390c35a..5c6e678aa3 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -152,3 +152,12 @@ $ git log -2 --pretty=tformat:%h 4da45bef \
4da45be
7134973
---------------------
++
+In addition, any unrecognized string that has a `%` in it is interpreted
+as if it has `tformat:` in front of it. For example, these two are
+equivalent:
++
+---------------------
+$ git log -2 --pretty=tformat:%h 4da45bef
+$ git log -2 --pretty=%h 4da45bef
+---------------------
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 5f21efe407..bff94991b6 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -1,4 +1,5 @@
--pretty[='<format>']::
+--format[='<format>']::
Pretty-print the contents of the commit logs in a given format,
where '<format>' can be one of 'oneline', 'short', 'medium',
@@ -17,6 +18,10 @@ configuration (see linkgit:git-config[1]).
This should make "--pretty=oneline" a whole lot more readable for
people using 80-column terminals.
+--oneline::
+ This is a shorthand for "--pretty=oneline --abbrev-commit"
+ used together.
+
--encoding[=<encoding>]::
The commit objects record the encoding used for the log message
in their encoding header; this option can be used to tell the
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 539863b1f9..e66ca9f70c 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -66,6 +66,12 @@ Steps to parse options
non-option arguments in `argv[]`.
`argc` is updated appropriately because of the assignment.
+
+You can also pass NULL instead of a usage array as fourth parameter of
+parse_options(), to avoid displaying a help screen with usage info and
+option list. This should only be done if necessary, e.g. to implement
+a limited parser for only a subset of the options that needs to be run
+before the full parser, which in turn shows the full help message.
++
Flags are the bitwise-or of:
`PARSE_OPT_KEEP_DASHDASH`::
@@ -77,6 +83,28 @@ Flags are the bitwise-or of:
Using this flag, processing is stopped at the first non-option
argument.
+`PARSE_OPT_KEEP_ARGV0`::
+ Keep the first argument, which contains the program name. It's
+ removed from argv[] by default.
+
+`PARSE_OPT_KEEP_UNKNOWN`::
+ Keep unknown arguments instead of erroring out. This doesn't
+ work for all combinations of arguments as users might expect
+ it to do. E.g. if the first argument in `--unknown --known`
+ takes a value (which we can't know), the second one is
+ mistakenly interpreted as a known option. Similarly, if
+ `PARSE_OPT_STOP_AT_NON_OPTION` is set, the second argument in
+ `--unknown value` will be mistakenly interpreted as a
+ non-option, not as a value belonging to the unknown option,
+ the parser early. That's why parse_options() errors out if
+ both options are set.
+
+`PARSE_OPT_NO_INTERNAL_HELP`::
+ By default, parse_options() handles `-h`, `--help` and
+ `--help-all` internally, by showing a help screen. This option
+ turns it off and allows one to add custom handlers for these
+ options, or to just leave them unknown.
+
Data Structure
--------------
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index e6097c23aa..97fc1e0519 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.6.2.1
+DEF_VER=v1.6.2.GIT
LF='
'
diff --git a/Makefile b/Makefile
index 0675c43e73..1087884be6 100644
--- a/Makefile
+++ b/Makefile
@@ -1640,3 +1640,27 @@ check-docs::
check-builtins::
./check-builtins.sh
+### Test suite coverage testing
+#
+.PHONY: coverage coverage-clean coverage-build coverage-report
+
+coverage:
+ $(MAKE) coverage-build
+ $(MAKE) coverage-report
+
+coverage-clean:
+ rm -f *.gcda *.gcno
+
+COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
+COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
+
+coverage-build: coverage-clean
+ $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
+ $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
+ -j1 test
+
+coverage-report:
+ gcov -b *.c
+ grep '^function.*called 0 ' *.c.gcov \
+ | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
+ | tee coverage-untested-functions
diff --git a/RelNotes b/RelNotes
index cc85675c62..dd8bc4bb4a 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.6.2.1.txt \ No newline at end of file
+Documentation/RelNotes-1.6.3.txt \ No newline at end of file
diff --git a/archive.c b/archive.c
index e6de0397cc..96b62d4309 100644
--- a/archive.c
+++ b/archive.c
@@ -253,6 +253,7 @@ static int parse_archive_args(int argc, const char **argv,
const char *base = NULL;
const char *remote = NULL;
const char *exec = NULL;
+ const char *output = NULL;
int compression_level = -1;
int verbose = 0;
int i;
@@ -262,6 +263,8 @@ static int parse_archive_args(int argc, const char **argv,
OPT_STRING(0, "format", &format, "fmt", "archive format"),
OPT_STRING(0, "prefix", &base, "prefix",
"prepend prefix to each pathname in the archive"),
+ OPT_STRING(0, "output", &output, "file",
+ "write the archive to this file"),
OPT__VERBOSE(&verbose),
OPT__COMPR('0', &compression_level, "store only", 0),
OPT__COMPR('1', &compression_level, "compress faster", 1),
@@ -290,6 +293,8 @@ static int parse_archive_args(int argc, const char **argv,
die("Unexpected option --remote");
if (exec)
die("Option --exec can only be used together with --remote");
+ if (output)
+ die("Unexpected option --output");
if (!base)
base = "";
diff --git a/builtin-archive.c b/builtin-archive.c
index 5ceec433fd..60adef9363 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -5,44 +5,35 @@
#include "cache.h"
#include "builtin.h"
#include "archive.h"
+#include "parse-options.h"
#include "pkt-line.h"
#include "sideband.h"
-static int run_remote_archiver(const char *remote, int argc,
- const char **argv)
+static void create_output_file(const char *output_file)
+{
+ int output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+ if (output_fd < 0)
+ die("could not create archive file: %s ", output_file);
+ if (output_fd != 1) {
+ if (dup2(output_fd, 1) < 0)
+ die("could not redirect output");
+ else
+ close(output_fd);
+ }
+}
+
+static int run_remote_archiver(int argc, const char **argv,
+ const char *remote, const char *exec)
{
char *url, buf[LARGE_PACKET_MAX];
int fd[2], i, len, rv;
struct child_process *conn;
- const char *exec = "git-upload-archive";
- int exec_at = 0, exec_value_at = 0;
-
- for (i = 1; i < argc; i++) {
- const char *arg = argv[i];
- if (!prefixcmp(arg, "--exec=")) {
- if (exec_at)
- die("multiple --exec specified");
- exec = arg + 7;
- exec_at = i;
- } else if (!strcmp(arg, "--exec")) {
- if (exec_at)
- die("multiple --exec specified");
- if (i + 1 >= argc)
- die("option --exec requires a value");
- exec = argv[i + 1];
- exec_at = i;
- exec_value_at = ++i;
- }
- }
url = xstrdup(remote);
conn = git_connect(fd, url, exec, 0);
- for (i = 1; i < argc; i++) {
- if (i == exec_at || i == exec_value_at)
- continue;
+ for (i = 1; i < argc; i++)
packet_write(fd[1], "argument %s\n", argv[i]);
- }
packet_flush(fd[1]);
len = packet_read_line(fd[0], buf, sizeof(buf));
@@ -69,51 +60,33 @@ static int run_remote_archiver(const char *remote, int argc,
return !!rv;
}
-static const char *extract_remote_arg(int *ac, const char **av)
-{
- int ix, iy, cnt = *ac;
- int no_more_options = 0;
- const char *remote = NULL;
-
- for (ix = iy = 1; ix < cnt; ix++) {
- const char *arg = av[ix];
- if (!strcmp(arg, "--"))
- no_more_options = 1;
- if (!no_more_options) {
- if (!prefixcmp(arg, "--remote=")) {
- if (remote)
- die("Multiple --remote specified");
- remote = arg + 9;
- continue;
- } else if (!strcmp(arg, "--remote")) {
- if (remote)
- die("Multiple --remote specified");
- if (++ix >= cnt)
- die("option --remote requires a value");
- remote = av[ix];
- continue;
- }
- if (arg[0] != '-')
- no_more_options = 1;
- }
- if (ix != iy)
- av[iy] = arg;
- iy++;
- }
- if (remote) {
- av[--cnt] = NULL;
- *ac = cnt;
- }
- return remote;
-}
+#define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH | \
+ PARSE_OPT_KEEP_ARGV0 | \
+ PARSE_OPT_KEEP_UNKNOWN | \
+ PARSE_OPT_NO_INTERNAL_HELP )
int cmd_archive(int argc, const char **argv, const char *prefix)
{
+ const char *exec = "git-upload-archive";
+ const char *output = NULL;
const char *remote = NULL;
+ struct option local_opts[] = {
+ OPT_STRING(0, "output", &output, "file",
+ "write the archive to this file"),
+ OPT_STRING(0, "remote", &remote, "repo",
+ "retrieve the archive from remote repository <repo>"),
+ OPT_STRING(0, "exec", &exec, "cmd",
+ "path to the remote git-upload-archive command"),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, local_opts, NULL, PARSE_OPT_KEEP_ALL);
+
+ if (output)
+ create_output_file(output);
- remote = extract_remote_arg(&argc, argv);
if (remote)
- return run_remote_archiver(remote, argc, argv);
+ return run_remote_archiver(argc, argv, remote, exec);
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
diff --git a/builtin-blame.c b/builtin-blame.c
index 114a214ed3..2aedd17c39 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1,5 +1,5 @@
/*
- * Pickaxe
+ * Blame
*
* Copyright (c) 2006, Junio C Hamano
*/
@@ -40,6 +40,10 @@ static int reverse;
static int blank_boundary;
static int incremental;
static int xdl_opts = XDF_NEED_MINIMAL;
+
+static enum date_mode blame_date_mode = DATE_ISO8601;
+static size_t blame_date_width;
+
static struct string_list mailmap;
#ifndef DEBUG
@@ -74,6 +78,7 @@ static unsigned blame_copy_score;
*/
struct origin {
int refcnt;
+ struct origin *previous;
struct commit *commit;
mmfile_t file;
unsigned char blob_sha1[20];
@@ -115,6 +120,8 @@ static inline struct origin *origin_incref(struct origin *o)
static void origin_decref(struct origin *o)
{
if (o && --o->refcnt <= 0) {
+ if (o->previous)
+ origin_decref(o->previous);
free(o->file.ptr);
free(o);
}
@@ -1198,6 +1205,10 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
struct origin *porigin = sg_origin[i];
if (!porigin)
continue;
+ if (!origin->previous) {
+ origin_incref(porigin);
+ origin->previous = porigin;
+ }
if (pass_blame_to_parent(sb, origin, porigin))
goto finish;
}
@@ -1415,6 +1426,39 @@ static void write_filename_info(const char *path)
}
/*
+ * Porcelain/Incremental format wants to show a lot of details per
+ * commit. Instead of repeating this every line, emit it only once,
+ * the first time each commit appears in the output.
+ */
+static int emit_one_suspect_detail(struct origin *suspect)
+{
+ struct commit_info ci;
+
+ if (suspect->commit->object.flags & METAINFO_SHOWN)
+ return 0;
+
+ suspect->commit->object.flags |= METAINFO_SHOWN;
+ get_commit_info(suspect->commit, &ci, 1);
+ printf("author %s\n", ci.author);
+ printf("author-mail %s\n", ci.author_mail);
+ printf("author-time %lu\n", ci.author_time);
+ printf("author-tz %s\n", ci.author_tz);
+ printf("committer %s\n", ci.committer);
+ printf("committer-mail %s\n", ci.committer_mail);
+ printf("committer-time %lu\n", ci.committer_time);
+ printf("committer-tz %s\n", ci.committer_tz);
+ printf("summary %s\n", ci.summary);
+ if (suspect->commit->object.flags & UNINTERESTING)
+ printf("boundary\n");
+ if (suspect->previous) {
+ struct origin *prev = suspect->previous;
+ printf("previous %s ", sha1_to_hex(prev->commit->object.sha1));
+ write_name_quoted(prev->path, stdout, '\n');
+ }
+ return 1;
+}
+
+/*
* The blame_entry is found to be guilty for the range. Mark it
* as such, and show it in incremental output.
*/
@@ -1429,22 +1473,7 @@ static void found_guilty_entry(struct blame_entry *ent)
printf("%s %d %d %d\n",
sha1_to_hex(suspect->commit->object.sha1),
ent->s_lno + 1, ent->lno + 1, ent->num_lines);
- if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
- struct commit_info ci;
- suspect->commit->object.flags |= METAINFO_SHOWN;
- get_commit_info(suspect->commit, &ci, 1);
- printf("author %s\n", ci.author);
- printf("author-mail %s\n", ci.author_mail);
- printf("author-time %lu\n", ci.author_time);
- printf("author-tz %s\n", ci.author_tz);
- printf("committer %s\n", ci.committer);
- printf("committer-mail %s\n", ci.committer_mail);
- printf("committer-time %lu\n", ci.committer_time);
- printf("committer-tz %s\n", ci.committer_tz);
- printf("summary %s\n", ci.summary);
- if (suspect->commit->object.flags & UNINTERESTING)
- printf("boundary\n");
- }
+ emit_one_suspect_detail(suspect);
write_filename_info(suspect->path);
maybe_flush_or_die(stdout, "stdout");
}
@@ -1507,24 +1536,20 @@ static const char *format_time(unsigned long time, const char *tz_str,
int show_raw_time)
{
static char time_buf[128];
- time_t t = time;
- int minutes, tz;
- struct tm *tm;
+ const char *time_str;
+ int time_len;
+ int tz;
if (show_raw_time) {
sprintf(time_buf, "%lu %s", time, tz_str);
- return time_buf;
}
-
- tz = atoi(tz_str);
- minutes = tz < 0 ? -tz : tz;
- minutes = (minutes / 100)*60 + (minutes % 100);
- minutes = tz < 0 ? -minutes : minutes;
- t = time + minutes * 60;
- tm = gmtime(&t);
-
- strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
- strcat(time_buf, tz_str);
+ else {
+ tz = atoi(tz_str);
+ time_str = show_date(time, tz, blame_date_mode);
+ time_len = strlen(time_str);
+ memcpy(time_buf, time_str, time_len);
+ memset(time_buf + time_len, ' ', blame_date_width - time_len);
+ }
return time_buf;
}
@@ -1551,24 +1576,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
ent->s_lno + 1,
ent->lno + 1,
ent->num_lines);
- if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
- struct commit_info ci;
- suspect->commit->object.flags |= METAINFO_SHOWN;
- get_commit_info(suspect->commit, &ci, 1);
- printf("author %s\n", ci.author);
- printf("author-mail %s\n", ci.author_mail);
- printf("author-time %lu\n", ci.author_time);
- printf("author-tz %s\n", ci.author_tz);
- printf("committer %s\n", ci.committer);
- printf("committer-mail %s\n", ci.committer_mail);
- printf("committer-time %lu\n", ci.committer_time);
- printf("committer-tz %s\n", ci.committer_tz);
- write_filename_info(suspect->path);
- printf("summary %s\n", ci.summary);
- if (suspect->commit->object.flags & UNINTERESTING)
- printf("boundary\n");
- }
- else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
+ if (emit_one_suspect_detail(suspect) ||
+ (suspect->commit->object.flags & MORE_THAN_ONE_PATH))
write_filename_info(suspect->path);
cp = nth_line(sb, ent->lno);
@@ -1806,36 +1815,6 @@ static void sanity_check_refcnt(struct scoreboard *sb)
baa = 1;
}
}
- for (ent = sb->ent; ent; ent = ent->next) {
- /* Mark the ones that haven't been checked */
- if (0 < ent->suspect->refcnt)
- ent->suspect->refcnt = -ent->suspect->refcnt;
- }
- for (ent = sb->ent; ent; ent = ent->next) {
- /*
- * ... then pick each and see if they have the the
- * correct refcnt.
- */
- int found;
- struct blame_entry *e;
- struct origin *suspect = ent->suspect;
-
- if (0 < suspect->refcnt)
- continue;
- suspect->refcnt = -suspect->refcnt; /* Unmark */
- for (found = 0, e = sb->ent; e; e = e->next) {
- if (e->suspect != suspect)
- continue;
- found++;
- }
- if (suspect->refcnt != found) {
- fprintf(stderr, "%s in %s has refcnt %d, not %d\n",
- ent->suspect->path,
- sha1_to_hex(ent->suspect->commit->object.sha1),
- ent->suspect->refcnt, found);
- baa = 2;
- }
- }
if (baa) {
int opt = 0160;
find_alignment(sb, &opt);
@@ -1975,6 +1954,12 @@ static int git_blame_config(const char *var, const char *value, void *cb)
blank_boundary = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "blame.date")) {
+ if (!value)
+ return config_error_nonbool(var);
+ blame_date_mode = parse_date_format(value);
+ return 0;
+ }
return git_default_config(var, value, cb);
}
@@ -2239,6 +2224,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
git_config(git_blame_config, NULL);
init_revisions(&revs, NULL);
+ revs.date_mode = blame_date_mode;
+
save_commit_buffer = 0;
dashdash_pos = 0;
@@ -2263,8 +2250,35 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_done:
argc = parse_options_end(&ctx);
- if (cmd_is_annotate)
+ if (cmd_is_annotate) {
output_option |= OUTPUT_ANNOTATE_COMPAT;
+ blame_date_mode = DATE_ISO8601;
+ } else {
+ blame_date_mode = revs.date_mode;
+ }
+
+ /* The maximum width used to show the dates */
+ switch (blame_date_mode) {
+ case DATE_RFC2822:
+ blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
+ break;
+ case DATE_ISO8601:
+ blame_date_width = sizeof("2006-10-19 16:00:04 -0700");
+ break;
+ case DATE_RAW:
+ blame_date_width = sizeof("1161298804 -0700");
+ break;
+ case DATE_SHORT:
+ blame_date_width = sizeof("2006-10-19");
+ break;
+ case DATE_RELATIVE:
+ /* "normal" is used as the fallback for "relative" */
+ case DATE_LOCAL:
+ case DATE_NORMAL:
+ blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
+ break;
+ }
+ blame_date_width -= 1; /* strip the null */
if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER))
opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
diff --git a/builtin-branch.c b/builtin-branch.c
index 504a981ad5..14d4b917e5 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -32,18 +32,18 @@ static unsigned char head_sha1[20];
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
- "\033[m", /* reset */
- "", /* PLAIN (normal) */
- "\033[31m", /* REMOTE (red) */
- "", /* LOCAL (normal) */
- "\033[32m", /* CURRENT (green) */
+ GIT_COLOR_RESET,
+ GIT_COLOR_NORMAL, /* PLAIN */
+ GIT_COLOR_RED, /* REMOTE */
+ GIT_COLOR_NORMAL, /* LOCAL */
+ GIT_COLOR_GREEN, /* CURRENT */
};
enum color_branch {
- COLOR_BRANCH_RESET = 0,
- COLOR_BRANCH_PLAIN = 1,
- COLOR_BRANCH_REMOTE = 2,
- COLOR_BRANCH_LOCAL = 3,
- COLOR_BRANCH_CURRENT = 4,
+ BRANCH_COLOR_RESET = 0,
+ BRANCH_COLOR_PLAIN = 1,
+ BRANCH_COLOR_REMOTE = 2,
+ BRANCH_COLOR_LOCAL = 3,
+ BRANCH_COLOR_CURRENT = 4,
};
static enum merge_filter {
@@ -56,15 +56,15 @@ static unsigned char merge_filter_ref[20];
static int parse_branch_color_slot(const char *var, int ofs)
{
if (!strcasecmp(var+ofs, "plain"))
- return COLOR_BRANCH_PLAIN;
+ return BRANCH_COLOR_PLAIN;
if (!strcasecmp(var+ofs, "reset"))
- return COLOR_BRANCH_RESET;
+ return BRANCH_COLOR_RESET;
if (!strcasecmp(var+ofs, "remote"))
- return COLOR_BRANCH_REMOTE;
+ return BRANCH_COLOR_REMOTE;
if (!strcasecmp(var+ofs, "local"))
- return COLOR_BRANCH_LOCAL;
+ return BRANCH_COLOR_LOCAL;
if (!strcasecmp(var+ofs, "current"))
- return COLOR_BRANCH_CURRENT;
+ return BRANCH_COLOR_CURRENT;
die("bad config variable '%s'", var);
}
@@ -188,7 +188,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
struct ref_item {
char *name;
- unsigned int kind;
+ char *dest;
+ unsigned int kind, len;
struct commit *commit;
};
@@ -200,22 +201,47 @@ struct ref_list {
int kinds;
};
+static char *resolve_symref(const char *src, const char *prefix)
+{
+ unsigned char sha1[20];
+ int flag;
+ const char *dst, *cp;
+
+ dst = resolve_ref(src, sha1, 0, &flag);
+ if (!(dst && (flag & REF_ISSYMREF)))
+ return NULL;
+ if (prefix && (cp = skip_prefix(dst, prefix)))
+ dst = cp;
+ return xstrdup(dst);
+}
+
static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
{
struct ref_list *ref_list = (struct ref_list*)(cb_data);
struct ref_item *newitem;
struct commit *commit;
- int kind;
- int len;
+ int kind, i;
+ const char *prefix, *orig_refname = refname;
+
+ static struct {
+ int kind;
+ const char *prefix;
+ int pfxlen;
+ } ref_kind[] = {
+ { REF_LOCAL_BRANCH, "refs/heads/", 11 },
+ { REF_REMOTE_BRANCH, "refs/remotes/", 13 },
+ };
/* Detect kind */
- if (!prefixcmp(refname, "refs/heads/")) {
- kind = REF_LOCAL_BRANCH;
- refname += 11;
- } else if (!prefixcmp(refname, "refs/remotes/")) {
- kind = REF_REMOTE_BRANCH;
- refname += 13;
- } else
+ for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
+ prefix = ref_kind[i].prefix;
+ if (strncmp(refname, prefix, ref_kind[i].pfxlen))
+ continue;
+ kind = ref_kind[i].kind;
+ refname += ref_kind[i].pfxlen;
+ break;
+ }
+ if (ARRAY_SIZE(ref_kind) <= i)
return 0;
commit = lookup_commit_reference_gently(sha1, 1);
@@ -246,9 +272,14 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
newitem->name = xstrdup(refname);
newitem->kind = kind;
newitem->commit = commit;
- len = strlen(newitem->name);
- if (len > ref_list->maxwidth)
- ref_list->maxwidth = len;
+ newitem->len = strlen(refname);
+ newitem->dest = resolve_symref(orig_refname, prefix);
+ /* adjust for "remotes/" */
+ if (newitem->kind == REF_REMOTE_BRANCH &&
+ ref_list->kinds != REF_REMOTE_BRANCH)
+ newitem->len += 8;
+ if (newitem->len > ref_list->maxwidth)
+ ref_list->maxwidth = newitem->len;
return 0;
}
@@ -257,8 +288,10 @@ static void free_ref_list(struct ref_list *ref_list)
{
int i;
- for (i = 0; i < ref_list->index; i++)
+ for (i = 0; i < ref_list->index; i++) {
free(ref_list->list[i].name);
+ free(ref_list->list[i].dest);
+ }
free(ref_list->list);
}
@@ -299,34 +332,46 @@ static int matches_merge_filter(struct commit *commit)
}
static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
- int abbrev, int current)
+ int abbrev, int current, char *prefix)
{
char c;
int color;
struct commit *commit = item->commit;
+ struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
if (!matches_merge_filter(commit))
return;
switch (item->kind) {
case REF_LOCAL_BRANCH:
- color = COLOR_BRANCH_LOCAL;
+ color = BRANCH_COLOR_LOCAL;
break;
case REF_REMOTE_BRANCH:
- color = COLOR_BRANCH_REMOTE;
+ color = BRANCH_COLOR_REMOTE;
break;
default:
- color = COLOR_BRANCH_PLAIN;
+ color = BRANCH_COLOR_PLAIN;
break;
}
c = ' ';
if (current) {
c = '*';
- color = COLOR_BRANCH_CURRENT;
+ color = BRANCH_COLOR_CURRENT;
}
- if (verbose) {
+ strbuf_addf(&name, "%s%s", prefix, item->name);
+ if (verbose)
+ strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
+ maxwidth, name.buf,
+ branch_get_color(BRANCH_COLOR_RESET));
+ else
+ strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
+ name.buf, branch_get_color(BRANCH_COLOR_RESET));
+
+ if (item->dest)
+ strbuf_addf(&out, " -> %s", item->dest);
+ else if (verbose) {
struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
const char *sub = " **** invalid ref ****";
@@ -340,28 +385,25 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
if (item->kind == REF_LOCAL_BRANCH)
fill_tracking_info(&stat, item->name);
- printf("%c %s%-*s%s %s %s%s\n", c, branch_get_color(color),
- maxwidth, item->name,
- branch_get_color(COLOR_BRANCH_RESET),
- find_unique_abbrev(item->commit->object.sha1, abbrev),
- stat.buf, sub);
+ strbuf_addf(&out, " %s %s%s",
+ find_unique_abbrev(item->commit->object.sha1, abbrev),
+ stat.buf, sub);
strbuf_release(&stat);
strbuf_release(&subject);
- } else {
- printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
- branch_get_color(COLOR_BRANCH_RESET));
}
+ printf("%s\n", out.buf);
+ strbuf_release(&name);
+ strbuf_release(&out);
}
static int calc_maxwidth(struct ref_list *refs)
{
- int i, l, w = 0;
+ int i, w = 0;
for (i = 0; i < refs->index; i++) {
if (!matches_merge_filter(refs->list[i].commit))
continue;
- l = strlen(refs->list[i].name);
- if (l > w)
- w = l;
+ if (refs->list[i].len > w)
+ w = refs->list[i].len;
}
return w;
}
@@ -397,11 +439,13 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
is_descendant_of(head_commit, with_commit)) {
struct ref_item item;
item.name = xstrdup("(no branch)");
+ item.len = strlen(item.name);
item.kind = REF_LOCAL_BRANCH;
+ item.dest = NULL;
item.commit = head_commit;
- if (strlen(item.name) > ref_list.maxwidth)
- ref_list.maxwidth = strlen(item.name);
- print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1);
+ if (item.len > ref_list.maxwidth)
+ ref_list.maxwidth = item.len;
+ print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, "");
free(item.name);
}
@@ -409,8 +453,11 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
int current = !detached &&
(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
!strcmp(ref_list.list[i].name, head);
+ char *prefix = (kinds != REF_REMOTE_BRANCH &&
+ ref_list.list[i].kind == REF_REMOTE_BRANCH)
+ ? "remotes/" : "";
print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,
- abbrev, current);
+ abbrev, current, prefix);
}
free_ref_list(&ref_list);
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 20b34ce6e1..c315f63398 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -295,6 +295,8 @@ static void show_local_changes(struct object *head)
init_revisions(&rev, NULL);
rev.abbrev = 0;
rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
+ if (diff_setup_done(&rev.diffopt) < 0)
+ die("diff_setup_done failed");
add_pending_object(&rev, head, NULL);
run_diff_index(&rev, 0);
}
diff --git a/builtin-clone.c b/builtin-clone.c
index c338910b1c..39523cee30 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -20,6 +20,7 @@
#include "dir.h"
#include "pack-refs.h"
#include "sigchain.h"
+#include "run-command.h"
/*
* Overall FIXMEs:
@@ -365,8 +366,6 @@ static void install_branch_config(const char *local,
int cmd_clone(int argc, const char **argv, const char *prefix)
{
- int use_local_hardlinks = 1;
- int use_separate_remote = 1;
int is_bundle = 0;
struct stat buf;
const char *repo_name, *repo, *work_tree, *git_dir;
@@ -377,6 +376,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
char *src_ref_prefix = "refs/heads/";
+ int err = 0;
struct refspec refspec;
@@ -388,9 +388,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (argc == 0)
die("You must specify a repository to clone.");
- if (option_no_hardlinks)
- use_local_hardlinks = 0;
-
if (option_mirror)
option_bare = 1;
@@ -399,7 +396,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die("--bare and --origin %s options are incompatible.",
option_origin);
option_no_checkout = 1;
- use_separate_remote = 0;
}
if (!option_origin)
@@ -631,6 +627,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(lock_file))
die("unable to write new index file");
+
+ err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
+ sha1_to_hex(remote_head->old_sha1), "1", NULL);
}
strbuf_release(&reflog_msg);
@@ -638,5 +637,5 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_release(&key);
strbuf_release(&value);
junk_pid = 0;
- return 0;
+ return err;
}
diff --git a/builtin-config.c b/builtin-config.c
index f71016204b..d52a057444 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -3,7 +3,7 @@
#include "color.h"
static const char git_config_set_usage[] =
-"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
+"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty] | --edit | -e ]";
static char *key;
static regex_t *key_regexp;
@@ -27,7 +27,7 @@ static int show_all_config(const char *key_, const char *value_, void *cb)
return 0;
}
-static int show_config(const char* key_, const char* value_, void *cb)
+static int show_config(const char *key_, const char *value_, void *cb)
{
char value[256];
const char *vptr = value;
@@ -74,7 +74,7 @@ static int show_config(const char* key_, const char* value_, void *cb)
return 0;
}
-static int get_value(const char* key_, const char* regex_)
+static int get_value(const char *key_, const char *regex_)
{
int ret = -1;
char *tl;
@@ -284,7 +284,7 @@ static int get_colorbool(int argc, const char **argv)
int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit;
- char* value;
+ char *value;
const char *file = setup_git_directory_gently(&nongit);
config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
@@ -362,6 +362,14 @@ int cmd_config(int argc, const char **argv, const char *prefix)
return get_color(argc-2, argv+2);
} else if (!strcmp(argv[1], "--get-colorbool")) {
return get_colorbool(argc-2, argv+2);
+ } else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) {
+ if (argc != 2)
+ usage(git_config_set_usage);
+ git_config(git_default_config, NULL);
+ launch_editor(config_exclusive_filename ?
+ config_exclusive_filename : git_path("config"),
+ NULL, NULL);
+ return 0;
} else
break;
argc--;
diff --git a/builtin-count-objects.c b/builtin-count-objects.c
index 62fd1f0961..b814fe5070 100644
--- a/builtin-count-objects.c
+++ b/builtin-count-objects.c
@@ -60,7 +60,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
hex[40] = 0;
if (get_sha1_hex(hex, sha1))
die("internal error");
- if (has_sha1_pack(sha1, NULL))
+ if (has_sha1_pack(sha1))
(*packed_loose)++;
}
}
diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c
index 8ecefd4f0f..79cedb72c4 100644
--- a/builtin-diff-tree.c
+++ b/builtin-diff-tree.c
@@ -102,7 +102,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
init_revisions(opt, prefix);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
- nr_sha1 = 0;
opt->abbrev = 0;
opt->diff = 1;
argc = setup_revisions(argc, argv, opt, NULL);
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 67fb80ec48..c2e5adc884 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -216,9 +216,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
if (args.depth > 0) {
char line[1024];
unsigned char sha1[20];
- int len;
- while ((len = packet_read_line(fd[0], line, sizeof(line)))) {
+ while (packet_read_line(fd[0], line, sizeof(line))) {
if (!prefixcmp(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index df18f4070f..a7883690d7 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -256,8 +256,7 @@ static void shortlog(const char *name, unsigned char *sha1,
int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
int limit = 20, i = 0, pos = 0;
- char line[1024];
- char *p = line, *sep = "";
+ char *sep = "";
unsigned char head_sha1[20];
const char *current_branch;
@@ -271,9 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
/* get a line */
while (pos < in->len) {
int len;
- char *newline;
+ char *newline, *p = in->buf + pos;
- p = in->buf + pos;
newline = strchr(p, '\n');
len = newline ? newline - p : strlen(p);
pos += len + !!newline;
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index e46b7adc97..5cbb4b081d 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -943,7 +943,6 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
return -1;
*sort_tail = s = xcalloc(1, sizeof(*s));
- sort_tail = &s->next;
if (*arg == '-') {
s->reverse = 1;
diff --git a/builtin-fsck.c b/builtin-fsck.c
index 64dffa5421..6436bc2248 100644
--- a/builtin-fsck.c
+++ b/builtin-fsck.c
@@ -160,7 +160,7 @@ static void check_reachable_object(struct object *obj)
* do a full fsck
*/
if (!obj->parsed) {
- if (has_sha1_pack(obj->sha1, NULL))
+ if (has_sha1_pack(obj->sha1))
return; /* it is in pack - forget about it */
printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
errors_found |= ERROR_REACHABLE;
diff --git a/builtin-log.c b/builtin-log.c
index 2ae39afccd..8684fcdb67 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -17,6 +17,7 @@
#include "run-command.h"
#include "shortlog.h"
#include "remote.h"
+#include "string-list.h"
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
@@ -428,6 +429,8 @@ static const char *fmt_patch_suffix = ".patch";
static int numbered = 0;
static int auto_number = 1;
+static char *default_attach = NULL;
+
static char **extra_hdr;
static int extra_hdr_nr;
static int extra_hdr_alloc;
@@ -459,6 +462,10 @@ static void add_header(const char *value)
extra_hdr[extra_hdr_nr++] = xstrndup(value, len);
}
+#define THREAD_SHALLOW 1
+#define THREAD_DEEP 2
+static int thread = 0;
+
static int git_format_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "format.headers")) {
@@ -488,6 +495,25 @@ static int git_format_config(const char *var, const char *value, void *cb)
auto_number = auto_number && numbered;
return 0;
}
+ if (!strcmp(var, "format.attach")) {
+ if (value && *value)
+ default_attach = xstrdup(value);
+ else
+ default_attach = xstrdup(git_version_string);
+ return 0;
+ }
+ if (!strcmp(var, "format.thread")) {
+ if (value && !strcasecmp(value, "deep")) {
+ thread = THREAD_DEEP;
+ return 0;
+ }
+ if (value && !strcasecmp(value, "shallow")) {
+ thread = THREAD_SHALLOW;
+ return 0;
+ }
+ thread = git_config_bool(var, value) && THREAD_SHALLOW;
+ return 0;
+ }
return git_log_config(var, value, cb);
}
@@ -766,7 +792,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int numbered_files = 0; /* _just_ numbers */
int subject_prefix = 0;
int ignore_if_in_upstream = 0;
- int thread = 0;
int cover_letter = 0;
int boundary_count = 0;
int no_binary_diff = 0;
@@ -787,6 +812,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.subject_prefix = fmt_patch_subject_prefix;
+ if (default_attach) {
+ rev.mime_boundary = default_attach;
+ rev.no_inline = 1;
+ }
+
/*
* Parse the arguments before setup_revisions(), or something
* like "git format-patch -o a123 HEAD^.." may fail; a123 is
@@ -849,6 +879,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.mime_boundary = argv[i] + 9;
rev.no_inline = 1;
}
+ else if (!strcmp(argv[i], "--no-attach")) {
+ rev.mime_boundary = NULL;
+ rev.no_inline = 0;
+ }
else if (!strcmp(argv[i], "--inline")) {
rev.mime_boundary = git_version_string;
rev.no_inline = 0;
@@ -859,8 +893,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
ignore_if_in_upstream = 1;
- else if (!strcmp(argv[i], "--thread"))
- thread = 1;
+ else if (!strcmp(argv[i], "--thread")
+ || !strcmp(argv[i], "--thread=shallow"))
+ thread = THREAD_SHALLOW;
+ else if (!strcmp(argv[i], "--thread=deep"))
+ thread = THREAD_DEEP;
+ else if (!strcmp(argv[i], "--no-thread"))
+ thread = 0;
else if (!prefixcmp(argv[i], "--in-reply-to="))
in_reply_to = argv[i] + 14;
else if (!strcmp(argv[i], "--in-reply-to")) {
@@ -1011,8 +1050,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
numbered = 1;
if (numbered)
rev.total = total + start_number - 1;
- if (in_reply_to)
- rev.ref_message_id = clean_message_id(in_reply_to);
+ if (in_reply_to || thread || cover_letter)
+ rev.ref_message_ids = xcalloc(1, sizeof(struct string_list));
+ if (in_reply_to) {
+ const char *msgid = clean_message_id(in_reply_to);
+ string_list_append(msgid, rev.ref_message_ids);
+ }
if (cover_letter) {
if (thread)
gen_message_id(&rev, "cover");
@@ -1031,15 +1074,33 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
/* Have we already had a message ID? */
if (rev.message_id) {
/*
- * If we've got the ID to be a reply
- * to, discard the current ID;
- * otherwise, make everything a reply
- * to that.
+ * For deep threading: make every mail
+ * a reply to the previous one, no
+ * matter what other options are set.
+ *
+ * For shallow threading:
+ *
+ * Without --cover-letter and
+ * --in-reply-to, make every mail a
+ * reply to the one before.
+ *
+ * With --in-reply-to but no
+ * --cover-letter, make every mail a
+ * reply to the <reply-to>.
+ *
+ * With --cover-letter, make every
+ * mail but the cover letter a reply
+ * to the cover letter. The cover
+ * letter is a reply to the
+ * --in-reply-to, if specified.
*/
- if (rev.ref_message_id)
+ if (thread == THREAD_SHALLOW
+ && rev.ref_message_ids->nr > 0
+ && (!cover_letter || rev.nr > 1))
free(rev.message_id);
else
- rev.ref_message_id = rev.message_id;
+ string_list_append(rev.message_id,
+ rev.ref_message_ids);
}
gen_message_id(&rev, sha1_to_hex(commit->object.sha1));
}
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index 2789ccdf7d..1eeeb4de6d 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -537,7 +537,6 @@ static int decode_header_bq(struct strbuf *it)
*/
strbuf_add(&outbuf, in, ep - in);
}
- in = ep;
}
/* E.g.
* ep : "=?iso-2022-jp?B?GyR...?= foo"
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index bcefa52c69..1c6d2c498b 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -1966,11 +1966,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
const unsigned char *sha1;
struct object *o;
- for (i = 0; i < revs->num_ignore_packed; i++) {
- if (matches_pack_name(p, revs->ignore_packed[i]))
- break;
- }
- if (revs->num_ignore_packed <= i)
+ if (p->pack_keep)
continue;
if (open_pack_index(p))
die("cannot open pack index");
@@ -2006,11 +2002,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
const unsigned char *sha1;
for (p = packed_git; p; p = p->next) {
- for (i = 0; i < revs->num_ignore_packed; i++) {
- if (matches_pack_name(p, revs->ignore_packed[i]))
- break;
- }
- if (revs->num_ignore_packed <= i)
+ if (p->pack_keep)
continue;
if (open_pack_index(p))
@@ -2208,7 +2200,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp("--unpacked", arg) ||
- !prefixcmp(arg, "--unpacked=") ||
+ !strcmp("--kept-pack-only", arg) ||
!strcmp("--reflog", arg) ||
!strcmp("--all", arg)) {
use_internal_rev_list = 1;
diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c
index 10cb8df845..2d5b2cd353 100644
--- a/builtin-prune-packed.c
+++ b/builtin-prune-packed.c
@@ -23,7 +23,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
memcpy(hex+2, de->d_name, 38);
if (get_sha1_hex(hex, sha1))
continue;
- if (!has_sha1_pack(sha1, NULL))
+ if (!has_sha1_pack(sha1))
continue;
memcpy(pathname + len, de->d_name, 38);
if (opts & DRY_RUN)
diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c
index 849f1fe6f9..a970b39505 100644
--- a/builtin-receive-pack.c
+++ b/builtin-receive-pack.c
@@ -675,7 +675,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
setup_path();
if (!enter_repo(dir, 0))
- die("'%s': unable to chdir or not a git archive", dir);
+ die("'%s' does not appear to be a git repository", dir);
if (is_repository_shallow())
die("attempt to push into a shallow repository");
diff --git a/builtin-remote.c b/builtin-remote.c
index ac69d37c8a..e171096ece 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -484,9 +484,8 @@ static int mv(int argc, const char **argv)
struct string_list_item *item = remote_branches.items + i;
int flag = 0;
unsigned char sha1[20];
- const char *symref;
- symref = resolve_ref(item->string, sha1, 1, &flag);
+ resolve_ref(item->string, sha1, 1, &flag);
if (!(flag & REF_ISSYMREF))
continue;
if (delete_ref(item->string, NULL, REF_NODEREF))
diff --git a/builtin-rerere.c b/builtin-rerere.c
index bd8fc77a7a..020af7377b 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -13,28 +13,17 @@ static const char git_rerere_usage[] =
static int cutoff_noresolve = 15;
static int cutoff_resolve = 60;
-static const char *rr_path(const char *name, const char *file)
-{
- return git_path("rr-cache/%s/%s", name, file);
-}
-
static time_t rerere_created_at(const char *name)
{
struct stat st;
- return stat(rr_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
-}
-
-static int has_resolution(const char *name)
-{
- struct stat st;
- return !stat(rr_path(name, "postimage"), &st);
+ return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
}
static void unlink_rr_item(const char *name)
{
- unlink(rr_path(name, "thisimage"));
- unlink(rr_path(name, "preimage"));
- unlink(rr_path(name, "postimage"));
+ unlink(rerere_path(name, "thisimage"));
+ unlink(rerere_path(name, "preimage"));
+ unlink(rerere_path(name, "postimage"));
rmdir(git_path("rr-cache/%s", name));
}
@@ -65,7 +54,7 @@ static void garbage_collect(struct string_list *rr)
then = rerere_created_at(e->d_name);
if (!then)
continue;
- cutoff = (has_resolution(e->d_name)
+ cutoff = (has_rerere_resolution(e->d_name)
? cutoff_resolve : cutoff_noresolve);
if (then < now - cutoff * 86400)
string_list_append(e->d_name, &to_remove);
@@ -124,7 +113,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[1], "clear")) {
for (i = 0; i < merge_rr.nr; i++) {
const char *name = (const char *)merge_rr.items[i].util;
- if (!has_resolution(name))
+ if (!has_rerere_resolution(name))
unlink_rr_item(name);
}
unlink(git_path("rr-cache/MERGE_RR"));
@@ -137,7 +126,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
for (i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
const char *name = (const char *)merge_rr.items[i].util;
- diff_two(rr_path(name, "preimage"), path, path, path);
+ diff_two(rerere_path(name, "preimage"), path, path, path);
}
else
usage(git_rerere_usage);
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index 436afa45f5..40d5fcb6b0 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -574,6 +574,45 @@ static struct commit_list *find_bisection(struct commit_list *list,
return best;
}
+static inline int log2i(int n)
+{
+ int log2 = 0;
+
+ for (; n > 1; n >>= 1)
+ log2++;
+
+ return log2;
+}
+
+static inline int exp2i(int n)
+{
+ return 1 << n;
+}
+
+/*
+ * Estimate the number of bisect steps left (after the current step)
+ *
+ * For any x between 0 included and 2^n excluded, the probability for
+ * n - 1 steps left looks like:
+ *
+ * P(2^n + x) == (2^n - x) / (2^n + x)
+ *
+ * and P(2^n + x) < 0.5 means 2^n < 3x
+ */
+static int estimate_bisect_steps(int all)
+{
+ int n, x, e;
+
+ if (all < 3)
+ return 0;
+
+ n = log2i(all);
+ e = exp2i(n);
+ x = all - e;
+
+ return (e < 3 * x) ? n : n - 1;
+}
+
int cmd_rev_list(int argc, const char **argv, const char *prefix)
{
struct commit_list *list;
@@ -688,12 +727,14 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
"bisect_nr=%d\n"
"bisect_good=%d\n"
"bisect_bad=%d\n"
- "bisect_all=%d\n",
+ "bisect_all=%d\n"
+ "bisect_steps=%d\n",
hex,
cnt - 1,
all - reaches - 1,
reaches - 1,
- all);
+ all,
+ estimate_bisect_steps(all));
return 0;
}
}
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index badd912038..b28091b445 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -101,7 +101,6 @@ static void insert_one_record(struct shortlog *log,
}
while (*oneline && isspace(*oneline) && *oneline != '\n')
oneline++;
- len = eol - oneline;
format_subject(&subject, oneline, " ");
buffer = strbuf_detach(&subject, NULL);
diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c
index a9b02fa32f..0206b416cb 100644
--- a/builtin-upload-archive.c
+++ b/builtin-upload-archive.c
@@ -35,7 +35,7 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix)
strcpy(buf, argv[1]); /* enter-repo smudges its argument */
if (!enter_repo(buf, 0))
- die("not a git archive");
+ die("'%s' does not appear to be a git repository", buf);
/* put received options in sent_argv[] */
sent_argc = 1;
diff --git a/cache.h b/cache.h
index 189151de25..fdc4ada43a 100644
--- a/cache.h
+++ b/cache.h
@@ -644,7 +644,8 @@ extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned l
extern int move_temp_to_file(const char *tmpfile, const char *filename);
-extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
+extern int has_sha1_pack(const unsigned char *sha1);
+extern int has_sha1_kept_pack(const unsigned char *sha1);
extern int has_sha1_file(const unsigned char *sha1);
extern int has_loose_object_nonlocal(const unsigned char *sha1);
@@ -839,7 +840,6 @@ extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsign
extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
-extern int matches_pack_name(struct packed_git *p, const char *name);
/* Dumb servers support */
extern int update_server_info(int);
diff --git a/color.c b/color.c
index db4dccfb77..62977f4808 100644
--- a/color.c
+++ b/color.c
@@ -1,8 +1,6 @@
#include "cache.h"
#include "color.h"
-#define COLOR_RESET "\033[m"
-
int git_use_color_default = 0;
static int parse_color(const char *name, int len)
@@ -54,7 +52,7 @@ void color_parse_mem(const char *value, int value_len, const char *var,
int bg = -2;
if (!strncasecmp(value, "reset", len)) {
- strcpy(dst, "\033[m");
+ strcpy(dst, GIT_COLOR_RESET);
return;
}
@@ -175,7 +173,7 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
r += fprintf(fp, "%s", color);
r += vfprintf(fp, fmt, args);
if (*color)
- r += fprintf(fp, "%s", COLOR_RESET);
+ r += fprintf(fp, "%s", GIT_COLOR_RESET);
if (trail)
r += fprintf(fp, "%s", trail);
return r;
@@ -217,7 +215,7 @@ int color_fwrite_lines(FILE *fp, const char *color,
char *p = memchr(buf, '\n', count);
if (p != buf && (fputs(color, fp) < 0 ||
fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
- fputs(COLOR_RESET, fp) < 0))
+ fputs(GIT_COLOR_RESET, fp) < 0))
return -1;
if (!p)
return 0;
diff --git a/color.h b/color.h
index 5019df82f7..6846be1706 100644
--- a/color.h
+++ b/color.h
@@ -4,6 +4,16 @@
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
#define COLOR_MAXLEN 24
+#define GIT_COLOR_NORMAL ""
+#define GIT_COLOR_RESET "\033[m"
+#define GIT_COLOR_BOLD "\033[1m"
+#define GIT_COLOR_RED "\033[31m"
+#define GIT_COLOR_GREEN "\033[32m"
+#define GIT_COLOR_YELLOW "\033[33m"
+#define GIT_COLOR_BLUE "\033[34m"
+#define GIT_COLOR_CYAN "\033[36m"
+#define GIT_COLOR_BG_RED "\033[41m"
+
/*
* This variable stores the value of color.ui
*/
diff --git a/combine-diff.c b/combine-diff.c
index bccc018ab2..b3b86aebcb 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -526,7 +526,6 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
return; /* result deleted */
while (1) {
- struct sline *sl = &sline[lno];
unsigned long hunk_end;
unsigned long rlines;
const char *hunk_comment = NULL;
@@ -592,7 +591,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
struct lline *ll;
int j;
unsigned long p_mask;
- sl = &sline[lno++];
+ struct sline *sl = &sline[lno++];
ll = (sl->flag & no_pre_delete) ? NULL : sl->lost_head;
while (ll) {
fputs(c_old, stdout);
diff --git a/compat/memmem.c b/compat/memmem.c
index cd0d877364..56bcb4277f 100644
--- a/compat/memmem.c
+++ b/compat/memmem.c
@@ -5,6 +5,8 @@ void *gitmemmem(const void *haystack, size_t haystack_len,
{
const char *begin = haystack;
const char *last_possible = begin + haystack_len - needle_len;
+ const char *tail = needle;
+ char point;
/*
* The first occurrence of the empty string is deemed to occur at
@@ -20,8 +22,9 @@ void *gitmemmem(const void *haystack, size_t haystack_len,
if (haystack_len < needle_len)
return NULL;
+ point = *tail++;
for (; begin <= last_possible; begin++) {
- if (!memcmp(begin, needle, needle_len))
+ if (*begin == point && !memcmp(begin + 1, tail, needle_len - 1))
return (void *)begin;
}
diff --git a/compat/mingw.c b/compat/mingw.c
index 3dbe6a77ff..27bcf3fd6b 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -46,7 +46,8 @@ static int do_lstat(const char *file_name, struct stat *buf)
buf->st_uid = 0;
buf->st_nlink = 1;
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
- buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
+ buf->st_size = fdata.nFileSizeLow |
+ (((off_t)fdata.nFileSizeHigh)<<32);
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
@@ -101,7 +102,7 @@ int mingw_fstat(int fd, struct stat *buf)
}
/* direct non-file handles to MS's fstat() */
if (GetFileType(fh) != FILE_TYPE_DISK)
- return fstat(fd, buf);
+ return _fstati64(fd, buf);
if (GetFileInformationByHandle(fh, &fdata)) {
buf->st_ino = 0;
@@ -109,7 +110,8 @@ int mingw_fstat(int fd, struct stat *buf)
buf->st_uid = 0;
buf->st_nlink = 1;
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
- buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
+ buf->st_size = fdata.nFileSizeLow |
+ (((off_t)fdata.nFileSizeHigh)<<32);
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
diff --git a/compat/mingw.h b/compat/mingw.h
index a255898801..6e24686442 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -163,11 +163,14 @@ int mingw_rename(const char*, const char*);
/* Use mingw_lstat() instead of lstat()/stat() and
* mingw_fstat() instead of fstat() on Windows.
*/
+#define off_t off64_t
+#define stat _stati64
+#define lseek _lseeki64
int mingw_lstat(const char *file_name, struct stat *buf);
int mingw_fstat(int fd, struct stat *buf);
#define fstat mingw_fstat
#define lstat mingw_lstat
-#define stat(x,y) mingw_lstat(x,y)
+#define _stati64(x,y) mingw_lstat(x,y)
int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime
diff --git a/connect.c b/connect.c
index 2f23ab3b87..7636bf976e 100644
--- a/connect.c
+++ b/connect.c
@@ -373,8 +373,6 @@ static void git_tcp_connect(int fd[2], char *host, int flags)
static char *git_proxy_command;
-static const char *rhost_name;
-static int rhost_len;
static int git_proxy_command_options(const char *var, const char *value,
void *cb)
@@ -383,6 +381,8 @@ static int git_proxy_command_options(const char *var, const char *value,
const char *for_pos;
int matchlen = -1;
int hostlen;
+ const char *rhost_name = cb;
+ int rhost_len = strlen(rhost_name);
if (git_proxy_command)
return 0;
@@ -426,11 +426,8 @@ static int git_proxy_command_options(const char *var, const char *value,
static int git_use_proxy(const char *host)
{
- rhost_name = host;
- rhost_len = strlen(host);
git_proxy_command = getenv("GIT_PROXY_COMMAND");
- git_config(git_proxy_command_options, NULL);
- rhost_name = NULL;
+ git_config(git_proxy_command_options, (void*)host);
return (git_proxy_command && *git_proxy_command);
}
@@ -507,7 +504,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
const char *prog, int flags)
{
char *url = xstrdup(url_orig);
- char *host, *path = url;
+ char *host, *path;
char *end;
int c;
struct child_process *conn;
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 0a3092f646..271b911f7a 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -62,7 +62,7 @@ esac
__gitdir ()
{
if [ -z "${1-}" ]; then
- if [ -n "$__git_dir" ]; then
+ if [ -n "${__git_dir-}" ]; then
echo "$__git_dir"
elif [ -d .git ]; then
echo .git
@@ -80,68 +80,72 @@ __gitdir ()
# returns text to add to bash PS1 prompt (includes branch name)
__git_ps1 ()
{
- local g="$(git rev-parse --git-dir 2>/dev/null)"
+ local g="$(__gitdir)"
if [ -n "$g" ]; then
local r
local b
- if [ -d "$g/rebase-apply" ]
- then
- if test -f "$g/rebase-apply/rebasing"
- then
+ if [ -d "$g/rebase-apply" ]; then
+ if [ -f "$g/rebase-apply/rebasing" ]; then
r="|REBASE"
- elif test -f "$g/rebase-apply/applying"
- then
+ elif [ -f "$g/rebase-apply/applying" ]; then
r="|AM"
else
r="|AM/REBASE"
fi
b="$(git symbolic-ref HEAD 2>/dev/null)"
- elif [ -f "$g/rebase-merge/interactive" ]
- then
+ elif [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
b="$(cat "$g/rebase-merge/head-name")"
- elif [ -d "$g/rebase-merge" ]
- then
+ elif [ -d "$g/rebase-merge" ]; then
r="|REBASE-m"
b="$(cat "$g/rebase-merge/head-name")"
- elif [ -f "$g/MERGE_HEAD" ]
- then
+ elif [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
b="$(git symbolic-ref HEAD 2>/dev/null)"
else
- if [ -f "$g/BISECT_LOG" ]
- then
+ if [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi
- if ! b="$(git symbolic-ref HEAD 2>/dev/null)"
- then
- if ! b="$(git describe --exact-match HEAD 2>/dev/null)"
- then
- b="$(cut -c1-7 "$g/HEAD")..."
+ if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then
+ if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then
+ if [ -r "$g/HEAD" ]; then
+ b="$(cut -c1-7 "$g/HEAD")..."
+ fi
fi
fi
fi
local w
local i
+ local c
- if test -n "${GIT_PS1_SHOWDIRTYSTATE-}"; then
- if test "$(git config --bool bash.showDirtyState)" != "false"; then
- git diff --no-ext-diff --ignore-submodules \
- --quiet --exit-code || w="*"
- if git rev-parse --quiet --verify HEAD >/dev/null; then
- git diff-index --cached --quiet \
- --ignore-submodules HEAD -- || i="+"
- else
- i="#"
+ if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
+ if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then
+ c="BARE:"
+ else
+ b="GIT_DIR!"
+ fi
+ elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
+ if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
+ if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
+ git diff --no-ext-diff --ignore-submodules \
+ --quiet --exit-code || w="*"
+ if git rev-parse --quiet --verify HEAD >/dev/null; then
+ git diff-index --cached --quiet \
+ --ignore-submodules HEAD -- || i="+"
+ else
+ i="#"
+ fi
fi
fi
fi
- if [ -n "${1-}" ]; then
- printf "$1" "${b##refs/heads/}$w$i$r"
- else
- printf " (%s)" "${b##refs/heads/}$w$i$r"
+ if [ -n "$b" ]; then
+ if [ -n "${1-}" ]; then
+ printf "$1" "$c${b##refs/heads/}$w$i$r"
+ else
+ printf " (%s)" "$c${b##refs/heads/}$w$i$r"
+ fi
fi
fi
}
@@ -299,7 +303,7 @@ __git_remotes ()
__git_merge_strategies ()
{
- if [ -n "$__git_merge_strategylist" ]; then
+ if [ -n "${__git_merge_strategylist-}" ]; then
echo "$__git_merge_strategylist"
return
fi
@@ -383,9 +387,88 @@ __git_complete_revlist ()
esac
}
+__git_complete_remote_or_refspec ()
+{
+ local cmd="${COMP_WORDS[1]}"
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
+ while [ $c -lt $COMP_CWORD ]; do
+ i="${COMP_WORDS[c]}"
+ case "$i" in
+ --all|--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
+ -*) ;;
+ *) remote="$i"; break ;;
+ esac
+ c=$((++c))
+ done
+ if [ -z "$remote" ]; then
+ __gitcomp "$(__git_remotes)"
+ return
+ fi
+ if [ $no_complete_refspec = 1 ]; then
+ COMPREPLY=()
+ return
+ fi
+ [ "$remote" = "." ] && remote=
+ case "$cur" in
+ *:*)
+ case "$COMP_WORDBREAKS" in
+ *:*) : great ;;
+ *) pfx="${cur%%:*}:" ;;
+ esac
+ cur="${cur#*:}"
+ lhs=0
+ ;;
+ +*)
+ pfx="+"
+ cur="${cur#+}"
+ ;;
+ esac
+ case "$cmd" in
+ fetch)
+ if [ $lhs = 1 ]; then
+ __gitcomp "$(__git_refs2 "$remote")" "$pfx" "$cur"
+ else
+ __gitcomp "$(__git_refs)" "$pfx" "$cur"
+ fi
+ ;;
+ pull)
+ if [ $lhs = 1 ]; then
+ __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur"
+ else
+ __gitcomp "$(__git_refs)" "$pfx" "$cur"
+ fi
+ ;;
+ push)
+ if [ $lhs = 1 ]; then
+ __gitcomp "$(__git_refs)" "$pfx" "$cur"
+ else
+ __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur"
+ fi
+ ;;
+ esac
+}
+
+__git_complete_strategy ()
+{
+ case "${COMP_WORDS[COMP_CWORD-1]}" in
+ -s|--strategy)
+ __gitcomp "$(__git_merge_strategies)"
+ return 0
+ esac
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ case "$cur" in
+ --strategy=*)
+ __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}"
+ return 0
+ ;;
+ esac
+ return 1
+}
+
__git_all_commands ()
{
- if [ -n "$__git_all_commandlist" ]; then
+ if [ -n "${__git_all_commandlist-}" ]; then
echo "$__git_all_commandlist"
return
fi
@@ -403,7 +486,7 @@ __git_all_commandlist="$(__git_all_commands 2>/dev/null)"
__git_porcelain_commands ()
{
- if [ -n "$__git_porcelain_commandlist" ]; then
+ if [ -n "${__git_porcelain_commandlist-}" ]; then
echo "$__git_porcelain_commandlist"
return
fi
@@ -826,27 +909,21 @@ _git_diff ()
__git_complete_file
}
+__git_fetch_options="
+ --quiet --verbose --append --upload-pack --force --keep --depth=
+ --tags --no-tags
+"
+
_git_fetch ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
-
- if [ "$COMP_CWORD" = 2 ]; then
- __gitcomp "$(__git_remotes)"
- else
- case "$cur" in
- *:*)
- local pfx=""
- case "$COMP_WORDBREAKS" in
- *:*) : great ;;
- *) pfx="${cur%%:*}:" ;;
- esac
- __gitcomp "$(__git_refs)" "$pfx" "${cur#*:}"
- ;;
- *)
- __gitcomp "$(__git_refs2 "${COMP_WORDS[2]}")"
- ;;
- esac
- fi
+ case "$cur" in
+ --*)
+ __gitcomp "$__git_fetch_options"
+ return
+ ;;
+ esac
+ __git_complete_remote_or_refspec
}
_git_format_patch ()
@@ -1014,6 +1091,11 @@ _git_log ()
" "" "${cur##--pretty=}"
return
;;
+ --format=*)
+ __gitcomp "$__git_log_pretty_formats
+ " "" "${cur##--format=}"
+ return
+ ;;
--date=*)
__gitcomp "
relative iso8601 rfc2822 short local default
@@ -1029,7 +1111,7 @@ _git_log ()
--follow
--abbrev-commit --abbrev=
--relative-date --date=
- --pretty=
+ --pretty= --format= --oneline
--cherry-pick
--graph
--decorate
@@ -1045,24 +1127,19 @@ _git_log ()
__git_complete_revlist
}
+__git_merge_options="
+ --no-commit --no-stat --log --no-log --squash --strategy
+ --commit --stat --no-squash --ff --no-ff
+"
+
_git_merge ()
{
+ __git_complete_strategy && return
+
local cur="${COMP_WORDS[COMP_CWORD]}"
- case "${COMP_WORDS[COMP_CWORD-1]}" in
- -s|--strategy)
- __gitcomp "$(__git_merge_strategies)"
- return
- esac
case "$cur" in
- --strategy=*)
- __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}"
- return
- ;;
--*)
- __gitcomp "
- --no-commit --no-stat --log --no-log --squash --strategy
- --commit --stat --no-squash --ff --no-ff
- "
+ __gitcomp "$__git_merge_options"
return
esac
__gitcomp "$(__git_refs)"
@@ -1111,40 +1188,44 @@ _git_name_rev ()
_git_pull ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
+ __git_complete_strategy && return
- if [ "$COMP_CWORD" = 2 ]; then
- __gitcomp "$(__git_remotes)"
- else
- __gitcomp "$(__git_refs "${COMP_WORDS[2]}")"
- fi
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ case "$cur" in
+ --*)
+ __gitcomp "
+ --rebase --no-rebase
+ $__git_merge_options
+ $__git_fetch_options
+ "
+ return
+ ;;
+ esac
+ __git_complete_remote_or_refspec
}
_git_push ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
-
- if [ "$COMP_CWORD" = 2 ]; then
+ case "${COMP_WORDS[COMP_CWORD-1]}" in
+ --repo)
__gitcomp "$(__git_remotes)"
- else
- case "$cur" in
- *:*)
- local pfx=""
- case "$COMP_WORDBREAKS" in
- *:*) : great ;;
- *) pfx="${cur%%:*}:" ;;
- esac
-
- __gitcomp "$(__git_refs "${COMP_WORDS[2]}")" "$pfx" "${cur#*:}"
- ;;
- +*)
- __gitcomp "$(__git_refs)" + "${cur#+}"
- ;;
- *)
- __gitcomp "$(__git_refs)"
- ;;
- esac
- fi
+ return
+ esac
+ case "$cur" in
+ --repo=*)
+ __gitcomp "$(__git_remotes)" "" "${cur##--repo=}"
+ return
+ ;;
+ --*)
+ __gitcomp "
+ --all --mirror --tags --dry-run --force --verbose
+ --receive-pack= --repo=
+ "
+ return
+ ;;
+ esac
+ __git_complete_remote_or_refspec
}
_git_rebase ()
@@ -1154,16 +1235,8 @@ _git_rebase ()
__gitcomp "--continue --skip --abort"
return
fi
- case "${COMP_WORDS[COMP_CWORD-1]}" in
- -s|--strategy)
- __gitcomp "$(__git_merge_strategies)"
- return
- esac
+ __git_complete_strategy && return
case "$cur" in
- --strategy=*)
- __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}"
- return
- ;;
--*)
__gitcomp "--onto --merge --strategy --interactive"
return
@@ -1541,8 +1614,13 @@ _git_show ()
" "" "${cur##--pretty=}"
return
;;
+ --format=*)
+ __gitcomp "$__git_log_pretty_formats
+ " "" "${cur##--format=}"
+ return
+ ;;
--*)
- __gitcomp "--pretty=
+ __gitcomp "--pretty= --format=
$__git_diff_common_options
"
return
@@ -1841,7 +1919,7 @@ _gitk ()
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
- local g="$(git rev-parse --git-dir 2>/dev/null)"
+ local g="$(__gitdir)"
local merge=""
if [ -f $g/MERGE_HEAD ]; then
merge="--merge"
diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool
index 0cda3d2eea..0deda3a0e4 100755
--- a/contrib/difftool/git-difftool
+++ b/contrib/difftool/git-difftool
@@ -4,7 +4,7 @@
# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
# git-difftool-helper script. This script exports
# GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and
-# GIT_DIFFTOOL_NO_PROMPT and GIT_MERGE_TOOL for use by git-difftool-helper.
+# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper.
# Any arguments that are unknown to this script are forwarded to 'git diff'.
use strict;
@@ -49,12 +49,12 @@ sub generate_command
}
if ($arg eq '-t' or $arg eq '--tool') {
usage() if $#ARGV <= $idx;
- $ENV{GIT_MERGE_TOOL} = $ARGV[$idx + 1];
+ $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
$skip_next = 1;
next;
}
if ($arg =~ /^--tool=/) {
- $ENV{GIT_MERGE_TOOL} = substr($arg, 7);
+ $ENV{GIT_DIFF_TOOL} = substr($arg, 7);
next;
}
if ($arg eq '--no-prompt') {
diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper
index db3af6a833..9c0a13452a 100755
--- a/contrib/difftool/git-difftool-helper
+++ b/contrib/difftool/git-difftool-helper
@@ -128,8 +128,10 @@ launch_merge_tool () {
cleanup_temp_files
}
-# Verifies that mergetool.<tool>.cmd exists
+# Verifies that (difftool|mergetool).<tool>.cmd exists
valid_custom_tool() {
+ merge_tool_cmd="$(git config difftool.$1.cmd)"
+ test -z "$merge_tool_cmd" &&
merge_tool_cmd="$(git config mergetool.$1.cmd)"
test -n "$merge_tool_cmd"
}
@@ -150,8 +152,11 @@ valid_tool() {
}
# Sets up the merge_tool_path variable.
-# This handles the mergetool.<tool>.path configuration.
+# This handles the difftool.<tool>.path configuration.
+# This also falls back to mergetool defaults.
init_merge_tool_path() {
+ merge_tool_path=$(git config difftool."$1".path)
+ test -z "$merge_tool_path" &&
merge_tool_path=$(git config mergetool."$1".path)
if test -z "$merge_tool_path"; then
case "$1" in
@@ -165,15 +170,19 @@ init_merge_tool_path() {
fi
}
-# Allow the GIT_MERGE_TOOL variable to provide a default value
+# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
+test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
-# If not merge tool was specified then use the merge.tool
+# If merge tool was not specified then use the diff.tool
# configuration variable. If that's invalid then reset merge_tool.
+# Fallback to merge.tool.
if test -z "$merge_tool"; then
+ merge_tool=$(git config diff.tool)
+ test -z "$merge_tool" &&
merge_tool=$(git config merge.tool)
if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
- echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
+ echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
echo >&2 "Resetting to default..."
unset merge_tool
fi
diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt
index 6e2610cda6..2b7bc03ec3 100644
--- a/contrib/difftool/git-difftool.txt
+++ b/contrib/difftool/git-difftool.txt
@@ -32,23 +32,23 @@ OPTIONS
vimdiff, gvimdiff, ecmerge, and opendiff
+
If a merge resolution program is not specified, 'git-difftool'
-will use the configuration variable `merge.tool`. If the
-configuration variable `merge.tool` is not set, 'git difftool'
+will use the configuration variable `diff.tool`. If the
+configuration variable `diff.tool` is not set, 'git-difftool'
will pick a suitable default.
+
You can explicitly provide a full path to the tool by setting the
-configuration variable `mergetool.<tool>.path`. For example, you
+configuration variable `difftool.<tool>.path`. For example, you
can configure the absolute path to kdiff3 by setting
-`mergetool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
+`difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
tool is available in PATH.
+
Instead of running one of the known merge tool programs,
'git-difftool' can be customized to run an alternative program
by specifying the command line to invoke in a configuration
-variable `mergetool.<tool>.cmd`.
+variable `difftool.<tool>.cmd`.
+
When 'git-difftool' is invoked with this tool (either through the
-`-t` or `--tool` option or the `merge.tool` configuration variable)
+`-t` or `--tool` option or the `diff.tool` configuration variable)
the configured command line will be invoked with the following
variables available: `$LOCAL` is set to the name of the temporary
file containing the contents of the diff pre-image and `$REMOTE`
@@ -61,24 +61,24 @@ with custom merge tool commands and has the same value as `$LOCAL`.
CONFIG VARIABLES
----------------
-merge.tool::
- The default merge tool to use.
-+
-See the `--tool=<tool>` option above for more details.
+'git-difftool' falls back to 'git-mergetool' config variables when the
+difftool equivalents have not been defined.
-merge.keepBackup::
- The original, unedited file content can be saved to a file with
- a `.orig` extension. Defaults to `true` (i.e. keep the backup files).
+diff.tool::
+ The default merge tool to use.
-mergetool.<tool>.path::
+difftool.<tool>.path::
Override the path for the given tool. This is useful in case
your tool is not in the PATH.
-mergetool.<tool>.cmd::
+difftool.<tool>.cmd::
Specify the command to invoke the specified merge tool.
+
See the `--tool=<tool>` option above for more details.
+merge.keepBackup::
+ The original, unedited file content can be saved to a file with
+ a `.orig` extension. Defaults to `true` (i.e. keep the backup files).
SEE ALSO
--------
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 3832f60225..342529db30 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -1142,7 +1142,7 @@ class P4Sync(Command):
s = ''
for (key, val) in self.users.items():
- s += "%s\t%s\n" % (key, val)
+ s += "%s\t%s\n" % (key.expandtabs(1), val.expandtabs(1))
open(self.getUserCacheFilename(), "wb").write(s)
self.userMapFromPerforceServer = True
diff --git a/daemon.c b/daemon.c
index d93cf960f9..13401f1baf 100644
--- a/daemon.c
+++ b/daemon.c
@@ -229,7 +229,7 @@ static char *path_ok(char *directory)
}
if (!path) {
- logerror("'%s': unable to chdir or not a git archive", dir);
+ logerror("'%s' does not appear to be a git repository", dir);
return NULL;
}
diff --git a/diff-no-index.c b/diff-no-index.c
index 0a14268ba9..598687b50a 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -38,6 +38,10 @@ static int get_mode(const char *path, int *mode)
if (!path || !strcmp(path, "/dev/null"))
*mode = 0;
+#ifdef _WIN32
+ else if (!strcasecmp(path, "nul"))
+ *mode = 0;
+#endif
else if (!strcmp(path, "-"))
*mode = create_ce_mode(0666);
else if (lstat(path, &st))
diff --git a/diff.c b/diff.c
index 006aa017e2..75d9fab8f8 100644
--- a/diff.c
+++ b/diff.c
@@ -30,14 +30,14 @@ int diff_auto_refresh_index = 1;
static int diff_mnemonic_prefix;
static char diff_colors[][COLOR_MAXLEN] = {
- "\033[m", /* reset */
- "", /* PLAIN (normal) */
- "\033[1m", /* METAINFO (bold) */
- "\033[36m", /* FRAGINFO (cyan) */
- "\033[31m", /* OLD (red) */
- "\033[32m", /* NEW (green) */
- "\033[33m", /* COMMIT (yellow) */
- "\033[41m", /* WHITESPACE (red background) */
+ GIT_COLOR_RESET,
+ GIT_COLOR_NORMAL, /* PLAIN */
+ GIT_COLOR_BOLD, /* METAINFO */
+ GIT_COLOR_CYAN, /* FRAGINFO */
+ GIT_COLOR_RED, /* OLD */
+ GIT_COLOR_GREEN, /* NEW */
+ GIT_COLOR_YELLOW, /* COMMIT */
+ GIT_COLOR_BG_RED, /* WHITESPACE */
};
static void diff_filespec_load_driver(struct diff_filespec *one);
@@ -875,7 +875,7 @@ static void fill_print_name(struct diffstat_file *file)
static void show_stats(struct diffstat_t* data, struct diff_options *options)
{
- int i, len, add, del, total, adds = 0, dels = 0;
+ int i, len, add, del, adds = 0, dels = 0;
int max_change = 0, max_len = 0;
int total_files = data->nr;
int width, name_width;
@@ -978,14 +978,12 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
*/
add = added;
del = deleted;
- total = add + del;
adds += add;
dels += del;
if (width <= max_change) {
add = scale_linear(add, width, max_change);
del = scale_linear(del, width, max_change);
- total = add + del;
}
show_name(options->file, prefix, name, len, reset, set);
fprintf(options->file, "%5d%s", added + deleted,
@@ -1783,7 +1781,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
* objects however would tend to be slower as they need
* to be individually opened and inflated.
*/
- if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL))
+ if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1))
return 0;
len = strlen(name);
@@ -2567,13 +2565,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
/* xdiff options */
else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space"))
- options->xdl_opts |= XDF_IGNORE_WHITESPACE;
+ DIFF_XDL_SET(options, IGNORE_WHITESPACE);
else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
- options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
+ DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE);
else if (!strcmp(arg, "--ignore-space-at-eol"))
- options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL;
+ DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
else if (!strcmp(arg, "--patience"))
- options->xdl_opts |= XDF_PATIENCE_DIFF;
+ DIFF_XDL_SET(options, PATIENCE_DIFF);
/* flags options */
else if (!strcmp(arg, "--binary")) {
@@ -2594,10 +2592,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
DIFF_OPT_SET(options, COLOR_DIFF);
else if (!strcmp(arg, "--no-color"))
DIFF_OPT_CLR(options, COLOR_DIFF);
- else if (!strcmp(arg, "--color-words"))
- options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
+ else if (!strcmp(arg, "--color-words")) {
+ DIFF_OPT_SET(options, COLOR_DIFF);
+ DIFF_OPT_SET(options, COLOR_DIFF_WORDS);
+ }
else if (!prefixcmp(arg, "--color-words=")) {
- options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
+ DIFF_OPT_SET(options, COLOR_DIFF);
+ DIFF_OPT_SET(options, COLOR_DIFF_WORDS);
options->word_regex = arg + 14;
}
else if (!strcmp(arg, "--exit-code"))
diff --git a/diff.h b/diff.h
index 6703a4fb4f..6616877ee5 100644
--- a/diff.h
+++ b/diff.h
@@ -69,6 +69,9 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)
+#define DIFF_XDL_TST(opts, flag) ((opts)->xdl_opts & XDF_##flag)
+#define DIFF_XDL_SET(opts, flag) ((opts)->xdl_opts |= XDF_##flag)
+#define DIFF_XDL_CLR(opts, flag) ((opts)->xdl_opts &= ~XDF_##flag)
struct diff_options {
const char *filter;
diff --git a/diffcore-break.c b/diffcore-break.c
index 31cdcfe8bc..d7097bb576 100644
--- a/diffcore-break.c
+++ b/diffcore-break.c
@@ -45,7 +45,7 @@ static int should_break(struct diff_filespec *src,
* The value we return is 1 if we want the pair to be broken,
* or 0 if we do not.
*/
- unsigned long delta_size, base_size, max_size;
+ unsigned long delta_size, max_size;
unsigned long src_copied, literal_added, src_removed;
*merge_score_p = 0; /* assume no deletion --- "do not break"
@@ -64,7 +64,6 @@ static int should_break(struct diff_filespec *src,
if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0))
return 0; /* error but caught downstream */
- base_size = ((src->size < dst->size) ? src->size : dst->size);
max_size = ((src->size > dst->size) ? src->size : dst->size);
if (max_size < MINIMUM_BREAK_SIZE)
return 0; /* we do not break too small filepair */
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index af9fffe6e8..574b3e8337 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -10,7 +10,7 @@ static unsigned int contains(struct diff_filespec *one,
regex_t *regexp)
{
unsigned int cnt;
- unsigned long offset, sz;
+ unsigned long sz;
const char *data;
if (diff_populate_filespec(one, 0))
return 0;
@@ -33,15 +33,13 @@ static unsigned int contains(struct diff_filespec *one,
}
} else { /* Classic exact string match */
- /* Yes, I've heard of strstr(), but the thing is *data may
- * not be NUL terminated. Sue me.
- */
- for (offset = 0; offset + len <= sz; offset++) {
- /* we count non-overlapping occurrences of needle */
- if (!memcmp(needle, data + offset, len)) {
- offset += len - 1;
- cnt++;
- }
+ while (sz) {
+ const char *found = memmem(data, sz, needle, len);
+ if (!found)
+ break;
+ sz -= found - data + len;
+ data = found + len;
+ cnt++;
}
}
diff_free_filespec_data(one);
diff --git a/fast-import.c b/fast-import.c
index 3748ddf48d..beeac0d004 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1745,21 +1745,19 @@ static void parse_data(struct strbuf *sb)
static int validate_raw_date(const char *src, char *result, int maxlen)
{
const char *orig_src = src;
- char *endp, sign;
- unsigned long date;
+ char *endp;
errno = 0;
- date = strtoul(src, &endp, 10);
+ strtoul(src, &endp, 10);
if (errno || endp == src || *endp != ' ')
return -1;
src = endp + 1;
if (*src != '-' && *src != '+')
return -1;
- sign = *src;
- date = strtoul(src + 1, &endp, 10);
+ strtoul(src + 1, &endp, 10);
if (errno || endp == src || *endp || (endp - orig_src) >= maxlen)
return -1;
diff --git a/fsck.c b/fsck.c
index 97f76c5815..511b82cba9 100644
--- a/fsck.c
+++ b/fsck.c
@@ -148,20 +148,17 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
struct tree_desc desc;
unsigned o_mode;
const char *o_name;
- const unsigned char *o_sha1;
init_tree_desc(&desc, item->buffer, item->size);
o_mode = 0;
o_name = NULL;
- o_sha1 = NULL;
while (desc.size) {
unsigned mode;
const char *name;
- const unsigned char *sha1;
- sha1 = tree_entry_extract(&desc, &name, &mode);
+ tree_entry_extract(&desc, &name, &mode);
if (strchr(name, '/'))
has_full_path = 1;
@@ -207,7 +204,6 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
o_mode = mode;
o_name = name;
- o_sha1 = sha1;
}
retval = 0;
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 064d4c68d0..def062a9e2 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -802,6 +802,10 @@ EOF
|| $ENV{VISUAL} || $ENV{EDITOR} || "vi";
system('sh', '-c', $editor.' "$@"', $editor, $hunkfile);
+ if ($? != 0) {
+ return undef;
+ }
+
open $fh, '<', $hunkfile
or die "failed to open hunk edit file for reading: " . $!;
my @newtext = grep { !/^#/ } <$fh>;
diff --git a/git-bisect.sh b/git-bisect.sh
index 10ad340920..e313bdea70 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -512,7 +512,7 @@ bisect_next() {
# commit is also a "skip" commit (see above).
exit_if_skipped_commits "$bisect_rev"
- bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this"
+ bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)"
}
bisect_visualize() {
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 9a09ba1382..20f6f51750 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -232,7 +232,9 @@ while read sha1 type name
do
case "$force,$name" in
,$orig_namespace*)
- die "Namespace $orig_namespace not empty"
+ die "Cannot create a new backup.
+A previous backup already exists in $orig_namespace
+Force overwriting the backup with -f"
;;
t,$orig_namespace*)
git update-ref -d "$name" $sha1
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 0843372b57..5f4419b69b 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -49,7 +49,7 @@ resolve_full_httpd () {
esac
httpd_only="$(echo $httpd | cut -f1 -d' ')"
- if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null;; esac
+ if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null 2>&1;; esac
then
full_httpd=$httpd
else
@@ -179,11 +179,74 @@ lighttpd_conf () {
cat > "$conf" <<EOF
server.document-root = "$fqgitdir/gitweb"
server.port = $port
-server.modules = ( "mod_cgi" )
+server.modules = ( "mod_setenv", "mod_cgi" )
server.indexfiles = ( "gitweb.cgi" )
server.pid-file = "$fqgitdir/pid"
+server.errorlog = "$fqgitdir/gitweb/error.log"
+
+# to enable, add "mod_access", "mod_accesslog" to server.modules
+# variable above and uncomment this
+#accesslog.filename = "$fqgitdir/gitweb/access.log"
+
+setenv.add-environment = ( "PATH" => "/usr/local/bin:/usr/bin:/bin" )
+
cgi.assign = ( ".cgi" => "" )
-mimetype.assign = ( ".css" => "text/css" )
+
+# mimetype mapping
+mimetype.assign = (
+ ".pdf" => "application/pdf",
+ ".sig" => "application/pgp-signature",
+ ".spl" => "application/futuresplash",
+ ".class" => "application/octet-stream",
+ ".ps" => "application/postscript",
+ ".torrent" => "application/x-bittorrent",
+ ".dvi" => "application/x-dvi",
+ ".gz" => "application/x-gzip",
+ ".pac" => "application/x-ns-proxy-autoconfig",
+ ".swf" => "application/x-shockwave-flash",
+ ".tar.gz" => "application/x-tgz",
+ ".tgz" => "application/x-tgz",
+ ".tar" => "application/x-tar",
+ ".zip" => "application/zip",
+ ".mp3" => "audio/mpeg",
+ ".m3u" => "audio/x-mpegurl",
+ ".wma" => "audio/x-ms-wma",
+ ".wax" => "audio/x-ms-wax",
+ ".ogg" => "application/ogg",
+ ".wav" => "audio/x-wav",
+ ".gif" => "image/gif",
+ ".jpg" => "image/jpeg",
+ ".jpeg" => "image/jpeg",
+ ".png" => "image/png",
+ ".xbm" => "image/x-xbitmap",
+ ".xpm" => "image/x-xpixmap",
+ ".xwd" => "image/x-xwindowdump",
+ ".css" => "text/css",
+ ".html" => "text/html",
+ ".htm" => "text/html",
+ ".js" => "text/javascript",
+ ".asc" => "text/plain",
+ ".c" => "text/plain",
+ ".cpp" => "text/plain",
+ ".log" => "text/plain",
+ ".conf" => "text/plain",
+ ".text" => "text/plain",
+ ".txt" => "text/plain",
+ ".dtd" => "text/xml",
+ ".xml" => "text/xml",
+ ".mpeg" => "video/mpeg",
+ ".mpg" => "video/mpeg",
+ ".mov" => "video/quicktime",
+ ".qt" => "video/quicktime",
+ ".avi" => "video/x-msvideo",
+ ".asf" => "video/x-ms-asf",
+ ".asx" => "video/x-ms-asf",
+ ".wmv" => "video/x-ms-wmv",
+ ".bz2" => "application/x-bzip",
+ ".tbz" => "application/x-bzip-compressed-tar",
+ ".tar.bz2" => "application/x-bzip-compressed-tar",
+ "" => "text/plain"
+ )
EOF
test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf"
}
diff --git a/git-pull.sh b/git-pull.sh
index 25adddfddf..8a26763206 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -16,7 +16,7 @@ cd_to_toplevel
test -z "$(git ls-files -u)" ||
die "You are in the middle of a conflicted merge."
-strategy_args= no_stat= no_commit= squash= no_ff= log_arg= verbosity=
+strategy_args= diffstat= no_commit= squash= no_ff= log_arg= verbosity=
curr_branch=$(git symbolic-ref -q HEAD)
curr_branch_short=$(echo "$curr_branch" | sed "s|refs/heads/||")
rebase=$(git config --bool branch.$curr_branch_short.rebase)
@@ -28,9 +28,9 @@ do
-v|--verbose)
verbosity="$verbosity -v" ;;
-n|--no-stat|--no-summary)
- no_stat=-n ;;
+ diffstat=--no-stat ;;
--stat|--summary)
- no_stat=$1 ;;
+ diffstat=--stat ;;
--log|--no-log)
log_arg=$1 ;;
--no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
@@ -188,7 +188,7 @@ fi
merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
test true = "$rebase" &&
- exec git-rebase $strategy_args --onto $merge_head \
+ exec git-rebase $diffstat $strategy_args --onto $merge_head \
${oldremoteref:-$merge_head}
-exec git-merge $no_stat $no_commit $squash $no_ff $log_arg $strategy_args \
+exec git-merge $diffstat $no_commit $squash $no_ff $log_arg $strategy_args \
"$merge_name" HEAD $merge_head $verbosity
diff --git a/git-rebase.sh b/git-rebase.sh
index 368c0ef434..d38ab0b83f 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
-USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'
+USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--onto <newbase>] [<upstream>|--root] [<branch>]'
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
same name. When the --onto option is provided the new branch starts
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -46,8 +46,10 @@ do_merge=
dotest="$GIT_DIR"/rebase-merge
prec=4
verbose=
+diffstat=$(git config --bool rebase.stat)
git_am_opt=
rebase_root=
+force_rebase=
continue_merge () {
test -n "$prev_head" || die "prev_head must be defined"
@@ -289,11 +291,23 @@ do
esac
do_merge=t
;;
+ -n|--no-stat)
+ diffstat=
+ ;;
+ --stat)
+ diffstat=t
+ ;;
-v|--verbose)
verbose=t
+ diffstat=t
;;
--whitespace=*)
git_am_opt="$git_am_opt $1"
+ case "$1" in
+ --whitespace=fix|--whitespace=strip)
+ force_rebase=t
+ ;;
+ esac
;;
-C*)
git_am_opt="$git_am_opt $1"
@@ -301,6 +315,9 @@ do
--root)
rebase_root=t
;;
+ -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force_rebas|--force-rebase)
+ force_rebase=t
+ ;;
-*)
usage
;;
@@ -420,17 +437,15 @@ if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
# linear history?
! (git rev-list --parents "$onto".."$branch" | grep " .* ") > /dev/null
then
- # Lazily switch to the target branch if needed...
- test -z "$switch_to" || git checkout "$switch_to"
- echo >&2 "Current branch $branch_name is up to date."
- exit 0
-fi
-
-if test -n "$verbose"
-then
- echo "Changes from $mb to $onto:"
- # We want color (if set), but no pager
- GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
+ if test -z "$force_rebase"
+ then
+ # Lazily switch to the target branch if needed...
+ test -z "$switch_to" || git checkout "$switch_to"
+ echo >&2 "Current branch $branch_name is up to date."
+ exit 0
+ else
+ echo "Current branch $branch_name is up to date, rebase forced."
+ fi
fi
# Detach HEAD and reset the tree
@@ -438,6 +453,16 @@ echo "First, rewinding head to replay your work on top of it..."
git checkout -q "$onto^0" || die "could not detach HEAD"
git update-ref ORIG_HEAD $branch
+if test -n "$diffstat"
+then
+ if test -n "$verbose"
+ then
+ echo "Changes from $mb to $onto:"
+ fi
+ # We want color (if set), but no pager
+ GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
+fi
+
# If the $onto is a proper descendant of the tip of the branch, then
# we just fast forwarded.
if test "$mb" = "$branch"
diff --git a/git-repack.sh b/git-repack.sh
index be6db5e805..0144c2d7b9 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -60,6 +60,7 @@ case ",$all_into_one," in
args='--unpacked --incremental'
;;
,t,)
+ args= existing=
if [ -d "$PACKDIR" ]; then
for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \
| sed -e 's/^\.\///' -e 's/\.pack$//'`
@@ -67,10 +68,13 @@ case ",$all_into_one," in
if [ -e "$PACKDIR/$e.keep" ]; then
: keep
else
- args="$args --unpacked=$e.pack"
existing="$existing $e"
fi
done
+ if test -n "$existing"
+ then
+ args="--kept-pack-only"
+ fi
if test -n "$args" -a -n "$unpack_unreachable" -a \
-n "$remove_redundant"
then
diff --git a/git-send-email.perl b/git-send-email.perl
index adf7ecb5c3..57127aa823 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -75,6 +75,8 @@ git send-email [options] <file | directory | rev-list options >
--[no-]thread * Use In-Reply-To: field. Default on.
Administering:
+ --confirm <str> * Confirm recipients before sending;
+ auto, cc, compose, always, or never.
--quiet * Output one line of info per email.
--dry-run * Don't actually send the emails.
--[no-]validate * Perform patch sanity checks. Default on.
@@ -181,7 +183,7 @@ sub do_edit {
my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd);
my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
-my ($validate);
+my ($validate, $confirm);
my (@suppress_cc);
my %config_bool_settings = (
@@ -207,6 +209,7 @@ my %config_settings = (
"suppresscc" => \@suppress_cc,
"envelopesender" => \$envelope_sender,
"multiedit" => \$multiedit,
+ "confirm" => \$confirm,
);
# Handle Uncouth Termination
@@ -258,6 +261,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
"suppress-from!" => \$suppress_from,
"suppress-cc=s" => \@suppress_cc,
"signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
+ "confirm=s" => \$confirm,
"dry-run" => \$dry_run,
"envelope-sender=s" => \$envelope_sender,
"thread!" => \$thread,
@@ -346,6 +350,14 @@ if ($suppress_cc{'body'}) {
delete $suppress_cc{'body'};
}
+# Set confirm's default value
+my $confirm_unconfigured = !defined $confirm;
+if ($confirm_unconfigured) {
+ $confirm = scalar %suppress_cc ? 'compose' : 'auto';
+};
+die "Unknown --confirm setting: '$confirm'\n"
+ unless $confirm =~ /^(?:auto|cc|compose|always|never)/;
+
# Debugging, print out the suppressions.
if (0) {
print "suppressions:\n";
@@ -663,25 +675,13 @@ if (!defined $smtp_server) {
$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
}
-if ($compose) {
- while (1) {
- $_ = $term->readline("Send this email? (y|n) ");
- last if defined $_;
- print "\n";
- }
-
- if (uc substr($_,0,1) ne 'Y') {
- cleanup_compose_files();
- exit(0);
- }
-
- if ($compose > 0) {
- @files = ($compose_filename . ".final", @files);
- }
+if ($compose && $compose > 0) {
+ @files = ($compose_filename . ".final", @files);
}
# Variables we set as part of the loop over files
-our ($message_id, %mail, $subject, $reply_to, $references, $message);
+our ($message_id, %mail, $subject, $reply_to, $references, $message,
+ $needs_confirm, $message_num);
sub extract_valid_address {
my $address = shift;
@@ -837,6 +837,37 @@ X-Mailer: git-send-email $gitversion
unshift (@sendmail_parameters,
'-f', $raw_from) if(defined $envelope_sender);
+ if ($needs_confirm && !$dry_run) {
+ print "\n$header\n";
+ if ($needs_confirm eq "inform") {
+ $confirm_unconfigured = 0; # squelch this message for the rest of this run
+ print " The Cc list above has been expanded by additional\n";
+ print " addresses found in the patch commit message. By default\n";
+ print " send-email prompts before sending whenever this occurs.\n";
+ print " This behavior is controlled by the sendemail.confirm\n";
+ print " configuration setting.\n";
+ print "\n";
+ print " For additional information, run 'git send-email --help'.\n";
+ print " To retain the current behavior, but squelch this message,\n";
+ print " run 'git config --global sendemail.confirm auto'.\n\n";
+ }
+ while (1) {
+ chomp ($_ = $term->readline(
+ "Send this email? ([y]es|[n]o|[q]uit|[a]ll): "
+ ));
+ last if /^(?:yes|y|no|n|quit|q|all|a)/i;
+ print "\n";
+ }
+ if (/^n/i) {
+ return;
+ } elsif (/^q/i) {
+ cleanup_compose_files();
+ exit(0);
+ } elsif (/^a/i) {
+ $confirm = 'never';
+ }
+ }
+
if ($dry_run) {
# We don't want to send the email.
} elsif ($smtp_server =~ m#^/#) {
@@ -935,6 +966,7 @@ X-Mailer: git-send-email $gitversion
$reply_to = $initial_reply_to;
$references = $initial_reply_to || '';
$subject = $initial_subject;
+$message_num = 0;
foreach my $t (@files) {
open(F,"<",$t) or die "can't open file $t";
@@ -943,11 +975,12 @@ foreach my $t (@files) {
my $author_encoding;
my $has_content_type;
my $body_encoding;
- @cc = @initial_cc;
+ @cc = ();
@xh = ();
my $input_format = undef;
my @header = ();
$message = "";
+ $message_num++;
# First unfold multiline header fields
while(<F>) {
last if /^\s*$/;
@@ -1080,6 +1113,14 @@ foreach my $t (@files) {
}
}
+ $needs_confirm = (
+ $confirm eq "always" or
+ ($confirm =~ /^(?:auto|cc)$/ && @cc) or
+ ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
+ $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
+
+ @cc = (@initial_cc, @cc);
+
send_message();
# set up for the next message
@@ -1094,13 +1135,10 @@ foreach my $t (@files) {
$message_id = undef;
}
-if ($compose) {
- cleanup_compose_files();
-}
+cleanup_compose_files();
sub cleanup_compose_files() {
- unlink($compose_filename, $compose_filename . ".final");
-
+ unlink($compose_filename, $compose_filename . ".final") if $compose;
}
$smtp->quit if $smtp;
diff --git a/git-submodule.sh b/git-submodule.sh
index 204aab671e..0a27232b90 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -167,9 +167,18 @@ cmd_add()
;;
esac
- # strip trailing slashes from path
- path=$(echo "$path" | sed -e 's|/*$||')
-
+ # normalize path:
+ # multiple //; leading ./; /./; /../; trailing /
+ path=$(printf '%s/\n' "$path" |
+ sed -e '
+ s|//*|/|g
+ s|^\(\./\)*||
+ s|/\./|/|g
+ :start
+ s|\([^/]*\)/\.\./||
+ tstart
+ s|/*$||
+ ')
git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
die "'$path' already exists in the index"
diff --git a/git-svn.perl b/git-svn.perl
index 959eb52f3f..8be6be00c6 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -2351,7 +2351,10 @@ sub match_paths {
if (my $path = $paths->{"/$self->{path}"}) {
return ($path->{action} eq 'D') ? 0 : 1;
}
- $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//;
+ my $repos_root = $self->ra->{repos_root};
+ my $extended_path = $self->{url} . '/' . $self->{path};
+ $extended_path =~ s#^\Q$repos_root\E(/|$)##;
+ $self->{path_regex} ||= qr/^\/\Q$extended_path\E\//;
if (grep /$self->{path_regex}/, keys %$paths) {
return 1;
}
diff --git a/http.c b/http.c
index ee58799ca8..56f18f1b03 100644
--- a/http.c
+++ b/http.c
@@ -573,31 +573,21 @@ static inline int hex(int v)
static char *quote_ref_url(const char *base, const char *ref)
{
+ struct strbuf buf = STRBUF_INIT;
const char *cp;
- char *dp, *qref;
- int len, baselen, ch;
+ int ch;
- baselen = strlen(base);
- len = baselen + 2; /* '/' after base and terminating NUL */
- for (cp = ref; (ch = *cp) != 0; cp++, len++)
+ strbuf_addstr(&buf, base);
+ if (buf.len && buf.buf[buf.len - 1] != '/' && *ref != '/')
+ strbuf_addstr(&buf, "/");
+
+ for (cp = ref; (ch = *cp) != 0; cp++)
if (needs_quote(ch))
- len += 2; /* extra two hex plus replacement % */
- qref = xmalloc(len);
- memcpy(qref, base, baselen);
- dp = qref + baselen;
- *(dp++) = '/';
- for (cp = ref; (ch = *cp) != 0; cp++) {
- if (needs_quote(ch)) {
- *dp++ = '%';
- *dp++ = hex((ch >> 4) & 0xF);
- *dp++ = hex(ch & 0xF);
- }
+ strbuf_addf(&buf, "%%%02x", ch);
else
- *dp++ = ch;
- }
- *dp = 0;
+ strbuf_addch(&buf, *cp);
- return qref;
+ return strbuf_detach(&buf, NULL);
}
int http_fetch_ref(const char *base, struct ref *ref)
diff --git a/imap-send.c b/imap-send.c
index f91293c23f..8154cb2116 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -135,6 +135,7 @@ struct imap_server_conf {
char *pass;
int use_ssl;
int ssl_verify;
+ int use_html;
};
struct imap_store_conf {
@@ -578,7 +579,7 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
n = socket_write(&imap->buf.sock, cmd->cb.data, cmd->cb.dlen);
free(cmd->cb.data);
if (n != cmd->cb.dlen ||
- (n = socket_write(&imap->buf.sock, "\r\n", 2)) != 2) {
+ socket_write(&imap->buf.sock, "\r\n", 2) != 2) {
free(cmd->cmd);
free(cmd);
return NULL;
@@ -1263,6 +1264,53 @@ static int imap_store_msg(struct store *gctx, struct msg_data *data, int *uid)
return DRV_OK;
}
+static void encode_html_chars(struct strbuf *p)
+{
+ int i;
+ for (i = 0; i < p->len; i++) {
+ if (p->buf[i] == '&')
+ strbuf_splice(p, i, 1, "&amp;", 5);
+ if (p->buf[i] == '<')
+ strbuf_splice(p, i, 1, "&lt;", 4);
+ if (p->buf[i] == '>')
+ strbuf_splice(p, i, 1, "&gt;", 4);
+ if (p->buf[i] == '"')
+ strbuf_splice(p, i, 1, "&quot;", 6);
+ }
+}
+static void wrap_in_html(struct msg_data *msg)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct strbuf **lines;
+ struct strbuf **p;
+ static char *content_type = "Content-Type: text/html;\n";
+ static char *pre_open = "<pre>\n";
+ static char *pre_close = "</pre>\n";
+ int added_header = 0;
+
+ strbuf_attach(&buf, msg->data, msg->len, msg->len);
+ lines = strbuf_split(&buf, '\n');
+ strbuf_release(&buf);
+ for (p = lines; *p; p++) {
+ if (! added_header) {
+ if ((*p)->len == 1 && *((*p)->buf) == '\n') {
+ strbuf_addstr(&buf, content_type);
+ strbuf_addbuf(&buf, *p);
+ strbuf_addstr(&buf, pre_open);
+ added_header = 1;
+ continue;
+ }
+ }
+ else
+ encode_html_chars(*p);
+ strbuf_addbuf(&buf, *p);
+ }
+ strbuf_addstr(&buf, pre_close);
+ strbuf_list_free(lines);
+ msg->len = buf.len;
+ msg->data = strbuf_detach(&buf, NULL);
+}
+
#define CHUNKSIZE 0x1000
static int read_message(FILE *f, struct msg_data *msg)
@@ -1339,6 +1387,7 @@ static struct imap_server_conf server = {
NULL, /* pass */
0, /* use_ssl */
1, /* ssl_verify */
+ 0, /* use_html */
};
static char *imap_folder;
@@ -1377,6 +1426,8 @@ static int git_imap_config(const char *key, const char *val, void *cb)
server.tunnel = xstrdup(val);
else if (!strcmp("sslverify", key))
server.ssl_verify = git_config_bool(key, val);
+ else if (!strcmp("preformattedHTML", key))
+ server.use_html = git_config_bool(key, val);
return 0;
}
@@ -1439,6 +1490,8 @@ int main(int argc, char **argv)
fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
if (!split_msg(&all_msgs, &msg, &ofs))
break;
+ if (server.use_html)
+ wrap_in_html(&msg);
r = imap_store_msg(ctx, &msg, &uid);
if (r != DRV_OK)
break;
diff --git a/log-tree.c b/log-tree.c
index 84a74e544b..9565c184db 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -6,6 +6,7 @@
#include "log-tree.h"
#include "reflog-walk.h"
#include "refs.h"
+#include "string-list.h"
struct decoration name_decoration = { "object names" };
@@ -79,18 +80,18 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
*/
static int detect_any_signoff(char *letter, int size)
{
- char ch, *cp;
+ char *cp;
int seen_colon = 0;
int seen_at = 0;
int seen_name = 0;
int seen_head = 0;
cp = letter + size;
- while (letter <= --cp && (ch = *cp) == '\n')
+ while (letter <= --cp && *cp == '\n')
continue;
while (letter <= cp) {
- ch = *cp--;
+ char ch = *cp--;
if (ch == '\n')
break;
@@ -211,9 +212,13 @@ void log_write_email_headers(struct rev_info *opt, const char *name,
printf("Message-Id: <%s>\n", opt->message_id);
graph_show_oneline(opt->graph);
}
- if (opt->ref_message_id) {
- printf("In-Reply-To: <%s>\nReferences: <%s>\n",
- opt->ref_message_id, opt->ref_message_id);
+ if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {
+ int i, n;
+ n = opt->ref_message_ids->nr;
+ printf("In-Reply-To: <%s>\n", opt->ref_message_ids->items[n-1].string);
+ for (i = 0; i < n; i++)
+ printf("%s<%s>\n", (i > 0 ? "\t" : "References: "),
+ opt->ref_message_ids->items[i].string);
graph_show_oneline(opt->graph);
}
if (opt->mime_boundary) {
diff --git a/parse-options.c b/parse-options.c
index 4c5d09dd25..cf71bcffd2 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -244,6 +244,9 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
ctx->out = argv;
ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
ctx->flags = flags;
+ if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
+ (flags & PARSE_OPT_STOP_AT_NON_OPTION))
+ die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
}
static int usage_with_options_internal(const char * const *,
@@ -253,6 +256,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
const struct option *options,
const char * const usagestr[])
{
+ int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
+
/* we must reset ->opt, unknown short option leave it dangling */
ctx->opt = NULL;
@@ -268,18 +273,18 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
if (arg[1] != '-') {
ctx->opt = arg + 1;
- if (*ctx->opt == 'h')
+ if (internal_help && *ctx->opt == 'h')
return parse_options_usage(usagestr, options);
switch (parse_short_opt(ctx, options)) {
case -1:
return parse_options_usage(usagestr, options);
case -2:
- return PARSE_OPT_UNKNOWN;
+ goto unknown;
}
if (ctx->opt)
check_typos(arg + 1, options);
while (ctx->opt) {
- if (*ctx->opt == 'h')
+ if (internal_help && *ctx->opt == 'h')
return parse_options_usage(usagestr, options);
switch (parse_short_opt(ctx, options)) {
case -1:
@@ -292,7 +297,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
*/
ctx->argv[0] = xstrdup(ctx->opt - 1);
*(char *)ctx->argv[0] = '-';
- return PARSE_OPT_UNKNOWN;
+ goto unknown;
}
}
continue;
@@ -306,16 +311,22 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
break;
}
- if (!strcmp(arg + 2, "help-all"))
+ if (internal_help && !strcmp(arg + 2, "help-all"))
return usage_with_options_internal(usagestr, options, 1);
- if (!strcmp(arg + 2, "help"))
+ if (internal_help && !strcmp(arg + 2, "help"))
return parse_options_usage(usagestr, options);
switch (parse_long_opt(ctx, arg + 2, options)) {
case -1:
return parse_options_usage(usagestr, options);
case -2:
- return PARSE_OPT_UNKNOWN;
+ goto unknown;
}
+ continue;
+unknown:
+ if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
+ return PARSE_OPT_UNKNOWN;
+ ctx->out[ctx->cpidx++] = ctx->argv[0];
+ ctx->opt = NULL;
}
return PARSE_OPT_DONE;
}
@@ -356,6 +367,9 @@ int parse_options(int argc, const char **argv, const struct option *options,
int usage_with_options_internal(const char * const *usagestr,
const struct option *opts, int full)
{
+ if (!usagestr)
+ return PARSE_OPT_HELP;
+
fprintf(stderr, "usage: %s\n", *usagestr++);
while (*usagestr && **usagestr)
fprintf(stderr, " or: %s\n", *usagestr++);
diff --git a/parse-options.h b/parse-options.h
index 912290549b..f8ef1db128 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -21,6 +21,8 @@ enum parse_opt_flags {
PARSE_OPT_KEEP_DASHDASH = 1,
PARSE_OPT_STOP_AT_NON_OPTION = 2,
PARSE_OPT_KEEP_ARGV0 = 4,
+ PARSE_OPT_KEEP_UNKNOWN = 8,
+ PARSE_OPT_NO_INTERNAL_HELP = 16,
};
enum parse_opt_option_flags {
diff --git a/pretty.c b/pretty.c
index e9540e46da..efa70245f1 100644
--- a/pretty.c
+++ b/pretty.c
@@ -10,6 +10,15 @@
static char *user_format;
+static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
+{
+ free(user_format);
+ user_format = xstrdup(cp);
+ if (is_tformat)
+ rev->use_terminator = 1;
+ rev->commit_format = CMIT_FMT_USERFORMAT;
+}
+
void get_commit_format(const char *arg, struct rev_info *rev)
{
int i;
@@ -33,12 +42,7 @@ void get_commit_format(const char *arg, struct rev_info *rev)
return;
}
if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
- const char *cp = strchr(arg, ':') + 1;
- free(user_format);
- user_format = xstrdup(cp);
- if (arg[0] == 't')
- rev->use_terminator = 1;
- rev->commit_format = CMIT_FMT_USERFORMAT;
+ save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't');
return;
}
for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
@@ -50,6 +54,10 @@ void get_commit_format(const char *arg, struct rev_info *rev)
return;
}
}
+ if (strchr(arg, '%')) {
+ save_user_format(rev, arg, 1);
+ return;
+ }
die("invalid --pretty format: %s", arg);
}
@@ -127,7 +135,6 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
int namelen;
unsigned long time;
int tz;
- const char *filler = " ";
if (fmt == CMIT_FMT_ONELINE)
return;
@@ -146,7 +153,6 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
while (line < name_tail && isspace(name_tail[-1]))
name_tail--;
display_name_length = name_tail - line;
- filler = "";
strbuf_addstr(sb, "From: ");
add_rfc2047(sb, line, display_name_length, encoding);
strbuf_add(sb, name_tail, namelen - display_name_length);
@@ -154,7 +160,7 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
} else {
strbuf_addf(sb, "%s: %.*s%.*s\n", what,
(fmt == CMIT_FMT_FULLER) ? 4 : 0,
- filler, namelen, line);
+ " ", namelen, line);
}
switch (fmt) {
case CMIT_FMT_MEDIUM:
@@ -567,16 +573,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
return end - placeholder + 1;
}
if (!prefixcmp(placeholder + 1, "red")) {
- strbuf_addstr(sb, "\033[31m");
+ strbuf_addstr(sb, GIT_COLOR_RED);
return 4;
} else if (!prefixcmp(placeholder + 1, "green")) {
- strbuf_addstr(sb, "\033[32m");
+ strbuf_addstr(sb, GIT_COLOR_GREEN);
return 6;
} else if (!prefixcmp(placeholder + 1, "blue")) {
- strbuf_addstr(sb, "\033[34m");
+ strbuf_addstr(sb, GIT_COLOR_BLUE);
return 5;
} else if (!prefixcmp(placeholder + 1, "reset")) {
- strbuf_addstr(sb, "\033[m");
+ strbuf_addstr(sb, GIT_COLOR_RESET);
return 6;
} else
return 0;
diff --git a/remote.c b/remote.c
index d7079c6dd8..7efaa023b9 100644
--- a/remote.c
+++ b/remote.c
@@ -495,7 +495,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
int is_glob;
const char *lhs, *rhs;
- llen = is_glob = 0;
+ is_glob = 0;
lhs = refspec[i];
if (*lhs == '+') {
diff --git a/rerere.c b/rerere.c
index 3518207c17..713c6e16ac 100644
--- a/rerere.c
+++ b/rerere.c
@@ -12,15 +12,15 @@ static int rerere_autoupdate;
static char *merge_rr_path;
-static const char *rr_path(const char *name, const char *file)
+const char *rerere_path(const char *hex, const char *file)
{
- return git_path("rr-cache/%s/%s", name, file);
+ return git_path("rr-cache/%s/%s", hex, file);
}
-static int has_resolution(const char *name)
+int has_rerere_resolution(const char *hex)
{
struct stat st;
- return !stat(rr_path(name, "postimage"), &st);
+ return !stat(rerere_path(hex, "postimage"), &st);
}
static void read_rr(struct string_list *rr)
@@ -208,12 +208,12 @@ static int merge(const char *name, const char *path)
mmbuffer_t result = {NULL, 0};
xpparam_t xpp = {XDF_NEED_MINIMAL};
- if (handle_file(path, NULL, rr_path(name, "thisimage")) < 0)
+ if (handle_file(path, NULL, rerere_path(name, "thisimage")) < 0)
return 1;
- if (read_mmfile(&cur, rr_path(name, "thisimage")) ||
- read_mmfile(&base, rr_path(name, "preimage")) ||
- read_mmfile(&other, rr_path(name, "postimage")))
+ if (read_mmfile(&cur, rerere_path(name, "thisimage")) ||
+ read_mmfile(&base, rerere_path(name, "preimage")) ||
+ read_mmfile(&other, rerere_path(name, "postimage")))
return 1;
ret = xdl_merge(&base, &cur, "", &other, "",
&xpp, XDL_MERGE_ZEALOUS, &result);
@@ -291,7 +291,7 @@ static int do_plain_rerere(struct string_list *rr, int fd)
string_list_insert(path, rr)->util = hex;
if (mkdir(git_path("rr-cache/%s", hex), 0755))
continue;
- handle_file(path, NULL, rr_path(hex, "preimage"));
+ handle_file(path, NULL, rerere_path(hex, "preimage"));
fprintf(stderr, "Recorded preimage for '%s'\n", path);
}
}
@@ -307,7 +307,7 @@ static int do_plain_rerere(struct string_list *rr, int fd)
const char *path = rr->items[i].string;
const char *name = (const char *)rr->items[i].util;
- if (has_resolution(name)) {
+ if (has_rerere_resolution(name)) {
if (!merge(name, path)) {
if (rerere_autoupdate)
string_list_insert(path, &update);
@@ -326,7 +326,7 @@ static int do_plain_rerere(struct string_list *rr, int fd)
continue;
fprintf(stderr, "Recorded resolution for '%s'.\n", path);
- copy_file(rr_path(name, "postimage"), path, 0666);
+ copy_file(rerere_path(name, "postimage"), path, 0666);
mark_resolved:
rr->items[i].util = NULL;
}
diff --git a/rerere.h b/rerere.h
index f9b03862fe..13313f3f2b 100644
--- a/rerere.h
+++ b/rerere.h
@@ -5,5 +5,7 @@
extern int setup_rerere(struct string_list *);
extern int rerere(void);
+extern const char *rerere_path(const char *hex, const char *file);
+extern int has_rerere_resolution(const char *hex);
#endif
diff --git a/revision.c b/revision.c
index 286e416b75..f5771c7898 100644
--- a/revision.c
+++ b/revision.c
@@ -994,16 +994,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
add_grep(revs, pattern, GREP_PATTERN_BODY);
}
-static void add_ignore_packed(struct rev_info *revs, const char *name)
-{
- int num = ++revs->num_ignore_packed;
-
- revs->ignore_packed = xrealloc(revs->ignore_packed,
- sizeof(const char *) * (num + 1));
- revs->ignore_packed[num-1] = name;
- revs->ignore_packed[num] = NULL;
-}
-
static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
int *unkc, const char **unkv)
{
@@ -1116,12 +1106,12 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->edge_hint = 1;
} else if (!strcmp(arg, "--unpacked")) {
revs->unpacked = 1;
- free(revs->ignore_packed);
- revs->ignore_packed = NULL;
- revs->num_ignore_packed = 0;
- } else if (!prefixcmp(arg, "--unpacked=")) {
+ revs->kept_pack_only = 0;
+ } else if (!strcmp(arg, "--kept-pack-only")) {
revs->unpacked = 1;
- add_ignore_packed(revs, arg+11);
+ revs->kept_pack_only = 1;
+ } else if (!prefixcmp(arg, "--unpacked=")) {
+ die("--unpacked=<packfile> no longer supported.");
} else if (!strcmp(arg, "-r")) {
revs->diff = 1;
DIFF_OPT_SET(&revs->diffopt, RECURSIVE);
@@ -1144,9 +1134,13 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (!strcmp(arg, "--pretty")) {
revs->verbose_header = 1;
get_commit_format(arg+8, revs);
- } else if (!prefixcmp(arg, "--pretty=")) {
+ } else if (!prefixcmp(arg, "--pretty=") || !prefixcmp(arg, "--format=")) {
revs->verbose_header = 1;
get_commit_format(arg+9, revs);
+ } else if (!strcmp(arg, "--oneline")) {
+ revs->verbose_header = 1;
+ get_commit_format("oneline", revs);
+ revs->abbrev_commit = 1;
} else if (!strcmp(arg, "--graph")) {
revs->topo_order = 1;
revs->rewrite_parents = 1;
@@ -1685,7 +1679,10 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
{
if (commit->object.flags & SHOWN)
return commit_ignore;
- if (revs->unpacked && has_sha1_pack(commit->object.sha1, revs->ignore_packed))
+ if (revs->unpacked &&
+ (revs->kept_pack_only
+ ? has_sha1_kept_pack(commit->object.sha1)
+ : has_sha1_pack(commit->object.sha1)))
return commit_ignore;
if (revs->show_all)
return commit_show;
diff --git a/revision.h b/revision.h
index 7cf848771b..ad123d78c5 100644
--- a/revision.h
+++ b/revision.h
@@ -49,7 +49,8 @@ struct rev_info {
blob_objects:1,
edge_hint:1,
limited:1,
- unpacked:1, /* see also ignore_packed below */
+ unpacked:1,
+ kept_pack_only:1,
boundary:2,
left_right:1,
rewrite_parents:1,
@@ -80,16 +81,13 @@ struct rev_info {
missing_newline:1;
enum date_mode date_mode;
- const char **ignore_packed; /* pretend objects in these are unpacked */
- int num_ignore_packed;
-
unsigned int abbrev;
enum cmit_fmt commit_format;
struct log_info *loginfo;
int nr, total;
const char *mime_boundary;
char *message_id;
- const char *ref_message_id;
+ struct string_list *ref_message_ids;
const char *add_signoff;
const char *extra_headers;
const char *log_reencode;
diff --git a/sha1_file.c b/sha1_file.c
index 032300c4c6..456317356f 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1919,25 +1919,8 @@ off_t find_pack_entry_one(const unsigned char *sha1,
return 0;
}
-int matches_pack_name(struct packed_git *p, const char *name)
-{
- const char *last_c, *c;
-
- if (!strcmp(p->pack_name, name))
- return 1;
-
- for (c = p->pack_name, last_c = c; *c;)
- if (*c == '/')
- last_c = ++c;
- else
- ++c;
- if (!strcmp(last_c, name))
- return 1;
-
- return 0;
-}
-
-static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
+static int find_pack_ent(const unsigned char *sha1, struct pack_entry *e,
+ int kept_pack_only)
{
static struct packed_git *last_found = (void *)1;
struct packed_git *p;
@@ -1949,15 +1932,8 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, cons
p = (last_found == (void *)1) ? packed_git : last_found;
do {
- if (ignore_packed) {
- const char **ig;
- for (ig = ignore_packed; *ig; ig++)
- if (matches_pack_name(p, *ig))
- break;
- if (*ig)
- goto next;
- }
-
+ if (kept_pack_only && !p->pack_keep)
+ goto next;
if (p->num_bad_objects) {
unsigned i;
for (i = 0; i < p->num_bad_objects; i++)
@@ -1997,6 +1973,16 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, cons
return 0;
}
+static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
+{
+ return find_pack_ent(sha1, e, 0);
+}
+
+static int find_kept_pack_entry(const unsigned char *sha1, struct pack_entry *e)
+{
+ return find_pack_ent(sha1, e, 1);
+}
+
struct packed_git *find_sha1_pack(const unsigned char *sha1,
struct packed_git *packs)
{
@@ -2038,7 +2024,7 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
struct pack_entry e;
int status;
- if (!find_pack_entry(sha1, &e, NULL)) {
+ if (!find_pack_entry(sha1, &e)) {
/* Most likely it's a loose object. */
status = sha1_loose_object_info(sha1, sizep);
if (status >= 0)
@@ -2046,7 +2032,7 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
/* Not a loose object; someone else may have just packed it. */
reprepare_packed_git();
- if (!find_pack_entry(sha1, &e, NULL))
+ if (!find_pack_entry(sha1, &e))
return status;
}
@@ -2065,7 +2051,7 @@ static void *read_packed_sha1(const unsigned char *sha1,
struct pack_entry e;
void *data;
- if (!find_pack_entry(sha1, &e, NULL))
+ if (!find_pack_entry(sha1, &e))
return NULL;
data = cache_or_unpack_entry(e.p, e.offset, size, type, 1);
if (!data) {
@@ -2464,17 +2450,23 @@ int has_pack_file(const unsigned char *sha1)
return 1;
}
-int has_sha1_pack(const unsigned char *sha1, const char **ignore_packed)
+int has_sha1_pack(const unsigned char *sha1)
+{
+ struct pack_entry e;
+ return find_pack_entry(sha1, &e);
+}
+
+int has_sha1_kept_pack(const unsigned char *sha1)
{
struct pack_entry e;
- return find_pack_entry(sha1, &e, ignore_packed);
+ return find_kept_pack_entry(sha1, &e);
}
int has_sha1_file(const unsigned char *sha1)
{
struct pack_entry e;
- if (find_pack_entry(sha1, &e, NULL))
+ if (find_pack_entry(sha1, &e))
return 1;
return has_loose_object(sha1);
}
diff --git a/t/Makefile b/t/Makefile
index ed49c20b16..09623414a7 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -38,4 +38,7 @@ full-svn-test:
$(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
$(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8
-.PHONY: pre-clean $(T) aggregate-results clean
+valgrind:
+ GIT_TEST_OPTS=--valgrind $(MAKE)
+
+.PHONY: pre-clean $(T) aggregate-results clean valgrind
diff --git a/t/README b/t/README
index f208cf1db9..d8f6c7de6d 100644
--- a/t/README
+++ b/t/README
@@ -39,7 +39,8 @@ this:
* passed all 3 test(s)
You can pass --verbose (or -v), --debug (or -d), and --immediate
-(or -i) command line argument to the test.
+(or -i) command line argument to the test, or by setting GIT_TEST_OPTS
+appropriately before running "make".
--verbose::
This makes the test more verbose. Specifically, the
@@ -58,6 +59,21 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
This causes additional long-running tests to be run (where
available), for more exhaustive testing.
+--valgrind::
+ Execute all Git binaries with valgrind and exit with status
+ 126 on errors (just like regular tests, this will only stop
+ the test script when running under -i). Valgrind errors
+ go to stderr, so you might want to pass the -v option, too.
+
+ Since it makes no sense to run the tests with --valgrind and
+ not see any output, this option implies --verbose. For
+ convenience, it also implies --tee.
+
+--tee::
+ In addition to printing the test output to the terminal,
+ write it to files named 't/test-results/$TEST_NAME.out'.
+ As the names depend on the tests' file names, it is safe to
+ run the tests with this option in parallel.
Skipping Tests
--------------
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index af6e5e1d6a..f460e40416 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -4,6 +4,9 @@ DocumentRoot www
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog access.log common
ErrorLog error.log
+<IfModule !mod_log_config.c>
+ LoadModule log_config_module modules/mod_log_config.so
+</IfModule>
<IfDefine Darwin>
LoadModule log_config_module modules/mod_log_config.so
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 4597af0eb6..a22632f483 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -28,4 +28,71 @@ test_expect_success 'loose objects borrowed from alternate are not missing' '
)
'
+# Corruption tests follow. Make sure to remove all traces of the
+# specific corruption you test afterwards, lest a later test trip over
+# it.
+
+test_expect_success 'object with bad sha1' '
+ sha=$(echo blob | git hash-object -w --stdin) &&
+ echo $sha &&
+ old=$(echo $sha | sed "s+^..+&/+") &&
+ new=$(dirname $old)/ffffffffffffffffffffffffffffffffffffff &&
+ sha="$(dirname $new)$(basename $new)"
+ mv .git/objects/$old .git/objects/$new &&
+ git update-index --add --cacheinfo 100644 $sha foo &&
+ tree=$(git write-tree) &&
+ cmt=$(echo bogus | git commit-tree $tree) &&
+ git update-ref refs/heads/bogus $cmt &&
+ (git fsck 2>out; true) &&
+ grep "$sha.*corrupt" out &&
+ rm -f .git/objects/$new &&
+ git update-ref -d refs/heads/bogus &&
+ git read-tree -u --reset HEAD
+'
+
+test_expect_success 'branch pointing to non-commit' '
+ git rev-parse HEAD^{tree} > .git/refs/heads/invalid &&
+ git fsck 2>out &&
+ grep "not a commit" out &&
+ git update-ref -d refs/heads/invalid
+'
+
+cat > invalid-tag <<EOF
+object ffffffffffffffffffffffffffffffffffffffff
+type commit
+tag invalid
+tagger T A Gger <tagger@example.com> 1234567890 -0000
+
+This is an invalid tag.
+EOF
+
+test_expect_failure 'tag pointing to nonexistent' '
+ tag=$(git hash-object -w --stdin < invalid-tag) &&
+ echo $tag > .git/refs/tags/invalid &&
+ git fsck --tags 2>out &&
+ cat out &&
+ grep "could not load tagged object" out &&
+ rm .git/refs/tags/invalid
+'
+
+cat > wrong-tag <<EOF
+object $(echo blob | git hash-object -w --stdin)
+type commit
+tag wrong
+tagger T A Gger <tagger@example.com> 1234567890 -0000
+
+This is an invalid tag.
+EOF
+
+test_expect_failure 'tag pointing to something else than its type' '
+ tag=$(git hash-object -w --stdin < wrong-tag) &&
+ echo $tag > .git/refs/tags/wrong &&
+ git fsck --tags 2>out &&
+ cat out &&
+ grep "some sane error message" out &&
+ rm .git/refs/tags/wrong
+'
+
+
+
test_done
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
new file mode 100755
index 0000000000..809d1c4ed4
--- /dev/null
+++ b/t/t3203-branch-output.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+test_description='git branch display tests'
+. ./test-lib.sh
+
+test_expect_success 'make commits' '
+ echo content >file &&
+ git add file &&
+ git commit -m one &&
+ echo content >>file &&
+ git commit -a -m two
+'
+
+test_expect_success 'make branches' '
+ git branch branch-one
+ git branch branch-two HEAD^
+'
+
+test_expect_success 'make remote branches' '
+ git update-ref refs/remotes/origin/branch-one branch-one
+ git update-ref refs/remotes/origin/branch-two branch-two
+ git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/branch-one
+'
+
+cat >expect <<'EOF'
+ branch-one
+ branch-two
+* master
+EOF
+test_expect_success 'git branch shows local branches' '
+ git branch >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+ origin/HEAD -> origin/branch-one
+ origin/branch-one
+ origin/branch-two
+EOF
+test_expect_success 'git branch -r shows remote branches' '
+ git branch -r >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+ branch-one
+ branch-two
+* master
+ remotes/origin/HEAD -> origin/branch-one
+ remotes/origin/branch-one
+ remotes/origin/branch-two
+EOF
+test_expect_success 'git branch -a shows local and remote branches' '
+ git branch -a >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+two
+one
+two
+EOF
+test_expect_success 'git branch -v shows branch summaries' '
+ git branch -v >tmp &&
+ awk "{print \$NF}" <tmp >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+* (no branch)
+ branch-one
+ branch-two
+ master
+EOF
+test_expect_success 'git branch shows detached HEAD properly' '
+ git checkout HEAD^0 &&
+ git branch >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
index 5391080943..85fc7c4af8 100755
--- a/t/t3406-rebase-message.sh
+++ b/t/t3406-rebase-message.sh
@@ -22,7 +22,8 @@ test_expect_success setup '
git checkout topic &&
quick_one A &&
quick_one B &&
- quick_one Z
+ quick_one Z &&
+ git tag start
'
@@ -41,4 +42,24 @@ test_expect_success 'rebase -m' '
'
+test_expect_success 'rebase --stat' '
+ git reset --hard start
+ git rebase --stat master >diffstat.txt &&
+ grep "^ fileX | *1 +$" diffstat.txt
+'
+
+test_expect_success 'rebase w/config rebase.stat' '
+ git reset --hard start
+ git config rebase.stat true &&
+ git rebase master >diffstat.txt &&
+ grep "^ fileX | *1 +$" diffstat.txt
+'
+
+test_expect_success 'rebase -n overrides config rebase.stat config' '
+ git reset --hard start
+ git config rebase.stat true &&
+ git rebase -n master >diffstat.txt &&
+ ! grep "^ fileX | *1 +$" diffstat.txt
+'
+
test_done
diff --git a/t/t3409-rebase-hook.sh b/t/t3413-rebase-hook.sh
index 098b75507b..098b75507b 100755
--- a/t/t3409-rebase-hook.sh
+++ b/t/t3413-rebase-hook.sh
diff --git a/t/t4002-diff-basic.sh b/t/t4002-diff-basic.sh
index cc3681f161..18695ce821 100755
--- a/t/t4002-diff-basic.sh
+++ b/t/t4002-diff-basic.sh
@@ -258,4 +258,12 @@ test_expect_success \
git diff-tree -r -R $tree_A $tree_B >.test-b &&
cmp -s .test-a .test-b'
+test_expect_success \
+ 'diff can read from stdin' \
+ 'test_must_fail git diff --no-index -- MN - < NN |
+ grep -v "^index" | sed "s#/-#/NN#" >.test-a &&
+ test_must_fail git diff --no-index -- MN NN |
+ grep -v "^index" >.test-b &&
+ test_cmp .test-a .test-b'
+
test_done
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 3cf5b5c4ea..f64aa48d24 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -87,7 +87,7 @@ nul_to_q() {
test_expect_success 'diff --no-index with binary creation' '
echo Q | q_to_nul >binary &&
- (:# hide error code from diff, which just indicates differences
+ (: hide error code from diff, which just indicates differences
git diff --binary --no-index /dev/null binary >current ||
true
) &&
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 9c709022ef..9cd5a6e685 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -207,6 +207,10 @@ log --root -c --patch-with-stat --summary master
log --root --cc --patch-with-stat --summary master
log -SF master
log -SF -p master
+log --decorate --all
+
+rev-list --parents HEAD
+rev-list --children HEAD
whatchanged master
whatchanged -p master
@@ -268,6 +272,7 @@ diff --no-index --name-status dir2 dir
diff --no-index --name-status -- dir2 dir
diff --no-index dir dir3
diff master master^ side
+diff --dirstat master~1 master~2
EOF
test_done
diff --git a/t/t4013/diff.diff_--dirstat_master~1_master~2 b/t/t4013/diff.diff_--dirstat_master~1_master~2
new file mode 100644
index 0000000000..b672e1ca63
--- /dev/null
+++ b/t/t4013/diff.diff_--dirstat_master~1_master~2
@@ -0,0 +1,3 @@
+$ git diff --dirstat master~1 master~2
+ 40.0% dir/
+$
diff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all
new file mode 100644
index 0000000000..12da8ac07d
--- /dev/null
+++ b/t/t4013/diff.log_--decorate_--all
@@ -0,0 +1,34 @@
+$ git log --decorate --all
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+ This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial)
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.rev-list_--children_HEAD b/t/t4013/diff.rev-list_--children_HEAD
new file mode 100644
index 0000000000..e7f17d5aa0
--- /dev/null
+++ b/t/t4013/diff.rev-list_--children_HEAD
@@ -0,0 +1,7 @@
+$ git rev-list --children HEAD
+59d314ad6f356dd08601a4cd5e530381da3e3c64
+c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a 59d314ad6f356dd08601a4cd5e530381da3e3c64
+9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 59d314ad6f356dd08601a4cd5e530381da3e3c64
+1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+444ac553ac7612cc88969031b02b3767fb8a353a 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+$
diff --git a/t/t4013/diff.rev-list_--parents_HEAD b/t/t4013/diff.rev-list_--parents_HEAD
new file mode 100644
index 0000000000..65d2a80208
--- /dev/null
+++ b/t/t4013/diff.rev-list_--parents_HEAD
@@ -0,0 +1,7 @@
+$ git rev-list --parents HEAD
+59d314ad6f356dd08601a4cd5e530381da3e3c64 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a 444ac553ac7612cc88969031b02b3767fb8a353a
+9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 444ac553ac7612cc88969031b02b3767fb8a353a
+444ac553ac7612cc88969031b02b3767fb8a353a
+$
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index f045898fe3..ebfc4a6590 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -138,56 +138,243 @@ test_expect_success 'multiple files' '
ls patches/0001-Side-changes-1.patch patches/0002-Side-changes-2.patch patches/0003-Side-changes-3-with-n-backslash-n-in-it.patch
'
-test_expect_success 'thread' '
+check_threading () {
+ expect="$1" &&
+ shift &&
+ (git format-patch --stdout "$@"; echo $? > status.out) |
+ # Prints everything between the Message-ID and In-Reply-To,
+ # and replaces all Message-ID-lookalikes by a sequence number
+ perl -ne '
+ if (/^(message-id|references|in-reply-to)/i) {
+ $printing = 1;
+ } elsif (/^\S/) {
+ $printing = 0;
+ }
+ if ($printing) {
+ $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
+ for $k (keys %h) {s/$k/$h{$k}/};
+ print;
+ }
+ print "---\n" if /^From /i;
+ ' > actual &&
+ test 0 = "$(cat status.out)" &&
+ test_cmp "$expect" actual
+}
+
+cat >> expect.no-threading <<EOF
+---
+---
+---
+EOF
- rm -rf patches/ &&
+test_expect_success 'no threading' '
git checkout side &&
- git format-patch --thread -o patches/ master &&
- FIRST_MID=$(grep "Message-Id:" patches/0001-* | sed "s/^[^<]*\(<[^>]*>\).*$/\1/") &&
- for i in patches/0002-* patches/0003-*
- do
- grep "References: $FIRST_MID" $i &&
- grep "In-Reply-To: $FIRST_MID" $i || break
- done
+ check_threading expect.no-threading master
'
-test_expect_success 'thread in-reply-to' '
+cat > expect.thread <<EOF
+---
+Message-Id: <0>
+---
+Message-Id: <1>
+In-Reply-To: <0>
+References: <0>
+---
+Message-Id: <2>
+In-Reply-To: <0>
+References: <0>
+EOF
- rm -rf patches/ &&
- git checkout side &&
- git format-patch --in-reply-to="<test.message>" --thread -o patches/ master &&
- FIRST_MID="<test.message>" &&
- for i in patches/*
- do
- grep "References: $FIRST_MID" $i &&
- grep "In-Reply-To: $FIRST_MID" $i || break
- done
+test_expect_success 'thread' '
+ check_threading expect.thread --thread master
'
-test_expect_success 'thread cover-letter' '
+cat > expect.in-reply-to <<EOF
+---
+Message-Id: <0>
+In-Reply-To: <1>
+References: <1>
+---
+Message-Id: <2>
+In-Reply-To: <1>
+References: <1>
+---
+Message-Id: <3>
+In-Reply-To: <1>
+References: <1>
+EOF
- rm -rf patches/ &&
- git checkout side &&
- git format-patch --cover-letter --thread -o patches/ master &&
- FIRST_MID=$(grep "Message-Id:" patches/0000-* | sed "s/^[^<]*\(<[^>]*>\).*$/\1/") &&
- for i in patches/0001-* patches/0002-* patches/0003-*
- do
- grep "References: $FIRST_MID" $i &&
- grep "In-Reply-To: $FIRST_MID" $i || break
- done
+test_expect_success 'thread in-reply-to' '
+ check_threading expect.in-reply-to --in-reply-to="<test.message>" \
+ --thread master
'
+cat > expect.cover-letter <<EOF
+---
+Message-Id: <0>
+---
+Message-Id: <1>
+In-Reply-To: <0>
+References: <0>
+---
+Message-Id: <2>
+In-Reply-To: <0>
+References: <0>
+---
+Message-Id: <3>
+In-Reply-To: <0>
+References: <0>
+EOF
+
+test_expect_success 'thread cover-letter' '
+ check_threading expect.cover-letter --cover-letter --thread master
+'
+
+cat > expect.cl-irt <<EOF
+---
+Message-Id: <0>
+In-Reply-To: <1>
+References: <1>
+---
+Message-Id: <2>
+In-Reply-To: <0>
+References: <1>
+ <0>
+---
+Message-Id: <3>
+In-Reply-To: <0>
+References: <1>
+ <0>
+---
+Message-Id: <4>
+In-Reply-To: <0>
+References: <1>
+ <0>
+EOF
+
test_expect_success 'thread cover-letter in-reply-to' '
+ check_threading expect.cl-irt --cover-letter \
+ --in-reply-to="<test.message>" --thread master
+'
- rm -rf patches/ &&
- git checkout side &&
- git format-patch --cover-letter --in-reply-to="<test.message>" --thread -o patches/ master &&
- FIRST_MID="<test.message>" &&
- for i in patches/*
- do
- grep "References: $FIRST_MID" $i &&
- grep "In-Reply-To: $FIRST_MID" $i || break
- done
+test_expect_success 'thread explicit shallow' '
+ check_threading expect.cl-irt --cover-letter \
+ --in-reply-to="<test.message>" --thread=shallow master
+'
+
+cat > expect.deep <<EOF
+---
+Message-Id: <0>
+---
+Message-Id: <1>
+In-Reply-To: <0>
+References: <0>
+---
+Message-Id: <2>
+In-Reply-To: <1>
+References: <0>
+ <1>
+EOF
+
+test_expect_success 'thread deep' '
+ check_threading expect.deep --thread=deep master
+'
+
+cat > expect.deep-irt <<EOF
+---
+Message-Id: <0>
+In-Reply-To: <1>
+References: <1>
+---
+Message-Id: <2>
+In-Reply-To: <0>
+References: <1>
+ <0>
+---
+Message-Id: <3>
+In-Reply-To: <2>
+References: <1>
+ <0>
+ <2>
+EOF
+
+test_expect_success 'thread deep in-reply-to' '
+ check_threading expect.deep-irt --thread=deep \
+ --in-reply-to="<test.message>" master
+'
+
+cat > expect.deep-cl <<EOF
+---
+Message-Id: <0>
+---
+Message-Id: <1>
+In-Reply-To: <0>
+References: <0>
+---
+Message-Id: <2>
+In-Reply-To: <1>
+References: <0>
+ <1>
+---
+Message-Id: <3>
+In-Reply-To: <2>
+References: <0>
+ <1>
+ <2>
+EOF
+
+test_expect_success 'thread deep cover-letter' '
+ check_threading expect.deep-cl --cover-letter --thread=deep master
+'
+
+cat > expect.deep-cl-irt <<EOF
+---
+Message-Id: <0>
+In-Reply-To: <1>
+References: <1>
+---
+Message-Id: <2>
+In-Reply-To: <0>
+References: <1>
+ <0>
+---
+Message-Id: <3>
+In-Reply-To: <2>
+References: <1>
+ <0>
+ <2>
+---
+Message-Id: <4>
+In-Reply-To: <3>
+References: <1>
+ <0>
+ <2>
+ <3>
+EOF
+
+test_expect_success 'thread deep cover-letter in-reply-to' '
+ check_threading expect.deep-cl-irt --cover-letter \
+ --in-reply-to="<test.message>" --thread=deep master
+'
+
+test_expect_success 'thread via config' '
+ git config format.thread true &&
+ check_threading expect.thread master
+'
+
+test_expect_success 'thread deep via config' '
+ git config format.thread deep &&
+ check_threading expect.deep master
+'
+
+test_expect_success 'thread config + override' '
+ git config format.thread deep &&
+ check_threading expect.thread --thread master
+'
+
+test_expect_success 'thread config + --no-thread' '
+ git config format.thread deep &&
+ check_threading expect.no-threading --no-thread master
'
test_expect_success 'excessive subject' '
diff --git a/t/t4017-quiet.sh b/t/t4035-diff-quiet.sh
index e747e84227..e747e84227 100755
--- a/t/t4017-quiet.sh
+++ b/t/t4035-diff-quiet.sh
diff --git a/t/t4021-format-patch-signer-mime.sh b/t/t4036-format-patch-signer-mime.sh
index ba43f18549..ba43f18549 100755
--- a/t/t4021-format-patch-signer-mime.sh
+++ b/t/t4036-format-patch-signer-mime.sh
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 7b976ee36d..b98619035c 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -37,6 +37,46 @@ test_expect_success setup '
'
+printf "sixth\nfifth\nfourth\nthird\nsecond\ninitial" > expect
+test_expect_success 'pretty' '
+
+ git log --pretty="format:%s" > actual &&
+ test_cmp expect actual
+'
+
+printf "sixth\nfifth\nfourth\nthird\nsecond\ninitial\n" > expect
+test_expect_success 'pretty (tformat)' '
+
+ git log --pretty="tformat:%s" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'pretty (shortcut)' '
+
+ git log --pretty="%s" > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'format' '
+
+ git log --format="%s" > actual &&
+ test_cmp expect actual
+'
+
+cat > expect << EOF
+804a787 sixth
+394ef78 fifth
+5d31159 fourth
+2fbe8c0 third
+f7dab8e second
+3a2fdcb initial
+EOF
+test_expect_success 'oneline' '
+
+ git log --oneline > actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'diff-filter=A' '
actual=$(git log --pretty="format:%s" --diff-filter=A HEAD) &&
@@ -134,5 +174,153 @@ test_expect_success 'log --grep -i' '
test_cmp expect actual
'
+cat > expect <<EOF
+* Second
+* sixth
+* fifth
+* fourth
+* third
+* second
+* initial
+EOF
+
+test_expect_success 'simple log --graph' '
+ git log --graph --pretty=tformat:%s >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'set up merge history' '
+ git checkout -b side HEAD~4 &&
+ test_commit side-1 1 1 &&
+ test_commit side-2 2 2 &&
+ git checkout master &&
+ git merge side
+'
+
+cat > expect <<\EOF
+* Merge branch 'side'
+|\
+| * side-2
+| * side-1
+* | Second
+* | sixth
+* | fifth
+* | fourth
+|/
+* third
+* second
+* initial
+EOF
+
+test_expect_success 'log --graph with merge' '
+ git log --graph --date-order --pretty=tformat:%s |
+ sed "s/ *$//" >actual &&
+ test_cmp expect actual
+'
+
+cat > expect <<\EOF
+* commit master
+|\ Merge: A B
+| | Author: A U Thor <author@example.com>
+| |
+| | Merge branch 'side'
+| |
+| * commit side
+| | Author: A U Thor <author@example.com>
+| |
+| | side-2
+| |
+| * commit tags/side-1
+| | Author: A U Thor <author@example.com>
+| |
+| | side-1
+| |
+* | commit master~1
+| | Author: A U Thor <author@example.com>
+| |
+| | Second
+| |
+* | commit master~2
+| | Author: A U Thor <author@example.com>
+| |
+| | sixth
+| |
+* | commit master~3
+| | Author: A U Thor <author@example.com>
+| |
+| | fifth
+| |
+* | commit master~4
+|/ Author: A U Thor <author@example.com>
+|
+| fourth
+|
+* commit tags/side-1~1
+| Author: A U Thor <author@example.com>
+|
+| third
+|
+* commit tags/side-1~2
+| Author: A U Thor <author@example.com>
+|
+| second
+|
+* commit tags/side-1~3
+ Author: A U Thor <author@example.com>
+
+ initial
+EOF
+
+test_expect_success 'log --graph with full output' '
+ git log --graph --date-order --pretty=short |
+ git name-rev --name-only --stdin |
+ sed "s/Merge:.*/Merge: A B/;s/ *$//" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'set up more tangled history' '
+ git checkout -b tangle HEAD~6 &&
+ test_commit tangle-a tangle-a a &&
+ git merge master~3 &&
+ git merge side~1 &&
+ git checkout master &&
+ git merge tangle
+'
+
+cat > expect <<\EOF
+* Merge branch 'tangle'
+|\
+| * Merge branch 'side' (early part) into tangle
+| |\
+| * \ Merge branch 'master' (early part) into tangle
+| |\ \
+| * | | tangle-a
+* | | | Merge branch 'side'
+|\ \ \ \
+| * | | | side-2
+| | | |/
+| | |/|
+| |/| |
+| * | | side-1
+* | | | Second
+* | | | sixth
+| | |/
+| |/|
+|/| |
+* | | fifth
+* | | fourth
+|/ /
+* | third
+|/
+* second
+* initial
+EOF
+
+test_expect_success 'log --graph with merge' '
+ git log --graph --date-order --pretty=tformat:%s |
+ sed "s/ *$//" >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
new file mode 100755
index 0000000000..04f7bae850
--- /dev/null
+++ b/t/t4204-patch-id.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description='git patch-id'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit initial foo a &&
+ test_commit first foo b &&
+ git checkout -b same HEAD^ &&
+ test_commit same-msg foo b &&
+ git checkout -b notsame HEAD^ &&
+ test_commit notsame-msg foo c
+'
+
+test_expect_success 'patch-id output is well-formed' '
+ git log -p -1 | git patch-id > output &&
+ grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output
+'
+
+get_patch_id () {
+ git log -p -1 "$1" | git patch-id |
+ sed "s# .*##" > patch-id_"$1"
+}
+
+test_expect_success 'patch-id detects equality' '
+ get_patch_id master &&
+ get_patch_id same &&
+ test_cmp patch-id_master patch-id_same
+'
+
+test_expect_success 'patch-id detects inequality' '
+ get_patch_id master &&
+ get_patch_id notsame &&
+ ! test_cmp patch-id_master patch-id_notsame
+'
+
+test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index c942c8be85..b7e362834b 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -86,6 +86,10 @@ test_expect_success \
'git archive vs. the same in a bare repo' \
'test_cmp b.tar b3.tar'
+test_expect_success 'git archive with --output' \
+ 'git archive --output=b4.tar HEAD &&
+ test_cmp b.tar b4.tar'
+
test_expect_success \
'validate file modification time' \
'mkdir extract &&
@@ -172,6 +176,10 @@ test_expect_success \
'git archive --format=zip vs. the same in a bare repo' \
'test_cmp d.zip d1.zip'
+test_expect_success 'git archive --format=zip with --output' \
+ 'git archive --format=zip --output=d2.zip HEAD &&
+ test_cmp d.zip d2.zip'
+
$UNZIP -v >/dev/null 2>&1
if [ $? -eq 127 ]; then
echo "Skipping ZIP tests, because unzip was not found"
diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh
index 9b2e1a94c5..4fdb418550 100755
--- a/t/t5403-post-checkout-hook.sh
+++ b/t/t5403-post-checkout-hook.sh
@@ -71,4 +71,16 @@ test_expect_success 'post-checkout receives the right args when not switching br
test $old = $new -a $flag = 0
'
+mkdir -p templates/hooks
+cat >templates/hooks/post-checkout <<'EOF'
+#!/bin/sh
+echo $@ > $GIT_DIR/post-checkout.args
+EOF
+chmod +x templates/hooks/post-checkout
+
+test_expect_success 'post-checkout hook is triggered by clone' '
+ git clone --template=templates . clone3 &&
+ test -f clone3/.git/post-checkout.args
+'
+
test_done
diff --git a/t/t5521-pull-symlink.sh b/t/t5522-pull-symlink.sh
index 5672b51e2e..5672b51e2e 100755
--- a/t/t5521-pull-symlink.sh
+++ b/t/t5522-pull-symlink.sh
diff --git a/t/t5705-clone-2gb.sh b/t/t5705-clone-2gb.sh
new file mode 100755
index 0000000000..9f52154cac
--- /dev/null
+++ b/t/t5705-clone-2gb.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+test_description='Test cloning a repository larger than 2 gigabyte'
+. ./test-lib.sh
+
+test -z "$GIT_TEST_CLONE_2GB" &&
+say "Skipping expensive 2GB clone test; enable it with GIT_TEST_CLONE_2GB=t" &&
+test_done &&
+exit
+
+test_expect_success 'setup' '
+
+ git config pack.compression 0 &&
+ git config pack.depth 0 &&
+ blobsize=$((20*1024*1024)) &&
+ blobcount=$((2*1024*1024*1024/$blobsize+1)) &&
+ i=1 &&
+ (while test $i -le $blobcount
+ do
+ printf "Generating blob $i/$blobcount\r" >&2 &&
+ printf "blob\nmark :$i\ndata $blobsize\n" &&
+ #test-genrandom $i $blobsize &&
+ printf "%-${blobsize}s" $i &&
+ echo "M 100644 :$i $i" >> commit
+ i=$(($i+1)) ||
+ echo $? > exit-status
+ done &&
+ echo "commit refs/heads/master" &&
+ echo "author A U Thor <author@email.com> 123456789 +0000" &&
+ echo "committer C O Mitter <committer@email.com> 123456789 +0000" &&
+ echo "data 5" &&
+ echo ">2gb" &&
+ cat commit) |
+ git fast-import &&
+ test ! -f exit-status
+
+'
+
+test_expect_success 'clone' '
+
+ git clone --bare --no-hardlinks . clone
+
+'
+
+test_done
diff --git a/t/t6023-merge-rename-nocruft.sh b/t/t6034-merge-rename-nocruft.sh
index 65be95fbaa..65be95fbaa 100755
--- a/t/t6023-merge-rename-nocruft.sh
+++ b/t/t6034-merge-rename-nocruft.sh
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index b8cb2df667..af690ec6c1 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -47,6 +47,55 @@ test_expect_success 'Prepare submodule testing' '
GIT_CONFIG=.gitmodules git config submodule.example.url git://example.com/init.git
'
+test_expect_success 'Prepare submodule add testing' '
+ submodurl=$(pwd)
+ (
+ mkdir addtest &&
+ cd addtest &&
+ git init
+ )
+'
+
+test_expect_success 'submodule add' '
+ (
+ cd addtest &&
+ git submodule add "$submodurl" submod &&
+ git submodule init
+ )
+'
+
+test_expect_success 'submodule add with ./ in path' '
+ (
+ cd addtest &&
+ git submodule add "$submodurl" ././dotsubmod/./frotz/./ &&
+ git submodule init
+ )
+'
+
+test_expect_success 'submodule add with // in path' '
+ (
+ cd addtest &&
+ git submodule add "$submodurl" slashslashsubmod///frotz// &&
+ git submodule init
+ )
+'
+
+test_expect_success 'submodule add with /.. in path' '
+ (
+ cd addtest &&
+ git submodule add "$submodurl" dotdotsubmod/../realsubmod/frotz/.. &&
+ git submodule init
+ )
+'
+
+test_expect_success 'submodule add with ./, /.. and // in path' '
+ (
+ cd addtest &&
+ git submodule add "$submodurl" dot/dotslashsubmod/./../..////realsubmod2/a/b/c/d/../../../../frotz//.. &&
+ git submodule init
+ )
+'
+
test_expect_success 'status should fail for unmapped paths' '
if git submodule status
then
diff --git a/t/t7502-status.sh b/t/t7508-status.sh
index 93f875f500..93f875f500 100755
--- a/t/t7502-status.sh
+++ b/t/t7508-status.sh
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 4df4f965cb..08d5b91c91 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -35,6 +35,47 @@ test_expect_success 'Extract patches' '
patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
'
+# Test no confirm early to ensure remaining tests will not hang
+test_no_confirm () {
+ rm -f no_confirm_okay
+ echo n | \
+ GIT_SEND_EMAIL_NOTTY=1 \
+ git send-email \
+ --from="Example <from@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $@ \
+ $patches > stdout &&
+ test_must_fail grep "Send this email" stdout &&
+ > no_confirm_okay
+}
+
+# Exit immediately to prevent hang if a no-confirm test fails
+check_no_confirm () {
+ test -f no_confirm_okay || {
+ say 'No confirm test failed; skipping remaining tests to prevent hanging'
+ test_done
+ }
+}
+
+test_expect_success 'No confirm with --suppress-cc' '
+ test_no_confirm --suppress-cc=sob
+'
+check_no_confirm
+
+test_expect_success 'No confirm with --confirm=never' '
+ test_no_confirm --confirm=never
+'
+check_no_confirm
+
+# leave sendemail.confirm set to never after this so that none of the
+# remaining tests prompt unintentionally.
+test_expect_success 'No confirm with sendemail.confirm=never' '
+ git config sendemail.confirm never &&
+ test_no_confirm --compose --subject=foo
+'
+check_no_confirm
+
test_expect_success 'Send patches' '
git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
'
@@ -175,15 +216,13 @@ test_set_editor "$(pwd)/fake-editor"
test_expect_success '--compose works' '
clean_fake_sendmail &&
- echo y | \
- GIT_SEND_EMAIL_NOTTY=1 \
- git send-email \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches \
- 2>errors
+ git send-email \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches \
+ 2>errors
'
test_expect_success 'first message is compose text' '
@@ -375,15 +414,56 @@ test_expect_success '--suppress-cc=cc' '
test_suppression cc
'
+test_confirm () {
+ echo y | \
+ GIT_SEND_EMAIL_NOTTY=1 \
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $@ \
+ $patches | grep "Send this email"
+}
+
+test_expect_success '--confirm=always' '
+ test_confirm --confirm=always --suppress-cc=all
+'
+
+test_expect_success '--confirm=auto' '
+ test_confirm --confirm=auto
+'
+
+test_expect_success '--confirm=cc' '
+ test_confirm --confirm=cc
+'
+
+test_expect_success '--confirm=compose' '
+ test_confirm --confirm=compose --compose
+'
+
+test_expect_success 'confirm by default (due to cc)' '
+ CONFIRM=$(git config --get sendemail.confirm) &&
+ git config --unset sendemail.confirm &&
+ test_confirm &&
+ git config sendemail.confirm $CONFIRM
+'
+
+test_expect_success 'confirm by default (due to --compose)' '
+ CONFIRM=$(git config --get sendemail.confirm) &&
+ git config --unset sendemail.confirm &&
+ test_confirm --suppress-cc=all --compose
+ ret="$?"
+ git config sendemail.confirm ${CONFIRM:-never}
+ test $ret = "0"
+'
+
test_expect_success '--compose adds MIME for utf8 body' '
clean_fake_sendmail &&
(echo "#!$SHELL_PATH" &&
echo "echo utf8 body: àéìöú >>\"\$1\""
) >fake-editor-utf8 &&
chmod +x fake-editor-utf8 &&
- echo y | \
GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- GIT_SEND_EMAIL_NOTTY=1 \
git send-email \
--compose --subject foo \
--from="Example <nobody@example.com>" \
@@ -405,9 +485,7 @@ test_expect_success '--compose respects user mime type' '
echo " echo utf8 body: àéìöú) >\"\$1\""
) >fake-editor-utf8-mime &&
chmod +x fake-editor-utf8-mime &&
- echo y | \
GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
- GIT_SEND_EMAIL_NOTTY=1 \
git send-email \
--compose --subject foo \
--from="Example <nobody@example.com>" \
@@ -421,9 +499,7 @@ test_expect_success '--compose respects user mime type' '
test_expect_success '--compose adds MIME for utf8 subject' '
clean_fake_sendmail &&
- echo y | \
GIT_EDITOR="\"$(pwd)/fake-editor\"" \
- GIT_SEND_EMAIL_NOTTY=1 \
git send-email \
--compose --subject utf8-sübjëct \
--from="Example <nobody@example.com>" \
@@ -445,7 +521,7 @@ test_expect_success 'detects ambiguous reference/file conflict' '
test_expect_success 'feed two files' '
rm -fr outdir &&
git format-patch -2 -o outdir &&
- GIT_SEND_EMAIL_NOTTY=1 git send-email \
+ git send-email \
--dry-run \
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
diff --git a/t/t9108-git-svn-multi-glob.sh b/t/t9109-git-svn-multi-glob.sh
index 8f79c3f251..8f79c3f251 100755
--- a/t/t9108-git-svn-multi-glob.sh
+++ b/t/t9109-git-svn-multi-glob.sh
diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index fd185011b7..fd185011b7 100755
--- a/t/t9106-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 0c455929e4..1e01a912ab 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -3,6 +3,22 @@
# Copyright (c) 2005 Junio C Hamano
#
+# if --tee was passed, write the output not only to the terminal, but
+# additionally to the file test-results/$BASENAME.out, too.
+case "$GIT_TEST_TEE_STARTED, $* " in
+done,*)
+ # do not redirect again
+ ;;
+*' --tee '*|*' --va'*)
+ mkdir -p test-results
+ BASE=test-results/$(basename "$0" .sh)
+ (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
+ echo $? > $BASE.exit) | tee $BASE.out
+ test "$(cat $BASE.exit)" = 0
+ exit
+ ;;
+esac
+
# Keep the original TERM for say_color
ORIGINAL_TERM=$TERM
@@ -94,6 +110,10 @@ do
--no-python)
# noop now...
shift ;;
+ --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
+ valgrind=t; verbose=t; shift ;;
+ --tee)
+ shift ;; # was handled already
*)
break ;;
esac
@@ -434,7 +454,7 @@ test_create_repo () {
repo="$1"
mkdir -p "$repo"
cd "$repo" || error "Cannot setup test environment"
- "$GIT_EXEC_PATH/git" init "--template=$GIT_EXEC_PATH/templates/blt/" >&3 2>&4 ||
+ "$GIT_EXEC_PATH/git" init "--template=$owd/../templates/blt/" >&3 2>&4 ||
error "cannot run git init -- have you built things yet?"
mv .git/hooks .git/hooks-disabled
cd "$owd"
@@ -444,7 +464,7 @@ test_done () {
trap - EXIT
test_results_dir="$TEST_DIRECTORY/test-results"
mkdir -p "$test_results_dir"
- test_results_path="$test_results_dir/${0%-*}-$$"
+ test_results_path="$test_results_dir/${0%.sh}-$$"
echo "total $test_count" >> $test_results_path
echo "success $test_success" >> $test_results_path
@@ -492,8 +512,73 @@ test_done () {
# Test the binaries we have just built. The tests are kept in
# t/ subdirectory and are run in 'trash directory' subdirectory.
TEST_DIRECTORY=$(pwd)
-PATH=$TEST_DIRECTORY/..:$PATH
-GIT_EXEC_PATH=$(pwd)/..
+if test -z "$valgrind"
+then
+ PATH=$TEST_DIRECTORY/..:$PATH
+ GIT_EXEC_PATH=$TEST_DIRECTORY/..
+else
+ make_symlink () {
+ test -h "$2" &&
+ test "$1" = "$(readlink "$2")" || {
+ # be super paranoid
+ if mkdir "$2".lock
+ then
+ rm -f "$2" &&
+ ln -s "$1" "$2" &&
+ rm -r "$2".lock
+ else
+ while test -d "$2".lock
+ do
+ say "Waiting for lock on $2."
+ sleep 1
+ done
+ fi
+ }
+ }
+
+ make_valgrind_symlink () {
+ # handle only executables
+ test -x "$1" || return
+
+ base=$(basename "$1")
+ symlink_target=$TEST_DIRECTORY/../$base
+ # do not override scripts
+ if test -x "$symlink_target" &&
+ test ! -d "$symlink_target" &&
+ test "#!" != "$(head -c 2 < "$symlink_target")"
+ then
+ symlink_target=../valgrind.sh
+ fi
+ case "$base" in
+ *.sh|*.perl)
+ symlink_target=../unprocessed-script
+ esac
+ # create the link, or replace it if it is out of date
+ make_symlink "$symlink_target" "$GIT_VALGRIND/bin/$base" || exit
+ }
+
+ # override all git executables in TEST_DIRECTORY/..
+ GIT_VALGRIND=$TEST_DIRECTORY/valgrind
+ mkdir -p "$GIT_VALGRIND"/bin
+ for file in $TEST_DIRECTORY/../git* $TEST_DIRECTORY/../test-*
+ do
+ make_valgrind_symlink $file
+ done
+ OLDIFS=$IFS
+ IFS=:
+ for path in $PATH
+ do
+ ls "$path"/git-* 2> /dev/null |
+ while read file
+ do
+ make_valgrind_symlink "$file"
+ done
+ done
+ IFS=$OLDIFS
+ PATH=$GIT_VALGRIND/bin:$PATH
+ GIT_EXEC_PATH=$GIT_VALGRIND/bin
+ export GIT_VALGRIND
+fi
GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
unset GIT_CONFIG
GIT_CONFIG_NOSYSTEM=1
diff --git a/t/valgrind/.gitignore b/t/valgrind/.gitignore
new file mode 100644
index 0000000000..d4ae6676d1
--- /dev/null
+++ b/t/valgrind/.gitignore
@@ -0,0 +1,2 @@
+/bin/
+/templates
diff --git a/t/valgrind/analyze.sh b/t/valgrind/analyze.sh
new file mode 100755
index 0000000000..d8105d9fab
--- /dev/null
+++ b/t/valgrind/analyze.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+
+out_prefix=$(dirname "$0")/../test-results/valgrind.out
+output=
+count=0
+total_count=0
+missing_message=
+new_line='
+'
+
+# start outputting the current valgrind error in $out_prefix.++$count,
+# and the test case which failed in the corresponding .message file
+start_output () {
+ test -z "$output" || return
+
+ # progress
+ total_count=$(($total_count+1))
+ test -t 2 && printf "\rFound %d errors" $total_count >&2
+
+ count=$(($count+1))
+ output=$out_prefix.$count
+ : > $output
+
+ echo "*** $1 ***" > $output.message
+}
+
+finish_output () {
+ test ! -z "$output" || return
+ output=
+
+ # if a test case has more than one valgrind error, we need to
+ # copy the last .message file to the previous errors
+ test -z "$missing_message" || {
+ while test $missing_message -lt $count
+ do
+ cp $out_prefix.$count.message \
+ $out_prefix.$missing_message.message
+ missing_message=$(($missing_message+1))
+ done
+ missing_message=
+ }
+}
+
+# group the valgrind errors by backtrace
+output_all () {
+ last_line=
+ j=0
+ i=1
+ while test $i -le $count
+ do
+ # output <number> <backtrace-in-one-line>
+ echo "$i $(tr '\n' ' ' < $out_prefix.$i)"
+ i=$(($i+1))
+ done |
+ sort -t ' ' -k 2 | # order by <backtrace-in-one-line>
+ while read number line
+ do
+ # find duplicates, do not output backtrace twice
+ if test "$line" != "$last_line"
+ then
+ last_line=$line
+ j=$(($j+1))
+ printf "\nValgrind error $j:\n\n"
+ cat $out_prefix.$number
+ printf "\nfound in:\n"
+ fi
+ # print the test case where this came from
+ printf "\n"
+ cat $out_prefix.$number.message
+ done
+}
+
+handle_one () {
+ OLDIFS=$IFS
+ IFS="$new_line"
+ while read line
+ do
+ case "$line" in
+ # backtrace, possibly a new one
+ ==[0-9]*)
+
+ # Does the current valgrind error have a message yet?
+ case "$output" in
+ *.message)
+ test -z "$missing_message" &&
+ missing_message=$count
+ output=
+ esac
+
+ start_output $(basename $1)
+ echo "$line" |
+ sed 's/==[0-9]*==/==valgrind==/' >> $output
+ ;;
+ # end of backtrace
+ '}')
+ test -z "$output" || {
+ echo "$line" >> $output
+ test $output = ${output%.message} &&
+ output=$output.message
+ }
+ ;;
+ # end of test case
+ '')
+ finish_output
+ ;;
+ # normal line; if $output is set, print the line
+ *)
+ test -z "$output" || echo "$line" >> $output
+ ;;
+ esac
+ done < $1
+ IFS=$OLDIFS
+
+ # just to be safe
+ finish_output
+}
+
+for test_script in "$(dirname "$0")"/../test-results/*.out
+do
+ handle_one $test_script
+done
+
+output_all
diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp
new file mode 100644
index 0000000000..9e013fa3b2
--- /dev/null
+++ b/t/valgrind/default.supp
@@ -0,0 +1,45 @@
+{
+ ignore-zlib-errors-cond
+ Memcheck:Cond
+ obj:*libz.so*
+}
+
+{
+ ignore-zlib-errors-value8
+ Memcheck:Value8
+ obj:*libz.so*
+}
+
+{
+ ignore-zlib-errors-value4
+ Memcheck:Value4
+ obj:*libz.so*
+}
+
+{
+ ignore-ldso-cond
+ Memcheck:Cond
+ obj:*ld-*.so
+}
+
+{
+ ignore-ldso-addr8
+ Memcheck:Addr8
+ obj:*ld-*.so
+}
+
+{
+ ignore-ldso-addr4
+ Memcheck:Addr4
+ obj:*ld-*.so
+}
+
+{
+ writing-data-from-zlib-triggers-even-more-errors
+ Memcheck:Param
+ write(buf)
+ obj:/lib/ld-*.so
+ fun:write_in_full
+ fun:write_buffer
+ fun:write_loose_object
+}
diff --git a/t/valgrind/valgrind.sh b/t/valgrind/valgrind.sh
new file mode 100755
index 0000000000..582b4dca94
--- /dev/null
+++ b/t/valgrind/valgrind.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+base=$(basename "$0")
+
+TRACK_ORIGINS=
+
+VALGRIND_VERSION=$(valgrind --version)
+VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)')
+VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)')
+test 3 -gt "$VALGRIND_MAJOR" ||
+test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" ||
+TRACK_ORIGINS=--track-origins=yes
+
+exec valgrind -q --error-exitcode=126 \
+ --leak-check=no \
+ --suppressions="$GIT_VALGRIND/default.supp" \
+ --gen-suppressions=all \
+ $TRACK_ORIGINS \
+ --log-fd=4 \
+ --input-fd=4 \
+ $GIT_VALGRIND_OPTIONS \
+ "$GIT_VALGRIND"/../../"$base" "$@"
diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample
index 93c605594f..a3f68ae3b4 100755
--- a/templates/hooks--update.sample
+++ b/templates/hooks--update.sample
@@ -43,10 +43,12 @@ allowdeletetag=$(git config --bool hooks.allowdeletetag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
-if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then
+case "$projectdesc" in
+"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
-fi
+ ;;
+esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
diff --git a/templates/this--description b/templates/this--description
index c6f25e80b8..498b267a8c 100644
--- a/templates/this--description
+++ b/templates/this--description
@@ -1 +1 @@
-Unnamed repository; edit this file to name it for gitweb.
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/upload-pack.c b/upload-pack.c
index 19c24db643..a49d872447 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -397,12 +397,11 @@ static int get_common_commits(void)
static char line[1000];
unsigned char sha1[20];
char hex[41], last_hex[41];
- int len;
save_commit_buffer = 0;
for(;;) {
- len = packet_read_line(0, line, sizeof(line));
+ int len = packet_read_line(0, line, sizeof(line));
reset_timeout();
if (!len) {
@@ -410,7 +409,7 @@ static int get_common_commits(void)
packet_write(1, "NAK\n");
continue;
}
- len = strip(line, len);
+ strip(line, len);
if (!prefixcmp(line, "have ")) {
switch (got_sha1(line+5, sha1)) {
case -1: /* they have what we do not */
@@ -645,7 +644,7 @@ int main(int argc, char **argv)
dir = argv[i];
if (!enter_repo(dir, strict))
- die("'%s': unable to chdir or not a git archive", dir);
+ die("'%s' does not appear to be a git repository", dir);
if (is_repository_shallow())
die("attempt to fetch/clone from a shallow repository");
if (getenv("GIT_DEBUG_SEND_PACK"))
diff --git a/wt-status.c b/wt-status.c
index 96ff2f8f56..dd87339ff7 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -15,11 +15,11 @@ int wt_status_relative_paths = 1;
int wt_status_use_color = -1;
int wt_status_submodule_summary;
static char wt_status_colors[][COLOR_MAXLEN] = {
- "", /* WT_STATUS_HEADER: normal */
- "\033[32m", /* WT_STATUS_UPDATED: green */
- "\033[31m", /* WT_STATUS_CHANGED: red */
- "\033[31m", /* WT_STATUS_UNTRACKED: red */
- "\033[31m", /* WT_STATUS_NOBRANCH: red */
+ GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
+ GIT_COLOR_GREEN, /* WT_STATUS_UPDATED */
+ GIT_COLOR_RED, /* WT_STATUS_CHANGED */
+ GIT_COLOR_RED, /* WT_STATUS_UNTRACKED */
+ GIT_COLOR_RED, /* WT_STATUS_NOBRANCH */
};
enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
diff --git a/xdiff-interface.c b/xdiff-interface.c
index d782f06d99..b9b0db8d86 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -15,11 +15,10 @@ static int parse_num(char **cp_p, int *num_p)
{
char *cp = *cp_p;
int num = 0;
- int read_some;
while ('0' <= *cp && *cp <= '9')
num = num * 10 + *cp++ - '0';
- if (!(read_some = cp - *cp_p))
+ if (!(cp - *cp_p))
return -1;
*cp_p = cp;
*num_p = num;