Merge branch 'bk/submodule-in-recursive-merge'
authorJunio C Hamano <gitster@pobox.com>
Wed, 19 Oct 2011 17:48:38 +0000 (10:48 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 19 Oct 2011 17:48:38 +0000 (10:48 -0700)
* bk/submodule-in-recursive-merge:
submodule: Search for merges only at end of recursive merge
submodule: Demonstrate known breakage during recursive merge

96 files changed:
Documentation/Makefile
Documentation/RelNotes/1.7.7.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.8.txt
Documentation/config.txt
Documentation/diff-options.txt
Documentation/git-commit-tree.txt
Documentation/git-grep.txt
Documentation/git-instaweb.txt
Documentation/git-svn.txt
Documentation/gitweb.conf.txt [new file with mode: 0644]
Documentation/gitweb.txt [new file with mode: 0644]
Makefile
attr.c
bisect.c
builtin/apply.c
builtin/archive.c
builtin/check-attr.c
builtin/checkout.c
builtin/commit.c
builtin/config.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/grep.c
builtin/merge.c
builtin/mv.c
builtin/receive-pack.c
bundle.c
cache.h
command-list.txt
commit.c
commit.h
compat/mingw.c
compat/mingw.h
compat/qsort.c
compat/win32/syslog.c
config.c
contrib/completion/git-completion.bash
daemon.c
diff.c
environment.c
fast-import.c
git-bisect.sh
git-gui/git-gui.sh
git-gui/lib/blame.tcl
git-gui/lib/choose_rev.tcl
git-gui/lib/commit.tcl
git-gui/lib/index.tcl
git-gui/lib/line.tcl [new file with mode: 0644]
git-gui/lib/search.tcl
git-gui/po/README
git-gui/po/sv.po
git-merge-one-file.sh
git-pull.sh
git-rebase.sh
git-send-email.perl
git-svn.perl
git-web--browse.sh
git.spec.in
gitweb/INSTALL
gitweb/README
http-fetch.c
http-push.c
http.c
http.h
ident.c
log-tree.c
mergetools/bc3
name-hash.c
refs.c
remote-curl.c
revision.c
revision.h
show-index.c
strbuf.c
t/lib-httpd.sh
t/t0003-attributes.sh
t/t1011-read-tree-sparse-checkout.sh
t/t1020-subdirectory.sh
t/t1300-repo-config.sh
t/t1304-default-acl.sh
t/t1402-check-ref-format.sh
t/t2020-checkout-detach.sh
t/t2022-checkout-paths.sh [new file with mode: 0755]
t/t3000-ls-files-others.sh
t/t4254-am-corrupt.sh [new file with mode: 0755]
t/t5516-fetch-push.sh
t/t5550-http-fetch.sh
t/t7810-grep.sh
t/t9001-send-email.sh
t/t9162-git-svn-dcommit-interactive.sh [new file with mode: 0644]
t/t9300-fast-import.sh
t/t9901-git-web--browse.sh [new file with mode: 0755]
unpack-trees.c
url.c
url.h
xdiff/xprepare.c
index 6346a75dda72533667a96eea2bd65bb280383f99..551325604e84713c87e2e95105861626e09fbef5 100644 (file)
@@ -1,9 +1,9 @@
 MAN1_TXT= \
        $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
                $(wildcard git-*.txt)) \
-       gitk.txt git.txt
+       gitk.txt gitweb.txt git.txt
 MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt githooks.txt \
-       gitrepository-layout.txt
+       gitrepository-layout.txt gitweb.conf.txt
 MAN7_TXT=gitcli.txt gittutorial.txt gittutorial-2.txt \
        gitcvs-migration.txt gitcore-tutorial.txt gitglossary.txt \
        gitdiffcore.txt gitnamespaces.txt gitrevisions.txt gitworkflows.txt
diff --git a/Documentation/RelNotes/1.7.7.1.txt b/Documentation/RelNotes/1.7.7.1.txt
new file mode 100644 (file)
index 0000000..02d7c02
--- /dev/null
@@ -0,0 +1,39 @@
+Git v1.7.7.1 Release Notes
+==========================
+
+Fixes since v1.7.7
+------------------
+
+ * "git diff $tree $path" used to apply the pathspec at the output stage,
+   reading the whole tree, wasting resources.
+
+ * The code to check for updated submodules during a "git fetch" of the
+   superproject had an unnecessary quadratic loop.
+
+ * "git fetch" from a large bundle did not enable the progress output.
+
+ * When "git fsck --lost-and-found" found that an empty blob object in the
+   object store is unreachable, it incorrectly reported an error after
+   writing the lost blob out successfully.
+
+ * "git filter-branch" did not refresh the index before checking that the
+   working tree was clean.
+
+ * "git grep $tree" when run with multiple threads had an unsafe access to
+   the object database that should have been protected with mutex.
+
+ * The "--ancestry-path" option to "git log" and friends misbehaved in a
+   history with complex criss-cross merges and showed an uninteresting
+   side history as well.
+
+ * Test t1304 assumed LOGNAME is always set, which may not be true on
+   some systems.
+
+ * Tests with --valgrind failed to find "mergetool" scriptlets.
+
+ * "git patch-id" miscomputed the patch-id in a patch that has a line longer
+   than 1kB.
+
+ * When an "exec" insn failed after modifying the index and/or the working
+   tree during "rebase -i", we now check and warn that the changes need to
+   be cleaned up.
index 27585834694217350f6bcbfbc34ce56e46e1c6a0..0576c36f8a3e0dd30944285d8c4c68040b999bf0 100644 (file)
@@ -4,14 +4,28 @@ Git v1.7.8 Release Notes (draft)
 Updates since v1.7.7
 --------------------
 
+ * Some git-svn and git-gui updates.
+
+ * Updates to bash completion scripts.
+
  * The build procedure has been taught to take advantage of computed
    dependency automatically when the complier supports it.
 
  * The date parser now accepts timezone designators that lack minutes
    part and also has a colon between "hh:mm".
 
+ * On some BSD systems, adding +s bit on directories is detrimental
+   (it is not necessary on BSD to begin with). The installation
+   procedure has been updated to take this into account.
+
+ * The contents of the /etc/mailname file, if exists, is used as the
+   default value of the hostname part of the committer/author e-mail.
+
  * "git am" learned how to read from patches generated by Hg.
 
+ * "git archive" talking with a remote repository can report errors
+   from the remote side in a more informative way.
+
  * "git branch" learned an explicit --list option to ask for branches
    listed, optionally with a glob matching pattern to limit its output.
 
@@ -21,6 +35,11 @@ Updates since v1.7.7
  * Variants of "git cherry-pick" and "git revert" that take multiple
    commits learned to "--continue".
 
+ * Errors at the network layer is logged by "git daemon".
+
+ * "git diff" learned "--minimal" option to spend extra cycles to come
+   up with a minimal patch output.
+
  * "git fetch" learned to honor transfer.fsckobjects configuration to
    validate the objects that were received from the other end, just like
    "git receive-pack" (the receiving end of "git push") does.
@@ -33,6 +52,17 @@ Updates since v1.7.7
  * "git for-each-ref" learned "%(contents:subject)", "%(contents:body)"
    and "%(contents:signature)". The last one is useful for signed tags.
 
+ * "git grep" used to incorrectly pay attention to .gitignore files
+   scattered in the directory it was working in even when "--no-index"
+   option was used. It no longer does this. The "--exclude-standard"
+   option needs to be given to explicitly activate the ignore
+   mechanism.
+
+ * "git grep" learned "--untracked" option, where given patterns are
+    searched in untracked (but not ignored) files as well as tracked
+    files in the working tree, so that matches in new but not yet
+    added files do not get missed.
+
  * "git ls-remote" learned to respond to "-h"(elp) requests.
 
  * "git send-email" learned to respond to "-h"(elp) requests.
@@ -82,48 +112,57 @@ included in this release.
    a corrupt packet.
    (merge 6cdf022 sp/smart-http-failure later to maint).
 
+ * HTTP transport did not use pushurl correctly, and also did not tell
+   what host it is trying to authenticate with when asking for
+   credentials.
+   (merge deba493 jk/http-auth later to maint).
+
  * Adding many refs to the local repository in one go (e.g. "git fetch"
    that fetches many tags) and looking up a ref by name in a repository
    with too many refs were unnecessarily slow.
    (merge 17d68a54d jp/get-ref-dir-unsorted later to maint).
 
- * "git remote rename $a $b" were not careful to match the remote name
-   against $a (i.e. source side of the remote nickname).
-   (merge b52d00aed mz/remote-rename later to maint).
+ * After incorrectly written third-party tools store a tag object in
+   HEAD, git diagnosed it as a repository corruption and refused to
+   proceed in order to avoid spreading the damage. We now gracefully
+   recover from such a situation by pretending as if the commit that
+   is pointed at by the tag were in HEAD.
+   (merge baf18fc nd/maint-autofix-tag-in-head later to maint).
 
- * "git diff $tree $path" used to apply the pathspec at the output stage,
-   reading the whole tree, wasting resources.
-   (merge 2f88c1970 jc/diff-index-unpack later to maint).
+ * Report from "git commit" on untracked files was confused under
+   core.ignorecase option.
+   (merge 2548183b jk/name-hash-dirent later to maint).
 
- * "git diff --[num]stat" used to use the number of lines of context
-   different from the default, potentially giving different results from
-   "git diff | diffstat" and confusing the users.
-   (merge f01cae918 jc/maint-diffstat-numstat-context later to maint).
+ * The attribute mechanism did not use case insensitive match when
+   core.ignorecase was set.
+   (merge 6eba621 bc/attr-ignore-case later to maint).
 
- * The code to check for updated submodules during a "git fetch" of the
-   superproject had an unnecessary quadratic loop.
-   (merge 6859de45 jk/maint-fetch-submodule-check-fix later to maint).
+ * "git apply --whitespace=error" did not bother to report the exact
+   line number in the patch that introduced new blank lines at the end
+   of the file.
+   (merge 8557263 jc/apply-blank-at-eof-fix later to maint).
 
- * "git fetch" from a large bundle did not enable the progress output.
-   (merge be042aff jc/maint-bundle-too-quiet later to maint).
+ * "git bisect" did not notice when it failed to update the working tree
+   to the next commit to be tested.
+   (merge 1acf11717 js/bisect-no-checkout later to maint).
 
- * When "git fsck --lost-and-found" found that an empty blob object in the
-   object store is unreachable, it incorrectly reported an error after
-   writing the lost blob out successfully.
-   (merge eb726f2d jc/maint-fsck-fwrite-size-check later to maint).
+ * "git checkout $tree $directory/" resurrected paths locally removed or
+   modified only in the working tree in $directory/ that did not appear
+   in $directory of the given $tree. They should have been kept intact.
+   (merge 0a1283b jc/checkout-from-tree-keep-local-changes later to maint).
 
- * "git filter-branch" did not refresh the index before checking that the
-   working tree was clean.
-   (merge 5347a50f jk/filter-branch-require-clean-work-tree later to maint).
+ * "git config --bool --get-regexp" failed to separate the variable name
+   and its value "true" when the variable is defined without "= true".
+   (merge 880e3cc mm/maint-config-explicit-bool-display later to maint).
 
- * "git grep $tree" when run with multiple threads had an unsafe access to
-   the object database that should have been protected with mutex.
-   (merge 8cb5775b2 nm/grep-object-sha1-lock later to maint).
+ * "git remote rename $a $b" were not careful to match the remote name
+   against $a (i.e. source side of the remote nickname).
+   (merge b52d00aed mz/remote-rename later to maint).
 
- * The "--ancestry-path" option to "git log" and friends misbehaved in a
-   history with complex criss-cross merges and showed an uninteresting
-   side history as well.
-   (merge c05b988a6 bk/ancestry-path later to maint).
+ * "git diff --[num]stat" used to use the number of lines of context
+   different from the default, potentially giving different results from
+   "git diff | diffstat" and confusing the users.
+   (merge f01cae918 jc/maint-diffstat-numstat-context later to maint).
 
  * "git merge" did not understand ":/<pattern>" as a way to name a commit.
 
@@ -131,17 +170,14 @@ included in this release.
    the file that may not even have any conflict.
    (merge 6d9990a jm/mergetool-pathspec later to maint).
 
- * Tests with --valgrind failed to find "mergetool" scriptlets.
-   (merge ee0d7bf92 tr/mergetool-valgrind later to maint).
-
- * "git patch-id" miscomputed the patch-id in a patch that has a line longer
-   than 1kB.
-   (merge b9ab810b ms/patch-id-with-overlong-line later to maint).
+ * "git pull" and "git rebase" did not work well even when GIT_WORK_TREE is
+   set correctly with GIT_DIR if the current directory is outside the working
+   tree.
+   (merge 035b5bf jk/pull-rebase-with-work-tree later to maint).
 
- * When an "exec" insn failed after modifying the index and/or the working
-   tree during "rebase -i", we now check and warn that the changes need to
-   be cleaned up.
-   (merge 1686519a mm/rebase-i-exec-edit later to maint).
+ " "git push" on the receiving end used to call post-receive and post-update
+   hooks for attempted removal of non-existing refs.
+   (merge 160b81ed ph/push-to-delete-nothing later to maint).
 
  * "gitweb" used to produce a non-working link while showing the contents
    of a blob, when JavaScript actions are enabled.
@@ -149,7 +185,7 @@ included in this release.
 
 ---
 exec >/var/tmp/1
-O=v1.7.7-236-g5366afa
+O=v1.7.7-368-g9638384
 echo O=$(git describe --always master)
 git log --first-parent --oneline --reverse ^$O master
 echo
index 03296b7eb8e015f6e6eae58f5bdf192e1461a4bf..b30c7e6278adae733cb32345cab719b506cb1760 100644 (file)
@@ -1071,6 +1071,23 @@ All gitcvs variables except for 'gitcvs.usecrlfattr' and
 is one of "ext" and "pserver") to make them apply only for the given
 access method.
 
+gitweb.category::
+gitweb.description::
+gitweb.owner::
+gitweb.url::
+       See linkgit:gitweb[1] for description.
+
+gitweb.avatar::
+gitweb.blame::
+gitweb.grep::
+gitweb.highlight::
+gitweb.patches::
+gitweb.pickaxe::
+gitweb.remote_heads::
+gitweb.showsizes::
+gitweb.snapshot::
+       See linkgit:gitweb.conf[5] for description.
+
 grep.lineNumber::
        If set to true, enable '-n' option by default.
 
index b620b3afeca14166840fb76b4cefe1e4038fb47e..5c53bdba948ea817e01e169a9fc183d4fc2d1313 100644 (file)
@@ -45,6 +45,10 @@ ifndef::git-format-patch[]
        Synonym for `-p --raw`.
 endif::git-format-patch[]
 
+--minimal::
+       Spend extra time to make sure the smallest possible
+       diff is produced.
+
 --patience::
        Generate a diff using the "patience diff" algorithm.
 
index 0fdb82ee8697a53beab6defd4db9eca8840b1dd0..02133d5fc9a14df7f4fe24d97bdf9980e77f807a 100644 (file)
@@ -68,7 +68,9 @@ if set:
 
 In case (some of) these environment variables are not set, the information
 is taken from the configuration items user.name and user.email, or, if not
-present, system user name and fully qualified hostname.
+present, system user name and the hostname used for outgoing mail (taken
+from `/etc/mailname` and falling back to the fully qualified hostname when
+that file does not exist).
 
 A commit comment is read from stdin. If a changelog
 entry is not provided via "<" redirection, 'git commit-tree' will just wait
@@ -90,6 +92,10 @@ Discussion
 
 include::i18n.txt[]
 
+FILES
+-----
+/etc/mailname
+
 SEE ALSO
 --------
 linkgit:git-write-tree[1]
index e44a4988b7a7ed7100da6e2ba098d7fda17a2f83..15d6711d46754e9659561b4372b46ec3c6654d6b 100644 (file)
@@ -23,7 +23,7 @@ SYNOPSIS
           [-A <post-context>] [-B <pre-context>] [-C <context>]
           [-f <file>] [-e] <pattern>
           [--and|--or|--not|(|)|-e <pattern>...]
-          [--cached | --no-index | <tree>...]
+          [ [--exclude-standard] [--cached | --no-index | --untracked] | <tree>...]
           [--] [<pathspec>...]
 
 DESCRIPTION
@@ -49,7 +49,20 @@ OPTIONS
        blobs registered in the index file.
 
 --no-index::
-       Search files in the current directory, not just those tracked by git.
+       Search files in the current directory that is not managed by git.
+
+--untracked::
+       In addition to searching in the tracked files in the working
+       tree, search also in untracked files.
+
+--no-exclude-standard::
+       Also search in ignored files by not honoring the `.gitignore`
+       mechanism. Only useful with `--untracked`.
+
+--exclude-standard::
+       Do not pay attention to ignored files specified via the `.gitignore`
+       mechanism.  Only useful when searching files in the current directory
+       with `--no-index`.
 
 -a::
 --text::
index ea95c90460b976ee187833c248366af579065f83..f3eef510f2ba906f64e802a4ea9e1d671530aca4 100644 (file)
@@ -84,6 +84,10 @@ If the configuration variable 'instaweb.browser' is not set,
 'web.browser' will be used instead if it is defined. See
 linkgit:git-web{litdd}browse[1] for more information about this.
 
+SEE ALSO
+--------
+linkgit:gitweb[1]
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index f977e8780b5e152b18d07a61fde8c2f86f98a0ce..34ee785064128bce0feb2cfc86d3040b42a8f428 100644 (file)
@@ -234,6 +234,14 @@ svn:mergeinfo property in the SVN repository when possible. Currently, this can
 only be done when dcommitting non-fast-forward merges where all parents but the
 first have already been pushed into SVN.
 
+--interactive;;
+       Ask the user to confirm that a patch set should actually be sent to SVN.
+       For each patch, one may answer "yes" (accept this patch), "no" (discard this
+       patch), "all" (accept all patches), or "quit".
+       +
+       'git svn dcommit' returns immediately if answer if "no" or "quit", without
+       commiting anything to SVN.
+
 'branch'::
        Create a branch in the SVN repository.
 
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
new file mode 100644 (file)
index 0000000..4ca3e27
--- /dev/null
@@ -0,0 +1,884 @@
+gitweb.conf(5)
+==============
+
+NAME
+----
+gitweb.conf - Gitweb (git web interface) configuration file
+
+SYNOPSIS
+--------
+/etc/gitweb.conf, /etc/gitweb-common.conf, $GITWEBDIR/gitweb_config.perl
+
+DESCRIPTION
+-----------
+
+The gitweb CGI script for viewing Git repositories over the web uses a
+perl script fragment as its configuration file.  You can set variables
+using "`our $variable = value`"; text from a "#" character until the
+end of a line is ignored.  See *perlsyn*(1) for details.
+
+An example:
+
+    # gitweb configuration file for http://git.example.org
+    #
+    our $projectroot = "/srv/git"; # FHS recommendation
+    our $site_name = 'Example.org >> Repos';
+
+
+The configuration file is used to override the default settings that
+were built into gitweb at the time the 'gitweb.cgi' script was generated.
+
+While one could just alter the configuration settings in the gitweb
+CGI itself, those changes would be lost upon upgrade.  Configuration
+settings might also be placed into a file in the same directory as the
+CGI script with the default name 'gitweb_config.perl' -- allowing
+one to have multiple gitweb instances with different configurations by
+the use of symlinks.
+
+Note that some configuration can be controlled on per-repository rather than
+gitweb-wide basis: see "Per-repository gitweb configuration" subsection on
+linkgit:gitweb[1] manpage.
+
+
+DISCUSSION
+----------
+Gitweb reads configuration data from the following sources in the
+following order:
+
+ * built-in values (some set during build stage),
+
+ * common system-wide configuration file (defaults to
+   '/etc/gitweb-common.conf'),
+
+ * either per-instance configuration file (defaults to 'gitweb_config.perl'
+   in the same directory as the installed gitweb), or if it does not exists
+   then fallback system-wide configuration file (defaults to '/etc/gitweb.conf').
+
+Values obtained in later configuration files override values obtained earlier
+in the above sequence.
+
+Locations of the common system-wide configuration file, the fallback
+system-wide configuration file and the per-instance configuration file
+are defined at compile time using build-time Makefile configuration
+variables, respectively `GITWEB_CONFIG_COMMON`, `GITWEB_CONFIG_SYSTEM`
+and `GITWEB_CONFIG`.
+
+You can also override locations of gitweb configuration files during
+runtime by setting the following environment variables:
+`GITWEB_CONFIG_COMMON`, `GITWEB_CONFIG_SYSTEM` and `GITWEB_CONFIG`
+to a non-empty value.
+
+
+The syntax of the configuration files is that of Perl, since these files are
+handled by sourcing them as fragments of Perl code (the language that
+gitweb itself is written in). Variables are typically set using the
+`our` qualifier (as in "`our $variable = <value>;`") to avoid syntax
+errors if a new version of gitweb no longer uses a variable and therefore
+stops declaring it.
+
+You can include other configuration file using read_config_file()
+subroutine.  For example, one might want to put gitweb configuration
+related to access control for viewing repositories via Gitolite (one
+of git repository management tools) in a separate file, e.g. in
+'/etc/gitweb-gitolite.conf'.  To include it, put
+
+--------------------------------------------------
+read_config_file("/etc/gitweb-gitolite.conf");
+--------------------------------------------------
+
+somewhere in gitweb configuration file used, e.g. in per-installation
+gitweb configuration file.  Note that read_config_file() checks itself
+that the file it reads exists, and does nothing if it is not found.
+It also handles errors in included file.
+
+
+The default configuration with no configuration file at all may work
+perfectly well for some installations.  Still, a configuration file is
+useful for customizing or tweaking the behavior of gitweb in many ways, and
+some optional features will not be present unless explicitly enabled using
+the configurable `%features` variable (see also "Configuring gitweb
+features" section below).
+
+
+CONFIGURATION VARIABLES
+-----------------------
+Some configuration variables have their default values (embedded in the CGI
+script) set during building gitweb -- if that is the case, this fact is put
+in their description.  See gitweb's 'INSTALL' file for instructions on building
+and installing gitweb.
+
+
+Location of repositories
+~~~~~~~~~~~~~~~~~~~~~~~~
+The configuration variables described below control how gitweb finds
+git repositories, and how repositories are displayed and accessed.
+
+See also "Repositories" and later subsections in linkgit:gitweb[1] manpage.
+
+$projectroot::
+       Absolute filesystem path which will be prepended to project path;
+       the path to repository is `$projectroot/$project`.  Set to
+       `$GITWEB_PROJECTROOT` during installation.  This variable has to be
+       set correctly for gitweb to find repositories.
++
+For example, if `$projectroot` is set to "/srv/git" by putting the following
+in gitweb config file:
++
+----------------------------------------------------------------------------
+our $projectroot = "/srv/git";
+----------------------------------------------------------------------------
++
+then
++
+------------------------------------------------
+http://git.example.com/gitweb.cgi?p=foo/bar.git
+------------------------------------------------
++
+and its path_info based equivalent
++
+------------------------------------------------
+http://git.example.com/gitweb.cgi/foo/bar.git
+------------------------------------------------
++
+will map to the path '/srv/git/foo/bar.git' on the filesystem.
+
+$projects_list::
+       Name of a plain text file listing projects, or a name of directory
+       to be scanned for projects.
++
+Project list files should list one project per line, with each line
+having the following format
++
+-----------------------------------------------------------------------------
+<URI-encoded filesystem path to repository> SP <URI-encoded repository owner>
+-----------------------------------------------------------------------------
++
+The default value of this variable is determined by the `GITWEB_LIST`
+makefile variable at installation time.  If this variable is empty, gitweb
+will fall back to scanning the `$projectroot` directory for repositories.
+
+$project_maxdepth::
+       If `$projects_list` variable is unset, gitweb will recursively
+       scan filesystem for git repositories.  The `$project_maxdepth`
+       is used to limit traversing depth, relative to `$projectroot`
+       (starting point); it means that directories which are further
+       from `$projectroot` than `$project_maxdepth` will be skipped.
++
+It is purely performance optimization, originally intended for MacOS X,
+where recursive directory traversal is slow.  Gitweb follows symbolic
+links, but it detects cycles, ignoring any duplicate files and directories.
++
+The default value of this variable is determined by the build-time
+configuration variable `GITWEB_PROJECT_MAXDEPTH`, which defaults to
+2007.
+
+$export_ok::
+       Show repository only if this file exists (in repository).  Only
+       effective if this variable evaluates to true.  Can be set when
+       building gitweb by setting `GITWEB_EXPORT_OK`.  This path is
+       relative to `GIT_DIR`.  git-daemon[1] uses 'git-daemon-export-ok',
+       unless started with `--export-all`.  By default this variable is
+       not set, which means that this feature is turned off.
+
+$export_auth_hook::
+       Function used to determine which repositories should be shown.
+       This subroutine should take one parameter, the full path to
+       a project, and if it returns true, that project will be included
+       in the projects list and can be accessed through gitweb as long
+       as it fulfills the other requirements described by $export_ok,
+       $projects_list, and $projects_maxdepth.  Example:
++
+----------------------------------------------------------------------------
+our $export_auth_hook = sub { return -e "$_[0]/git-daemon-export-ok"; };
+----------------------------------------------------------------------------
++
+though the above might be done by using `$export_ok` instead
++
+----------------------------------------------------------------------------
+our $export_ok = "git-daemon-export-ok";
+----------------------------------------------------------------------------
++
+If not set (default), it means that this feature is disabled.
++
+See also more involved example in "Controlling access to git repositories"
+subsection on linkgit:gitweb[1] manpage.
+
+$strict_export::
+       Only allow viewing of repositories also shown on the overview page.
+       This for example makes `$gitweb_export_ok` file decide if repository is
+       available and not only if it is shown.  If `$gitweb_list` points to
+       file with list of project, only those repositories listed would be
+       available for gitweb.  Can be set during building gitweb via
+       `GITWEB_STRICT_EXPORT`.  By default this variable is not set, which
+       means that you can directly access those repositories that are hidden
+       from projects list page (e.g. the are not listed in the $projects_list
+       file).
+
+
+Finding files
+~~~~~~~~~~~~~
+The following configuration variables tell gitweb where to find files.
+The values of these variables are paths on the filesystem.
+
+$GIT::
+       Core git executable to use.  By default set to `$GIT_BINDIR/git`, which
+       in turn is by default set to `$(bindir)/git`.  If you use git installed
+       from a binary package, you should usually set this to "/usr/bin/git".
+       This can just be "git" if your web server has a sensible PATH; from
+       security point of view it is better to use absolute path to git binary.
+       If you have multiple git versions installed it can be used to choose
+       which one to use.  Must be (correctly) set for gitweb to be able to
+       work.
+
+$mimetypes_file::
+       File to use for (filename extension based) guessing of MIME types before
+       trying '/etc/mime.types'.  *NOTE* that this path, if relative, is taken
+       as relative to the current git repository, not to CGI script.  If unset,
+       only '/etc/mime.types' is used (if present on filesystem).  If no mimetypes
+       file is found, mimetype guessing based on extension of file is disabled.
+       Unset by default.
+
+$highlight_bin::
+       Path to the highlight executable to use (it must be the one from
+       http://www.andre-simon.de[] due to assumptions about parameters and output).
+       By default set to 'highlight'; set it to full path to highlight
+       executable if it is not installed on your web server's PATH.
+       Note that 'highlight' feature must be set for gitweb to actually
+       use syntax hightlighting.
++
+*NOTE*: if you want to add support for new file type (supported by
+"highlight" but not used by gitweb), you need to modify `%highlight_ext`
+or `%highlight_basename`, depending on whether you detect type of file
+based on extension (for example "sh") or on its basename (for example
+"Makefile").  The keys of these hashes are extension and basename,
+respectively, and value for given key is name of syntax to be passed via
+`--syntax <syntax>` to highlighter.
++
+For example if repositories you are hosting use "phtml" extension for
+PHP files, and you want to have correct syntax-highlighting for those
+files, you can add the following to gitweb configuration:
++
+---------------------------------------------------------
+our %highlight_ext;
+$highlight_ext{'phtml'} = 'php';
+---------------------------------------------------------
+
+
+Links and their targets
+~~~~~~~~~~~~~~~~~~~~~~~
+The configuration variables described below configure some of gitweb links:
+their target and their look (text or image), and where to find page
+prerequisites (stylesheet, favicon, images, scripts).  Usually they are left
+at their default values, with the possible exception of `@stylesheets`
+variable.
+
+@stylesheets::
+       List of URIs of stylesheets (relative to the base URI of a page). You
+       might specify more than one stylesheet, for example to use "gitweb.css"
+       as base with site specific modifications in a separate stylesheet
+       to make it easier to upgrade gitweb.  For example, you can add
+       a `site` stylesheet by putting
++
+----------------------------------------------------------------------------
+push @stylesheets, "gitweb-site.css";
+----------------------------------------------------------------------------
++
+in the gitweb config file.  Those values that are relative paths are
+relative to base URI of gitweb.
++
+This list should contain the URI of gitweb's standard stylesheet.  The default
+URI of gitweb stylesheet can be set at build time using the `GITWEB_CSS`
+makefile variable.  Its default value is 'static/gitweb.css'
+(or 'static/gitweb.min.css' if the `CSSMIN` variable is defined,
+i.e. if CSS minifier is used during build).
++
+*Note*: there is also a legacy `$stylesheet` configuration variable, which was
+used by older gitweb.  If `$stylesheet` variable is defined, only CSS stylesheet
+given by this variable is used by gitweb.
+
+$logo::
+       Points to the location where you put 'git-logo.png' on your web
+       server, or to be more the generic URI of logo, 72x27 size).  This image
+       is displayed in the top right corner of each gitweb page and used as
+       a logo for the Atom feed.  Relative to the base URI of gitweb (as a path).
+       Can be adjusted when building gitweb using `GITWEB_LOGO` variable
+       By default set to 'static/git-logo.png'.
+
+$favicon::
+       Points to the location where you put 'git-favicon.png' on your web
+       server, or to be more the generic URI of favicon, which will be served
+       as "image/png" type.  Web browsers that support favicons (website icons)
+       may display them in the browser's URL bar and next to the site name in
+       bookmarks.  Relative to the base URI of gitweb.  Can be adjusted at
+       build time using `GITWEB_FAVICON` variable.
+       By default set to 'static/git-favicon.png'.
+
+$javascript::
+       Points to the location where you put 'gitweb.js' on your web server,
+       or to be more generic the URI of JavaScript code used by gitweb.
+       Relative to the base URI of gitweb.  Can be set at build time using
+       the `GITWEB_JS` build-time configuration variable.
++
+The default value is either 'static/gitweb.js', or 'static/gitweb.min.js' if
+the `JSMIN` build variable was defined, i.e. if JavaScript minifier was used
+at build time.  *Note* that this single file is generated from multiple
+individual JavaScript "modules".
+
+$home_link::
+       Target of the home link on the top of all pages (the first part of view
+       "breadcrumbs").  By default it is set to the absolute URI of a current page
+       (to the value of `$my_uri` variable, or to "/" if `$my_uri` is undefined
+       or is an empty string).
+
+$home_link_str::
+       Label for the "home link" at the top of all pages, leading to `$home_link`
+       (usually the main gitweb page, which contains the projects list).  It is
+       used as the first component of gitweb's "breadcrumb trail":
+       `<home link> / <project> / <action>`.  Can be set at build time using
+       the `GITWEB_HOME_LINK_STR` variable.  By default it is set to "projects",
+       as this link leads to the list of projects.  Other popular choice it to
+       set it to the name of site.
+
+$logo_url::
+$logo_label::
+       URI and label (title) for the Git logo link (or your site logo,
+       if you chose to use different logo image). By default, these both
+       refer to git homepage, http://git-scm.com[]; in the past, they pointed
+       to git documentation at http://www.kernel.org[].
+
+
+Changing gitweb's look
+~~~~~~~~~~~~~~~~~~~~~~
+You can adjust how pages generated by gitweb look using the variables described
+below.  You can change the site name, add common headers and footers for all
+pages, and add a description of this gitweb installation on its main page
+(which is the projects list page), etc.
+
+$site_name::
+       Name of your site or organization, to appear in page titles.  Set it
+       to something descriptive for clearer bookmarks etc.  If this variable
+       is not set or is, then gitweb uses the value of the `SERVER_NAME`
+       CGI environment variable, setting site name to "$SERVER_NAME Git",
+       or "Untitled Git" if this variable is not set (e.g. if running gitweb
+       as standalone script).
++
+Can be set using the `GITWEB_SITENAME` at build time.  Unset by default.
+
+$site_header::
+       Name of a file with HTML to be included at the top of each page.
+       Relative to the directory containing the 'gitweb.cgi' script.
+       Can be set using `GITWEB_SITE_HEADER` at build time.  No default
+       value.
+
+$site_footer::
+       Name of a file with HTML to be included at the bottom of each page.
+       Relative to the directory containing the 'gitweb.cgi' script.
+       Can be set using `GITWEB_SITE_FOOTER` at build time.  No default
+       value.
+
+$home_text::
+       Name of a HTML file which, if it exists, is included on the
+       gitweb projects overview page ("projects_list" view).  Relative to
+       the directory containing the gitweb.cgi script.  Default value
+       can be adjusted during build time using `GITWEB_HOMETEXT` variable.
+       By default set to 'indextext.html'.
+
+$projects_list_description_width::
+       The width (in characters) of the "Description" column of the projects list.
+       Longer descriptions will be truncated (trying to cut at word boundary);
+       the full description is available in the 'title' attribute (usually shown on
+       mouseover).  The default is 25, which might be too small if you
+       use long project descriptions.
+
+$default_projects_order::
+       Default value of ordering of projects on projects list page, which
+       means the ordering used if you don't explicitly sort projects list
+       (if there is no "o" CGI query parameter in the URL).  Valid values
+       are "none" (unsorted), "project" (projects are by project name,
+       i.e. path to repository relative to `$projectroot`), "descr"
+       (project description), "owner", and "age" (by date of most current
+       commit).
++
+Default value is "project".  Unknown value means unsorted.
+
+
+Changing gitweb's behavior
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+These configuration variables control _internal_ gitweb behavior.
+
+$default_blob_plain_mimetype::
+       Default mimetype for the blob_plain (raw) view, if mimetype checking
+       doesn't result in some other type; by default "text/plain".
+       Gitweb guesses mimetype of a file to display based on extension
+       of its filename, using `$mimetypes_file` (if set and file exists)
+       and '/etc/mime.types' files (see *mime.types*(5) manpage; only
+       filename extension rules are supported by gitweb).
+
+$default_text_plain_charset::
+       Default charset for text files. If this is not set, the web server
+       configuration will be used.  Unset by default.
+
+$fallback_encoding::
+       Gitweb assumes this charset when a line contains non-UTF-8 characters.
+       The fallback decoding is used without error checking, so it can be even
+       "utf-8". The value must be a valid encoding; see the *Encoding::Supported*(3pm)
+       man page for a list. The default is "latin1", aka. "iso-8859-1".
+
+@diff_opts::
+       Rename detection options for git-diff and git-diff-tree. The default is
+       (\'-M'); set it to (\'-C') or (\'-C', \'-C') to also detect copies,
+       or set it to () i.e. empty list if you don't want to have renames
+       detection.
++
+*Note* that rename and especially copy detection can be quite
+CPU-intensive.  Note also that non git tools can have problems with
+patches generated with options mentioned above, especially when they
+involve file copies (\'-C') or criss-cross renames (\'-B').
+
+
+Some optional features and policies
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Most of features are configured via `%feature` hash; however some of extra
+gitweb features can be turned on and configured using variables described
+below.  This list beside configuration variables that control how gitweb
+looks does contain variables configuring administrative side of gitweb
+(e.g. cross-site scripting prevention; admittedly this as side effect
+affects how "summary" pages look like, or load limiting).
+
+@git_base_url_list::
+       List of git base URLs.  These URLs are used to generate URLs
+       describing from where to fetch a project, which are shown on
+       project summary page.  The full fetch URL is "`$git_base_url/$project`",
+       for each element of this list. You can set up multiple base URLs
+       (for example one for `git://` protocol, and one for `http://`
+       protocol).
++
+Note that per repository configuration can be set in '$GIT_DIR/cloneurl'
+file, or as values of multi-value `gitweb.url` configuration variable in
+project config.  Per-repository configuration takes precedence over value
+composed from `@git_base_url_list` elements and project name.
++
+You can setup one single value (single entry/item in this list) at build
+time by setting the `GITWEB_BASE_URL` built-time configuration variable.
+By default it is set to (), i.e. an empty list.  This means that gitweb
+would not try to create project URL (to fetch) from project name.
+
+$projects_list_group_categories::
+       Whether to enables the grouping of projects by category on the project
+       list page. The category of a project is determined by the
+       `$GIT_DIR/category` file or the `gitweb.category` variable in each
+       repository's configuration.  Disabled by default (set to 0).
+
+$project_list_default_category::
+       Default category for projects for which none is specified.  If this is
+       set to the empty string, such projects will remain uncategorized and
+       listed at the top, above categorized projects.  Used only if project
+       categories are enabled, which means if `$projects_list_group_categories`
+       is true.  By default set to "" (empty string).
+
+$prevent_xss::
+       If true, some gitweb features are disabled to prevent content in
+       repositories from launching cross-site scripting (XSS) attacks.  Set this
+       to true if you don't trust the content of your repositories.
+       False by default (set to 0).
+
+$maxload::
+       Used to set the maximum load that we will still respond to gitweb queries.
+       If the server load exceeds this value then gitweb will return
+       "503 Service Unavailable" error.  The server load is taken to be 0
+       if gitweb cannot determine its value.  Currently it works only on Linux,
+       where it uses '/proc/loadavg'; the load there is the number of active
+       tasks on the system -- processes that are actually running -- averaged
+       over the last minute.
++
+Set `$maxload` to undefined value (`undef`) to turn this feature off.
+The default value is 300.
+
+$per_request_config::
+       If this is set to code reference, it will be run once for each request.
+       You can set parts of configuration that change per session this way.
+       For example, one might use the following code in a gitweb configuration
+       file
++
+--------------------------------------------------------------------------------
+our $per_request_config = sub {
+       $ENV{GL_USER} = $cgi->remote_user || "gitweb";
+};
+--------------------------------------------------------------------------------
++
+If `$per_request_config` is not a code reference, it is interpreted as boolean
+value.  If it is true gitweb will process config files once per request,
+and if it is false gitweb will process config files only once, each time it
+is executed.  True by default (set to 1).
++
+*NOTE*: `$my_url`, `$my_uri`, and `$base_url` are overwritten with their default
+values before every request, so if you want to change them, be sure to set
+this variable to true or a code reference effecting the desired changes.
++
+This variable matters only when using persistent web environments that
+serve multiple requests using single gitweb instance, like mod_perl,
+FastCGI or Plackup.
+
+
+Other variables
+~~~~~~~~~~~~~~~
+Usually you should not need to change (adjust) any of configuration
+variables described below; they should be automatically set by gitweb to
+correct value.
+
+
+$version::
+       Gitweb version, set automatically when creating gitweb.cgi from
+       gitweb.perl. You might want to modify it if you are running modified
+       gitweb, for example
++
+---------------------------------------------------
+our $version .= " with caching";
+---------------------------------------------------
++
+if you run modified version of gitweb with caching support.  This variable
+is purely informational, used e.g. in the "generator" meta header in HTML
+header.
+
+$my_url::
+$my_uri::
+       Full URL and absolute URL of the gitweb script;
+       in earlier versions of gitweb you might have need to set those
+       variables, but now there should be no need to do it.  See
+       `$per_request_config` if you need to set them still.
+
+$base_url::
+       Base URL for relative URLs in pages generated by gitweb,
+       (e.g. `$logo`, `$favicon`, `@stylesheets` if they are relative URLs),
+       needed and used '<base href="$base_url">' only for URLs with nonempty
+       PATH_INFO.  Usually gitweb sets its value correctly,
+       and there is no need to set this variable, e.g. to $my_uri or "/".
+       See `$per_request_config` if you need to override it anyway.
+
+
+CONFIGURING GITWEB FEATURES
+---------------------------
+Many gitweb features can be enabled (or disabled) and configured using the
+`%feature` hash.  Names of gitweb features are keys of this hash.
+
+Each `%feature` hash element is a hash reference and has the following
+structure:
+----------------------------------------------------------------------
+"<feature_name>" => {
+       "sub" => <feature-sub (subroutine)>,
+       "override" => <allow-override (boolean)>,
+       "default" => [ <options>... ]
+},
+----------------------------------------------------------------------
+Some features cannot be overridden per project.  For those
+features the structure of appropriate `%feature` hash element has a simpler
+form:
+----------------------------------------------------------------------
+"<feature_name>" => {
+       "override" => 0,
+       "default" => [ <options>... ]
+},
+----------------------------------------------------------------------
+As one can see it lacks the \'sub' element.
+
+The meaning of each part of feature configuration is described
+below:
+
+default::
+       List (array reference) of feature parameters (if there are any),
+       used also to toggle (enable or disable) given feature.
++
+Note that it is currently *always* an array reference, even if
+feature doesn't accept any configuration parameters, and \'default'
+is used only to turn it on or off.  In such case you turn feature on
+by setting this element to `[1]`, and torn it off by setting it to
+`[0]`.  See also the passage about the "blame" feature in the "Examples"
+section.
++
+To disable features that accept parameters (are configurable), you
+need to set this element to empty list i.e. `[]`.
+
+override::
+       If this field has a true value then the given feature is
+       overriddable, which means that it can be configured
+       (or enabled/disabled) on a per-repository basis.
++
+Usually given "<feature>" is configurable via the `gitweb.<feature>`
+config variable in the per-repository git configuration file.
++
+*Note* that no feature is overriddable by default.
+
+sub::
+       Internal detail of implementation.  What is important is that
+       if this field is not present then per-repository override for
+       given feature is not supported.
++
+You wouldn't need to ever change it in gitweb config file.
+
+
+Features in `%feature`
+~~~~~~~~~~~~~~~~~~~~~~
+The gitweb features that are configurable via `%feature` hash are listed
+below.  This should be a complete list, but ultimately the authoritative
+and complete list is in gitweb.cgi source code, with features described
+in the comments.
+
+blame::
+       Enable the "blame" and "blame_incremental" blob views, showing for
+       each line the last commit that modified it; see linkgit:git-blame[1].
+       This can be very CPU-intensive and is therefore disabled by default.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.blame` configuration variable (boolean).
+
+snapshot::
+       Enable and configure the "snapshot" action, which allows user to
+       download a compressed archive of any tree or commit, as produced
+       by linkgit:git-archive[1] and possibly additionally compressed.
+       This can potentially generate high traffic if you have large project.
++
+The value of \'default' is a list of names of snapshot formats,
+defined in `%known_snapshot_formats` hash, that you wish to offer.
+Supported formats include "tgz", "tbz2", "txz" (gzip/bzip2/xz
+compressed tar archive) and "zip"; please consult gitweb sources for
+a definitive list.  By default only "tgz" is offered.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.blame` configuration variable, which contains
+a comma separated list of formats or "none" to disable snapshots.
+Unknown values are ignored.
+
+grep::
+       Enable grep search, which lists the files in currently selected
+       tree (directory) containing the given string; see linkgit:git-grep[1].
+       This can be potentially CPU-intensive, of course.  Enabled by default.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.grep` configuration variable (boolean).
+
+pickaxe::
+       Enable the so called pickaxe search, which will list the commits
+       that introduced or removed a given string in a file.  This can be
+       practical and quite faster alternative to "blame" action, but it is
+       still potentially CPU-intensive.  Enabled by default.
++
+The pickaxe search is described in linkgit:git-log[1] (the
+description of `-S<string>` option, which refers to pickaxe entry in
+linkgit:gitdiffcore[7] for more details).
++
+This feature can be configured on a per-repository basis by setting
+repository's `gitweb.pickaxe` configuration variable (boolean).
+
+show-sizes::
+       Enable showing size of blobs (ordinary files) in a "tree" view, in a
+       separate column, similar to what `ls -l` does; see description of
+       `-l` option in linkgit:git-ls-tree[1] manpage.  This costs a bit of
+       I/O.  Enabled by default.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.showsizes` configuration variable (boolean).
+
+patches::
+       Enable and configure "patches" view, which displays list of commits in email
+       (plain text) output format; see also linkgit:git-format-patch[1].
+       The value is the maximum number of patches in a patchset generated
+       in "patches" view.  Set the 'default' field to a list containing single
+       item of or to an empty list to disable patch view, or to a list
+       containing a single negative number to remove any limit.
+       Default value is 16.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.patches` configuration variable (integer).
+
+avatar::
+       Avatar support.  When this feature is enabled, views such as
+       "shortlog" or "commit" will display an avatar associated with
+       the email of each committer and author.
++
+Currently available providers are *"gravatar"* and *"picon"*.
+Only one provider at a time can be selected ('default' is one element list).
+If an unknown provider is specified, the feature is disabled.
+*Note* that some providers might require extra Perl packages to be
+installed; see 'gitweb/INSTALL' for more details.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.avatar` configuration variable.
++
+See also `%avatar_size` with pixel sizes for icons and avatars
+("default" is used for one-line like "log" and "shortlog", "double"
+is used for two-line like "commit", "commitdiff" or "tag").  If the
+default font sizes or lineheights are changed (e.g. via adding extra
+CSS stylesheet in `@stylesheets`), it may be appropriate to change
+these values.
+
+highlight::
+       Server-side syntax highlight support in "blob" view.  It requires
+       `$highlight_bin` program to be available (see the description of
+       this variable in the "Configuration variables" section above),
+       and therefore is disabled by default.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.highlight` configuration variable (boolean).
+
+remote_heads::
+       Enable displaying remote heads (remote-tracking branches) in the "heads"
+       list.  In most cases the list of remote-tracking branches is an
+       unnecessary internal private detail, and this feature is therefore
+       disabled by default.  linkgit:git-instaweb[1], which is usually used
+       to browse local repositories, enables and uses this feature.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.remote_heads` configuration variable (boolean).
+
+
+The remaining features cannot be overridden on a per project basis.
+
+search::
+       Enable text search, which will list the commits which match author,
+       committer or commit text to a given string; see the description of
+       `--author`, `--committer` and `--grep` options in linkgit:git-log[1]
+       manpage.  Enabled by default.
++
+Project specific override is not supported.
+
+forks::
+       If this feature is enabled, gitweb considers projects in
+       subdirectories of project root (basename) to be forks of existing
+       projects.  For each project `$projname.git`, projects in the
+       `$projname/` directory and its subdirectories will not be
+       shown in the main projects list.  Instead, a \'+' mark is shown
+       next to `$projname`, which links to a "forks" view that lists all
+       the forks (all projects in `$projname/` subdirectory).  Additionally
+       a "forks" view for a project is linked from project summary page.
++
+If the project list is taken from a file (`$projects_list` points to a
+file), forks are only recognized if they are listed after the main project
+in that file.
++
+Project specific override is not supported.
+
+actions::
+       Insert custom links to the action bar of all project pages.  This
+       allows you to link to third-party scripts integrating into gitweb.
++
+The "default" value consists of a list of triplets in the form
+`("<label>", "<link>", "<position>")` where "position" is the label
+after which to insert the link, "link" is a format string where `%n`
+expands to the project name, `%f` to the project path within the
+filesystem (i.e. "$projectroot/$project"), `%h` to the current hash
+(\'h' gitweb parameter) and `%b` to the current hash base
+(\'hb' gitweb parameter); `%%` expands to \'%'.
++
+For example, at the time this page was written, the http://repo.or.cz[]
+git hosting site set it to the following to enable graphical log
+(using the third party tool *git-browser*):
++
+----------------------------------------------------------------------
+$feature{'actions'}{'default'} =
+       [ ('graphiclog', '/git-browser/by-commit.html?r=%n', 'summary')];
+----------------------------------------------------------------------
++
+This adds a link titled "graphiclog" after the "summary" link, leading to
+`git-browser` script, passing `r=<project>` as a query parameter.
++
+Project specific override is not supported.
+
+timed::
+       Enable displaying how much time and how many git commands it took to
+       generate and display each page in the page footer (at the bottom of
+       page).  For example the footer might contain: "This page took 6.53325
+       seconds and 13 git commands to generate."  Disabled by default.
++
+Project specific override is not supported.
+
+javascript-timezone::
+       Enable and configure the ability to change a common timezone for dates
+       in gitweb output via JavaScript.  Dates in gitweb output include
+       authordate and committerdate in "commit", "commitdiff" and "log"
+       views, and taggerdate in "tag" view.  Enabled by default.
++
+The value is a list of three values: a default timezone (for if the client
+hasn't selected some other timezone and saved it in a cookie), a name of cookie
+where to store selected timezone, and a CSS class used to mark up
+dates for manipulation.  If you want to turn this feature off, set "default"
+to empty list: `[]`.
++
+Typical gitweb config files will only change starting (default) timezone,
+and leave other elements at their default values:
++
+---------------------------------------------------------------------------
+$feature{'javascript-timezone'}{'default'}[0] = "utc";
+---------------------------------------------------------------------------
++
+The example configuration presented here is guaranteed to be backwards
+and forward compatible.
++
+Timezone values can be "local" (for local timezone that browser uses), "utc"
+(what gitweb uses when JavaScript or this feature is disabled), or numerical
+timezones in the form of "+/-HHMM", such as "+0200".
++
+Project specific override is not supported.
+
+
+EXAMPLES
+--------
+
+To enable blame, pickaxe search, and snapshot support (allowing "tar.gz" and
+"zip" snapshots), while allowing individual projects to turn them off, put
+the following in your GITWEB_CONFIG file:
+
+       $feature{'blame'}{'default'} = [1];
+       $feature{'blame'}{'override'} = 1;
+
+       $feature{'pickaxe'}{'default'} = [1];
+       $feature{'pickaxe'}{'override'} = 1;
+
+       $feature{'snapshot'}{'default'} = ['zip', 'tgz'];
+       $feature{'snapshot'}{'override'} = 1;
+
+If you allow overriding for the snapshot feature, you can specify which
+snapshot formats are globally disabled. You can also add any command line
+options you want (such as setting the compression level). For instance, you
+can disable Zip compressed snapshots and set *gzip*(1) to run at level 6 by
+adding the following lines to your gitweb configuration file:
+
+       $known_snapshot_formats{'zip'}{'disabled'} = 1;
+       $known_snapshot_formats{'tgz'}{'compressor'} = ['gzip','-6'];
+
+ENVIRONMENT
+-----------
+The location of per-instance and system-wide configuration files can be
+overridden using the following environment variables:
+
+GITWEB_CONFIG::
+       Sets location of per-instance configuration file.
+GITWEB_CONFIG_SYSTEM::
+       Sets location of fallback system-wide configuration file.
+       This file is read only if per-instance one does not exist.
+GITWEB_CONFIG_COMMON::
+       Sets location of common system-wide configuration file.
+
+
+FILES
+-----
+gitweb_config.perl::
+       This is default name of per-instance configuration file.  The
+       format of this file is described above.
+/etc/gitweb.conf::
+       This is default name of fallback system-wide configuration
+       file.  This file is used only if per-instance configuration
+       variable is not found.
+/etc/gitweb-common.conf::
+       This is default name of common system-wide configuration
+       file.
+
+
+SEE ALSO
+--------
+linkgit:gitweb[1], linkgit:git-instaweb[1]
+
+'gitweb/README', 'gitweb/INSTALL'
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitweb.txt b/Documentation/gitweb.txt
new file mode 100644 (file)
index 0000000..605a085
--- /dev/null
@@ -0,0 +1,704 @@
+gitweb(1)
+=========
+
+NAME
+----
+gitweb - Git web interface (web frontend to Git repositories)
+
+SYNOPSIS
+--------
+To get started with gitweb, run linkgit:git-instaweb[1] from a git repository.
+This would configure and start your web server, and run web browser pointing to
+gitweb.
+
+
+DESCRIPTION
+-----------
+Gitweb provides a web interface to git repositories.  It's features include:
+
+* Viewing multiple Git repositories with common root.
+* Browsing every revision of the repository.
+* Viewing the contents of files in the repository at any revision.
+* Viewing the revision log of branches, history of files and directories,
+  see what was changed when, by who.
+* Viewing the blame/annotation details of any file (if enabled).
+* Generating RSS and Atom feeds of commits, for any branch.
+  The feeds are auto-discoverable in modern web browsers.
+* Viewing everything that was changed in a revision, and step through
+  revisions one at a time, viewing the history of the repository.
+* Finding commits which commit messages matches given search term.
+
+See http://git.kernel.org/?p=git/git.git;a=tree;f=gitweb[] or
+http://repo.or.cz/w/git.git/tree/HEAD:/gitweb/[] for gitweb source code,
+browsed using gitweb itself.
+
+
+CONFIGURATION
+-------------
+Various aspects of gitweb's behavior can be controlled through the configuration
+file 'gitweb_config.perl' or '/etc/gitweb.conf'.  See the linkgit:gitweb.conf[5]
+for details.
+
+Repositories
+~~~~~~~~~~~~
+Gitweb can show information from one or more Git repositories.  These
+repositories have to be all on local filesystem, and have to share common
+repository root, i.e. be all under a single parent repository (but see also
+"Advanced web server setup" section, "Webserver configuration with multiple
+projects' root" subsection).
+
+-----------------------------------------------------------------------
+our $projectroot = '/path/to/parent/directory';
+-----------------------------------------------------------------------
+
+The default value for `$projectroot` is '/pub/git'.  You can change it during
+building gitweb via `GITWEB_PROJECTROOT` build configuration variable.
+
+By default all git repositories under `$projectroot` are visible and available
+to gitweb.  The list of projects is generated by default by scanning the
+`$projectroot` directory for git repositories (for object databases to be
+more exact; gitweb is not interested in a working area, and is best suited
+to showing "bare" repositories).
+
+The name of repository in gitweb is path to it's `$GIT_DIR` (it's object
+database) relative to `$projectroot`.  Therefore the repository $repo can be
+found at "$projectroot/$repo".
+
+
+Projects list file format
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Instead of having gitweb find repositories by scanning filesystem
+starting from $projectroot, you can provide a pre-generated list of
+visible projects by setting `$projects_list` to point to a plain text
+file with a list of projects (with some additional info).
+
+This file uses the following format:
+
+* One record (for project / repository) per line; does not support line
+continuation (newline escaping).
+
+* Leading and trailing whitespace are ignored.
+
+* Whitespace separated fields; any run of whitespace can be used as field
+separator (rules for Perl's "`split(" ", $line)`").
+
+* Fields use modified URI encoding, defined in RFC 3986, section 2.1
+(Percent-Encoding), or rather "Query string encoding" (see
+link:http://en.wikipedia.org/wiki/Query_string#URL_encoding[]), the difference
+being that SP (" ") can be encoded as "{plus}" (and therefore "{plus}" has to be
+also percent-encoded).
++
+Reserved characters are: "%" (used for encoding), "{plus}" (can be used to
+encode SPACE), all whitespace characters as defined in Perl, including SP,
+TAB and LF, (used to separate fields in a record).
+
+* Currently recognized fields are:
+<repository path>::
+       path to repository GIT_DIR, relative to `$projectroot`
+<repository owner>::
+       displayed as repository owner, preferably full name, or email,
+       or both
+
+You can generate the projects list index file using the project_index action
+(the 'TXT' link on projects list page) directly from gitweb; see also
+"Generating projects list using gitweb" section below.
+
+Example contents:
+-----------------------------------------------------------------------
+foo.git       Joe+R+Hacker+<joe@example.com>
+foo/bar.git   O+W+Ner+<owner@example.org>
+-----------------------------------------------------------------------
+
+
+By default this file controls only which projects are *visible* on projects
+list page (note that entries that do not point to correctly recognized git
+repositories won't be displayed by gitweb).  Even if a project is not
+visible on projects list page, you can view it nevertheless by hand-crafting
+a gitweb URL.  By setting `$strict_export` configuration variable (see
+linkgit:gitweb.conf[5]) to true value you can allow viewing only of
+repositories also shown on the overview page (i.e. only projects explicitly
+listed in projects list file will be accessible).
+
+
+Generating projects list using gitweb
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We assume that GITWEB_CONFIG has its default Makefile value, namely
+'gitweb_config.perl'. Put the following in 'gitweb_make_index.perl' file:
+----------------------------------------------------------------------------
+read_config_file("gitweb_config.perl");
+$projects_list = $projectroot;
+----------------------------------------------------------------------------
+
+Then create the following script to get list of project in the format
+suitable for GITWEB_LIST build configuration variable (or
+`$projects_list` variable in gitweb config):
+
+----------------------------------------------------------------------------
+#!/bin/sh
+
+export GITWEB_CONFIG="gitweb_make_index.perl"
+export GATEWAY_INTERFACE="CGI/1.1"
+export HTTP_ACCEPT="*/*"
+export REQUEST_METHOD="GET"
+export QUERY_STRING="a=project_index"
+
+perl -- /var/www/cgi-bin/gitweb.cgi
+----------------------------------------------------------------------------
+
+Run this script and save its output to a file.  This file could then be used
+as projects list file, which means that you can set `$projects_list` to its
+filename.
+
+
+Controlling access to git repositories
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+By default all git repositories under `$projectroot` are visible and
+available to gitweb.  You can however configure how gitweb controls access
+to repositories.
+
+* As described in "Projects list file format" section, you can control which
+projects are *visible* by selectively including repositories in projects
+list file, and setting `$projects_list` gitweb configuration variable to
+point to it.  With `$strict_export` set, projects list file can be used to
+control which repositories are *available* as well.
+
+* You can configure gitweb to only list and allow viewing of the explicitly
+exported repositories, via `$export_ok` variable in gitweb config file; see
+linkgit:gitweb.conf[5] manpage.  If it evaluates to true, gitweb shows
+repositories only if this file named by `$export_ok` exists in its object
+database (if directory has the magic file named `$export_ok`).
++
+For example linkgit:git-daemon[1] by default (unless `--export-all` option
+is used) allows pulling only for those repositories that have
+'git-daemon-export-ok' file.  Adding
++
+--------------------------------------------------------------------------
+our $export_ok = "git-daemon-export-ok";
+--------------------------------------------------------------------------
++
+makes gitweb show and allow access only to those repositories that can be
+fetched from via `git://` protocol.
+
+* Finally, it is possible to specify an arbitrary perl subroutine that will
+be called for each repository to determine if it can be exported.  The
+subroutine receives an absolute path to the project (repository) as its only
+parameter (i.e. "$projectroot/$project").
++
+For example, if you use mod_perl to run the script, and have dumb
+HTTP protocol authentication configured for your repositories, you
+can use the following hook to allow access only if the user is
+authorized to read the files:
++
+--------------------------------------------------------------------------
+$export_auth_hook = sub {
+       use Apache2::SubRequest ();
+       use Apache2::Const -compile => qw(HTTP_OK);
+       my $path = "$_[0]/HEAD";
+       my $r    = Apache2::RequestUtil->request;
+       my $sub  = $r->lookup_file($path);
+       return $sub->filename eq $path
+           && $sub->status == Apache2::Const::HTTP_OK;
+};
+--------------------------------------------------------------------------
+
+
+Per-repository gitweb configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can configure individual repositories shown in gitweb by creating file
+in the 'GIT_DIR' of git repository, or by setting some repo configuration
+variable (in 'GIT_DIR/config', see linkgit:git-config[1]).
+
+You can use the following files in repository:
+
+README.html::
+       A html file (HTML fragment) which is included on the gitweb project
+       "summary" page inside `<div>` block element. You can use it for longer
+       description of a project, to provide links (for example to project's
+       homepage), etc. This is recognized only if XSS prevention is off
+       (`$prevent_xss` is false, see linkgit:gitweb.conf[5]); a way to include
+       a README safely when XSS prevention is on may be worked out in the
+       future.
+
+description (or `gitweb.description`)::
+       Short (shortened to `$projects_list_description_width` in the projects
+       list page, which is 25 characters by default; see
+       linkgit:gitweb.conf[5]) single line description of a project (of a
+       repository).  Plain text file; HTML will be escaped.  By default set to
++
+-------------------------------------------------------------------------------
+Unnamed repository; edit this file to name it for gitweb.
+-------------------------------------------------------------------------------
++
+from the template during repository creation, usually installed in
+'/usr/share/git-core/templates/'.  You can use the `gitweb.description` repo
+configuration variable, but the file takes precedence.
+
+category (or `gitweb.category`)::
+       Singe line category of a project, used to group projects if
+       `$projects_list_group_categories` is enabled.  By default (file and
+       configuration variable absent), uncategorized projects are put in the
+       `$project_list_default_category` category.  You can use the
+       `gitweb.category` repo configuration variable, but the file takes
+       precedence.
++
+The configuration variables `$projects_list_group_categories` and
+`$project_list_default_category` are described in linkgit:gitweb.conf[5]
+
+cloneurl (or multiple-valued `gitweb.url`)::
+       File with repository URL (used for clone and fetch), one per line.
+       Displayed in the project summary page. You can use multiple-valued
+       `gitweb.url` repository configuration variable for that, but the file
+       takes precedence.
++
+This is per-repository enhancement / version of global prefix-based
+`@git_base_url_list` gitweb configuration variable (see
+linkgit:gitweb.conf[5]).
+
+gitweb.owner::
+       You can use the `gitweb.owner` repository configuration variable to set
+       repository's owner.  It is displayed in the project list and summary
+       page.
++
+If it's not set, filesystem directory's owner is used (via GECOS field,
+i.e. real name field from *getpwuid*(3)) if `$projects_list` is unset
+(gitweb scans `$projectroot` for repositories); if `$projects_list`
+points to file with list of repositories, then project owner defaults to
+value from this file for given repository.
+
+various `gitweb.*` config variables (in config)::
+       Read description of `%feature` hash for detailed list, and descriptions.
+       See also "Configuring gitweb features" section in linkgit:gitweb.conf[5]
+
+
+ACTIONS, AND URLS
+-----------------
+Gitweb can use path_info (component) based URLs, or it can pass all necessary
+information via query parameters.  The typical gitweb URLs are broken down in to
+five components:
+
+-----------------------------------------------------------------------
+.../gitweb.cgi/<repo>/<action>/<revision>:/<path>?<arguments>
+-----------------------------------------------------------------------
+
+repo::
+       The repository the action will be performed on.
++
+All actions except for those that list all available projects,
+in whatever form, require this parameter.
+
+action::
+       The action that will be run.  Defaults to 'projects_list' if repo
+       is not set, and to 'summary' otherwise.
+
+revision::
+       Revision shown.  Defaults to HEAD.
+
+path::
+       The path within the <repository> that the action is performed on,
+       for those actions that require it.
+
+arguments::
+       Any arguments that control the behaviour of the action.
+
+Some actions require or allow to specify two revisions, and sometimes even two
+pathnames.  In most general form such path_info (component) based gitweb URL
+looks like this:
+
+-----------------------------------------------------------------------
+.../gitweb.cgi/<repo>/<action>/<revision_from>:/<path_from>..<revision_to>:/<path_to>?<arguments>
+-----------------------------------------------------------------------
+
+
+Each action is implemented as a subroutine, and must be present in %actions
+hash.  Some actions are disabled by default, and must be turned on via feature
+mechanism.  For example to enable 'blame' view add the following to gitweb
+configuration file:
+
+-----------------------------------------------------------------------
+$feature{'blame'}{'default'} = [1];
+-----------------------------------------------------------------------
+
+
+Actions:
+~~~~~~~~
+The standard actions are:
+
+project_list::
+       Lists the available Git repositories.  This is the default command if no
+       repository is specified in the URL.
+
+summary::
+       Displays summary about given repository.  This is the default command if
+       no action is specified in URL, and only repository is specified.
+
+heads::
+remotes::
+       Lists all local or all remote-tracking branches in given repository.
++
+The latter is not available by default, unless configured.
+
+tags::
+       List all tags (lightweight and annotated) in given repository.
+
+blob::
+tree::
+       Shows the files and directories in a given repository path, at given
+       revision.  This is default command if no action is specified in the URL,
+       and path is given.
+
+blob_plain::
+       Returns the raw data for the file in given repository, at given path and
+       revision.  Links to this action are marked 'raw'.
+
+blobdiff::
+       Shows the difference between two revisions of the same file.
+
+blame::
+blame_incremental::
+       Shows the blame (also called annotation) information for a file. On a
+       per line basis it shows the revision in which that line was last changed
+       and the user that committed the change.  The incremental version (which
+       if configured is used automatically when JavaScript is enabled) uses
+       Ajax to incrementally add blame info to the contents of given file.
++
+This action is disabled by default for performance reasons.
+
+commit::
+commitdiff::
+       Shows information about a specific commit in a repository.  The 'commit'
+       view shows information about commit in more detail, the 'commitdiff'
+       action shows changeset for given commit.
+
+patch::
+       Returns the commit in plain text mail format, suitable for applying with
+       linkgit:git-am[1].
+
+tag::
+       Display specific annotated tag (tag object).
+
+log::
+shortlog::
+       Shows log information (commit message or just commit subject) for a
+       given branch (starting from given revision).
++
+The 'shortlog' view is more compact; it shows one commit per line.
+
+history::
+       Shows history of the file or directory in a given repository path,
+       starting from given revision (defaults to HEAD, i.e. default branch).
++
+This view is similar to 'shortlog' view.
+
+rss::
+atom::
+       Generates an RSS (or Atom) feed of changes to repository.
+
+
+WEBSERVER CONFIGURATION
+-----------------------
+This section explains how to configure some common webservers to run gitweb. In
+all cases, `/path/to/gitweb` in the examples is the directory you ran installed
+gitweb in, and contains `gitweb_config.perl`.
+
+If you've configured a web server that isn't listed here for gitweb, please send
+in the instructions so they can be included in a future release.
+
+Apache as CGI
+~~~~~~~~~~~~~
+Apache must be configured to support CGI scripts in the directory in
+which gitweb is installed.  Let's assume that it is '/var/www/cgi-bin'
+directory.
+
+-----------------------------------------------------------------------
+ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
+
+<Directory "/var/www/cgi-bin">
+    Options Indexes FollowSymlinks ExecCGI
+    AllowOverride None
+    Order allow,deny
+    Allow from all
+</Directory>
+-----------------------------------------------------------------------
+
+With that configuration the full path to browse repositories would be:
+
+  http://server/cgi-bin/gitweb.cgi
+
+Apache with mod_perl, via ModPerl::Registry
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can use mod_perl with gitweb.  You must install Apache::Registry
+(for mod_perl 1.x) or ModPerl::Registry (for mod_perl 2.x) to enable
+this support.
+
+Assuming that gitweb is installed to '/var/www/perl', the following
+Apache configuration (for mod_perl 2.x) is suitable.
+
+-----------------------------------------------------------------------
+Alias /perl "/var/www/perl"
+
+<Directory "/var/www/perl">
+    SetHandler perl-script
+    PerlResponseHandler ModPerl::Registry
+    PerlOptions +ParseHeaders
+    Options Indexes FollowSymlinks +ExecCGI
+    AllowOverride None
+    Order allow,deny
+    Allow from all
+</Directory>
+-----------------------------------------------------------------------
+
+With that configuration the full path to browse repositories would be:
+
+  http://server/perl/gitweb.cgi
+
+Apache with FastCGI
+~~~~~~~~~~~~~~~~~~~
+Gitweb works with Apache and FastCGI.  First you need to rename, copy
+or symlink gitweb.cgi to gitweb.fcgi.  Let's assume that gitweb is
+installed in '/usr/share/gitweb' directory.  The following Apache
+configuration is suitable (UNTESTED!)
+
+-----------------------------------------------------------------------
+FastCgiServer /usr/share/gitweb/gitweb.cgi
+ScriptAlias /gitweb /usr/share/gitweb/gitweb.cgi
+
+Alias /gitweb/static /usr/share/gitweb/static
+<Directory /usr/share/gitweb/static>
+    SetHandler default-handler
+</Directory>
+-----------------------------------------------------------------------
+
+With that configuration the full path to browse repositories would be:
+
+  http://server/gitweb
+
+
+ADVANCED WEB SERVER SETUP
+-------------------------
+All of those examples use request rewriting, and need `mod_rewrite`
+(or equivalent; examples below are written for Apache).
+
+Single URL for gitweb and for fetching
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you want to have one URL for both gitweb and your `http://`
+repositories, you can configure Apache like this:
+
+-----------------------------------------------------------------------
+<VirtualHost *:80>
+    ServerName    git.example.org
+    DocumentRoot  /pub/git
+    SetEnv        GITWEB_CONFIG   /etc/gitweb.conf
+
+    # turning on mod rewrite
+    RewriteEngine on
+
+    # make the front page an internal rewrite to the gitweb script
+    RewriteRule ^/$  /cgi-bin/gitweb.cgi
+
+    # make access for "dumb clients" work
+    RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ \
+               /cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
+</VirtualHost>
+-----------------------------------------------------------------------
+
+The above configuration expects your public repositories to live under
+'/pub/git' and will serve them as `http://git.domain.org/dir-under-pub-git`,
+both as cloneable GIT URL and as browseable gitweb interface.  If you then
+start your linkgit:git-daemon[1] with `--base-path=/pub/git --export-all`
+then you can even use the `git://` URL with exactly the same path.
+
+Setting the environment variable `GITWEB_CONFIG` will tell gitweb to use the
+named file (i.e. in this example '/etc/gitweb.conf') as a configuration for
+gitweb.  You don't really need it in above example; it is required only if
+your configuration file is in different place than built-in (during
+compiling gitweb) 'gitweb_config.perl' or '/etc/gitweb.conf'.  See
+linkgit:gitweb.conf[5] for details, especially information about precedence
+rules.
+
+If you use the rewrite rules from the example you *might* also need
+something like the following in your gitweb configuration file
+('/etc/gitweb.conf' following example):
+----------------------------------------------------------------------------
+@stylesheets = ("/some/absolute/path/gitweb.css");
+$my_uri    = "/";
+$home_link = "/";
+$per_request_config = 1;
+----------------------------------------------------------------------------
+Nowadays though gitweb should create HTML base tag when needed (to set base
+URI for relative links), so it should work automatically.
+
+
+Webserver configuration with multiple projects' root
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you want to use gitweb with several project roots you can edit your
+Apache virtual host and gitweb configuration files in the following way.
+
+The virtual host configuration (in Apache configuration file) should look
+like this:
+--------------------------------------------------------------------------
+<VirtualHost *:80>
+    ServerName    git.example.org
+    DocumentRoot  /pub/git
+    SetEnv        GITWEB_CONFIG  /etc/gitweb.conf
+
+    # turning on mod rewrite
+    RewriteEngine on
+
+    # make the front page an internal rewrite to the gitweb script
+    RewriteRule ^/$  /cgi-bin/gitweb.cgi  [QSA,L,PT]
+
+    # look for a public_git folder in unix users' home
+    # http://git.example.org/~<user>/
+    RewriteRule ^/\~([^\/]+)(/|/gitweb.cgi)?$  /cgi-bin/gitweb.cgi \
+               [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+    # http://git.example.org/+<user>/
+    #RewriteRule ^/\+([^\/]+)(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
+                [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+    # http://git.example.org/user/<user>/
+    #RewriteRule ^/user/([^\/]+)/(gitweb.cgi)?$        /cgi-bin/gitweb.cgi \
+                [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+    # defined list of project roots
+    RewriteRule ^/scm(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
+               [QSA,E=GITWEB_PROJECTROOT:/pub/scm/,L,PT]
+    RewriteRule ^/var(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
+               [QSA,E=GITWEB_PROJECTROOT:/var/git/,L,PT]
+
+    # make access for "dumb clients" work
+    RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ \
+               /cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
+</VirtualHost>
+--------------------------------------------------------------------------
+
+Here actual project root is passed to gitweb via `GITWEB_PROJECT_ROOT`
+environment variable from a web server, so you need to put the following
+line in gitweb configuration file ('/etc/gitweb.conf' in above example):
+--------------------------------------------------------------------------
+$projectroot = $ENV{'GITWEB_PROJECTROOT'} || "/pub/git";
+--------------------------------------------------------------------------
+*Note* that this requires to be set for each request, so either
+`$per_request_config` must be false, or the above must be put in code
+referenced by `$per_request_config`;
+
+These configurations enable two things. First, each unix user (`<user>`) of
+the server will be able to browse through gitweb git repositories found in
+'~/public_git/' with the following url:
+
+  http://git.example.org/~<user>/
+
+If you do not want this feature on your server just remove the second
+rewrite rule.
+
+If you already use `mod_userdir` in your virtual host or you don't want to
+use the \'~' as first character, just comment or remove the second rewrite
+rule, and uncomment one of the following according to what you want.
+
+Second, repositories found in '/pub/scm/' and '/var/git/' will be accessible
+through `http://git.example.org/scm/` and `http://git.example.org/var/`.
+You can add as many project roots as you want by adding rewrite rules like
+the third and the fourth.
+
+
+PATH_INFO usage
+~~~~~~~~~~~~~~~
+If you enable PATH_INFO usage in gitweb by putting
+----------------------------------------------------------------------------
+$feature{'pathinfo'}{'default'} = [1];
+----------------------------------------------------------------------------
+in your gitweb configuration file, it is possible to set up your server so
+that it consumes and produces URLs in the form
+
+  http://git.example.com/project.git/shortlog/sometag
+
+i.e. without 'gitweb.cgi' part, by using a configuration such as the
+following.  This configuration assumes that '/var/www/gitweb' is the
+DocumentRoot of your webserver, contains the gitweb.cgi script and
+complementary static files (stylesheet, favicon, JavaScript):
+
+----------------------------------------------------------------------------
+<VirtualHost *:80>
+       ServerAlias git.example.com
+
+       DocumentRoot /var/www/gitweb
+
+       <Directory /var/www/gitweb>
+               Options ExecCGI
+               AddHandler cgi-script cgi
+
+               DirectoryIndex gitweb.cgi
+
+               RewriteEngine On
+               RewriteCond %{REQUEST_FILENAME} !-f
+               RewriteCond %{REQUEST_FILENAME} !-d
+               RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
+       </Directory>
+</VirtualHost>
+----------------------------------------------------------------------------
+The rewrite rule guarantees that existing static files will be properly
+served, whereas any other URL will be passed to gitweb as PATH_INFO
+parameter.
+
+*Notice* that in this case you don't need special settings for
+`@stylesheets`, `$my_uri` and `$home_link`, but you lose "dumb client"
+access to your project .git dirs (described in "Single URL for gitweb and
+for fetching" section).  A possible workaround for the latter is the
+following: in your project root dir (e.g. '/pub/git') have the projects
+named *without* a .git extension (e.g. '/pub/git/project' instead of
+'/pub/git/project.git') and configure Apache as follows:
+----------------------------------------------------------------------------
+<VirtualHost *:80>
+       ServerAlias git.example.com
+
+       DocumentRoot /var/www/gitweb
+
+       AliasMatch ^(/.*?)(\.git)(/.*)?$ /pub/git$1$3
+       <Directory /var/www/gitweb>
+               Options ExecCGI
+               AddHandler cgi-script cgi
+
+               DirectoryIndex gitweb.cgi
+
+               RewriteEngine On
+               RewriteCond %{REQUEST_FILENAME} !-f
+               RewriteCond %{REQUEST_FILENAME} !-d
+               RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
+       </Directory>
+</VirtualHost>
+----------------------------------------------------------------------------
+
+The additional AliasMatch makes it so that
+
+  http://git.example.com/project.git
+
+will give raw access to the project's git dir (so that the project can be
+cloned), while
+
+  http://git.example.com/project
+
+will provide human-friendly gitweb access.
+
+This solution is not 100% bulletproof, in the sense that if some project has
+a named ref (branch, tag) starting with 'git/', then paths such as
+
+  http://git.example.com/project/command/abranch..git/abranch
+
+will fail with a 404 error.
+
+
+BUGS
+----
+Please report any bugs or feature requests to git@vger.kernel.org,
+putting "gitweb" in the subject of email.
+
+SEE ALSO
+--------
+linkgit:gitweb.conf[5], linkgit:git-instaweb[1]
+
+'gitweb/README', 'gitweb/INSTALL'
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 0d230227c2de3ad8ae78de640d682258189111e3..17404c43d64d08aff0bdf9b4e6b6eeddf9b8a5e7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -822,6 +822,7 @@ ifeq ($(uname_S),GNU/kFreeBSD)
        NO_STRLCPY = YesPlease
        NO_MKSTEMPS = YesPlease
        HAVE_PATHS_H = YesPlease
+       DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
 endif
 ifeq ($(uname_S),UnixWare)
        CC = cc
diff --git a/attr.c b/attr.c
index 33cb4e4d113cbb3816ba824cb06bf494a4bd9bc3..76b079f0f530e1372b2866f40cce21ec5266394c 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -11,6 +11,7 @@
 #include "cache.h"
 #include "exec_cmd.h"
 #include "attr.h"
+#include "dir.h"
 
 const char git_attr__true[] = "(builtin)true";
 const char git_attr__false[] = "\0(builtin)false";
@@ -20,8 +21,6 @@ static const char git_attr__unknown[] = "(builtin)unknown";
 #define ATTR__UNSET NULL
 #define ATTR__UNKNOWN git_attr__unknown
 
-static const char *attributes_file;
-
 /* This is a randomly chosen prime. */
 #define HASHSIZE 257
 
@@ -494,14 +493,6 @@ static int git_attr_system(void)
        return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
 }
 
-static int git_attr_config(const char *var, const char *value, void *dummy)
-{
-       if (!strcmp(var, "core.attributesfile"))
-               return git_config_pathname(&attributes_file, var, value);
-
-       return 0;
-}
-
 static void bootstrap_attr_stack(void)
 {
        if (!attr_stack) {
@@ -521,9 +512,8 @@ static void bootstrap_attr_stack(void)
                        }
                }
 
-               git_config(git_attr_config, NULL);
-               if (attributes_file) {
-                       elem = read_attr_from_file(attributes_file, 1);
+               if (git_attributes_file) {
+                       elem = read_attr_from_file(git_attributes_file, 1);
                        if (elem) {
                                elem->origin = NULL;
                                elem->prev = attr_stack;
@@ -533,7 +523,7 @@ static void bootstrap_attr_stack(void)
 
                if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
                        elem = read_attr(GITATTRIBUTES_FILE, 1);
-                       elem->origin = strdup("");
+                       elem->origin = xstrdup("");
                        elem->prev = attr_stack;
                        attr_stack = elem;
                        debug_push(elem);
@@ -552,7 +542,6 @@ static void prepare_attr_stack(const char *path)
 {
        struct attr_stack *elem, *info;
        int dirlen, len;
-       struct strbuf pathbuf;
        const char *cp;
 
        cp = strrchr(path, '/');
@@ -561,8 +550,6 @@ static void prepare_attr_stack(const char *path)
        else
                dirlen = cp - path;
 
-       strbuf_init(&pathbuf, dirlen+2+strlen(GITATTRIBUTES_FILE));
-
        /*
         * At the bottom of the attribute stack is the built-in
         * set of attribute definitions, followed by the contents
@@ -607,27 +594,28 @@ static void prepare_attr_stack(const char *path)
         * Read from parent directories and push them down
         */
        if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
-               while (1) {
-                       char *cp;
+               struct strbuf pathbuf = STRBUF_INIT;
 
+               while (1) {
                        len = strlen(attr_stack->origin);
                        if (dirlen <= len)
                                break;
-                       strbuf_reset(&pathbuf);
-                       strbuf_add(&pathbuf, path, dirlen);
+                       cp = memchr(path + len + 1, '/', dirlen - len - 1);
+                       if (!cp)
+                               cp = path + dirlen;
+                       strbuf_add(&pathbuf, path, cp - path);
                        strbuf_addch(&pathbuf, '/');
-                       cp = strchr(pathbuf.buf + len + 1, '/');
-                       strcpy(cp + 1, GITATTRIBUTES_FILE);
+                       strbuf_addstr(&pathbuf, GITATTRIBUTES_FILE);
                        elem = read_attr(pathbuf.buf, 0);
-                       *cp = '\0';
-                       elem->origin = strdup(pathbuf.buf);
+                       strbuf_setlen(&pathbuf, cp - path);
+                       elem->origin = strbuf_detach(&pathbuf, NULL);
                        elem->prev = attr_stack;
                        attr_stack = elem;
                        debug_push(elem);
                }
-       }
 
-       strbuf_release(&pathbuf);
+               strbuf_release(&pathbuf);
+       }
 
        /*
         * Finally push the "info" one at the top of the stack.
@@ -644,7 +632,7 @@ static int path_matches(const char *pathname, int pathlen,
                /* match basename */
                const char *basename = strrchr(pathname, '/');
                basename = basename ? basename + 1 : pathname;
-               return (fnmatch(pattern, basename, 0) == 0);
+               return (fnmatch_icase(pattern, basename, 0) == 0);
        }
        /*
         * match with FNM_PATHNAME; the pattern has base implicitly
@@ -658,7 +646,7 @@ static int path_matches(const char *pathname, int pathlen,
                return 0;
        if (baselen != 0)
                baselen++;
-       return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;
+       return fnmatch_icase(pattern, pathname + baselen, FNM_PATHNAME) == 0;
 }
 
 static int macroexpand_one(int attr_nr, int rem);
index de05bf824620324e42b7a27571ecd3e763cf7e8f..6e186e29cc4a6a74944798e8c4248219e9c5997f 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -800,25 +800,25 @@ static int check_ancestors(const char *prefix)
 {
        struct rev_info revs;
        struct object_array pending_copy;
-       int i, res;
+       int res;
 
        bisect_rev_setup(&revs, prefix, "^%s", "%s", 0);
 
        /* Save pending objects, so they can be cleaned up later. */
-       memset(&pending_copy, 0, sizeof(pending_copy));
-       for (i = 0; i < revs.pending.nr; i++)
-               add_object_array(revs.pending.objects[i].item,
-                                revs.pending.objects[i].name,
-                                &pending_copy);
+       pending_copy = revs.pending;
+       revs.leak_pending = 1;
 
+       /*
+        * bisect_common calls prepare_revision_walk right away, which
+        * (together with .leak_pending = 1) makes us the sole owner of
+        * the list of pending objects.
+        */
        bisect_common(&revs);
        res = (revs.commits != NULL);
 
        /* Clean up objects used, as they will be reused. */
-       for (i = 0; i < pending_copy.nr; i++) {
-               struct object *o = pending_copy.objects[i].item;
-               clear_commit_marks((struct commit *)o, ALL_REV_FLAGS);
-       }
+       clear_commit_marks_for_object_array(&pending_copy, ALL_REV_FLAGS);
+       free(pending_copy.objects);
 
        return res;
 }
index 872e40ab1e0401a480ee8e852d09899f4d4553ed..84a8a0b52136c4d1e43ec10f9ef5ed76b7d3c12f 100644 (file)
@@ -1407,6 +1407,9 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
                                            "%d leading pathname components (line %d)" , p_value, linenr);
                                patch->old_name = patch->new_name = patch->def_name;
                        }
+                       if (!patch->is_delete && !patch->new_name)
+                               die("git diff header lacks filename information "
+                                   "(line %d)", linenr);
                        patch->is_toplevel_relative = 1;
                        *hdrsize = git_hdr_len;
                        return offset;
@@ -2447,6 +2450,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
        char *old, *oldlines;
        struct strbuf newlines;
        int new_blank_lines_at_end = 0;
+       int found_new_blank_lines_at_end = 0;
+       int hunk_linenr = frag->linenr;
        unsigned long leading, trailing;
        int pos, applied_pos;
        struct image preimage;
@@ -2540,14 +2545,18 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
                                error("invalid start of line: '%c'", first);
                        return -1;
                }
-               if (added_blank_line)
+               if (added_blank_line) {
+                       if (!new_blank_lines_at_end)
+                               found_new_blank_lines_at_end = hunk_linenr;
                        new_blank_lines_at_end++;
+               }
                else if (is_blank_context)
                        ;
                else
                        new_blank_lines_at_end = 0;
                patch += len;
                size -= len;
+               hunk_linenr++;
        }
        if (inaccurate_eof &&
            old > oldlines && old[-1] == '\n' &&
@@ -2629,7 +2638,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
                    preimage.nr + applied_pos >= img->nr &&
                    (ws_rule & WS_BLANK_AT_EOF) &&
                    ws_error_action != nowarn_ws_error) {
-                       record_ws_error(WS_BLANK_AT_EOF, "+", 1, frag->linenr);
+                       record_ws_error(WS_BLANK_AT_EOF, "+", 1,
+                                       found_new_blank_lines_at_end);
                        if (ws_error_action == correct_ws_error) {
                                while (new_blank_lines_at_end--)
                                        remove_last_line(&postimage);
index 883c0092ad43d602136e68d2afde8e319a904676..931956def986bbdf5b77e163f1b18c961e7be09c 100644 (file)
@@ -61,6 +61,8 @@ static int run_remote_archiver(int argc, const char **argv,
        if (strcmp(buf, "ACK")) {
                if (len > 5 && !prefixcmp(buf, "NACK "))
                        die(_("git archive: NACK %s"), buf + 5);
+               if (len > 4 && !prefixcmp(buf, "ERR "))
+                       die(_("remote error: %s"), buf + 4);
                die(_("git archive: protocol error"));
        }
 
index ded0d836d39d101f7879fecb11e7057a006c1b17..44c421eb0fe9cd8947d6666d15d790bc241ee7f3 100644 (file)
@@ -94,6 +94,8 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
        struct git_attr_check *check;
        int cnt, i, doubledash, filei;
 
+       git_config(git_default_config, NULL);
+
        argc = parse_options(argc, argv, prefix, check_attr_options,
                             check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
 
index 04df4d786ecf9fe541b62e89d85f6b0ae684b439..2a8077242500d54ac50d5829a86b14803fc69126 100644 (file)
@@ -72,7 +72,7 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
        hashcpy(ce->sha1, sha1);
        memcpy(ce->name, base, baselen);
        memcpy(ce->name + baselen, pathname, len - baselen);
-       ce->ce_flags = create_ce_flags(len, 0);
+       ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE;
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
        return 0;
@@ -229,6 +229,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
 
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
+               if (source_tree && !(ce->ce_flags & CE_UPDATE))
+                       continue;
                match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
        }
 
@@ -267,6 +269,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
        state.refresh_cache = 1;
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
+               if (source_tree && !(ce->ce_flags & CE_UPDATE))
+                       continue;
                if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
                        if (!ce_stage(ce)) {
                                errs |= checkout_entry(ce, &state, NULL);
@@ -589,23 +593,11 @@ static void update_refs_for_switch(struct checkout_opts *opts,
                report_tracking(new);
 }
 
-static int add_one_ref_to_rev_list_arg(const char *refname,
-                                      const unsigned char *sha1,
-                                      int flags,
-                                      void *cb_data)
+static int add_pending_uninteresting_ref(const char *refname,
+                                        const unsigned char *sha1,
+                                        int flags, void *cb_data)
 {
-       argv_array_push(cb_data, refname);
-       return 0;
-}
-
-static int clear_commit_marks_from_one_ref(const char *refname,
-                                     const unsigned char *sha1,
-                                     int flags,
-                                     void *cb_data)
-{
-       struct commit *commit = lookup_commit_reference_gently(sha1, 1);
-       if (commit)
-               clear_commit_marks(commit, -1);
+       add_pending_sha1(cb_data, refname, sha1, flags | UNINTERESTING);
        return 0;
 }
 
@@ -674,18 +666,21 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
  */
 static void orphaned_commit_warning(struct commit *commit)
 {
-       struct argv_array args = ARGV_ARRAY_INIT;
        struct rev_info revs;
-
-       argv_array_push(&args, "(internal)");
-       argv_array_push(&args, sha1_to_hex(commit->object.sha1));
-       argv_array_push(&args, "--not");
-       for_each_ref(add_one_ref_to_rev_list_arg, &args);
-       argv_array_push(&args, "--");
+       struct object *object = &commit->object;
+       struct object_array refs;
 
        init_revisions(&revs, NULL);
-       if (setup_revisions(args.argc - 1, args.argv, &revs, NULL) != 1)
-               die(_("internal error: only -- alone should have been left"));
+       setup_revisions(0, NULL, &revs, NULL);
+
+       object->flags &= ~UNINTERESTING;
+       add_pending_object(&revs, object, sha1_to_hex(object->sha1));
+
+       for_each_ref(add_pending_uninteresting_ref, &revs);
+
+       refs = revs.pending;
+       revs.leak_pending = 1;
+
        if (prepare_revision_walk(&revs))
                die(_("internal error in revision walk"));
        if (!(commit->object.flags & UNINTERESTING))
@@ -693,9 +688,8 @@ static void orphaned_commit_warning(struct commit *commit)
        else
                describe_detached_head(_("Previous HEAD position was"), commit);
 
-       argv_array_clear(&args);
-       clear_commit_marks(commit, -1);
-       for_each_ref(clear_commit_marks_from_one_ref, NULL);
+       clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
+       free(refs.objects);
 }
 
 static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
index b9ab5ef3146ff0536cb79dabf8c77605e4974c31..c46f2d18e10bcb3b1b458d4ae94d2d3522305632 100644 (file)
@@ -1393,7 +1393,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        if (get_sha1("HEAD", sha1))
                current_head = NULL;
        else {
-               current_head = lookup_commit(sha1);
+               current_head = lookup_commit_or_die(sha1, "HEAD");
                if (!current_head || parse_commit(current_head))
                        die(_("could not parse HEAD commit"));
        }
@@ -1425,6 +1425,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                        pptr = &commit_list_insert(c->item, pptr)->next;
        } else if (whence == FROM_MERGE) {
                struct strbuf m = STRBUF_INIT;
+               struct commit *commit;
                FILE *fp;
 
                if (!reflog_msg)
@@ -1438,7 +1439,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                        unsigned char sha1[20];
                        if (get_sha1_hex(m.buf, sha1) < 0)
                                die(_("Corrupt MERGE_HEAD file (%s)"), m.buf);
-                       pptr = &commit_list_insert(lookup_commit(sha1), pptr)->next;
+                       commit = lookup_commit_or_die(sha1, "MERGE_HEAD");
+                       pptr = &commit_list_insert(commit, pptr)->next;
                }
                fclose(fp);
                strbuf_release(&m);
index 0b4ecac855dce9b70878de4d15f4d317254d9ef3..0315ad76f881aab9a64084f8d2fdd2019907e4cb 100644 (file)
@@ -99,6 +99,7 @@ static int show_config(const char *key_, const char *value_, void *cb)
        const char *vptr = value;
        int must_free_vptr = 0;
        int dup_error = 0;
+       int must_print_delim = 0;
 
        if (!use_key_regexp && strcmp(key_, key))
                return 0;
@@ -109,10 +110,8 @@ static int show_config(const char *key_, const char *value_, void *cb)
                return 0;
 
        if (show_keys) {
-               if (value_)
-                       printf("%s%c", key_, key_delim);
-               else
-                       printf("%s", key_);
+               printf("%s", key_);
+               must_print_delim = 1;
        }
        if (seen && !do_all)
                dup_error = 1;
@@ -130,16 +129,23 @@ static int show_config(const char *key_, const char *value_, void *cb)
        } else if (types == TYPE_PATH) {
                git_config_pathname(&vptr, key_, value_);
                must_free_vptr = 1;
+       } else if (value_) {
+               vptr = value_;
+       } else {
+               /* Just show the key name */
+               vptr = "";
+               must_print_delim = 0;
        }
-       else
-               vptr = value_?value_:"";
        seen++;
        if (dup_error) {
                error("More than one value for the key %s: %s",
                                key_, vptr);
        }
-       else
+       else {
+               if (must_print_delim)
+                       printf("%c", key_delim);
                printf("%s%c", vptr, term);
+       }
        if (must_free_vptr)
                /* If vptr must be freed, it's a pointer to a
                 * dynamically allocated buffer, it's safe to cast to
index 7a4e41cca75b87d3e5a7c4690658d9879777e965..1adf6c176f31b2ece263bc1f07eee8c7e0b40098 100644 (file)
@@ -379,8 +379,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                url = xstrdup("foreign");
 
        rm = ref_map;
-       if (check_everything_connected(iterate_ref_map, 0, &rm))
-               return error(_("%s did not send all necessary objects\n"), url);
+       if (check_everything_connected(iterate_ref_map, 0, &rm)) {
+               rc = error(_("%s did not send all necessary objects\n"), url);
+               goto abort;
+       }
 
        for (rm = ref_map; rm; rm = rm->next) {
                struct ref *ref = NULL;
@@ -462,12 +464,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                                fprintf(stderr, " %s\n", note);
                }
        }
-       free(url);
-       fclose(fp);
+
        if (rc & STORE_REF_ERROR_DF_CONFLICT)
                error(_("some local refs could not be updated; try running\n"
                      " 'git remote prune %s' to remove any old, conflicting "
                      "branches"), remote_name);
+
+ abort:
+       free(url);
+       fclose(fp);
        return rc;
 }
 
index 75816329d6153c35e0763b35f70cfaf165f2a4b8..7e2f22589dcb14d5ba95ce1331ef816a458533d0 100644 (file)
@@ -293,7 +293,7 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
                struct commit *head;
                struct rev_info rev;
 
-               head = lookup_commit(head_sha1);
+               head = lookup_commit_or_die(head_sha1, "HEAD");
                init_revisions(&rev, NULL);
                rev.commit_format = CMIT_FMT_ONELINE;
                rev.ignore_merges = 1;
index a286692e467710d92346ab6900e98f1126cb967d..7d0779f6cfd60149379f957941ebef18aef735ab 100644 (file)
@@ -640,13 +640,15 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
        return hit;
 }
 
-static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec)
+static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
+                         int exc_std)
 {
        struct dir_struct dir;
        int i, hit = 0;
 
        memset(&dir, 0, sizeof(dir));
-       setup_standard_excludes(&dir);
+       if (exc_std)
+               setup_standard_excludes(&dir);
 
        fill_directory(&dir, pathspec->raw);
        for (i = 0; i < dir.nr; i++) {
@@ -753,7 +755,7 @@ static int help_callback(const struct option *opt, const char *arg, int unset)
 int cmd_grep(int argc, const char **argv, const char *prefix)
 {
        int hit = 0;
-       int cached = 0;
+       int cached = 0, untracked = 0, opt_exclude = -1;
        int seen_dashdash = 0;
        int external_grep_allowed__ignored;
        const char *show_in_pager = NULL, *default_pager = "dummy";
@@ -777,8 +779,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT_BOOLEAN(0, "cached", &cached,
                        "search in index instead of in the work tree"),
-               OPT_BOOLEAN(0, "index", &use_index,
-                       "--no-index finds in contents not managed by git"),
+               { OPTION_BOOLEAN, 0, "index", &use_index, NULL,
+                       "finds in contents not managed by git",
+                       PARSE_OPT_NOARG | PARSE_OPT_NEGHELP },
+               OPT_BOOLEAN(0, "untracked", &untracked,
+                       "search in both tracked and untracked files"),
+               OPT_SET_INT(0, "exclude-standard", &opt_exclude,
+                           "search also in ignored files", 1),
                OPT_GROUP(""),
                OPT_BOOLEAN('v', "invert-match", &opt.invert,
                        "show non-matching lines"),
@@ -1048,13 +1055,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        if (!show_in_pager)
                setup_pager();
 
+       if (!use_index && (untracked || cached))
+               die(_("--cached or --untracked cannot be used with --no-index."));
 
-       if (!use_index) {
-               if (cached)
-                       die(_("--cached cannot be used with --no-index."));
+       if (!use_index || untracked) {
+               int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
                if (list.nr)
-                       die(_("--no-index cannot be used with revs."));
-               hit = grep_directory(&opt, &pathspec);
+                       die(_("--no-index or --untracked cannot be used with revs."));
+               hit = grep_directory(&opt, &pathspec, use_exclude);
+       } else if (0 <= opt_exclude) {
+               die(_("--[no-]exclude-standard cannot be used for tracked contents."));
        } else if (!list.nr) {
                if (!cached)
                        setup_work_tree();
index ee56974371fa9224ecb4b8203fb1356b6cf6e156..7d593097dea987e580d1e79f010faf23c1f98fb0 100644 (file)
@@ -50,7 +50,6 @@ static int fast_forward_only;
 static int allow_trivial = 1, have_message;
 static struct strbuf merge_msg;
 static struct commit_list *remoteheads;
-static unsigned char head[20], stash[20];
 static struct strategy **use_strategies;
 static size_t use_strategies_nr, use_strategies_alloc;
 static const char **xopts;
@@ -217,7 +216,7 @@ static void drop_save(void)
        unlink(git_path("MERGE_MODE"));
 }
 
-static void save_state(void)
+static int save_state(unsigned char *stash)
 {
        int len;
        struct child_process cp;
@@ -236,11 +235,12 @@ static void save_state(void)
 
        if (finish_command(&cp) || len < 0)
                die(_("stash failed"));
-       else if (!len)
-               return;
+       else if (!len)          /* no changes */
+               return -1;
        strbuf_setlen(&buffer, buffer.len-1);
        if (get_sha1(buffer.buf, stash))
                die(_("not a valid object: %s"), buffer.buf);
+       return 0;
 }
 
 static void read_empty(unsigned const char *sha1, int verbose)
@@ -278,7 +278,8 @@ static void reset_hard(unsigned const char *sha1, int verbose)
                die(_("read-tree failed"));
 }
 
-static void restore_state(void)
+static void restore_state(const unsigned char *head,
+                         const unsigned char *stash)
 {
        struct strbuf sb = STRBUF_INIT;
        const char *args[] = { "stash", "apply", NULL, NULL };
@@ -308,10 +309,9 @@ static void finish_up_to_date(const char *msg)
        drop_save();
 }
 
-static void squash_message(void)
+static void squash_message(struct commit *commit)
 {
        struct rev_info rev;
-       struct commit *commit;
        struct strbuf out = STRBUF_INIT;
        struct commit_list *j;
        int fd;
@@ -326,7 +326,6 @@ static void squash_message(void)
        rev.ignore_merges = 1;
        rev.commit_format = CMIT_FMT_MEDIUM;
 
-       commit = lookup_commit(head);
        commit->object.flags |= UNINTERESTING;
        add_pending_object(&rev, &commit->object, NULL);
 
@@ -355,9 +354,11 @@ static void squash_message(void)
        strbuf_release(&out);
 }
 
-static void finish(const unsigned char *new_head, const char *msg)
+static void finish(struct commit *head_commit,
+                  const unsigned char *new_head, const char *msg)
 {
        struct strbuf reflog_message = STRBUF_INIT;
+       const unsigned char *head = head_commit->object.sha1;
 
        if (!msg)
                strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION"));
@@ -368,7 +369,7 @@ static void finish(const unsigned char *new_head, const char *msg)
                        getenv("GIT_REFLOG_ACTION"), msg);
        }
        if (squash) {
-               squash_message();
+               squash_message(head_commit);
        } else {
                if (verbosity >= 0 && !merge_msg.len)
                        printf(_("No merge message -- not updating HEAD\n"));
@@ -671,7 +672,7 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 }
 
 static int try_merge_strategy(const char *strategy, struct commit_list *common,
-                             const char *head_arg)
+                             struct commit *head, const char *head_arg)
 {
        int index_fd;
        struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
@@ -717,7 +718,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                        commit_list_insert(j->item, &reversed);
 
                index_fd = hold_locked_index(lock, 1);
-               clean = merge_recursive(&o, lookup_commit(head),
+               clean = merge_recursive(&o, head,
                                remoteheads->item, reversed, &result);
                if (active_cache_changed &&
                                (write_cache(index_fd, active_cache, active_nr) ||
@@ -868,25 +869,26 @@ static void run_prepare_commit_msg(void)
        read_merge_msg();
 }
 
-static int merge_trivial(void)
+static int merge_trivial(struct commit *head)
 {
        unsigned char result_tree[20], result_commit[20];
        struct commit_list *parent = xmalloc(sizeof(*parent));
 
        write_tree_trivial(result_tree);
        printf(_("Wonderful.\n"));
-       parent->item = lookup_commit(head);
+       parent->item = head;
        parent->next = xmalloc(sizeof(*parent->next));
        parent->next->item = remoteheads->item;
        parent->next->next = NULL;
        run_prepare_commit_msg();
        commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
-       finish(result_commit, "In-index merge");
+       finish(head, result_commit, "In-index merge");
        drop_save();
        return 0;
 }
 
-static int finish_automerge(struct commit_list *common,
+static int finish_automerge(struct commit *head,
+                           struct commit_list *common,
                            unsigned char *result_tree,
                            const char *wt_strategy)
 {
@@ -897,12 +899,12 @@ static int finish_automerge(struct commit_list *common,
        free_commit_list(common);
        if (allow_fast_forward) {
                parents = remoteheads;
-               commit_list_insert(lookup_commit(head), &parents);
+               commit_list_insert(head, &parents);
                parents = reduce_heads(parents);
        } else {
                struct commit_list **pptr = &parents;
 
-               pptr = &commit_list_insert(lookup_commit(head),
+               pptr = &commit_list_insert(head,
                                pptr)->next;
                for (j = remoteheads; j; j = j->next)
                        pptr = &commit_list_insert(j->item, pptr)->next;
@@ -912,7 +914,7 @@ static int finish_automerge(struct commit_list *common,
        run_prepare_commit_msg();
        commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
        strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
-       finish(result_commit, buf.buf);
+       finish(head, result_commit, buf.buf);
        strbuf_release(&buf);
        drop_save();
        return 0;
@@ -946,7 +948,8 @@ static int suggest_conflicts(int renormalizing)
        return 1;
 }
 
-static struct commit *is_old_style_invocation(int argc, const char **argv)
+static struct commit *is_old_style_invocation(int argc, const char **argv,
+                                             const unsigned char *head)
 {
        struct commit *second_token = NULL;
        if (argc > 2) {
@@ -1018,9 +1021,12 @@ static int setup_with_upstream(const char ***argv)
 int cmd_merge(int argc, const char **argv, const char *prefix)
 {
        unsigned char result_tree[20];
+       unsigned char stash[20];
+       unsigned char head_sha1[20];
+       struct commit *head_commit;
        struct strbuf buf = STRBUF_INIT;
        const char *head_arg;
-       int flag, head_invalid = 0, i;
+       int flag, i;
        int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
        struct commit_list *common = NULL;
        const char *best_strategy = NULL, *wt_strategy = NULL;
@@ -1033,11 +1039,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * Check if we are _not_ on a detached HEAD, i.e. if there is a
         * current branch.
         */
-       branch = resolve_ref("HEAD", head, 0, &flag);
+       branch = resolve_ref("HEAD", head_sha1, 0, &flag);
        if (branch && !prefixcmp(branch, "refs/heads/"))
                branch += 11;
-       if (is_null_sha1(head))
-               head_invalid = 1;
+       if (!branch || is_null_sha1(head_sha1))
+               head_commit = NULL;
+       else
+               head_commit = lookup_commit_or_die(head_sha1, "HEAD");
 
        git_config(git_merge_config, NULL);
 
@@ -1114,12 +1122,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * additional safety measure to check for it.
         */
 
-       if (!have_message && is_old_style_invocation(argc, argv)) {
+       if (!have_message && head_commit &&
+           is_old_style_invocation(argc, argv, head_commit->object.sha1)) {
                strbuf_addstr(&merge_msg, argv[0]);
                head_arg = argv[1];
                argv += 2;
                argc -= 2;
-       } else if (head_invalid) {
+       } else if (!head_commit) {
                struct object *remote_head;
                /*
                 * If the merged head is a valid one there is no reason
@@ -1166,7 +1175,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                }
        }
 
-       if (head_invalid || !argc)
+       if (!head_commit || !argc)
                usage_with_options(builtin_merge_usage,
                        builtin_merge_options);
 
@@ -1207,17 +1216,16 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        }
 
        if (!remoteheads->next)
-               common = get_merge_bases(lookup_commit(head),
-                               remoteheads->item, 1);
+               common = get_merge_bases(head_commit, remoteheads->item, 1);
        else {
                struct commit_list *list = remoteheads;
-               commit_list_insert(lookup_commit(head), &list);
+               commit_list_insert(head_commit, &list);
                common = get_octopus_merge_bases(list);
                free(list);
        }
 
-       update_ref("updating ORIG_HEAD", "ORIG_HEAD", head, NULL, 0,
-               DIE_ON_ERR);
+       update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.sha1,
+                  NULL, 0, DIE_ON_ERR);
 
        if (!common)
                ; /* No common ancestors found. We need a real merge. */
@@ -1231,13 +1239,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                return 0;
        } else if (allow_fast_forward && !remoteheads->next &&
                        !common->next &&
-                       !hashcmp(common->item->object.sha1, head)) {
+                       !hashcmp(common->item->object.sha1, head_commit->object.sha1)) {
                /* Again the most common case of merging one remote. */
                struct strbuf msg = STRBUF_INIT;
                struct object *o;
                char hex[41];
 
-               strcpy(hex, find_unique_abbrev(head, DEFAULT_ABBREV));
+               strcpy(hex, find_unique_abbrev(head_commit->object.sha1, DEFAULT_ABBREV));
 
                if (verbosity >= 0)
                        printf(_("Updating %s..%s\n"),
@@ -1252,10 +1260,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                if (!o)
                        return 1;
 
-               if (checkout_fast_forward(head, remoteheads->item->object.sha1))
+               if (checkout_fast_forward(head_commit->object.sha1, remoteheads->item->object.sha1))
                        return 1;
 
-               finish(o->sha1, msg.buf);
+               finish(head_commit, o->sha1, msg.buf);
                drop_save();
                return 0;
        } else if (!remoteheads->next && common->next)
@@ -1275,8 +1283,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        git_committer_info(IDENT_ERROR_ON_NO_NAME);
                        printf(_("Trying really trivial in-index merge...\n"));
                        if (!read_tree_trivial(common->item->object.sha1,
-                                       head, remoteheads->item->object.sha1))
-                               return merge_trivial();
+                                       head_commit->object.sha1, remoteheads->item->object.sha1))
+                               return merge_trivial(head_commit);
                        printf(_("Nope.\n"));
                }
        } else {
@@ -1295,8 +1303,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                         * merge_bases again, otherwise "git merge HEAD^
                         * HEAD^^" would be missed.
                         */
-                       common_one = get_merge_bases(lookup_commit(head),
-                               j->item, 1);
+                       common_one = get_merge_bases(head_commit, j->item, 1);
                        if (hashcmp(common_one->item->object.sha1,
                                j->item->object.sha1)) {
                                up_to_date = 0;
@@ -1323,21 +1330,18 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * sync with the head commit.  The strategies are responsible
         * to ensure this.
         */
-       if (use_strategies_nr != 1) {
-               /*
-                * Stash away the local changes so that we can try more
-                * than one.
-                */
-               save_state();
-       } else {
-               memcpy(stash, null_sha1, 20);
-       }
+       if (use_strategies_nr == 1 ||
+           /*
+            * Stash away the local changes so that we can try more than one.
+            */
+           save_state(stash))
+               hashcpy(stash, null_sha1);
 
        for (i = 0; i < use_strategies_nr; i++) {
                int ret;
                if (i) {
                        printf(_("Rewinding the tree to pristine...\n"));
-                       restore_state();
+                       restore_state(head_commit->object.sha1, stash);
                }
                if (use_strategies_nr != 1)
                        printf(_("Trying merge strategy %s...\n"),
@@ -1349,7 +1353,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                wt_strategy = use_strategies[i]->name;
 
                ret = try_merge_strategy(use_strategies[i]->name,
-                       common, head_arg);
+                                        common, head_commit, head_arg);
                if (!option_commit && !ret) {
                        merge_was_ok = 1;
                        /*
@@ -1391,14 +1395,15 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * auto resolved the merge cleanly.
         */
        if (automerge_was_ok)
-               return finish_automerge(common, result_tree, wt_strategy);
+               return finish_automerge(head_commit, common, result_tree,
+                                       wt_strategy);
 
        /*
         * Pick the result from the best strategy and have the user fix
         * it up.
         */
        if (!best_strategy) {
-               restore_state();
+               restore_state(head_commit->object.sha1, stash);
                if (use_strategies_nr > 1)
                        fprintf(stderr,
                                _("No merge strategy handled the merge.\n"));
@@ -1410,14 +1415,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                ; /* We already have its result in the working tree. */
        else {
                printf(_("Rewinding the tree to pristine...\n"));
-               restore_state();
+               restore_state(head_commit->object.sha1, stash);
                printf(_("Using the %s to prepare resolving by hand.\n"),
                        best_strategy);
-               try_merge_strategy(best_strategy, common, head_arg);
+               try_merge_strategy(best_strategy, common, head_commit, head_arg);
        }
 
        if (squash)
-               finish(NULL, NULL);
+               finish(head_commit, NULL, NULL);
        else {
                int fd;
                struct commit_list *j;
index 40f33ca4d0e6d0bb1733e0544029c6f588d09b59..5efe6c5760c43d0059a940ab9d4610b97092c8bd 100644 (file)
@@ -29,7 +29,11 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
                        to_copy--;
                if (to_copy != length || base_name) {
                        char *it = xmemdupz(result[i], to_copy);
-                       result[i] = base_name ? strdup(basename(it)) : it;
+                       if (base_name) {
+                               result[i] = xstrdup(basename(it));
+                               free(it);
+                       } else
+                               result[i] = it;
                }
        }
        return get_pathspec(prefix, result);
index e2d3f94661ffd89e08a1bf0e52ff07b366612b65..261b610d24017557c137d83a9c005b662e795b6a 100644 (file)
@@ -154,7 +154,8 @@ static void write_head_info(void)
 struct command {
        struct command *next;
        const char *error_string;
-       unsigned int skip_update;
+       unsigned int skip_update:1,
+                    did_not_exist:1;
        unsigned char old_sha1[20];
        unsigned char new_sha1[20];
        char ref_name[FLEX_ARRAY]; /* more */
@@ -264,6 +265,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
 
 struct receive_hook_feed_state {
        struct command *cmd;
+       int skip_broken;
        struct strbuf buf;
 };
 
@@ -272,7 +274,8 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
        struct receive_hook_feed_state *state = state_;
        struct command *cmd = state->cmd;
 
-       while (cmd && cmd->error_string)
+       while (cmd &&
+              state->skip_broken && (cmd->error_string || cmd->did_not_exist))
                cmd = cmd->next;
        if (!cmd)
                return -1; /* EOF */
@@ -288,13 +291,15 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
        return 0;
 }
 
-static int run_receive_hook(struct command *commands, const char *hook_name)
+static int run_receive_hook(struct command *commands, const char *hook_name,
+                           int skip_broken)
 {
        struct receive_hook_feed_state state;
        int status;
 
        strbuf_init(&state.buf, 0);
        state.cmd = commands;
+       state.skip_broken = skip_broken;
        if (feed_receive_hook(&state, NULL, NULL))
                return 0;
        state.cmd = commands;
@@ -485,8 +490,13 @@ static const char *update(struct command *cmd)
 
        if (is_null_sha1(new_sha1)) {
                if (!parse_object(old_sha1)) {
-                       rp_warning("Allowing deletion of corrupt ref.");
                        old_sha1 = NULL;
+                       if (ref_exists(name)) {
+                               rp_warning("Allowing deletion of corrupt ref.");
+                       } else {
+                               rp_warning("Deleting a non-existent ref.");
+                               cmd->did_not_exist = 1;
+                       }
                }
                if (delete_ref(namespaced_name, old_sha1, 0)) {
                        rp_error("failed to delete %s", name);
@@ -517,7 +527,7 @@ static void run_update_post_hook(struct command *commands)
        struct child_process proc;
 
        for (argc = 0, cmd = commands; cmd; cmd = cmd->next) {
-               if (cmd->error_string)
+               if (cmd->error_string || cmd->did_not_exist)
                        continue;
                argc++;
        }
@@ -528,7 +538,7 @@ static void run_update_post_hook(struct command *commands)
 
        for (argc = 1, cmd = commands; cmd; cmd = cmd->next) {
                char *p;
-               if (cmd->error_string)
+               if (cmd->error_string || cmd->did_not_exist)
                        continue;
                p = xmalloc(strlen(cmd->ref_name) + 1);
                strcpy(p, cmd->ref_name);
@@ -672,7 +682,7 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
                                       0, &cmd))
                set_connectivity_errors(commands);
 
-       if (run_receive_hook(commands, pre_receive_hook)) {
+       if (run_receive_hook(commands, pre_receive_hook, 0)) {
                for (cmd = commands; cmd; cmd = cmd->next)
                        cmd->error_string = "pre-receive hook declined";
                return;
@@ -940,7 +950,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                        unlink_or_warn(pack_lockfile);
                if (report_status)
                        report(commands, unpack_status);
-               run_receive_hook(commands, post_receive_hook);
+               run_receive_hook(commands, post_receive_hook, 1);
                run_update_post_hook(commands);
                if (auto_gc) {
                        const char *argv_gc_auto[] = {
index 6bf849740c6de45fe8ca11eca2a06a52c7ebc0bb..f82baae3bd2736cd0abca6b2412e3c4fd363b1e6 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -122,11 +122,8 @@ int verify_bundle(struct bundle_header *header, int verbose)
        req_nr = revs.pending.nr;
        setup_revisions(2, argv, &revs, NULL);
 
-       memset(&refs, 0, sizeof(struct object_array));
-       for (i = 0; i < revs.pending.nr; i++) {
-               struct object_array_entry *e = revs.pending.objects + i;
-               add_object_array(e->item, e->name, &refs);
-       }
+       refs = revs.pending;
+       revs.leak_pending = 1;
 
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
@@ -144,8 +141,8 @@ int verify_bundle(struct bundle_header *header, int verbose)
                                refs.objects[i].name);
                }
 
-       for (i = 0; i < refs.nr; i++)
-               clear_commit_marks((struct commit *)refs.objects[i].item, -1);
+       clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
+       free(refs.objects);
 
        if (verbose) {
                struct ref_list *r;
diff --git a/cache.h b/cache.h
index e39e1600189a6daae0eb29e165b08949f66bae9f..be07ec70863cae3f6e1c9d5dbc6dc555e444e30a 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -168,6 +168,7 @@ struct cache_entry {
        unsigned int ce_flags;
        unsigned char sha1[20];
        struct cache_entry *next;
+       struct cache_entry *dir_next;
        char name[FLEX_ARRAY]; /* more */
 };
 
@@ -589,6 +590,7 @@ extern int warn_ambiguous_refs;
 extern int shared_repository;
 extern const char *apply_default_whitespace;
 extern const char *apply_default_ignorewhitespace;
+extern const char *git_attributes_file;
 extern int zlib_compression_level;
 extern int core_compression_level;
 extern int core_compression_seen;
index 95bf18cf06b7c77789e68bd8ab0a312395fb5d86..a36ee9b0150278e8fc4b61e7226df18409b334be 100644 (file)
@@ -130,5 +130,6 @@ git-upload-pack                         synchelpers
 git-var                                 plumbinginterrogators
 git-verify-pack                         plumbinginterrogators
 git-verify-tag                          ancillaryinterrogators
+gitweb                                  ancillaryinterrogators
 git-whatchanged                         ancillaryinterrogators
 git-write-tree                          plumbingmanipulators
index 97b43279cdf46159462d5f56abc20f2161f4c7ea..73b7e00292ba2de33fa43b5f028fd807a460af34 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -39,6 +39,18 @@ struct commit *lookup_commit_reference(const unsigned char *sha1)
        return lookup_commit_reference_gently(sha1, 0);
 }
 
+struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_name)
+{
+       struct commit *c = lookup_commit_reference(sha1);
+       if (!c)
+               die(_("could not parse %s"), ref_name);
+       if (hashcmp(sha1, c->object.sha1)) {
+               warning(_("%s %s is not a commit!"),
+                       ref_name, sha1_to_hex(sha1));
+       }
+       return c;
+}
+
 struct commit *lookup_commit(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
@@ -430,6 +442,20 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
        }
 }
 
+void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark)
+{
+       struct object *object;
+       struct commit *commit;
+       unsigned int i;
+
+       for (i = 0; i < a->nr; i++) {
+               object = a->objects[i].item;
+               commit = lookup_commit_reference_gently(object->sha1, 1);
+               if (commit)
+                       clear_commit_marks(commit, mark);
+       }
+}
+
 struct commit *pop_commit(struct commit_list **stack)
 {
        struct commit_list *top = *stack;
index 12d100b8b6fcd092f3a6886a75c720011ef1b7dc..009b113e5bb5d04bdfb116897cc17dc5f5a2fa9c 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -38,6 +38,13 @@ struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
                                              int quiet);
 struct commit *lookup_commit_reference_by_name(const char *name);
 
+/*
+ * Look up object named by "sha1", dereference tag as necessary,
+ * get a commit and return it. If "sha1" does not dereference to
+ * a commit, use ref_name to report an error and die.
+ */
+struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_name);
+
 int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size);
 int parse_commit(struct commit *item);
 
@@ -126,6 +133,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
 struct commit *pop_commit(struct commit_list **stack);
 
 void clear_commit_marks(struct commit *commit, unsigned int mark);
+void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark);
 
 /*
  * Performs an in-place topological sort of list supplied.
index 6ef0cc4f99becd772a6fed1cfe2484a67b3a9000..efdc703257c9589018e59dc5bc93e9980e0f30b6 100644 (file)
@@ -1183,7 +1183,7 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
        }
        ai->ai_addrlen = sizeof(struct sockaddr_in);
        if (hints && (hints->ai_flags & AI_CANONNAME))
-               ai->ai_canonname = h ? strdup(h->h_name) : NULL;
+               ai->ai_canonname = h ? xstrdup(h->h_name) : NULL;
        else
                ai->ai_canonname = NULL;
 
@@ -1321,6 +1321,13 @@ static void ensure_socket_initialization(void)
        initialized = 1;
 }
 
+#undef gethostname
+int mingw_gethostname(char *name, int namelen)
+{
+    ensure_socket_initialization();
+    return gethostname(name, namelen);
+}
+
 #undef gethostbyname
 struct hostent *mingw_gethostbyname(const char *host)
 {
index ce9dd980eb211c0301c4008249c61fb0b09f1280..fecf0d07760d2211fac6db2e19ecbedaac81c57e 100644 (file)
@@ -190,6 +190,9 @@ char *mingw_getcwd(char *pointer, int len);
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 
+int mingw_gethostname(char *host, int namelen);
+#define gethostname mingw_gethostname
+
 struct hostent *mingw_gethostbyname(const char *host);
 #define gethostbyname mingw_gethostbyname
 
index d93dce2cf8fa33bd1fbefe131d2e41a6b954da61..9574d537bd38d3aa72ee040b106456088ee16a07 100644 (file)
@@ -55,7 +55,7 @@ void git_qsort(void *b, size_t n, size_t s,
                msort_with_tmp(b, n, s, cmp, buf);
        } else {
                /* It's somewhat large, so malloc it.  */
-               char *tmp = malloc(size);
+               char *tmp = xmalloc(size);
                msort_with_tmp(b, n, s, cmp, tmp);
                free(tmp);
        }
index 42b95a9b5169125fac7bde3caabb15f4cb6a351d..d015e436d57472bf9560a6f604705f52938c9f19 100644 (file)
@@ -1,5 +1,4 @@
 #include "../../git-compat-util.h"
-#include "../../strbuf.h"
 
 static HANDLE ms_eventlog;
 
@@ -16,13 +15,8 @@ void openlog(const char *ident, int logopt, int facility)
 
 void syslog(int priority, const char *fmt, ...)
 {
-       struct strbuf sb = STRBUF_INIT;
-       struct strbuf_expand_dict_entry dict[] = {
-               {"1", "% 1"},
-               {NULL, NULL}
-       };
        WORD logtype;
-       char *str;
+       char *str, *pos;
        int str_len;
        va_list ap;
 
@@ -39,11 +33,24 @@ void syslog(int priority, const char *fmt, ...)
        }
 
        str = malloc(str_len + 1);
+       if (!str) {
+               warning("malloc failed: '%s'", strerror(errno));
+               return;
+       }
+
        va_start(ap, fmt);
        vsnprintf(str, str_len + 1, fmt, ap);
        va_end(ap);
-       strbuf_expand(&sb, str, strbuf_expand_dict_cb, &dict);
-       free(str);
+
+       while ((pos = strstr(str, "%1")) != NULL) {
+               str = realloc(str, ++str_len + 1);
+               if (!str) {
+                       warning("realloc failed: '%s'", strerror(errno));
+                       return;
+               }
+               memmove(pos + 2, pos + 1, strlen(pos));
+               pos[1] = ' ';
+       }
 
        switch (priority) {
        case LOG_EMERG:
@@ -66,7 +73,6 @@ void syslog(int priority, const char *fmt, ...)
        }
 
        ReportEventA(ms_eventlog, logtype, 0, 0, NULL, 1, 0,
-           (const char **)&sb.buf, NULL);
-
-       strbuf_release(&sb);
+           (const char **)&str, NULL);
+       free(str);
 }
index a9e23594bd18b1cde49b55a40b2af8e2f3b74439..edf9914df6a1a789780c98d53b7b779908bb9141 100644 (file)
--- a/config.c
+++ b/config.c
@@ -491,6 +491,9 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.attributesfile"))
+               return git_config_pathname(&git_attributes_file, var, value);
+
        if (!strcmp(var, "core.bare")) {
                is_bare_repository_cfg = git_config_bool(var, value);
                return 0;
index 8648a36e7b8239e969dc8971f451431c298e405e..888e8e10ccd932df3aa8f30a3d83441d5485fc30 100755 (executable)
@@ -1259,12 +1259,9 @@ _git_commit ()
                        " "" "${cur##--cleanup=}"
                return
                ;;
-       --reuse-message=*)
-               __gitcomp "$(__git_refs)" "" "${cur##--reuse-message=}"
-               return
-               ;;
-       --reedit-message=*)
-               __gitcomp "$(__git_refs)" "" "${cur##--reedit-message=}"
+       --reuse-message=*|--reedit-message=*|\
+       --fixup=*|--squash=*)
+               __gitcomp "$(__git_refs)" "" "${cur#*=}"
                return
                ;;
        --untracked-files=*)
@@ -1278,7 +1275,7 @@ _git_commit ()
                        --dry-run --reuse-message= --reedit-message=
                        --reset-author --file= --message= --template=
                        --cleanup= --untracked-files --untracked-files=
-                       --verbose --quiet
+                       --verbose --quiet --fixup= --squash=
                        "
                return
        esac
@@ -1556,14 +1553,9 @@ _git_log ()
                merge="--merge"
        fi
        case "$cur" in
-       --pretty=*)
-               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
-                       " "" "${cur##--pretty=}"
-               return
-               ;;
-       --format=*)
+       --pretty=*|--format=*)
                __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
-                       " "" "${cur##--format=}"
+                       " "" "${cur#*=}"
                return
                ;;
        --date=*)
@@ -1671,11 +1663,9 @@ _git_notes ()
                        ;;
                esac
                ;;
-       add,--reuse-message=*|append,--reuse-message=*)
-               __gitcomp "$(__git_refs)" "" "${cur##--reuse-message=}"
-               ;;
+       add,--reuse-message=*|append,--reuse-message=*|\
        add,--reedit-message=*|append,--reedit-message=*)
-               __gitcomp "$(__git_refs)" "" "${cur##--reedit-message=}"
+               __gitcomp "$(__git_refs)" "" "${cur#*=}"
                ;;
        add,--*|append,--*)
                __gitcomp '--file= --message= --reedit-message=
@@ -1733,7 +1723,7 @@ _git_push ()
        --*)
                __gitcomp "
                        --all --mirror --tags --dry-run --force --verbose
-                       --receive-pack= --repo=
+                       --receive-pack= --repo= --set-upstream
                "
                return
                ;;
@@ -2370,14 +2360,9 @@ _git_show ()
        __git_has_doubledash && return
 
        case "$cur" in
-       --pretty=*)
-               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
-                       " "" "${cur##--pretty=}"
-               return
-               ;;
-       --format=*)
+       --pretty=*|--format=*)
                __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
-                       " "" "${cur##--format=}"
+                       " "" "${cur#*=}"
                return
                ;;
        --*)
index 4c8346d5a1fe1325de2dd335a4e61a2dad994211..5a1086198b5f3780b5bc348cae78af12d8775cad 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -257,11 +257,11 @@ static int run_service(char *dir, struct daemon_service *service)
        if (!enabled && !service->overridable) {
                logerror("'%s': service not enabled.", service->name);
                errno = EACCES;
-               return -1;
+               goto failed;
        }
 
        if (!(path = path_ok(dir)))
-               return -1;
+               goto failed;
 
        /*
         * Security on the cheap.
@@ -277,7 +277,7 @@ static int run_service(char *dir, struct daemon_service *service)
        if (!export_all_trees && access("git-daemon-export-ok", F_OK)) {
                logerror("'%s': repository not exported.", path);
                errno = EACCES;
-               return -1;
+               goto failed;
        }
 
        if (service->overridable) {
@@ -291,7 +291,7 @@ static int run_service(char *dir, struct daemon_service *service)
                logerror("'%s': service not enabled for '%s'",
                         service->name, path);
                errno = EACCES;
-               return -1;
+               goto failed;
        }
 
        /*
@@ -301,6 +301,10 @@ static int run_service(char *dir, struct daemon_service *service)
        signal(SIGTERM, SIG_IGN);
 
        return service->fn();
+
+failed:
+       packet_write(1, "ERR %s: access denied", dir);
+       return -1;
 }
 
 static void copy_to_log(int fd)
@@ -734,6 +738,29 @@ struct socketlist {
        size_t alloc;
 };
 
+static const char *ip2str(int family, struct sockaddr *sin, socklen_t len)
+{
+#ifdef NO_IPV6
+       static char ip[INET_ADDRSTRLEN];
+#else
+       static char ip[INET6_ADDRSTRLEN];
+#endif
+
+       switch (family) {
+#ifndef NO_IPV6
+       case AF_INET6:
+               inet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, len);
+               break;
+#endif
+       case AF_INET:
+               inet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, len);
+               break;
+       default:
+               strcpy(ip, "<unknown>");
+       }
+       return ip;
+}
+
 #ifndef NO_IPV6
 
 static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
@@ -780,15 +807,22 @@ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlis
 #endif
 
                if (set_reuse_addr(sockfd)) {
+                       logerror("Could not set SO_REUSEADDR: %s", strerror(errno));
                        close(sockfd);
                        continue;
                }
 
                if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
+                       logerror("Could not bind to %s: %s",
+                                ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen),
+                                strerror(errno));
                        close(sockfd);
                        continue;       /* not fatal */
                }
                if (listen(sockfd, 5) < 0) {
+                       logerror("Could not listen to %s: %s",
+                                ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen),
+                                strerror(errno));
                        close(sockfd);
                        continue;       /* not fatal */
                }
@@ -835,16 +869,23 @@ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlis
                return 0;
 
        if (set_reuse_addr(sockfd)) {
+               logerror("Could not set SO_REUSEADDR: %s", strerror(errno));
                close(sockfd);
                return 0;
        }
 
        if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
+               logerror("Could not listen to %s: %s",
+                        ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),
+                        strerror(errno));
                close(sockfd);
                return 0;
        }
 
        if (listen(sockfd, 5) < 0) {
+               logerror("Could not listen to %s: %s",
+                        ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),
+                        strerror(errno));
                close(sockfd);
                return 0;
        }
diff --git a/diff.c b/diff.c
index eed227a6ace278c47a68082015d942dc2fe9cba5..d922b77aef2da84824a8e14fc21961e36e6d2e36 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -3387,6 +3387,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        }
 
        /* xdiff options */
+       else if (!strcmp(arg, "--minimal"))
+               DIFF_XDL_SET(options, NEED_MINIMAL);
+       else if (!strcmp(arg, "--no-minimal"))
+               DIFF_XDL_CLR(options, NEED_MINIMAL);
        else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space"))
                DIFF_XDL_SET(options, IGNORE_WHITESPACE);
        else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
index 8174b703c4a6dd62b01dabb34acc2a6492b43ba2..0bee6a7a88299f8c89eedeee25cece1d3cdafef0 100644 (file)
@@ -29,6 +29,7 @@ const char *git_log_output_encoding;
 int shared_repository = PERM_UMASK;
 const char *apply_default_whitespace;
 const char *apply_default_ignorewhitespace;
+const char *git_attributes_file;
 int zlib_compression_level = Z_BEST_SPEED;
 int core_compression_level;
 int core_compression_seen;
index f9347f55bac6b2d9a775c165013aa7107790e5f4..8d8ea3c45c0be5481c7b452c27ee0d163d69fb00 100644 (file)
@@ -2411,6 +2411,8 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
        /* <committish> */
        s = lookup_branch(p);
        if (s) {
+               if (is_null_sha1(s->sha1))
+                       die("Can't add a note on empty branch.");
                hashcpy(commit_sha1, s->sha1);
        } else if (*p == ':') {
                uintmax_t commit_mark = strtoumax(p + 1, NULL, 10);
@@ -2712,6 +2714,8 @@ static void parse_new_tag(void)
        from = strchr(command_buf.buf, ' ') + 1;
        s = lookup_branch(from);
        if (s) {
+               if (is_null_sha1(s->sha1))
+                       die("Can't tag an empty branch.");
                hashcpy(sha1, s->sha1);
                type = OBJ_COMMIT;
        } else if (*from == ':') {
index 2524060475ef369c0b9a4641aa88dc2ad6083da4..99efbe884528ffa730d6c0297e20d9de93d5ad9e 100755 (executable)
@@ -126,7 +126,8 @@ bisect_start() {
                start_head=$(cat "$GIT_DIR/BISECT_START")
                if test "z$mode" != "z--no-checkout"
                then
-                       git checkout "$start_head" --
+                       git checkout "$start_head" -- ||
+                       die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <validbranch>'.")"
                fi
        else
                # Get rev from where we start.
index fd6a43d0a29986d38094df2818b66beba0f49234..f8971603f77a495b253b5470f5546d51dd6efd14 100755 (executable)
@@ -854,6 +854,7 @@ set default_config(gui.fontdiff) [font configure font_diff]
 # TODO: this option should be added to the git-config documentation
 set default_config(gui.maxfilesdisplayed) 5000
 set default_config(gui.usettk) 1
+set default_config(gui.warndetachedcommit) 1
 set font_descs {
        {fontui   font_ui   {mc "Main Font"}}
        {fontdiff font_diff {mc "Diff/Console Font"}}
@@ -1526,7 +1527,7 @@ proc run_prepare_commit_msg_hook {} {
 
        # prepare-commit-msg requires PREPARE_COMMIT_MSG exist.  From git-gui
        # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an
-       # empty file but existant file.
+       # empty file but existent file.
 
        set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a]
 
index 61e358f960ca949cac5664c67442b82d0afca65f..691941e95948e7d332d6984aa6e2cc0956147550 100644 (file)
@@ -22,6 +22,7 @@ field w_asim     ; # text column: annotations (simple computation)
 field w_file     ; # text column: actual file data
 field w_cviewer  ; # pane showing commit message
 field finder     ; # find mini-dialog frame
+field gotoline   ; # line goto mini-dialog frame
 field status     ; # status mega-widget instance
 field old_height ; # last known height of $w.file_pane
 
@@ -231,6 +232,11 @@ constructor new {i_commit i_path i_jump} {
                -column [expr {[llength $w_columns] - 1}] \
                ]
 
+       set gotoline [::linebar::new \
+               $w.file_pane.out.lf $w_file \
+               -column [expr {[llength $w_columns] - 1}] \
+               ]
+
        set w_cviewer $w.file_pane.cm.t
        text $w_cviewer \
                -background white \
@@ -274,7 +280,11 @@ constructor new {i_commit i_path i_jump} {
        $w.ctxm add command \
                -label [mc "Find Text..."] \
                -accelerator F7 \
-               -command [list searchbar::show $finder]
+               -command [cb _show_finder]
+       $w.ctxm add command \
+               -label [mc "Goto Line..."] \
+               -accelerator "Ctrl-G" \
+               -command [cb _show_linebar]
        menu $w.ctxm.enc
        build_encoding_menu $w.ctxm.enc [cb _setencoding]
        $w.ctxm add cascade \
@@ -341,10 +351,13 @@ constructor new {i_commit i_path i_jump} {
        bind $w_cviewer <Tab>       "[list focus $w_file];break"
        bind $w_cviewer <Button-1>   [list focus $w_cviewer]
        bind $w_file    <Visibility> [cb _focus_search $w_file]
-       bind $top       <F7>         [list searchbar::show $finder]
+       bind $top       <F7>         [cb _show_finder]
+       bind $top       <Key-slash>  [cb _show_finder]
+       bind $top    <Control-Key-s> [cb _show_finder]
        bind $top       <Escape>     [list searchbar::hide $finder]
        bind $top       <F3>         [list searchbar::find_next $finder]
        bind $top       <Shift-F3>   [list searchbar::find_prev $finder]
+       bind $top    <Control-Key-g> [cb _show_linebar]
        catch { bind $top <Shift-Key-XF86_Switch_VT_3> [list searchbar::find_prev $finder] }
 
        grid configure $w.header -sticky ew
@@ -1298,9 +1311,9 @@ method _position_tooltip {} {
        set pos_y [expr {[winfo pointery .] + 10}]
 
        set g "${req_w}x${req_h}"
-       if {$pos_x >= 0} {append g +}
+       if {[tk windowingsystem] eq "win32" || $pos_x >= 0} {append g +}
        append g $pos_x
-       if {$pos_y >= 0} {append g +}
+       if {[tk windowingsystem] eq "win32" || $pos_y >= 0} {append g +}
        append g $pos_y
 
        wm geometry $tooltip_wm $g
@@ -1336,4 +1349,14 @@ method _resize {new_height} {
        set old_height $new_height
 }
 
+method _show_finder {} {
+       linebar::hide $gotoline
+       searchbar::show $finder
+}
+
+method _show_linebar {} {
+       searchbar::hide $finder
+       linebar::show $gotoline
+}
+
 }
index c12d5e1698a1fcdcfa39bb69b475633b2f6c34c9..54c7957a66aa5784d47708edc05a1c95178ed7a2 100644 (file)
@@ -610,9 +610,9 @@ method _position_tooltip {} {
        set pos_y [expr {[winfo pointery .] + 10}]
 
        set g "${req_w}x${req_h}"
-       if {$pos_x >= 0} {append g +}
+       if {[tk windowingsystem] eq "win32" || $pos_x >= 0} {append g +}
        append g $pos_x
-       if {$pos_y >= 0} {append g +}
+       if {[tk windowingsystem] eq "win32" || $pos_y >= 0} {append g +}
        append g $pos_y
 
        wm geometry $tooltip_wm $g
index 5ce46877bfb24701187f5ff5e94ce4aaf8b666b2..372bed9948390483d66036231fce2fe8964d7bb6 100644 (file)
@@ -260,8 +260,23 @@ proc commit_prehook_wait {fd_ph curHEAD msg_p} {
 }
 
 proc commit_commitmsg {curHEAD msg_p} {
+       global is_detached repo_config
        global pch_error
 
+       if {$is_detached && $repo_config(gui.warndetachedcommit)} {
+               set msg [mc "You are about to commit on a detached head.\
+This is a potentially dangerous thing to do because if you switch\
+to another branch you will loose your changes and it can be difficult\
+to retrieve them later from the reflog. You should probably cancel this\
+commit and create a new branch to continue.\n\
+\n\
+Do you really want to proceed with your Commit?"]
+               if {[ask_popup $msg] ne yes} {
+                       unlock_index
+                       return
+               }
+       }
+
        # -- Run the commit-msg hook.
        #
        set fd_ph [githook_read commit-msg $msg_p]
index 5d7bbf23eddeb2ff146487b28a79feee1d296289..e38b647b71ea335d6771121cfd079de919ced55b 100644 (file)
@@ -356,12 +356,21 @@ proc do_add_all {} {
        global file_states
 
        set paths [list]
+       set unknown_paths [list]
        foreach path [array names file_states] {
                switch -glob -- [lindex $file_states($path) 0] {
                U? {continue}
                ?M -
                ?T -
                ?D {lappend paths $path}
+               ?O {lappend unknown_paths $path}
+               }
+       }
+       if {[llength $unknown_paths]} {
+               set reply [ask_popup [mc "There are unknown files do you also want
+to stage those?"]]
+               if {$reply} {
+                       set paths [concat $paths $unknown_paths]
                }
        }
        add_helper {Adding all changed files} $paths
diff --git a/git-gui/lib/line.tcl b/git-gui/lib/line.tcl
new file mode 100644 (file)
index 0000000..c160012
--- /dev/null
@@ -0,0 +1,81 @@
+# goto line number
+# based on code from gitk, Copyright (C) Paul Mackerras
+
+class linebar {
+
+field w
+field ctext
+
+field linenum   {}
+
+constructor new {i_w i_text args} {
+       global use_ttk NS
+       set w      $i_w
+       set ctext  $i_text
+
+       ${NS}::frame  $w
+       ${NS}::label  $w.l       -text [mc "Goto Line:"]
+       entry  $w.ent \
+               -textvariable ${__this}::linenum \
+               -background lightgreen \
+               -validate key \
+               -validatecommand [cb _validate %P]
+       ${NS}::button $w.bn      -text [mc Go] -command [cb _goto]
+
+       pack   $w.l   -side left
+       pack   $w.bn  -side right
+       pack   $w.ent -side left -expand 1 -fill x
+
+       eval grid conf $w -sticky we $args
+       grid remove $w
+
+       trace add variable linenum write [cb _goto_cb]
+       bind $w.ent <Return> [cb _goto]
+       bind $w.ent <Escape> [cb hide]
+
+       bind $w <Destroy> [list delete_this $this]
+       return $this
+}
+
+method show {} {
+       if {![visible $this]} {
+               grid $w
+       }
+       focus -force $w.ent
+}
+
+method hide {} {
+       if {[visible $this]} {
+               $w.ent delete 0 end
+               focus $ctext
+               grid remove $w
+       }
+}
+
+method visible {} {
+       return [winfo ismapped $w]
+}
+
+method editor {} {
+       return $w.ent
+}
+
+method _validate {P} {
+       # only accept numbers as input
+       string is integer $P
+}
+
+method _goto_cb {name ix op} {
+       after idle [cb _goto 1]
+}
+
+method _goto {{nohide {0}}} {
+       if {$linenum ne {}} {
+               $ctext see $linenum.0
+               if {!$nohide} {
+                       hide $this
+               }
+       }
+}
+
+}
index 7fdbf87bcdcf3e6d5a928dd4ac8a323509ea7953..ef3486f083c74f7f5e5fe9af861818ed0d64e89c 100644 (file)
@@ -35,6 +35,8 @@ constructor new {i_w i_text args} {
        grid remove $w
 
        trace add variable searchstring write [cb _incrsearch_cb]
+       bind $w.ent <Return> [cb find_next]
+       bind $w.ent <Shift-Return> [cb find_prev]
        
        bind $w <Destroy> [list delete_this $this]
        return $this
@@ -196,4 +198,4 @@ method scrolled {} {
        }
 }
 
-}
\ No newline at end of file
+}
index 595bbf5dee97e34eeab46b742225fce2f95ab052..0f5837d48e7040e9d2b07513666b608353736645 100644 (file)
@@ -18,28 +18,23 @@ specialized so-called "po file editors" (e.g. emacs po-mode, KBabel,
 poedit, GTranslator --- any of them would work well).  Please install
 them.
 
-You would then need to clone the git-gui internationalization project
-repository, so that you can work on it:
+You would then need to clone the git-gui project repository and create
+a feature branch to begin working:
 
-       $ git clone mob@repo.or.cz:/srv/git/git-gui/git-gui-i18n.git/
-       $ cd git-gui-i18n
-       $ git checkout --track -b mob origin/mob
-       $ git config remote.origin.push mob
+       $ git clone git://repo.or.cz/git-gui.git
+       $ cd git-gui.git
+       $ git checkout -b my-translation
 
-The "git checkout" command creates a 'mob' branch from upstream's
-corresponding branch and makes it your current branch.  You will be
-working on this branch.
-
-The "git config" command records in your repository configuration file
-that you would push "mob" branch to the upstream when you say "git
-push".
+The "git checkout" command creates a new branch to keep your work
+isolated and to make it simple to post your patch series when
+completed.  You will be working on this branch.
 
 
 2. Starting a new language.
 
-In the git-gui-i18n directory is a po/ subdirectory.  It has a
-handful files whose names end with ".po".  Is there a file that has
-messages in your language?
+In the git-gui directory is a po/ subdirectory.  It has a handful of
+files whose names end with ".po".  Is there a file that has messages
+in your language?
 
 If you do not know what your language should be named, you need to find
 it.  This currently follows ISO 639-1 two letter codes:
@@ -149,15 +144,18 @@ There is a trick to test your translation without first installing:
        $ make
        $ LANG=af ./git-gui.sh
 
-When you are satisfied with your translation, commit your changes, and
-push it back to the 'mob' branch:
+When you are satisfied with your translation, commit your changes then submit
+your patch series to the maintainer and the Git mailing list:
 
        $ edit po/af.po
        ... be sure to update Last-Translator: and
        ... PO-Revision-Date: lines.
        $ git add po/af.po
-       $ git commit -m 'Started Afrikaans translation.'
-       $ git push
+       $ git commit -s -m 'git-gui: added Afrikaans translation.'
+       $ git send-email --to 'git@vger.kernel.org' \
+          --cc 'Pat Thoyts <patthoyts@users.sourceforge.net>' \
+          --subject 'git-gui: Afrikaans translation' \
+          master..
 
 
 3. Updating your translation.
@@ -169,6 +167,7 @@ itself was updated and there are new messages that need translation.
 
 In any case, make sure you are up-to-date before starting your work:
 
+       $ git checkout master
        $ git pull
 
 In the former case, you will edit po/af.po (again, replace "af" with
index 8bd3c5d75feea3dfe310adbfab705d8045aa8367..24cc4e3675e05e9bd3bf7ea17335a67a3aa5166b 100644 (file)
@@ -1714,7 +1714,7 @@ msgstr ""
 
 #: lib/index.tcl:30
 msgid "Continue"
-msgstr "Forstätt"
+msgstr "Fortsätt"
 
 #: lib/index.tcl:33
 msgid "Unlock Index"
index 7aeb96952f668baef2fd18383806e13a20415f19..f612cb847aca981e16cb6006fa08d870497c6263 100755 (executable)
@@ -117,7 +117,7 @@ case "${1:-.}${2:-.}${3:-.}" in
 
                # If we do not have enough common material, it is not
                # worth trying two-file merge using common subsections.
-               expr "$sz0" \< "$sz1" \* 2 >/dev/null || : >$orig
+               expr $sz0 \< $sz1 \* 2 >/dev/null || : >$orig
                ;;
        *)
                echo "Auto-merging $4"
index 8c1370f81bfa95832de99d78aa3bee4f763b821a..9868a0bfb478707b361f664a252870b3d1939138 100755 (executable)
@@ -11,7 +11,7 @@ OPTIONS_SPEC=
 . git-sh-setup
 . git-sh-i18n
 set_reflog_action "pull${1+ $*}"
-require_work_tree
+require_work_tree_exists
 cd_to_toplevel
 
 
index 6759702c573f51ac00bf1b5c8abccf252cb4ff1d..00ca7b99fef35e21d24af844e6dbaa92cab5834f 100755 (executable)
@@ -63,7 +63,7 @@ skip!              skip current patch and continue
 "
 . git-sh-setup
 set_reflog_action rebase
-require_work_tree
+require_work_tree_exists
 cd_to_toplevel
 
 LF='
index 91607c5878953d69a8e32731023b2eb727bcc069..d491db92c9379cf0eea63182dd704feb6582b6e7 100755 (executable)
@@ -337,8 +337,16 @@ sub read_config {
        }
 
        foreach my $setting (keys %config_path_settings) {
-               my $target = $config_path_settings{$setting}->[0];
-               $$target = Git::config_path(@repo, "$prefix.$setting") unless (defined $$target);
+               my $target = $config_path_settings{$setting};
+               if (ref($target) eq "ARRAY") {
+                       unless (@$target) {
+                               my @values = Git::config_path(@repo, "$prefix.$setting");
+                               @$target = @values if (@values && defined $values[0]);
+                       }
+               }
+               else {
+                       $$target = Git::config_path(@repo, "$prefix.$setting") unless (defined $$target);
+               }
        }
 
        foreach my $setting (keys %config_settings) {
@@ -1090,7 +1098,7 @@ sub send_message {
                                        $smtp_encryption = '';
                                        # Send EHLO again to receive fresh
                                        # supported commands
-                                       $smtp->hello();
+                                       $smtp->hello($smtp_domain);
                                } else {
                                        die "Server does not support STARTTLS! ".$smtp->message;
                                }
index a0410f055406eaaf54ddb056d4b501b3cd250d72..b67fef0bf69da170a5a9748b9da8c31c6e1ca5c7 100755 (executable)
 $Git::SVN::Ra::_log_window_size = 100;
 $Git::SVN::_minimize_url = 'unset';
 
-if (! exists $ENV{SVN_SSH}) {
-       if (exists $ENV{GIT_SSH}) {
-               $ENV{SVN_SSH} = $ENV{GIT_SSH};
-               if ($^O eq 'msys') {
-                       $ENV{SVN_SSH} =~ s/\\/\\\\/g;
-                       $ENV{SVN_SSH} =~ s/(.*)/"$1"/;
-               }
-       }
+if (! exists $ENV{SVN_SSH} && exists $ENV{GIT_SSH}) {
+       $ENV{SVN_SSH} = $ENV{GIT_SSH};
+}
+
+if (exists $ENV{SVN_SSH} && $^O eq 'msys') {
+       $ENV{SVN_SSH} =~ s/\\/\\\\/g;
+       $ENV{SVN_SSH} =~ s/(.*)/"$1"/;
 }
 
 $Git::SVN::Log::TZ = $ENV{TZ};
@@ -87,14 +86,15 @@ BEGIN
        $_version, $_fetch_all, $_no_rebase, $_fetch_parent,
        $_merge, $_strategy, $_dry_run, $_local,
        $_prefix, $_no_checkout, $_url, $_verbose,
-       $_git_format, $_commit_url, $_tag, $_merge_info);
+       $_git_format, $_commit_url, $_tag, $_merge_info, $_interactive);
 $Git::SVN::_follow_parent = 1;
 $SVN::Git::Fetcher::_placeholder_filename = ".gitignore";
 $_q ||= 0;
 my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
                     'config-dir=s' => \$Git::SVN::Ra::config_dir,
                     'no-auth-cache' => \$Git::SVN::Prompt::_no_auth_cache,
-                    'ignore-paths=s' => \$SVN::Git::Fetcher::_ignore_regex );
+                    'ignore-paths=s' => \$SVN::Git::Fetcher::_ignore_regex,
+                    'ignore-refs=s' => \$Git::SVN::Ra::_ignore_refs_regex );
 my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
                'authors-file|A=s' => \$_authors,
                'authors-prog=s' => \$_authors_prog,
@@ -163,6 +163,7 @@ BEGIN
                          'revision|r=i' => \$_revision,
                          'no-rebase' => \$_no_rebase,
                          'mergeinfo=s' => \$_merge_info,
+                         'interactive|i' => \$_interactive,
                        %cmt_opts, %fc_opts } ],
        branch => [ \&cmd_branch,
                    'Create a branch in the SVN repository',
@@ -256,6 +257,27 @@ BEGIN
                {} ],
 );
 
+use Term::ReadLine;
+package FakeTerm;
+sub new {
+       my ($class, $reason) = @_;
+       return bless \$reason, shift;
+}
+sub readline {
+       my $self = shift;
+       die "Cannot use readline on FakeTerm: $$self";
+}
+package main;
+
+my $term = eval {
+       $ENV{"GIT_SVN_NOTTY"}
+               ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT
+               : new Term::ReadLine 'git-svn';
+};
+if ($@) {
+       $term = new FakeTerm "$@: going non-interactive";
+}
+
 my $cmd;
 for (my $i = 0; $i < @ARGV; $i++) {
        if (defined $cmd{$ARGV[$i]}) {
@@ -366,6 +388,36 @@ sub version {
        exit 0;
 }
 
+sub ask {
+       my ($prompt, %arg) = @_;
+       my $valid_re = $arg{valid_re};
+       my $default = $arg{default};
+       my $resp;
+       my $i = 0;
+
+       if ( !( defined($term->IN)
+            && defined( fileno($term->IN) )
+            && defined( $term->OUT )
+            && defined( fileno($term->OUT) ) ) ){
+               return defined($default) ? $default : undef;
+       }
+
+       while ($i++ < 10) {
+               $resp = $term->readline($prompt);
+               if (!defined $resp) { # EOF
+                       print "\n";
+                       return defined $default ? $default : undef;
+               }
+               if ($resp eq '' and defined $default) {
+                       return $default;
+               }
+               if (!defined $valid_re or $resp =~ /$valid_re/) {
+                       return $resp;
+               }
+       }
+       return undef;
+}
+
 sub do_git_init_db {
        unless (-d $ENV{GIT_DIR}) {
                my @init_db = ('init');
@@ -388,9 +440,12 @@ sub do_git_init_db {
                command_noisy('config', "$pfx.$i", $icv{$i});
                $set = $i;
        }
-       my $ignore_regex = \$SVN::Git::Fetcher::_ignore_regex;
-       command_noisy('config', "$pfx.ignore-paths", $$ignore_regex)
-               if defined $$ignore_regex;
+       my $ignore_paths_regex = \$SVN::Git::Fetcher::_ignore_regex;
+       command_noisy('config', "$pfx.ignore-paths", $$ignore_paths_regex)
+               if defined $$ignore_paths_regex;
+       my $ignore_refs_regex = \$Git::SVN::Ra::_ignore_refs_regex;
+       command_noisy('config', "$pfx.ignore-refs", $$ignore_refs_regex)
+               if defined $$ignore_refs_regex;
 
        if (defined $SVN::Git::Fetcher::_preserve_empty_dirs) {
                my $fname = \$SVN::Git::Fetcher::_placeholder_filename;
@@ -746,6 +801,27 @@ sub cmd_dcommit {
                     "If these changes depend on each other, re-running ",
                     "without --no-rebase may be required."
        }
+
+       if (defined $_interactive){
+               my $ask_default = "y";
+               foreach my $d (@$linear_refs){
+                       my ($fh, $ctx) = command_output_pipe(qw(show --summary), "$d");
+                       while (<$fh>){
+                               print $_;
+                       }
+                       command_close_pipe($fh, $ctx);
+                       $_ = ask("Commit this patch to SVN? ([y]es (default)|[n]o|[q]uit|[a]ll): ",
+                                valid_re => qr/^(?:yes|y|no|n|quit|q|all|a)/i,
+                                default => $ask_default);
+                       die "Commit this patch reply required" unless defined $_;
+                       if (/^[nq]/i) {
+                               exit(0);
+                       } elsif (/^a/i) {
+                               last;
+                       }
+               }
+       }
+
        my $expect_url = $url;
 
        my $push_merge_info = eval {
@@ -2119,6 +2195,8 @@ sub read_all_remotes {
                        $r->{$1}->{url} = $2;
                } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) {
                        $r->{$1}->{pushurl} = $2;
+               } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) {
+                       $r->{$1}->{ignore_refs_regex} = $2;
                } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
                        my ($remote, $t, $local_ref, $remote_ref) =
                                                             ($1, $2, $3, $4);
@@ -2155,6 +2233,16 @@ sub read_all_remotes {
                }
        } keys %$r;
 
+       foreach my $remote (keys %$r) {
+               foreach ( grep { defined $_ }
+                         map { $r->{$remote}->{$_} } qw(branches tags) ) {
+                       foreach my $rs ( @$_ ) {
+                               $rs->{ignore_refs_regex} =
+                                   $r->{$remote}->{ignore_refs_regex};
+                       }
+               }
+       }
+
        $r;
 }
 
@@ -5310,7 +5398,7 @@ sub apply_diff {
 }
 
 package Git::SVN::Ra;
-use vars qw/@ISA $config_dir $_log_window_size/;
+use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/;
 use strict;
 use warnings;
 my ($ra_invalid, $can_do_switch, %ignored_err, $RA);
@@ -5768,6 +5856,17 @@ sub get_dir_globbed {
        @finalents;
 }
 
+# return value: 0 -- don't ignore, 1 -- ignore
+sub is_ref_ignored {
+       my ($g, $p) = @_;
+       my $refname = $g->{ref}->full_path($p);
+       return 1 if defined($g->{ignore_refs_regex}) &&
+                   $refname =~ m!$g->{ignore_refs_regex}!;
+       return 0 unless defined($_ignore_refs_regex);
+       return 1 if $refname =~ m!$_ignore_refs_regex!o;
+       return 0;
+}
+
 sub match_globs {
        my ($self, $exists, $paths, $globs, $r) = @_;
 
@@ -5804,6 +5903,7 @@ sub match_globs {
                        next unless /$g->{path}->{regex}/;
                        my $p = $1;
                        my $pathname = $g->{path}->full_path($p);
+                       next if is_ref_ignored($g, $p);
                        next if $exists->{$pathname};
                        next if ($self->check_path($pathname, $r) !=
                                 $SVN::Node::dir);
index e9de241dd004a9f5d6d6d8e6a300a1fa5949a46d..1e827264b4cab04a801804b8d066f9d2cbb85edc 100755 (executable)
@@ -156,7 +156,7 @@ firefox|iceweasel|seamonkey|iceape)
        ;;
 google-chrome|chrome|chromium|chromium-browser)
        # No need to specify newTab. It's default in chromium
-       eval "$browser_path" "$@" &
+       "$browser_path" "$@" &
        ;;
 konqueror)
        case "$(basename "$browser_path")" in
@@ -164,10 +164,10 @@ konqueror)
                # It's simpler to use kfmclient to open a new tab in konqueror.
                browser_path="$(echo "$browser_path" | sed -e 's/konqueror$/kfmclient/')"
                type "$browser_path" > /dev/null 2>&1 || die "No '$browser_path' found."
-               eval "$browser_path" newTab "$@"
+               "$browser_path" newTab "$@" &
                ;;
        kfmclient)
-               eval "$browser_path" newTab "$@"
+               "$browser_path" newTab "$@" &
                ;;
        *)
                "$browser_path" "$@" &
@@ -175,7 +175,7 @@ konqueror)
        esac
        ;;
 w3m|elinks|links|lynx|open)
-       eval "$browser_path" "$@"
+       "$browser_path" "$@"
        ;;
 start)
        exec "$browser_path" '"web-browse"' "$@"
@@ -185,7 +185,7 @@ opera|dillo)
        ;;
 *)
        if test -n "$browser_cmd"; then
-               ( eval $browser_cmd "$@" )
+               ( eval "$browser_cmd \"\$@\"" )
        fi
        ;;
 esac
index 91c8462b7dae171247c40db7f7b5b36d2c0633a1..c562c622847b9559fd40ae867f0d3cb229fa784b 100644 (file)
@@ -199,7 +199,11 @@ rm -rf $RPM_BUILD_ROOT
 
 %files -n gitweb
 %defattr(-,root,root)
+%doc gitweb/README gitweb/INSTALL Documentation/*gitweb*.txt
 %{_datadir}/gitweb
+%{!?_without_docs: %{_mandir}/man1/*gitweb*.1*}
+%{!?_without_docs: %{_mandir}/man5/*gitweb*.5*}
+%{!?_without_docs: %doc Documentation/*gitweb*.html }
 
 %files -n perl-Git -f perl-files
 %defattr(-,root,root)
@@ -208,6 +212,9 @@ rm -rf $RPM_BUILD_ROOT
 # No files for you!
 
 %changelog
+* Sun Sep 18 2011 Jakub Narebski <jnareb@gmail.com>
+- Add gitweb manpages to 'gitweb' subpackage
+
 * Wed Jun 30 2010 Junio C Hamano <gitster@pobox.com>
 - Add 'gitweb' subpackage.
 
index f5efe7454ca42decbe7b113388bc6233e2311c1e..d134ffe4c75fcc303631cdac15c1bed011c45fd1 100644 (file)
@@ -229,7 +229,7 @@ Gitweb config file
 ------------------
 
 See also "Runtime gitweb configuration" section in README file
-for gitweb (in gitweb/README).
+for gitweb (in gitweb/README), and gitweb.conf(5) manpage.
 
 - You can configure gitweb further using the per-instance gitweb configuration file;
   by default this is a file named gitweb_config.perl in the same place as
@@ -287,97 +287,19 @@ adding the following lines to your $GITWEB_CONFIG:
 Gitweb repositories
 -------------------
 
-- By default all git repositories under projectroot are visible and
-  available to gitweb. The list of projects is generated by default by
-  scanning the projectroot directory for git repositories (for object
-  databases to be more exact).
-
-  You can provide a pre-generated list of [visible] repositories,
-  together with information about their owners (the project ownership
-  defaults to the owner of the repository directory otherwise), by setting
-  the GITWEB_LIST build configuration variable (or the $projects_list
-  variable in the gitweb config file) to point to a plain file.
-
-  Each line of the projects list file should consist of the url-encoded path
-  to the project repository database (relative to projectroot), followed
-  by the url-encoded project owner on the same line (separated by a space).
-  Spaces in both project path and project owner have to be encoded as either
-  '%20' or '+'.
-
-  Other characters that have to be url-encoded, i.e. replaced by '%'
-  followed by two-digit character number in octal, are: other whitespace
-  characters (because they are field separator in a record), plus sign '+'
-  (because it can be used as replacement for spaces), and percent sign '%'
-  (which is used for encoding / escaping).
-
-  You can generate the projects list index file using the project_index
-  action (the 'TXT' link on projects list page) directly from gitweb.
-
-- By default, even if a project is not visible on projects list page, you
-  can view it nevertheless by hand-crafting a gitweb URL. You can set the
-  GITWEB_STRICT_EXPORT build configuration variable (or the $strict_export
-  variable in the gitweb config file) to only allow viewing of
-  repositories also shown on the overview page.
-
-- Alternatively, you can configure gitweb to only list and allow
-  viewing of the explicitly exported repositories, via the
-  GITWEB_EXPORT_OK build configuration variable (or the $export_ok
-  variable in gitweb config file). If it evaluates to true, gitweb
-  shows repositories only if this file exists in its object database
-  (if directory has the magic file named $export_ok).
-
-- Finally, it is possible to specify an arbitrary perl subroutine that
-  will be called for each project to determine if it can be exported.
-  The subroutine receives an absolute path to the project as its only
-  parameter.
-
-  For example, if you use mod_perl to run the script, and have dumb
-  http protocol authentication configured for your repositories, you
-  can use the following hook to allow access only if the user is
-  authorized to read the files:
-
-    $export_auth_hook = sub {
-        use Apache2::SubRequest ();
-        use Apache2::Const -compile => qw(HTTP_OK);
-        my $path = "$_[0]/HEAD";
-        my $r    = Apache2::RequestUtil->request;
-        my $sub  = $r->lookup_file($path);
-        return $sub->filename eq $path
-            && $sub->status == Apache2::Const::HTTP_OK;
-    };
-
-
-Generating projects list using gitweb
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We assume that GITWEB_CONFIG has its default Makefile value, namely
-gitweb_config.perl. Put the following in gitweb_make_index.perl file:
-
-       $GITWEB_CONFIG = "gitweb_config.perl";
-       do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
-
-       $projects_list = $projectroot;
-
-Then create the following script to get list of project in the format
-suitable for GITWEB_LIST build configuration variable (or
-$projects_list variable in gitweb config):
-
-       #!/bin/sh
-
-       export GITWEB_CONFIG="gitweb_make_index.perl"
-       export GATEWAY_INTERFACE="CGI/1.1"
-       export HTTP_ACCEPT="*/*"
-       export REQUEST_METHOD="GET"
-       export QUERY_STRING="a=project_index"
-
-       perl -- /var/www/cgi-bin/gitweb.cgi
+By default gitweb shows all git repositories under single common repository
+root on a local filesystem; see description of GITWEB_PROJECTROOT build-time
+configuration variable above (and also of GITWEB_LIST).
+
+More advanced usage, like limiting access or visibility of repositories and
+managing multiple roots are described on gitweb manpage.
 
 
 Example web server configuration
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-See also "Webserver configuration" section in README file for gitweb
-(in gitweb/README).
+See also "Webserver configuration" and "Advanced web server setup" sections
+in gitweb(1) manpage.
 
 
 - Apache2, gitweb installed as CGI script,
index a9988200d6b67066b837e7298e0e1529057a4bca..6da4778b73e3ef1d098fce7655bf4ca5bb2443e5 100644 (file)
@@ -7,9 +7,18 @@ The one working on:
 From the git version 1.4.0 gitweb is bundled with git.
 
 
+Build time gitweb configuration
+-------------------------------
+There are many configuration variables which affect building gitweb (among
+others creating gitweb.cgi out of gitweb.perl by replacing placeholders such
+as `++GIT_BINDIR++` by their build-time values).
+
+Building and installing gitweb is described in gitweb's INSTALL file
+(in 'gitweb/INSTALL').
+
+
 Runtime gitweb configuration
 ----------------------------
-
 Gitweb obtains configuration data from the following sources in the
 following order:
 
@@ -41,400 +50,22 @@ Ultimate description on how to reconfigure the default features setting
 in your `GITWEB_CONFIG` or per-project in `project.git/config` can be found
 as comments inside 'gitweb.cgi'.
 
-See also the "Gitweb config file" (with an example of config file), and
-the "Gitweb repositories" sections in INSTALL file for gitweb.
-
-
-The gitweb config file is a fragment of perl code. You can set variables
-using "our $variable = value"; text from "#" character until the end
-of a line is ignored. See perlsyn(1) man page for details.
-
-Below is the list of variables which you might want to set in gitweb config.
-See the top of 'gitweb.cgi' for the full list of variables and their
-descriptions.
-
-Gitweb config file variables
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can set, among others, the following variables in gitweb config files
-(with the exception of $projectroot and $projects_list this list does
-not include variables usually directly set during build):
- * $GIT
-   Core git executable to use.  By default set to "$GIT_BINDIR/git", which
-   in turn is by default set to "$(bindir)/git".  If you use git from binary
-   package, set this to "/usr/bin/git".  This can just be "git" if your
-   webserver has a sensible PATH.  If you have multiple git versions
-   installed it can be used to choose which one to use.
- * $version
-   Gitweb version, set automatically when creating gitweb.cgi from
-   gitweb.perl. You might want to modify it if you are running modified
-   gitweb.
- * $projectroot
-   Absolute filesystem path which will be prepended to project path;
-   the path to repository is $projectroot/$project.  Set to
-   $GITWEB_PROJECTROOT during installation.  This variable have to be
-   set correctly for gitweb to find repositories.
- * $projects_list
-   Source of projects list, either directory to scan, or text file
-   with list of repositories (in the "<URI-encoded repository path> SP
-   <URI-encoded repository owner>" line format; actually there can be
-   any sequence of whitespace in place of space (SP)).  Set to
-   $GITWEB_LIST during installation.  If empty, $projectroot is used
-   to scan for repositories.
- * $my_url, $my_uri
-   Full URL and absolute URL of gitweb script;
-   in earlier versions of gitweb you might have need to set those
-   variables, now there should be no need to do it.  See
-   $per_request_config if you need to set them still.
- * $base_url
-   Base URL for relative URLs in pages generated by gitweb,
-   (e.g. $logo, $favicon, @stylesheets if they are relative URLs),
-   needed and used only for URLs with nonempty PATH_INFO via
-   <base href="$base_url">.  Usually gitweb sets its value correctly,
-   and there is no need to set this variable, e.g. to $my_uri or "/".
-   See $per_request_config if you need to set it anyway.
- * $home_link
-   Target of the home link on top of all pages (the first part of view
-   "breadcrumbs").  By default set to absolute URI of a page ($my_uri).
- * @stylesheets
-   List of URIs of stylesheets (relative to base URI of a page). You
-   might specify more than one stylesheet, for example use gitweb.css
-   as base, with site specific modifications in separate stylesheet
-   to make it easier to upgrade gitweb. You can add 'site' stylesheet
-   for example by using
-      push @stylesheets, "gitweb-site.css";
-   in the gitweb config file.
- * $logo_url, $logo_label
-   URI and label (title) of GIT logo link (or your site logo, if you choose
-   to use different logo image). By default they point to git homepage;
-   in the past they pointed to git documentation at www.kernel.org.
- * $projects_list_description_width
-   The width (in characters) of the projects list "Description" column.
-   Longer descriptions will be cut (trying to cut at word boundary);
-   full description is available as 'title' attribute (usually shown on
-   mouseover).  By default set to 25, which might be too small if you
-   use long project descriptions.
- * $projects_list_group_categories
-   Enables the grouping of projects by category on the project list page.
-   The category of a project is determined by the $GIT_DIR/category
-   file or the 'gitweb.category' variable in its repository configuration.
-   Disabled by default.
- * $project_list_default_category
-   Default category for projects for which none is specified.  If set
-   to the empty string, such projects will remain uncategorized and
-   listed at the top, above categorized projects.
- * @git_base_url_list
-   List of git base URLs used for URL to where fetch project from, shown
-   in project summary page.  Full URL is "$git_base_url/$project".
-   You can setup multiple base URLs (for example one for  git:// protocol
-   access, and one for http:// "dumb" protocol access).  Note that per
-   repository configuration in 'cloneurl' file, or as values of gitweb.url
-   project config.
- * $default_blob_plain_mimetype
-   Default mimetype for blob_plain (raw) view, if mimetype checking
-   doesn't result in some other type; by default 'text/plain'.
- * $default_text_plain_charset
-   Default charset for text files. If not set, web server configuration
-   would be used.
- * $mimetypes_file
-   File to use for (filename extension based) guessing of MIME types before
-   trying /etc/mime.types. Path, if relative, is taken currently as
-   relative to the current git repository.
- * $fallback_encoding
-   Gitweb assumes this charset if line contains non-UTF-8 characters.
-   Fallback decoding is used without error checking, so it can be even
-   'utf-8'. Value must be valid encoding; see Encoding::Supported(3pm) man
-   page for a list.   By default 'latin1', aka. 'iso-8859-1'.
- * @diff_opts
-   Rename detection options for git-diff and git-diff-tree. By default
-   ('-M'); set it to ('-C') or ('-C', '-C') to also detect copies, or
-   set it to () if you don't want to have renames detection.
- * $prevent_xss
-   If true, some gitweb features are disabled to prevent content in
-   repositories from launching cross-site scripting (XSS) attacks.  Set this
-   to true if you don't trust the content of your repositories. The default
-   is false.
- * $maxload
-   Used to set the maximum load that we will still respond to gitweb queries.
-   If server load exceed this value then return "503 Service Unavailable" error.
-   Server load is taken to be 0 if gitweb cannot determine its value.  Set it to
-   undefined value to turn it off.  The default is 300.
- * $highlight_bin
-   Path to the highlight executable to use (must be the one from
-   http://www.andre-simon.de due to assumptions about parameters and output).
-   Useful if highlight is not installed on your webserver's PATH.
-   [Default: highlight]
- * $per_request_config
-   If set to code reference, it would be run once per each request.  You can
-   set parts of configuration that change per session, e.g. by setting it to
-     sub { $ENV{GL_USER} = $cgi->remote_user || "gitweb"; }
-   Otherwise it is treated as boolean value: if true gitweb would process
-   config file once per request, if false it would process config file only
-   once.  Note: $my_url, $my_uri, and $base_url are overwritten with
-   their default values before every request, so if you want to change
-   them, be sure to set this variable to true or a code reference effecting
-   the desired changes.  The default is true.
-
-Projects list file format
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Instead of having gitweb find repositories by scanning filesystem starting
-from $projectroot (or $projects_list, if it points to directory), you can
-provide list of projects by setting $projects_list to a text file with list
-of projects (and some additional info).  This file uses the following
-format:
-
-One record (for project / repository) per line, whitespace separated fields;
-does not support (at least for now) lines continuation (newline escaping).
-Leading and trailing whitespace are ignored, any run of whitespace can be
-used as field separator (rules for Perl's "split(' ', $line)").  Keyed by
-the first field, which is project name, i.e. path to repository GIT_DIR
-relative to $projectroot.  Fields use modified URI encoding, defined in
-RFC 3986, section 2.1 (Percent-Encoding), or rather "Query string encoding"
-(see http://en.wikipedia.org/wiki/Query_string#URL_encoding), the difference
-being that SP (' ') can be encoded as '+' (and therefore '+' has to be also
-percent-encoded).  Reserved characters are: '%' (used for encoding), '+'
-(can be used to encode SPACE), all whitespace characters as defined in Perl,
-including SP, TAB and LF, (used to separate fields in a record).
-
-Currently list of fields is
- * <repository path>  - path to repository GIT_DIR, relative to $projectroot
- * <repository owner> - displayed as repository owner, preferably full name,
-                        or email, or both
-
-You can additionally use $projects_list file to limit which repositories
-are visible, and together with $strict_export to limit access to
-repositories (see "Gitweb repositories" section in gitweb/INSTALL).
-
-
-Per-repository gitweb configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can also configure individual repositories shown in gitweb by creating
-file in the GIT_DIR of git repository, or by setting some repo configuration
-variable (in GIT_DIR/config).
-
-You can use the following files in repository:
- * README.html
-   A .html file (HTML fragment) which is included on the gitweb project
-   summary page inside <div> block element. You can use it for longer
-   description of a project, to provide links (for example to project's
-   homepage), etc. This is recognized only if XSS prevention is off
-   ($prevent_xss is false); a way to include a readme safely when XSS
-   prevention is on may be worked out in the future.
- * description (or gitweb.description)
-   Short (shortened by default to 25 characters in the projects list page)
-   single line description of a project (of a repository). Plain text file;
-   HTML will be escaped. By default set to
-     Unnamed repository; edit this file to name it for gitweb.
-   from the template during repository creation. You can use the
-   gitweb.description repo configuration variable, but the file takes
-   precedence.
- * category (or gitweb.category)
-   Singe line category of a project, used to group projects if
-   $projects_list_group_categories is enabled. By default (file and
-   configuration variable absent), uncategorized projects are put in
-   the $project_list_default_category category. You can use the
-   gitweb.category repo configuration variable, but the file takes
-   precedence.
- * cloneurl (or multiple-valued gitweb.url)
-   File with repository URL (used for clone and fetch), one per line.
-   Displayed in the project summary page. You can use multiple-valued
-   gitweb.url repository configuration variable for that, but the file
-   takes precedence.
- * gitweb.owner
-   You can use the gitweb.owner repository configuration variable to set
-   repository's owner. It is displayed in the project list and summary
-   page. If it's not set, filesystem directory's owner is used
-   (via GECOS field / real name field from getpwiud(3)).
- * various gitweb.* config variables (in config)
-   Read description of %feature hash for detailed list, and some
-   descriptions.
-
-
-Webserver configuration
------------------------
-
-If you want to have one URL for both gitweb and your http://
-repositories, you can configure apache like this:
-
-<VirtualHost *:80>
-    ServerName         git.example.org
-    DocumentRoot       /pub/git
-    SetEnv                     GITWEB_CONFIG   /etc/gitweb.conf
-
-    # turning on mod rewrite
-    RewriteEngine on
-
-    # make the front page an internal rewrite to the gitweb script
-    RewriteRule ^/$  /cgi-bin/gitweb.cgi
-
-    # make access for "dumb clients" work
-    RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ /cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
-</VirtualHost>
-
-The above configuration expects your public repositories to live under
-/pub/git and will serve them as http://git.domain.org/dir-under-pub-git,
-both as cloneable GIT URL and as browseable gitweb interface.
-If you then start your git-daemon with --base-path=/pub/git --export-all
-then you can even use the git:// URL with exactly the same path.
-
-Setting the environment variable GITWEB_CONFIG will tell gitweb to use
-the named file (i.e. in this example /etc/gitweb.conf) as a
-configuration for gitweb.  Perl variables defined in here will
-override the defaults given at the head of the gitweb.perl (or
-gitweb.cgi).  Look at the comments in that file for information on
-which variables and what they mean.
-
-If you use the rewrite rules from the example you'll likely also need
-something like the following in your gitweb.conf (or gitweb_config.perl) file:
-
-  @stylesheets = ("/some/absolute/path/gitweb.css");
-  $my_uri = "/";
-  $home_link = "/";
-
-
-Webserver configuration with multiple projects' root
-----------------------------------------------------
-
-If you want to use gitweb with several project roots you can edit your apache
-virtual host and gitweb.conf configuration files like this :
-
-virtual host configuration :
-
-<VirtualHost *:80>
-    ServerName                 git.example.org
-    DocumentRoot               /pub/git
-    SetEnv                             GITWEB_CONFIG   /etc/gitweb.conf
-
-    # turning on mod rewrite
-    RewriteEngine on
-
-    # make the front page an internal rewrite to the gitweb script
-    RewriteRule ^/$            /cgi-bin/gitweb.cgi [QSA,L,PT]
-
-    # look for a public_git folder in unix users' home
-    # http://git.example.org/~<user>/
-    RewriteRule ^/\~([^\/]+)(/|/gitweb.cgi)?$  /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
-
-    # http://git.example.org/+<user>/
-    #RewriteRule ^/\+([^\/]+)(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
-
-    # http://git.example.org/user/<user>/
-    #RewriteRule ^/user/([^\/]+)/(gitweb.cgi)?$        /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
-
-    # defined list of project roots
-    RewriteRule ^/scm(/|/gitweb.cgi)?$         /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/pub/scm/,L,PT]
-    RewriteRule ^/var(/|/gitweb.cgi)?$         /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/var/git/,L,PT]
-
-    # make access for "dumb clients" work
-    RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ /cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
-</VirtualHost>
-
-gitweb.conf configuration :
-
-$projectroot = $ENV{'GITWEB_PROJECTROOT'} || "/pub/git";
-
-These configurations enable two things. First, each unix user (<user>) of the
-server will be able to browse through gitweb git repositories found in
-~/public_git/ with the following url : http://git.example.org/~<user>/
-
-If you do not want this feature on your server just remove the second rewrite rule.
-
-If you already use mod_userdir in your virtual host or you don't want to use
-the '~' as first character just comment or remove the second rewrite rule and
-uncomment one of the following according to what you want.
-
-Second, repositories found in /pub/scm/ and /var/git/ will be accesible
-through http://git.example.org/scm/ and http://git.example.org/var/.
-You can add as many project roots as you want by adding rewrite rules like the
-third and the fourth.
-
-
-PATH_INFO usage
------------------------
-If you enable PATH_INFO usage in gitweb by putting
-
-   $feature{'pathinfo'}{'default'} = [1];
-
-in your gitweb.conf, it is possible to set up your server so that it
-consumes and produces URLs in the form
-
-http://git.example.com/project.git/shortlog/sometag
-
-by using a configuration such as the following, that assumes that
-/var/www/gitweb is the DocumentRoot of your webserver, and that it
-contains the gitweb.cgi script and complementary static files
-(stylesheet, favicon):
-
-<VirtualHost *:80>
-       ServerAlias git.example.com
-
-       DocumentRoot /var/www/gitweb
-
-       <Directory /var/www/gitweb>
-               Options ExecCGI
-               AddHandler cgi-script cgi
-
-               DirectoryIndex gitweb.cgi
-
-               RewriteEngine On
-               RewriteCond %{REQUEST_FILENAME} !-f
-               RewriteCond %{REQUEST_FILENAME} !-d
-               RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
-       </Directory>
-</VirtualHost>
-
-The rewrite rule guarantees that existing static files will be properly
-served, whereas any other URL will be passed to gitweb as PATH_INFO
-parameter.
-
-Notice that in this case you don't need special settings for
-@stylesheets, $my_uri and $home_link, but you lose "dumb client" access
-to your project .git dirs. A possible workaround for the latter is the
-following: in your project root dir (e.g. /pub/git) have the projects
-named without a .git extension (e.g. /pub/git/project instead of
-/pub/git/project.git) and configure Apache as follows:
-
-<VirtualHost *:80>
-       ServerAlias git.example.com
-
-       DocumentRoot /var/www/gitweb
-
-       AliasMatch ^(/.*?)(\.git)(/.*)?$ /pub/git$1$3
-       <Directory /var/www/gitweb>
-               Options ExecCGI
-               AddHandler cgi-script cgi
-
-               DirectoryIndex gitweb.cgi
-
-               RewriteEngine On
-               RewriteCond %{REQUEST_FILENAME} !-f
-               RewriteCond %{REQUEST_FILENAME} !-d
-               RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
-       </Directory>
-</VirtualHost>
-
-The additional AliasMatch makes it so that
-
-http://git.example.com/project.git
-
-will give raw access to the project's git dir (so that the project can
-be cloned), while
-
-http://git.example.com/project
-
-will provide human-friendly gitweb access.
-
-This solution is not 100% bulletproof, in the sense that if some project
-has a named ref (branch, tag) starting with 'git/', then paths such as
+See also gitweb.conf(5) manpage.
 
-http://git.example.com/project/command/abranch..git/abranch
 
-will fail with a 404 error.
+Web server configuration
+------------------------
+Gitweb can be run as CGI script, as legacy mod_perl application (using
+ModPerl::Registry), and as FastCGI script.  You can find some simple examples
+in "Example web server configuration" section in INSTALL file for gitweb (in
+gitweb/INSTALL).
 
+See "Webserver configuration" and "Advanced web server setup" sections in
+gitweb(1) manpage.
 
 
+AUTHORS
+-------
 Originally written by:
   Kay Sievers <kay.sievers@vrfy.org>
 
index 8c4c5d2224a2493a648e6a34257bc150f2712dd0..69299b7bd2a956266bf581df9c23589a97fca805 100644 (file)
@@ -67,7 +67,7 @@ int main(int argc, const char **argv)
 
        git_config(git_default_config, NULL);
 
-       http_init(NULL);
+       http_init(NULL, url);
        walker = get_http_walker(url);
        walker->get_tree = get_tree;
        walker->get_history = get_history;
index 376331a76fcde24e6828eba0b88fec26d93fe56f..5d01be93440cdb343379fe0b05ff9155727f125c 100644 (file)
@@ -1606,10 +1606,10 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
        strbuf_release(&buffer);
 }
 
-static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1)
+static int verify_merge_base(unsigned char *head_sha1, struct ref *remote)
 {
-       struct commit *head = lookup_commit(head_sha1);
-       struct commit *branch = lookup_commit(branch_sha1);
+       struct commit *head = lookup_commit_or_die(head_sha1, "HEAD");
+       struct commit *branch = lookup_commit_or_die(remote->old_sha1, remote->name);
        struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
 
        return (merge_bases && !merge_bases->next && merge_bases->item == branch);
@@ -1680,7 +1680,7 @@ static int delete_remote_branch(const char *pattern, int force)
                        return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, sha1_to_hex(remote_ref->old_sha1));
 
                /* Remote branch must be an ancestor of remote HEAD */
-               if (!verify_merge_base(head_sha1, remote_ref->old_sha1)) {
+               if (!verify_merge_base(head_sha1, remote_ref)) {
                        return error("The branch '%s' is not an ancestor "
                                     "of your current HEAD.\n"
                                     "If you are sure you want to delete it,"
@@ -1747,7 +1747,6 @@ int main(int argc, char **argv)
        int i;
        int new_refs;
        struct ref *ref, *local_refs;
-       struct remote *remote;
 
        git_extract_argv0_path(argv[0]);
 
@@ -1821,14 +1820,7 @@ int main(int argc, char **argv)
 
        memset(remote_dir_exists, -1, 256);
 
-       /*
-        * Create a minimum remote by hand to give to http_init(),
-        * primarily to allow it to look at the URL.
-        */
-       remote = xcalloc(sizeof(*remote), 1);
-       ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
-       remote->url[remote->url_nr++] = repo->url;
-       http_init(remote);
+       http_init(NULL, repo->url);
 
 #ifdef USE_CURL_MULTI
        is_running_queue = 0;
diff --git a/http.c b/http.c
index fb3465f50c95ab9cb3e6fae1d1e594f6ae0b9c42..a4bc770e2d6196958ec5b795ca89be24be182a34 100644 (file)
--- a/http.c
+++ b/http.c
@@ -42,7 +42,7 @@ static long curl_low_speed_time = -1;
 static int curl_ftp_no_epsv;
 static const char *curl_http_proxy;
 static const char *curl_cookie_file;
-static char *user_name, *user_pass;
+static char *user_name, *user_pass, *description;
 static const char *user_agent;
 
 #if LIBCURL_VERSION_NUM >= 0x071700
@@ -139,6 +139,27 @@ static void process_curl_messages(void)
 }
 #endif
 
+static char *git_getpass_with_description(const char *what, const char *desc)
+{
+       struct strbuf prompt = STRBUF_INIT;
+       char *r;
+
+       if (desc)
+               strbuf_addf(&prompt, "%s for '%s': ", what, desc);
+       else
+               strbuf_addf(&prompt, "%s: ", what);
+       /*
+        * NEEDSWORK: for usernames, we should do something less magical that
+        * actually echoes the characters. However, we need to read from
+        * /dev/tty and not stdio, which is not portable (but getpass will do
+        * it for us). http.c uses the same workaround.
+        */
+       r = git_getpass(prompt.buf);
+
+       strbuf_release(&prompt);
+       return xstrdup(r);
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
        if (!strcmp("http.sslverify", var)) {
@@ -214,7 +235,7 @@ static void init_curl_http_auth(CURL *result)
        if (user_name) {
                struct strbuf up = STRBUF_INIT;
                if (!user_pass)
-                       user_pass = xstrdup(git_getpass("Password: "));
+                       user_pass = xstrdup(git_getpass_with_description("Password", description));
                strbuf_addf(&up, "%s:%s", user_name, user_pass);
                curl_easy_setopt(result, CURLOPT_USERPWD,
                                 strbuf_detach(&up, NULL));
@@ -229,7 +250,7 @@ static int has_cert_password(void)
                return 0;
        /* Only prompt the user once. */
        ssl_cert_password_required = -1;
-       ssl_cert_password = git_getpass("Certificate Password: ");
+       ssl_cert_password = git_getpass_with_description("Certificate Password", description);
        if (ssl_cert_password != NULL) {
                ssl_cert_password = xstrdup(ssl_cert_password);
                return 1;
@@ -307,8 +328,7 @@ static CURL *get_curl_handle(void)
 
 static void http_auth_init(const char *url)
 {
-       char *at, *colon, *cp, *slash, *decoded;
-       int len;
+       const char *at, *colon, *cp, *slash, *host;
 
        cp = strstr(url, "://");
        if (!cp)
@@ -324,34 +344,22 @@ static void http_auth_init(const char *url)
        at = strchr(cp, '@');
        colon = strchr(cp, ':');
        slash = strchrnul(cp, '/');
-       if (!at || slash <= at)
-               return; /* No credentials */
-       if (!colon || at <= colon) {
+       if (!at || slash <= at) {
+               /* No credentials, but we may have to ask for some later */
+               host = cp;
+       }
+       else if (!colon || at <= colon) {
                /* Only username */
-               len = at - cp;
-               user_name = xmalloc(len + 1);
-               memcpy(user_name, cp, len);
-               user_name[len] = '\0';
-               decoded = url_decode(user_name);
-               free(user_name);
-               user_name = decoded;
+               user_name = url_decode_mem(cp, at - cp);
                user_pass = NULL;
+               host = at + 1;
        } else {
-               len = colon - cp;
-               user_name = xmalloc(len + 1);
-               memcpy(user_name, cp, len);
-               user_name[len] = '\0';
-               decoded = url_decode(user_name);
-               free(user_name);
-               user_name = decoded;
-               len = at - (colon + 1);
-               user_pass = xmalloc(len + 1);
-               memcpy(user_pass, colon + 1, len);
-               user_pass[len] = '\0';
-               decoded = url_decode(user_pass);
-               free(user_pass);
-               user_pass = decoded;
+               user_name = url_decode_mem(cp, colon - cp);
+               user_pass = url_decode_mem(colon + 1, at - (colon + 1));
+               host = at + 1;
        }
+
+       description = url_decode_mem(host, slash - host);
 }
 
 static void set_from_env(const char **var, const char *envname)
@@ -361,7 +369,7 @@ static void set_from_env(const char **var, const char *envname)
                *var = val;
 }
 
-void http_init(struct remote *remote)
+void http_init(struct remote *remote, const char *url)
 {
        char *low_speed_limit;
        char *low_speed_time;
@@ -425,11 +433,11 @@ void http_init(struct remote *remote)
        if (getenv("GIT_CURL_FTP_NO_EPSV"))
                curl_ftp_no_epsv = 1;
 
-       if (remote && remote->url && remote->url[0]) {
-               http_auth_init(remote->url[0]);
+       if (url) {
+               http_auth_init(url);
                if (!ssl_cert_password_required &&
                    getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") &&
-                   !prefixcmp(remote->url[0], "https://"))
+                   !prefixcmp(url, "https://"))
                        ssl_cert_password_required = 1;
        }
 
@@ -847,7 +855,7 @@ static int http_request(const char *url, void *result, int target, int options)
                                 * but that is non-portable.  Using git_getpass() can at least be stubbed
                                 * on other platforms with a different implementation if/when necessary.
                                 */
-                               user_name = xstrdup(git_getpass("Username: "));
+                               user_name = xstrdup(git_getpass_with_description("Username", description));
                                init_curl_http_auth(slot->curl);
                                ret = HTTP_REAUTH;
                        }
@@ -870,13 +878,18 @@ static int http_request(const char *url, void *result, int target, int options)
        return ret;
 }
 
+static int http_request_reauth(const char *url, void *result, int target,
+                              int options)
+{
+       int ret = http_request(url, result, target, options);
+       if (ret != HTTP_REAUTH)
+               return ret;
+       return http_request(url, result, target, options);
+}
+
 int http_get_strbuf(const char *url, struct strbuf *result, int options)
 {
-       int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
-       if (http_ret == HTTP_REAUTH) {
-               http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
-       }
-       return http_ret;
+       return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options);
 }
 
 /*
@@ -899,7 +912,7 @@ static int http_get_file(const char *url, const char *filename, int options)
                goto cleanup;
        }
 
-       ret = http_request(url, result, HTTP_REQUEST_FILE, options);
+       ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
        fclose(result);
 
        if ((ret == HTTP_OK) && move_temp_to_file(tmpfile.buf, filename))
diff --git a/http.h b/http.h
index 0bf8592dc45209c9be5b8ddac3a53f6fc11e29be..3c332a98e9358a296b937453351018ac1042120e 100644 (file)
--- a/http.h
+++ b/http.h
@@ -86,7 +86,7 @@ extern void add_fill_function(void *data, int (*fill)(void *));
 extern void step_active_slots(void);
 #endif
 
-extern void http_init(struct remote *remote);
+extern void http_init(struct remote *remote, const char *url);
 extern void http_cleanup(void);
 
 extern int data_received;
diff --git a/ident.c b/ident.c
index 35a6f264737e700ddd45714a0e966422a0d756c7..f619619b82379c2d205c7d7ea101049e373ab90a 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -50,6 +50,54 @@ static void copy_gecos(const struct passwd *w, char *name, size_t sz)
 
 }
 
+static int add_mailname_host(char *buf, size_t len)
+{
+       FILE *mailname;
+
+       mailname = fopen("/etc/mailname", "r");
+       if (!mailname) {
+               if (errno != ENOENT)
+                       warning("cannot open /etc/mailname: %s",
+                               strerror(errno));
+               return -1;
+       }
+       if (!fgets(buf, len, mailname)) {
+               if (ferror(mailname))
+                       warning("cannot read /etc/mailname: %s",
+                               strerror(errno));
+               fclose(mailname);
+               return -1;
+       }
+       /* success! */
+       fclose(mailname);
+       return 0;
+}
+
+static void add_domainname(char *buf, size_t len)
+{
+       struct hostent *he;
+       size_t namelen;
+       const char *domainname;
+
+       if (gethostname(buf, len)) {
+               warning("cannot get host name: %s", strerror(errno));
+               strlcpy(buf, "(none)", len);
+               return;
+       }
+       namelen = strlen(buf);
+       if (memchr(buf, '.', namelen))
+               return;
+
+       he = gethostbyname(buf);
+       buf[namelen++] = '.';
+       buf += namelen;
+       len -= namelen;
+       if (he && (domainname = strchr(he->h_name, '.')))
+               strlcpy(buf, domainname + 1, len);
+       else
+               strlcpy(buf, "(none)", len);
+}
+
 static void copy_email(const struct passwd *pw)
 {
        /*
@@ -61,35 +109,29 @@ static void copy_email(const struct passwd *pw)
                die("Your sysadmin must hate you!");
        memcpy(git_default_email, pw->pw_name, len);
        git_default_email[len++] = '@';
-       gethostname(git_default_email + len, sizeof(git_default_email) - len);
-       if (!strchr(git_default_email+len, '.')) {
-               struct hostent *he = gethostbyname(git_default_email + len);
-               char *domainname;
-
-               len = strlen(git_default_email);
-               git_default_email[len++] = '.';
-               if (he && (domainname = strchr(he->h_name, '.')))
-                       strlcpy(git_default_email + len, domainname + 1,
-                               sizeof(git_default_email) - len);
-               else
-                       strlcpy(git_default_email + len, "(none)",
-                               sizeof(git_default_email) - len);
-       }
+
+       if (!add_mailname_host(git_default_email + len,
+                               sizeof(git_default_email) - len))
+               return; /* read from "/etc/mailname" (Debian) */
+       add_domainname(git_default_email + len,
+                       sizeof(git_default_email) - len);
 }
 
-static void setup_ident(void)
+static void setup_ident(const char **name, const char **emailp)
 {
        struct passwd *pw = NULL;
 
        /* Get the name ("gecos") */
-       if (!git_default_name[0]) {
+       if (!*name && !git_default_name[0]) {
                pw = getpwuid(getuid());
                if (!pw)
                        die("You don't exist. Go away!");
                copy_gecos(pw, git_default_name, sizeof(git_default_name));
        }
+       if (!*name)
+               *name = git_default_name;
 
-       if (!git_default_email[0]) {
+       if (!*emailp && !git_default_email[0]) {
                const char *email = getenv("EMAIL");
 
                if (email && email[0]) {
@@ -104,6 +146,8 @@ static void setup_ident(void)
                        copy_email(pw);
                }
        }
+       if (!*emailp)
+               *emailp = git_default_email;
 
        /* And set the default date */
        if (!git_default_date[0])
@@ -199,11 +243,7 @@ const char *fmt_ident(const char *name, const char *email,
        int warn_on_no_name = (flag & IDENT_WARN_ON_NO_NAME);
        int name_addr_only = (flag & IDENT_NO_DATE);
 
-       setup_ident();
-       if (!name)
-               name = git_default_name;
-       if (!email)
-               email = git_default_email;
+       setup_ident(&name, &email);
 
        if (!*name) {
                struct passwd *pw;
index 24c295ea1dc91180b9685299f48812593162bdfe..e7694a3a4ca2e6de7fe8f3b5458eb2b65591373a 100644 (file)
@@ -165,6 +165,14 @@ static void show_parents(struct commit *commit, int abbrev)
        }
 }
 
+static void show_children(struct rev_info *opt, struct commit *commit, int abbrev)
+{
+       struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
+       for ( ; p; p = p->next) {
+               printf(" %s", find_unique_abbrev(p->item->object.sha1, abbrev));
+       }
+}
+
 void show_decorations(struct rev_info *opt, struct commit *commit)
 {
        const char *prefix;
@@ -414,6 +422,8 @@ void show_log(struct rev_info *opt)
                fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
                if (opt->print_parents)
                        show_parents(commit, abbrev_commit);
+               if (opt->children.name)
+                       show_children(opt, commit, abbrev_commit);
                show_decorations(opt, commit);
                if (opt->graph && !graph_is_commit_finished(opt->graph)) {
                        putchar('\n');
@@ -473,6 +483,8 @@ void show_log(struct rev_info *opt)
                      stdout);
                if (opt->print_parents)
                        show_parents(commit, abbrev_commit);
+               if (opt->children.name)
+                       show_children(opt, commit, abbrev_commit);
                if (parent)
                        printf(" (from %s)",
                               find_unique_abbrev(parent->object.sha1,
index 27b3dd48b840139acd65ea742e04221c6400a485..b6319d206e2333e42469486604d4635e846e5faa 100644 (file)
@@ -16,5 +16,10 @@ merge_cmd () {
 }
 
 translate_merge_tool_path() {
-       echo bcompare
+       if type bcomp >/dev/null 2>/dev/null
+       then
+               echo bcomp
+       else
+               echo bcompare
+       fi
 }
index c6b6a3fe4cd94e48893b172c17b6e7df3bfa36f8..225dd769954fa0fcb6e70da58b2ce5ed88e9451e 100644 (file)
@@ -57,12 +57,10 @@ static void hash_index_entry_directories(struct index_state *istate, struct cach
                if (*ptr == '/') {
                        ++ptr;
                        hash = hash_name(ce->name, ptr - ce->name);
-                       if (!lookup_hash(hash, &istate->name_hash)) {
-                               pos = insert_hash(hash, ce, &istate->name_hash);
-                               if (pos) {
-                                       ce->next = *pos;
-                                       *pos = ce;
-                               }
+                       pos = insert_hash(hash, ce, &istate->name_hash);
+                       if (pos) {
+                               ce->dir_next = *pos;
+                               *pos = ce;
                        }
                }
        }
@@ -166,7 +164,10 @@ struct cache_entry *index_name_exists(struct index_state *istate, const char *na
                        if (same_name(ce, name, namelen, icase))
                                return ce;
                }
-               ce = ce->next;
+               if (icase && name[namelen - 1] == '/')
+                       ce = ce->dir_next;
+               else
+                       ce = ce->next;
        }
 
        /*
diff --git a/refs.c b/refs.c
index 9911c97b69a66ba0a4c7d3aff33b9d7b1d006796..cab4394ad180b5daf02889fea523fa54abf0560f 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -393,12 +393,22 @@ static struct ref_array *get_loose_refs(const char *submodule)
 #define MAXDEPTH 5
 #define MAXREFLEN (1024)
 
+/*
+ * Called by resolve_gitlink_ref_recursive() after it failed to read
+ * from "name", which is "module/.git/<refname>". Find <refname> in
+ * the packed-refs file for the submodule.
+ */
 static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refname, unsigned char *result)
 {
        int retval = -1;
        struct ref_entry *ref;
-       struct ref_array *array = get_packed_refs(name);
+       struct ref_array *array;
 
+       /* being defensive: resolve_gitlink_ref() did this for us */
+       if (pathlen < 6 || memcmp(name + pathlen - 6, "/.git/", 6))
+               die("Oops");
+       name[pathlen - 6] = '\0'; /* make it path to the submodule */
+       array = get_packed_refs(name);
        ref = search_ref_array(array, refname);
        if (ref != NULL) {
                memcpy(result, ref->sha1, 20);
index 0aa4bfed309d6c439fac4ff2a0df6a468307e7bf..0e720ee8bbf4cbc6a50336a1f1c93bfc63842fe3 100644 (file)
@@ -115,7 +115,7 @@ static struct discovery* discover_refs(const char *service)
        http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
 
        /* try again with "plain" url (no ? or & appended) */
-       if (http_ret != HTTP_OK) {
+       if (http_ret != HTTP_OK && http_ret != HTTP_NOAUTH) {
                free(refs_url);
                strbuf_reset(&buffer);
 
@@ -859,7 +859,7 @@ int main(int argc, const char **argv)
 
        url = strbuf_detach(&buf, NULL);
 
-       http_init(remote);
+       http_init(remote, url);
 
        do {
                if (strbuf_getline(&buf, stdin, '\n') == EOF) {
index 9bae329c153f33b5aa39f2dab2748dc56b2c3824..8764dde381111cfc9c8ea7eb3856223de9786ec9 100644 (file)
@@ -226,6 +226,13 @@ static struct object *get_reference(struct rev_info *revs, const char *name, con
        return object;
 }
 
+void add_pending_sha1(struct rev_info *revs, const char *name,
+                     const unsigned char *sha1, unsigned int flags)
+{
+       struct object *object = get_reference(revs, name, sha1, flags);
+       add_pending_object(revs, object, name);
+}
+
 static struct commit *handle_commit(struct rev_info *revs, struct object *object, const char *name)
 {
        unsigned long flags = object->flags;
@@ -897,7 +904,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, int flag,
        struct object *object = get_reference(cb->all_revs, path, sha1,
                                              cb->all_flags);
        add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
-       add_pending_object(cb->all_revs, object, path);
+       add_pending_sha1(cb->all_revs, path, sha1, cb->all_flags);
        return 0;
 }
 
@@ -1052,10 +1059,12 @@ static void prepare_show_merge(struct rev_info *revs)
        const char **prune = NULL;
        int i, prune_num = 1; /* counting terminating NULL */
 
-       if (get_sha1("HEAD", sha1) || !(head = lookup_commit(sha1)))
+       if (get_sha1("HEAD", sha1))
                die("--merge without HEAD?");
-       if (get_sha1("MERGE_HEAD", sha1) || !(other = lookup_commit(sha1)))
+       head = lookup_commit_or_die(sha1, "HEAD");
+       if (get_sha1("MERGE_HEAD", sha1))
                die("--merge without MERGE_HEAD?");
+       other = lookup_commit_or_die(sha1, "MERGE_HEAD");
        add_pending_object(revs, &head->object, "HEAD");
        add_pending_object(revs, &other->object, "MERGE_HEAD");
        bases = get_merge_bases(head, other, 1);
@@ -2048,7 +2057,8 @@ int prepare_revision_walk(struct rev_info *revs)
                }
                e++;
        }
-       free(list);
+       if (!revs->leak_pending)
+               free(list);
 
        if (revs->no_walk)
                return 0;
index 754f31b1cda81c474f71ab56f8d82e260adee968..6aa53d1aa708918e4bbbebb042e0bf75c1629b05 100644 (file)
@@ -118,6 +118,7 @@ struct rev_info {
                        date_mode_explicit:1,
                        preserve_subject:1;
        unsigned int    disable_stdin:1;
+       unsigned int    leak_pending:1;
 
        enum date_mode date_mode;
 
@@ -214,6 +215,7 @@ extern void add_object(struct object *obj,
                       const char *name);
 
 extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
+extern void add_pending_sha1(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags);
 
 extern void add_head_to_pending(struct rev_info *);
 
index 4c0ac138aff7b5add73e17fc9c3c4e409fd918e2..63f9da53237d4233bede66a28e4bcf27d5b44af1 100644 (file)
@@ -48,7 +48,7 @@ int main(int argc, char **argv)
                        unsigned char sha1[20];
                        uint32_t crc;
                        uint32_t off;
-               } *entries = malloc(nr * sizeof(entries[0]));
+               } *entries = xmalloc(nr * sizeof(entries[0]));
                for (i = 0; i < nr; i++)
                        if (fread(entries[i].sha1, 20, 1, stdin) != 1)
                                die("unable to read sha1 %u/%u", i, nr);
index 9ff1b597c995780026a32a92fab78a780d60329a..3ad2cc00160fbf24e1e4904bb37ce44e8c414ce5 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -357,7 +357,6 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
 {
        int ch;
 
-       strbuf_grow(sb, 0);
        if (feof(fp))
                return EOF;
 
index b8996a373a7444b54823f36159ea1a8634e4aeee..f7dc0781d5d0ec5afd7f1d0898bffa17a9b1b00e 100644 (file)
@@ -81,8 +81,7 @@ prepare_httpd() {
 
        if test -n "$LIB_HTTPD_SSL"
        then
-               HTTPD_URL=https://127.0.0.1:$LIB_HTTPD_PORT
-               AUTH_HTTPD_URL=https://user%40host:user%40host@127.0.0.1:$LIB_HTTPD_PORT
+               HTTPD_PROTO=https
 
                RANDFILE_PATH="$HTTPD_ROOT_PATH"/.rnd openssl req \
                        -config "$TEST_PATH/ssl.cnf" \
@@ -93,9 +92,12 @@ prepare_httpd() {
                export GIT_SSL_NO_VERIFY
                HTTPD_PARA="$HTTPD_PARA -DSSL"
        else
-               HTTPD_URL=http://127.0.0.1:$LIB_HTTPD_PORT
-               AUTH_HTTPD_URL=http://user%40host:user%40host@127.0.0.1:$LIB_HTTPD_PORT
+               HTTPD_PROTO=http
        fi
+       HTTPD_DEST=127.0.0.1:$LIB_HTTPD_PORT
+       HTTPD_URL=$HTTPD_PROTO://$HTTPD_DEST
+       HTTPD_URL_USER=$HTTPD_PROTO://user%40host@$HTTPD_DEST
+       HTTPD_URL_USER_PASS=$HTTPD_PROTO://user%40host:user%40host@$HTTPD_DEST
 
        if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN"
        then
index 46b0736b351d4676bdab16ec69ad1dfe42f3a900..dbb2623d930e433111f7e125749f5f1071e9ab3c 100755 (executable)
@@ -7,7 +7,7 @@ test_description=gitattributes
 attr_check () {
        path="$1" expect="$2"
 
-       git check-attr test -- "$path" >actual 2>err &&
+       git $3 check-attr test -- "$path" >actual 2>err &&
        echo "$path: test: $2" >expect &&
        test_cmp expect actual &&
        test_line_count = 0 err
@@ -23,6 +23,7 @@ test_expect_success 'setup' '
                echo "onoff test -test"
                echo "offon -test test"
                echo "no notest"
+               echo "A/e/F test=A/e/F"
        ) >.gitattributes &&
        (
                echo "g test=a/g" &&
@@ -84,6 +85,62 @@ test_expect_success 'attribute test' '
        attr_check a/b/d/yes unspecified
 '
 
+test_expect_success 'attribute matching is case sensitive when core.ignorecase=0' '
+
+       test_must_fail attr_check F f "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/F f "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/c/F f "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/G a/g "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/B/g a/b/g "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/b/G a/b/g "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/b/H a/b/h "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/b/D/g "a/b/d/*" "-c core.ignorecase=0" &&
+       test_must_fail attr_check oNoFf unset "-c core.ignorecase=0" &&
+       test_must_fail attr_check oFfOn set "-c core.ignorecase=0" &&
+       attr_check NO unspecified "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/b/D/NO "a/b/d/*" "-c core.ignorecase=0" &&
+       attr_check a/b/d/YES a/b/d/* "-c core.ignorecase=0" &&
+       test_must_fail attr_check a/E/f "A/e/F" "-c core.ignorecase=0"
+
+'
+
+test_expect_success 'attribute matching is case insensitive when core.ignorecase=1' '
+
+       attr_check F f "-c core.ignorecase=1" &&
+       attr_check a/F f "-c core.ignorecase=1" &&
+       attr_check a/c/F f "-c core.ignorecase=1" &&
+       attr_check a/G a/g "-c core.ignorecase=1" &&
+       attr_check a/B/g a/b/g "-c core.ignorecase=1" &&
+       attr_check a/b/G a/b/g "-c core.ignorecase=1" &&
+       attr_check a/b/H a/b/h "-c core.ignorecase=1" &&
+       attr_check a/b/D/g "a/b/d/*" "-c core.ignorecase=1" &&
+       attr_check oNoFf unset "-c core.ignorecase=1" &&
+       attr_check oFfOn set "-c core.ignorecase=1" &&
+       attr_check NO unspecified "-c core.ignorecase=1" &&
+       attr_check a/b/D/NO "a/b/d/*" "-c core.ignorecase=1" &&
+       attr_check a/b/d/YES unspecified "-c core.ignorecase=1" &&
+       attr_check a/E/f "A/e/F" "-c core.ignorecase=1"
+
+'
+
+test_expect_success 'check whether FS is case-insensitive' '
+       mkdir junk &&
+       echo good >junk/CamelCase &&
+       echo bad >junk/camelcase &&
+       if test "$(cat junk/CamelCase)" != good
+       then
+               test_set_prereq CASE_INSENSITIVE_FS
+       fi
+'
+
+test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' '
+       test_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" &&
+       test_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" &&
+       attr_check A/b/h a/b/h "-c core.ignorecase=1" &&
+       attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=1" &&
+       attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=1"
+'
+
 test_expect_success 'unnormalized paths' '
        attr_check ./f f &&
        attr_check ./a/g a/g &&
index 018c3546b6f05228a20dfb5ec9364d0a1575e4ff..5c0053a20bf2fbf1dd466ace5dc933e38ce3544d 100755 (executable)
@@ -234,4 +234,20 @@ test_expect_success 'read-tree --reset removes outside worktree' '
        test_cmp empty result
 '
 
+test_expect_success 'print errors when failed to update worktree' '
+       echo sub >.git/info/sparse-checkout &&
+       git checkout -f init &&
+       mkdir sub &&
+       touch sub/added sub/addedtoo &&
+       test_must_fail git checkout top 2>actual &&
+       cat >expected <<\EOF &&
+error: The following untracked working tree files would be overwritten by checkout:
+       sub/added
+       sub/addedtoo
+Please move or remove them before you can switch branches.
+Aborting
+EOF
+       test_cmp expected actual
+'
+
 test_done
index 3b1b985996e9a6b52b032ef45c5be9b1c57b60f6..e23ac0e69da8d3dba32f0d256a249a987356e825 100755 (executable)
@@ -118,7 +118,7 @@ test_expect_success 'alias expansion' '
        )
 '
 
-test_expect_success '!alias expansion' '
+test_expect_success NOT_MINGW '!alias expansion' '
        pwd >expect &&
        (
                git config alias.test !pwd &&
index 3e140c18f4183c41c76aaab0834f1d23ce7bcd2d..51caff047b0da1a6d1df7fa651b3a8c31e8ae3e2 100755 (executable)
@@ -7,28 +7,28 @@ test_description='Test git config in different settings'
 
 . ./test-lib.sh
 
-test -f .git/config && rm .git/config
-
-git config core.penguin "little blue"
+test_expect_success 'clear default config' '
+       rm -f .git/config
+'
 
 cat > expect << EOF
 [core]
        penguin = little blue
 EOF
-
-test_expect_success 'initial' 'cmp .git/config expect'
-
-git config Core.Movie BadPhysics
+test_expect_success 'initial' '
+       git config core.penguin "little blue" &&
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 [core]
        penguin = little blue
        Movie = BadPhysics
 EOF
-
-test_expect_success 'mixed case' 'cmp .git/config expect'
-
-git config Cores.WhatEver Second
+test_expect_success 'mixed case' '
+       git config Core.Movie BadPhysics &&
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 [core]
@@ -37,10 +37,10 @@ cat > expect << EOF
 [Cores]
        WhatEver = Second
 EOF
-
-test_expect_success 'similar section' 'cmp .git/config expect'
-
-git config CORE.UPPERCASE true
+test_expect_success 'similar section' '
+       git config Cores.WhatEver Second
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 [core]
@@ -50,8 +50,10 @@ cat > expect << EOF
 [Cores]
        WhatEver = Second
 EOF
-
-test_expect_success 'similar section' 'cmp .git/config expect'
+test_expect_success 'uppercase section' '
+       git config CORE.UPPERCASE true &&
+       test_cmp expect .git/config
+'
 
 test_expect_success 'replace with non-match' \
        'git config core.penguin kingpin !blue'
@@ -69,7 +71,34 @@ cat > expect << EOF
        WhatEver = Second
 EOF
 
-test_expect_success 'non-match result' 'cmp .git/config expect'
+test_expect_success 'non-match result' 'test_cmp expect .git/config'
+
+test_expect_success 'find mixed-case key by canonical name' '
+       echo Second >expect &&
+       git config cores.whatever >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'find mixed-case key by non-canonical name' '
+       echo Second >expect &&
+       git config CoReS.WhAtEvEr >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'subsections are not canonicalized by git-config' '
+       cat >>.git/config <<-\EOF &&
+       [section.SubSection]
+       key = one
+       [section "SubSection"]
+       key = two
+       EOF
+       echo one >expect &&
+       git config section.subsection.key >actual &&
+       test_cmp expect actual &&
+       echo two >expect &&
+       git config section.SubSection.key >actual &&
+       test_cmp expect actual
+'
 
 cat > .git/config <<\EOF
 [alpha]
@@ -88,7 +117,7 @@ bar = foo
 [beta]
 EOF
 
-test_expect_success 'unset with cont. lines is correct' 'cmp .git/config expect'
+test_expect_success 'unset with cont. lines is correct' 'test_cmp expect .git/config'
 
 cat > .git/config << EOF
 [beta] ; silly comment # another comment
@@ -116,7 +145,7 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
+test_expect_success 'multiple unset is correct' 'test_cmp expect .git/config'
 
 cp .git/config2 .git/config
 
@@ -140,9 +169,7 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'all replaced' 'cmp .git/config expect'
-
-git config beta.haha alpha
+test_expect_success 'all replaced' 'test_cmp expect .git/config'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -153,10 +180,10 @@ noIndent= sillyValue ; 'nother silly comment
        haha = alpha
 [nextSection] noNewline = ouch
 EOF
-
-test_expect_success 'really mean test' 'cmp .git/config expect'
-
-git config nextsection.nonewline wow
+test_expect_success 'really mean test' '
+       git config beta.haha alpha &&
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -168,11 +195,12 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection]
        nonewline = wow
 EOF
-
-test_expect_success 'really really mean test' 'cmp .git/config expect'
+test_expect_success 'really really mean test' '
+       git config nextsection.nonewline wow &&
+       test_cmp expect .git/config
+'
 
 test_expect_success 'get value' 'test alpha = $(git config beta.haha)'
-git config --unset beta.haha
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -183,10 +211,10 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection]
        nonewline = wow
 EOF
-
-test_expect_success 'unset' 'cmp .git/config expect'
-
-git config nextsection.NoNewLine "wow2 for me" "for me$"
+test_expect_success 'unset' '
+       git config --unset beta.haha &&
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -198,8 +226,10 @@ noIndent= sillyValue ; 'nother silly comment
        nonewline = wow
        NoNewLine = wow2 for me
 EOF
-
-test_expect_success 'multivar' 'cmp .git/config expect'
+test_expect_success 'multivar' '
+       git config nextsection.NoNewLine "wow2 for me" "for me$" &&
+       test_cmp expect .git/config
+'
 
 test_expect_success 'non-match' \
        'git config --get nextsection.nonewline !for'
@@ -214,8 +244,6 @@ test_expect_success 'ambiguous get' '
 test_expect_success 'get multivar' \
        'git config --get-all nextsection.nonewline'
 
-git config nextsection.nonewline "wow3" "wow$"
-
 cat > expect << EOF
 [beta] ; silly comment # another comment
 noIndent= sillyValue ; 'nother silly comment
@@ -226,8 +254,10 @@ noIndent= sillyValue ; 'nother silly comment
        nonewline = wow3
        NoNewLine = wow2 for me
 EOF
-
-test_expect_success 'multivar replace' 'cmp .git/config expect'
+test_expect_success 'multivar replace' '
+       git config nextsection.nonewline "wow3" "wow$" &&
+       test_cmp expect .git/config
+'
 
 test_expect_success 'ambiguous value' '
        test_must_fail git config nextsection.nonewline
@@ -241,8 +271,6 @@ test_expect_success 'invalid unset' '
        test_must_fail git config --unset somesection.nonewline
 '
 
-git config --unset nextsection.nonewline "wow3$"
-
 cat > expect << EOF
 [beta] ; silly comment # another comment
 noIndent= sillyValue ; 'nother silly comment
@@ -253,7 +281,10 @@ noIndent= sillyValue ; 'nother silly comment
        NoNewLine = wow2 for me
 EOF
 
-test_expect_success 'multivar unset' 'cmp .git/config expect'
+test_expect_success 'multivar unset' '
+       git config --unset nextsection.nonewline "wow3$" &&
+       test_cmp expect .git/config
+'
 
 test_expect_success 'invalid key' 'test_must_fail git config inval.2key blabla'
 
@@ -276,7 +307,7 @@ noIndent= sillyValue ; 'nother silly comment
        Alpha = beta
 EOF
 
-test_expect_success 'hierarchical section value' 'cmp .git/config expect'
+test_expect_success 'hierarchical section value' 'test_cmp expect .git/config'
 
 cat > expect << EOF
 beta.noindent=sillyValue
@@ -304,15 +335,16 @@ EOF
 test_expect_success '--get-regexp' \
        'git config --get-regexp in > output && cmp output expect'
 
-git config --add nextsection.nonewline "wow4 for you"
-
 cat > expect << EOF
 wow2 for me
 wow4 for you
 EOF
 
-test_expect_success '--add' \
-       'git config --get-all nextsection.nonewline > output && cmp output expect'
+test_expect_success '--add' '
+       git config --add nextsection.nonewline "wow4 for you" &&
+       git config --get-all nextsection.nonewline > output &&
+       test_cmp expect output
+'
 
 cat > .git/config << EOF
 [novalue]
@@ -333,6 +365,12 @@ test_expect_success 'get-regexp variable with no value' \
        'git config --get-regexp novalue > output &&
         cmp output expect'
 
+echo 'novalue.variable true' > expect
+
+test_expect_success 'get-regexp --bool variable with no value' \
+       'git config --bool --get-regexp novalue > output &&
+        cmp output expect'
+
 echo 'emptyvalue.variable ' > expect
 
 test_expect_success 'get-regexp variable with empty value' \
@@ -361,8 +399,6 @@ cat > .git/config << EOF
        c = d
 EOF
 
-git config a.x y
-
 cat > expect << EOF
 [a.b]
        c = d
@@ -370,10 +406,10 @@ cat > expect << EOF
        x = y
 EOF
 
-test_expect_success 'new section is partial match of another' 'cmp .git/config expect'
-
-git config b.x y
-git config a.b c
+test_expect_success 'new section is partial match of another' '
+       git config a.x y &&
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 [a.b]
@@ -385,7 +421,11 @@ cat > expect << EOF
        x = y
 EOF
 
-test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
+test_expect_success 'new variable inserts into proper section' '
+       git config b.x y &&
+       git config a.b c &&
+       test_cmp expect .git/config
+'
 
 test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' \
        'test_must_fail git config --file non-existing-config -l'
@@ -399,9 +439,10 @@ cat > expect << EOF
 ein.bahn=strasse
 EOF
 
-GIT_CONFIG=other-config git config -l > output
-
-test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
+test_expect_success 'alternative GIT_CONFIG' '
+       GIT_CONFIG=other-config git config -l >output &&
+       test_cmp expect output
+'
 
 test_expect_success 'alternative GIT_CONFIG (--file)' \
        'git config --file other-config -l > output && cmp output expect'
@@ -417,8 +458,6 @@ test_expect_success 'refer config from subdirectory' '
 
 '
 
-GIT_CONFIG=other-config git config anwohner.park ausweis
-
 cat > expect << EOF
 [ein]
        bahn = strasse
@@ -426,7 +465,10 @@ cat > expect << EOF
        park = ausweis
 EOF
 
-test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+test_expect_success '--set in alternative GIT_CONFIG' '
+       GIT_CONFIG=other-config git config anwohner.park ausweis &&
+       test_cmp expect other-config
+'
 
 cat > .git/config << EOF
 # Hallo
@@ -516,8 +558,6 @@ EOF
 test_expect_success "section was removed properly" \
        "test_cmp expect .git/config"
 
-rm .git/config
-
 cat > expect << EOF
 [gitcvs]
        enabled = true
@@ -528,10 +568,11 @@ EOF
 
 test_expect_success 'section ending' '
 
+       rm -f .git/config &&
        git config gitcvs.enabled true &&
        git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
        git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
-       cmp .git/config expect
+       test_cmp expect .git/config
 
 '
 
@@ -600,8 +641,6 @@ test_expect_success 'invalid bool (set)' '
 
        test_must_fail git config --bool bool.nobool foobar'
 
-rm .git/config
-
 cat > expect <<\EOF
 [bool]
        true1 = true
@@ -616,6 +655,7 @@ EOF
 
 test_expect_success 'set --bool' '
 
+       rm -f .git/config &&
        git config --bool bool.true1 01 &&
        git config --bool bool.true2 -1 &&
        git config --bool bool.true3 YeS &&
@@ -626,8 +666,6 @@ test_expect_success 'set --bool' '
        git config --bool bool.false4 FALSE &&
        cmp expect .git/config'
 
-rm .git/config
-
 cat > expect <<\EOF
 [int]
        val1 = 1
@@ -637,13 +675,12 @@ EOF
 
 test_expect_success 'set --int' '
 
+       rm -f .git/config &&
        git config --int int.val1 01 &&
        git config --int int.val2 -1 &&
        git config --int int.val3 5m &&
        cmp expect .git/config'
 
-rm .git/config
-
 cat >expect <<\EOF
 [bool]
        true1 = true
@@ -657,6 +694,7 @@ cat >expect <<\EOF
 EOF
 
 test_expect_success 'get --bool-or-int' '
+       rm -f .git/config &&
        (
                echo "[bool]"
                echo true1
@@ -676,7 +714,6 @@ test_expect_success 'get --bool-or-int' '
 
 '
 
-rm .git/config
 cat >expect <<\EOF
 [bool]
        true1 = true
@@ -690,6 +727,7 @@ cat >expect <<\EOF
 EOF
 
 test_expect_success 'set --bool-or-int' '
+       rm -f .git/config &&
        git config --bool-or-int bool.true1 true &&
        git config --bool-or-int bool.false1 false &&
        git config --bool-or-int bool.true2 yes &&
@@ -700,8 +738,6 @@ test_expect_success 'set --bool-or-int' '
        test_cmp expect .git/config
 '
 
-rm .git/config
-
 cat >expect <<\EOF
 [path]
        home = ~/
@@ -710,6 +746,7 @@ cat >expect <<\EOF
 EOF
 
 test_expect_success NOT_MINGW 'set --path' '
+       rm -f .git/config &&
        git config --path path.home "~/" &&
        git config --path path.normal "/dev/null" &&
        git config --path path.trailingtilde "foo~" &&
@@ -750,13 +787,6 @@ test_expect_success NOT_MINGW 'get --path copes with unset $HOME' '
        test_cmp expect result
 '
 
-rm .git/config
-
-git config quote.leading " test"
-git config quote.ending "test "
-git config quote.semicolon "test;test"
-git config quote.hash "test#test"
-
 cat > expect << EOF
 [quote]
        leading = " test"
@@ -764,8 +794,14 @@ cat > expect << EOF
        semicolon = "test;test"
        hash = "test#test"
 EOF
-
-test_expect_success 'quoting' 'cmp .git/config expect'
+test_expect_success 'quoting' '
+       rm -f .git/config &&
+       git config quote.leading " test" &&
+       git config quote.ending "test " &&
+       git config quote.semicolon "test;test" &&
+       git config quote.hash "test#test" &&
+       test_cmp expect .git/config
+'
 
 test_expect_success 'key with newline' '
        test_must_fail git config "key.with
@@ -790,9 +826,10 @@ section.noncont=not continued
 section.quotecont=cont;inued
 EOF
 
-git config --list > result
-
-test_expect_success 'value continued on next line' 'cmp result expect'
+test_expect_success 'value continued on next line' '
+       git config --list > result &&
+       cmp result expect
+'
 
 cat > .git/config <<\EOF
 [section "sub=section"]
@@ -813,16 +850,17 @@ barQsection.sub=section.val3
 Qsection.sub=section.val4
 Qsection.sub=section.val5Q
 EOF
+test_expect_success '--null --list' '
+       git config --null --list | nul_to_q >result &&
+       echo >>result &&
+       test_cmp expect result
+'
 
-git config --null --list | perl -pe 'y/\000/Q/' > result
-echo >>result
-
-test_expect_success '--null --list' 'cmp result expect'
-
-git config --null --get-regexp 'val[0-9]' | perl -pe 'y/\000/Q/' > result
-echo >>result
-
-test_expect_success '--null --get-regexp' 'cmp result expect'
+test_expect_success '--null --get-regexp' '
+       git config --null --get-regexp "val[0-9]" | nul_to_q >result &&
+       echo >>result &&
+       test_cmp expect result
+'
 
 test_expect_success 'inner whitespace kept verbatim' '
        git config section.val "foo       bar" &&
index b5d89a2250e41afe544b0d0f59f638e02d570cdd..2b962cfda70d998e9c2799cf8fc720b330cd118a 100755 (executable)
@@ -25,6 +25,11 @@ else
        test_set_prereq SETFACL
 fi
 
+if test -z "$LOGNAME"
+then
+       LOGNAME=$USER
+fi
+
 check_perms_and_acl () {
        test -r "$1" &&
        getfacl "$1" > actual &&
index 710fccad3637bb06f1947d36248bd6cdabba53fb..1ae4d87c929ec55a66d44bb23aecea8a2aea4346 100755 (executable)
@@ -5,38 +5,40 @@ test_description='Test git check-ref-format'
 . ./test-lib.sh
 
 valid_ref() {
-       if test "$#" = 1
-       then
-               test_expect_success "ref name '$1' is valid" \
-                       "git check-ref-format '$1'"
-       else
-               test_expect_success "ref name '$1' is valid with options $2" \
-                       "git check-ref-format $2 '$1'"
-       fi
+       prereq=
+       case $1 in
+       [A-Z]*)
+               prereq=$1
+               shift
+       esac
+       test_expect_success $prereq "ref name '$1' is valid${2:+ with options $2}" "
+               git check-ref-format $2 '$1'
+       "
 }
 invalid_ref() {
-       if test "$#" = 1
-       then
-               test_expect_success "ref name '$1' is invalid" \
-                       "test_must_fail git check-ref-format '$1'"
-       else
-               test_expect_success "ref name '$1' is invalid with options $2" \
-                       "test_must_fail git check-ref-format $2 '$1'"
-       fi
+       prereq=
+       case $1 in
+       [A-Z]*)
+               prereq=$1
+               shift
+       esac
+       test_expect_success $prereq "ref name '$1' is invalid${2:+ with options $2}" "
+               test_must_fail git check-ref-format $2 '$1'
+       "
 }
 
 invalid_ref ''
-invalid_ref '/'
-invalid_ref '/' --allow-onelevel
-invalid_ref '/' --normalize
-invalid_ref '/' '--allow-onelevel --normalize'
+invalid_ref NOT_MINGW '/'
+invalid_ref NOT_MINGW '/' --allow-onelevel
+invalid_ref NOT_MINGW '/' --normalize
+invalid_ref NOT_MINGW '/' '--allow-onelevel --normalize'
 valid_ref 'foo/bar/baz'
 valid_ref 'foo/bar/baz' --normalize
 invalid_ref 'refs///heads/foo'
 valid_ref 'refs///heads/foo' --normalize
 invalid_ref 'heads/foo/'
-invalid_ref '/heads/foo'
-valid_ref '/heads/foo' --normalize
+invalid_ref NOT_MINGW '/heads/foo'
+valid_ref NOT_MINGW '/heads/foo' --normalize
 invalid_ref '///heads/foo'
 valid_ref '///heads/foo' --normalize
 invalid_ref './foo'
@@ -115,14 +117,14 @@ invalid_ref "$ref" --refspec-pattern
 invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
 
 ref='/foo'
-invalid_ref "$ref"
-invalid_ref "$ref" --allow-onelevel
-invalid_ref "$ref" --refspec-pattern
-invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
-invalid_ref "$ref" --normalize
-valid_ref "$ref" '--allow-onelevel --normalize'
-invalid_ref "$ref" '--refspec-pattern --normalize'
-valid_ref "$ref" '--refspec-pattern --allow-onelevel --normalize'
+invalid_ref NOT_MINGW "$ref"
+invalid_ref NOT_MINGW "$ref" --allow-onelevel
+invalid_ref NOT_MINGW "$ref" --refspec-pattern
+invalid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref NOT_MINGW "$ref" --normalize
+valid_ref NOT_MINGW "$ref" '--allow-onelevel --normalize'
+invalid_ref NOT_MINGW "$ref" '--refspec-pattern --normalize'
+valid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel --normalize'
 
 test_expect_success "check-ref-format --branch @{-1}" '
        T=$(git write-tree) &&
@@ -155,21 +157,35 @@ test_expect_success 'check-ref-format --branch from subdir' '
 '
 
 valid_ref_normalized() {
-       test_expect_success "ref name '$1' simplifies to '$2'" "
+       prereq=
+       case $1 in
+       [A-Z]*)
+               prereq=$1
+               shift
+       esac
+       test_expect_success $prereq "ref name '$1' simplifies to '$2'" "
                refname=\$(git check-ref-format --normalize '$1') &&
-               test \"\$refname\" = '$2'"
+               test \"\$refname\" = '$2'
+       "
 }
 invalid_ref_normalized() {
-       test_expect_success "check-ref-format --normalize rejects '$1'" "
-               test_must_fail git check-ref-format --normalize '$1'"
+       prereq=
+       case $1 in
+       [A-Z]*)
+               prereq=$1
+               shift
+       esac
+       test_expect_success $prereq "check-ref-format --normalize rejects '$1'" "
+               test_must_fail git check-ref-format --normalize '$1'
+       "
 }
 
 valid_ref_normalized 'heads/foo' 'heads/foo'
 valid_ref_normalized 'refs///heads/foo' 'refs/heads/foo'
-valid_ref_normalized '/heads/foo' 'heads/foo'
+valid_ref_normalized NOT_MINGW '/heads/foo' 'heads/foo'
 valid_ref_normalized '///heads/foo' 'heads/foo'
 invalid_ref_normalized 'foo'
-invalid_ref_normalized '/foo'
+invalid_ref_normalized NOT_MINGW '/foo'
 invalid_ref_normalized 'heads/foo/../bar'
 invalid_ref_normalized 'heads/./foo'
 invalid_ref_normalized 'heads\foo'
index 2366f0f4141656666db9cdcd8975335df57b6a8f..068fba4c8e8706aa615d0401da1da47901113156 100755 (executable)
@@ -12,11 +12,14 @@ check_not_detached () {
 }
 
 ORPHAN_WARNING='you are leaving .* commit.*behind'
+PREV_HEAD_DESC='Previous HEAD position was'
 check_orphan_warning() {
-       test_i18ngrep "$ORPHAN_WARNING" "$1"
+       test_i18ngrep "$ORPHAN_WARNING" "$1" &&
+       test_i18ngrep ! "$PREV_HEAD_DESC" "$1"
 }
 check_no_orphan_warning() {
-       test_i18ngrep ! "$ORPHAN_WARNING" "$1"
+       test_i18ngrep ! "$ORPHAN_WARNING" "$1" &&
+       test_i18ngrep "$PREV_HEAD_DESC" "$1"
 }
 
 reset () {
diff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh
new file mode 100755 (executable)
index 0000000..56090d2
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+test_description='checkout $tree -- $paths'
+. ./test-lib.sh
+
+test_expect_success setup '
+       mkdir dir &&
+       >dir/master &&
+       echo common >dir/common &&
+       git add dir/master dir/common &&
+       test_tick && git commit -m "master has dir/master" &&
+       git checkout -b next &&
+       git mv dir/master dir/next0 &&
+       echo next >dir/next1 &&
+       git add dir &&
+       test_tick && git commit -m "next has dir/next but not dir/master"
+'
+
+test_expect_success 'checking out paths out of a tree does not clobber unrelated paths' '
+       git checkout next &&
+       git reset --hard &&
+       rm dir/next0 &&
+       cat dir/common >expect.common &&
+       echo modified >expect.next1 &&
+       cat expect.next1 >dir/next1 &&
+       echo untracked >expect.next2 &&
+       cat expect.next2 >dir/next2 &&
+
+       git checkout master dir &&
+
+       test_cmp expect.common dir/common &&
+       test_path_is_file dir/master &&
+       git diff --exit-code master dir/master &&
+
+       test_path_is_missing dir/next0 &&
+       test_cmp expect.next1 dir/next1 &&
+       test_path_is_file dir/next2 &&
+       test_must_fail git ls-files --error-unmatch dir/next2 &&
+       test_cmp expect.next2 dir/next2
+'
+
+test_done
index 2eec0118c4235c0aa9d85cb7112e1f72b49c5c5f..e9160dfc1d202c08aec032f5a78db098d89d21e0 100755 (executable)
@@ -65,4 +65,23 @@ test_expect_success '--no-empty-directory hides empty directory' '
        test_cmp expected3 output
 '
 
+test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '
+       git init super &&
+       git init sub &&
+       (
+               cd sub &&
+               >a &&
+               git add a &&
+               git commit -m sub &&
+               git pack-refs --all
+       ) &&
+       (
+               cd super &&
+               "$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" ../sub sub
+               git ls-files --others --exclude-standard >../actual
+       ) &&
+       echo sub/ >expect &&
+       test_cmp expect actual
+'
+
 test_done
diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh
new file mode 100755 (executable)
index 0000000..b7da95f
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+test_description='git am with corrupt input'
+. ./test-lib.sh
+
+# Note the missing "+++" line:
+cat > bad-patch.diff <<'EOF'
+From: A U Thor <au.thor@example.com>
+diff --git a/f b/f
+index 7898192..6178079 100644
+--- a/f
+@@ -1 +1 @@
+-a
++b
+EOF
+
+test_expect_success setup '
+       test $? = 0 &&
+       echo a > f &&
+       git add f &&
+       test_tick &&
+       git commit -m initial
+'
+
+# This used to fail before, too, but with a different diagnostic.
+#   fatal: unable to write file '(null)' mode 100644: Bad address
+# Also, it had the unwanted side-effect of deleting f.
+test_expect_success 'try to apply corrupted patch' '
+       git am bad-patch.diff 2> actual
+       test $? = 1
+'
+
+cat > expected <<EOF
+fatal: git diff header lacks filename information (line 4)
+EOF
+
+test_expect_success 'compare diagnostic; ensure file is still here' '
+       test $? = 0 &&
+       test -f f &&
+       test_cmp expected actual
+'
+
+test_done
index 3abb2907ea91c5ef6298ca7ee64b7a8156d65d96..b69cf574d7e9a272ea70864e87ed6556abe94f13 100755 (executable)
@@ -40,6 +40,40 @@ mk_test () {
        )
 }
 
+mk_test_with_hooks() {
+       mk_test "$@" &&
+       (
+               cd testrepo &&
+               mkdir .git/hooks &&
+               cd .git/hooks &&
+
+               cat >pre-receive <<-'EOF' &&
+               #!/bin/sh
+               cat - >>pre-receive.actual
+               EOF
+
+               cat >update <<-'EOF' &&
+               #!/bin/sh
+               printf "%s %s %s\n" "$@" >>update.actual
+               EOF
+
+               cat >post-receive <<-'EOF' &&
+               #!/bin/sh
+               cat - >>post-receive.actual
+               EOF
+
+               cat >post-update <<-'EOF' &&
+               #!/bin/sh
+               for ref in "$@"
+               do
+                       printf "%s\n" "$ref" >>post-update.actual
+               done
+               EOF
+
+               chmod +x pre-receive update post-receive post-update
+       )
+}
+
 mk_child() {
        rm -rf "$1" &&
        git clone testrepo "$1"
@@ -559,6 +593,169 @@ test_expect_success 'allow deleting an invalid remote ref' '
 
 '
 
+test_expect_success 'pushing valid refs triggers post-receive and post-update hooks' '
+       mk_test_with_hooks heads/master heads/next &&
+       orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
+       newmaster=$(git show-ref -s --verify refs/heads/master) &&
+       orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
+       newnext=$_z40 &&
+       git push testrepo refs/heads/master:refs/heads/master :refs/heads/next &&
+       (
+               cd testrepo/.git &&
+               cat >pre-receive.expect <<-EOF &&
+               $orgmaster $newmaster refs/heads/master
+               $orgnext $newnext refs/heads/next
+               EOF
+
+               cat >update.expect <<-EOF &&
+               refs/heads/master $orgmaster $newmaster
+               refs/heads/next $orgnext $newnext
+               EOF
+
+               cat >post-receive.expect <<-EOF &&
+               $orgmaster $newmaster refs/heads/master
+               $orgnext $newnext refs/heads/next
+               EOF
+
+               cat >post-update.expect <<-EOF &&
+               refs/heads/master
+               refs/heads/next
+               EOF
+
+               test_cmp pre-receive.expect pre-receive.actual &&
+               test_cmp update.expect update.actual &&
+               test_cmp post-receive.expect post-receive.actual &&
+               test_cmp post-update.expect post-update.actual
+       )
+'
+
+test_expect_success 'deleting dangling ref triggers hooks with correct args' '
+       mk_test_with_hooks heads/master &&
+       rm -f testrepo/.git/objects/??/* &&
+       git push testrepo :refs/heads/master &&
+       (
+               cd testrepo/.git &&
+               cat >pre-receive.expect <<-EOF &&
+               $_z40 $_z40 refs/heads/master
+               EOF
+
+               cat >update.expect <<-EOF &&
+               refs/heads/master $_z40 $_z40
+               EOF
+
+               cat >post-receive.expect <<-EOF &&
+               $_z40 $_z40 refs/heads/master
+               EOF
+
+               cat >post-update.expect <<-EOF &&
+               refs/heads/master
+               EOF
+
+               test_cmp pre-receive.expect pre-receive.actual &&
+               test_cmp update.expect update.actual &&
+               test_cmp post-receive.expect post-receive.actual &&
+               test_cmp post-update.expect post-update.actual
+       )
+'
+
+test_expect_success 'deletion of a non-existent ref is not fed to post-receive and post-update hooks' '
+       mk_test_with_hooks heads/master &&
+       orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
+       newmaster=$(git show-ref -s --verify refs/heads/master) &&
+       git push testrepo master :refs/heads/nonexistent &&
+       (
+               cd testrepo/.git &&
+               cat >pre-receive.expect <<-EOF &&
+               $orgmaster $newmaster refs/heads/master
+               $_z40 $_z40 refs/heads/nonexistent
+               EOF
+
+               cat >update.expect <<-EOF &&
+               refs/heads/master $orgmaster $newmaster
+               refs/heads/nonexistent $_z40 $_z40
+               EOF
+
+               cat >post-receive.expect <<-EOF &&
+               $orgmaster $newmaster refs/heads/master
+               EOF
+
+               cat >post-update.expect <<-EOF &&
+               refs/heads/master
+               EOF
+
+               test_cmp pre-receive.expect pre-receive.actual &&
+               test_cmp update.expect update.actual &&
+               test_cmp post-receive.expect post-receive.actual &&
+               test_cmp post-update.expect post-update.actual
+       )
+'
+
+test_expect_success 'deletion of a non-existent ref alone does trigger post-receive and post-update hooks' '
+       mk_test_with_hooks heads/master &&
+       git push testrepo :refs/heads/nonexistent &&
+       (
+               cd testrepo/.git &&
+               cat >pre-receive.expect <<-EOF &&
+               $_z40 $_z40 refs/heads/nonexistent
+               EOF
+
+               cat >update.expect <<-EOF &&
+               refs/heads/nonexistent $_z40 $_z40
+               EOF
+
+               test_cmp pre-receive.expect pre-receive.actual &&
+               test_cmp update.expect update.actual &&
+               test_path_is_missing post-receive.actual &&
+               test_path_is_missing post-update.actual
+       )
+'
+
+test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks with correct input' '
+       mk_test_with_hooks heads/master heads/next heads/pu &&
+       orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
+       newmaster=$(git show-ref -s --verify refs/heads/master) &&
+       orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
+       newnext=$_z40 &&
+       orgpu=$(cd testrepo && git show-ref -s --verify refs/heads/pu) &&
+       newpu=$(git show-ref -s --verify refs/heads/master) &&
+       git push testrepo refs/heads/master:refs/heads/master \
+           refs/heads/master:refs/heads/pu :refs/heads/next \
+           :refs/heads/nonexistent &&
+       (
+               cd testrepo/.git &&
+               cat >pre-receive.expect <<-EOF &&
+               $orgmaster $newmaster refs/heads/master
+               $orgnext $newnext refs/heads/next
+               $orgpu $newpu refs/heads/pu
+               $_z40 $_z40 refs/heads/nonexistent
+               EOF
+
+               cat >update.expect <<-EOF &&
+               refs/heads/master $orgmaster $newmaster
+               refs/heads/next $orgnext $newnext
+               refs/heads/pu $orgpu $newpu
+               refs/heads/nonexistent $_z40 $_z40
+               EOF
+
+               cat >post-receive.expect <<-EOF &&
+               $orgmaster $newmaster refs/heads/master
+               $orgnext $newnext refs/heads/next
+               $orgpu $newpu refs/heads/pu
+               EOF
+
+               cat >post-update.expect <<-EOF &&
+               refs/heads/master
+               refs/heads/next
+               refs/heads/pu
+               EOF
+
+               test_cmp pre-receive.expect pre-receive.actual &&
+               test_cmp update.expect update.actual &&
+               test_cmp post-receive.expect post-receive.actual &&
+               test_cmp post-update.expect post-update.actual
+       )
+'
+
 test_expect_success 'allow deleting a ref using --delete' '
        mk_test heads/master &&
        (cd testrepo && git config receive.denyDeleteCurrent warn) &&
index a1883ca6b649a236e5e08a5e4b76d1479353dcac..311a33ca84f693b9410bab9e282ad0ebcae87441 100755 (executable)
@@ -8,8 +8,8 @@ if test -n "$NO_CURL"; then
        test_done
 fi
 
-. "$TEST_DIRECTORY"/lib-httpd.sh
 LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
+. "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
 test_expect_success 'setup repository' '
@@ -35,11 +35,54 @@ test_expect_success 'clone http repository' '
        test_cmp file clone/file
 '
 
-test_expect_success 'clone http repository with authentication' '
+test_expect_success 'create password-protected repository' '
        mkdir "$HTTPD_DOCUMENT_ROOT_PATH/auth/" &&
-       cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" "$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git" &&
-       git clone $AUTH_HTTPD_URL/auth/repo.git clone-auth &&
-       test_cmp file clone-auth/file
+       cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+              "$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git"
+'
+
+test_expect_success 'setup askpass helpers' '
+       cat >askpass <<-EOF &&
+       #!/bin/sh
+       echo >>"$PWD/askpass-query" "askpass: \$*" &&
+       cat "$PWD/askpass-response"
+       EOF
+       chmod +x askpass &&
+       GIT_ASKPASS="$PWD/askpass" &&
+       export GIT_ASKPASS &&
+       >askpass-expect-none &&
+       echo "askpass: Password for '\''$HTTPD_DEST'\'': " >askpass-expect-pass &&
+       { echo "askpass: Username for '\''$HTTPD_DEST'\'': " &&
+         cat askpass-expect-pass
+       } >askpass-expect-both
+'
+
+test_expect_success 'cloning password-protected repository can fail' '
+       >askpass-query &&
+       echo wrong >askpass-response &&
+       test_must_fail git clone "$HTTPD_URL/auth/repo.git" clone-auth-fail &&
+       test_cmp askpass-expect-both askpass-query
+'
+
+test_expect_success 'http auth can use user/pass in URL' '
+       >askpass-query &&
+       echo wrong >askpass-reponse &&
+       git clone "$HTTPD_URL_USER_PASS/auth/repo.git" clone-auth-none &&
+       test_cmp askpass-expect-none askpass-query
+'
+
+test_expect_success 'http auth can use just user in URL' '
+       >askpass-query &&
+       echo user@host >askpass-response &&
+       git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-pass &&
+       test_cmp askpass-expect-pass askpass-query
+'
+
+test_expect_success 'http auth can request both user and pass' '
+       >askpass-query &&
+       echo user@host >askpass-response &&
+       git clone "$HTTPD_URL/auth/repo.git" clone-auth-both &&
+       test_cmp askpass-expect-both askpass-query
 '
 
 test_expect_success 'fetch changes via http' '
index 0d600163c8284a318fbd21f3a00dd7853b2f8956..81263b78516cbe2949ad7e426a5e44af188cccdd 100755 (executable)
@@ -554,7 +554,6 @@ test_expect_success 'outside of git repository' '
        mkdir -p non/git/sub &&
        echo hello >non/git/file1 &&
        echo world >non/git/sub/file2 &&
-       echo ".*o*" >non/git/.gitignore &&
        {
                echo file1:hello &&
                echo sub/file2:world
@@ -571,6 +570,23 @@ test_expect_success 'outside of git repository' '
                test_must_fail git grep o &&
                git grep --no-index o >../../actual.sub &&
                test_cmp ../../expect.sub ../../actual.sub
+       ) &&
+
+       echo ".*o*" >non/git/.gitignore &&
+       (
+               GIT_CEILING_DIRECTORIES="$(pwd)/non/git" &&
+               export GIT_CEILING_DIRECTORIES &&
+               cd non/git &&
+               test_must_fail git grep o &&
+               git grep --no-index --exclude-standard o >../actual.full &&
+               test_cmp ../expect.full ../actual.full &&
+
+               {
+                       echo ".gitignore:.*o*"
+                       cat ../expect.full
+               } >../expect.with.ignored &&
+               git grep --no-index --no-exclude o >../actual.full &&
+               test_cmp ../expect.with.ignored ../actual.full
        )
 '
 
@@ -583,6 +599,10 @@ test_expect_success 'inside git repository but with --no-index' '
        {
                echo file1:hello &&
                echo sub/file2:world
+       } >is/expect.unignored &&
+       {
+               echo ".gitignore:.*o*" &&
+               cat is/expect.unignored
        } >is/expect.full &&
        : >is/expect.empty &&
        echo file2:world >is/expect.sub &&
@@ -591,12 +611,24 @@ test_expect_success 'inside git repository but with --no-index' '
                git init &&
                test_must_fail git grep o >../actual.full &&
                test_cmp ../expect.empty ../actual.full &&
+
+               git grep --untracked o >../actual.unignored &&
+               test_cmp ../expect.unignored ../actual.unignored &&
+
                git grep --no-index o >../actual.full &&
                test_cmp ../expect.full ../actual.full &&
+
+               git grep --no-index --exclude-standard o >../actual.unignored &&
+               test_cmp ../expect.unignored ../actual.unignored &&
+
                cd sub &&
                test_must_fail git grep o >../../actual.sub &&
                test_cmp ../../expect.empty ../../actual.sub &&
+
                git grep --no-index o >../../actual.sub &&
+               test_cmp ../../expect.sub ../../actual.sub &&
+
+               git grep --untracked o >../../actual.sub &&
                test_cmp ../../expect.sub ../../actual.sub
        )
 '
index 579ddb7572c27889060da315ddecb773b6fa1272..8c12c65c72658acb37fa715fc93756381bc824bb 100755 (executable)
@@ -23,6 +23,7 @@ test_expect_success $PREREQ \
       echo do
       echo "  echo \"!\$a!\""
       echo "done >commandline\$output"
+      test_have_prereq MINGW && echo "dos2unix commandline\$output"
       echo "cat > msgtxt\$output"
       ) >fake.sendmail &&
      chmod +x ./fake.sendmail &&
@@ -1168,4 +1169,32 @@ test_expect_success $PREREQ '--force sends cover letter template anyway' '
        test -n "$(ls msgtxt*)"
 '
 
+test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' '
+       clean_fake_sendmail &&
+       echo "alias sbd  somebody@example.org" >.mailrc &&
+       git config --replace-all sendemail.aliasesfile "$(pwd)/.mailrc" &&
+       git config sendemail.aliasfiletype mailrc &&
+       git send-email \
+         --from="Example <nobody@example.com>" \
+         --to=sbd \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         outdir/0001-*.patch \
+         2>errors >out &&
+       grep "^!somebody@example\.org!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' '
+       clean_fake_sendmail &&
+       echo "alias sbd  someone@example.org" >~/.mailrc &&
+       git config --replace-all sendemail.aliasesfile "~/.mailrc" &&
+       git config sendemail.aliasfiletype mailrc &&
+       git send-email \
+         --from="Example <nobody@example.com>" \
+         --to=sbd \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         outdir/0001-*.patch \
+         2>errors >out &&
+       grep "^!someone@example\.org!$" commandline1
+'
+
 test_done
diff --git a/t/t9162-git-svn-dcommit-interactive.sh b/t/t9162-git-svn-dcommit-interactive.sh
new file mode 100644 (file)
index 0000000..e38d9fa
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# Copyright (c) 2011 Frédéric Heitzmann
+
+test_description='git svn dcommit --interactive series'
+. ./lib-git-svn.sh
+
+test_expect_success 'initialize repo' '
+       svn_cmd mkdir -m"mkdir test-interactive" "$svnrepo/test-interactive" &&
+       git svn clone "$svnrepo/test-interactive" test-interactive &&
+       cd test-interactive &&
+       touch foo && git add foo && git commit -m"foo: first commit" &&
+       git svn dcommit
+       '
+
+test_expect_success 'answers: y [\n] yes' '
+       (
+               echo "change #1" >> foo && git commit -a -m"change #1" &&
+               echo "change #2" >> foo && git commit -a -m"change #2" &&
+               echo "change #3" >> foo && git commit -a -m"change #3" &&
+               ( echo "y
+
+y" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
+               test $(git rev-parse HEAD) = $(git rev-parse remotes/git-svn)
+       )
+       '
+
+test_expect_success 'answers: yes yes no' '
+       (
+               echo "change #1" >> foo && git commit -a -m"change #1" &&
+               echo "change #2" >> foo && git commit -a -m"change #2" &&
+               echo "change #3" >> foo && git commit -a -m"change #3" &&
+               ( echo "yes
+yes
+no" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
+               test $(git rev-parse HEAD^^^) = $(git rev-parse remotes/git-svn) &&
+               git reset --hard remotes/git-svn
+       )
+       '
+
+test_expect_success 'answers: yes quit' '
+       (
+               echo "change #1" >> foo && git commit -a -m"change #1" &&
+               echo "change #2" >> foo && git commit -a -m"change #2" &&
+               echo "change #3" >> foo && git commit -a -m"change #3" &&
+               ( echo "yes
+quit" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
+               test $(git rev-parse HEAD^^^) = $(git rev-parse remotes/git-svn) &&
+               git reset --hard remotes/git-svn
+       )
+       '
+
+test_expect_success 'answers: all' '
+       (
+               echo "change #1" >> foo && git commit -a -m"change #1" &&
+               echo "change #2" >> foo && git commit -a -m"change #2" &&
+               echo "change #3" >> foo && git commit -a -m"change #3" &&
+               ( echo "all" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
+               test $(git rev-parse HEAD) = $(git rev-parse remotes/git-svn) &&
+               git reset --hard remotes/git-svn
+       )
+       '
+
+test_done
index 1a6c06631c1c2a8fc29b66c9265541b54e8a9715..438aaf6b14b8ae0cb35739d6006eaf646876107c 100755 (executable)
@@ -820,6 +820,18 @@ test_expect_success \
        'test 1 = `git rev-list J | wc -l` &&
         test 0 = `git ls-tree J | wc -l`'
 
+cat >input <<INPUT_END
+reset refs/heads/J2
+
+tag wrong_tag
+from refs/heads/J2
+data <<EOF
+Tag branch that was reset.
+EOF
+INPUT_END
+test_expect_success \
+       'J: tag must fail on empty branch' \
+       'test_must_fail git fast-import <input'
 ###
 ### series K
 ###
@@ -1975,6 +1987,23 @@ test_expect_success \
        'Q: verify second note for second commit' \
        'git cat-file blob refs/notes/foobar:$commit2 >actual && test_cmp expect actual'
 
+cat >input <<EOF
+reset refs/heads/Q0
+
+commit refs/heads/note-Q0
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+Note for an empty branch.
+COMMIT
+
+N inline refs/heads/Q0
+data <<NOTE
+some note
+NOTE
+EOF
+test_expect_success \
+       'Q: deny note on empty branch' \
+       'test_must_fail git fast-import <input'
 ###
 ### series R (feature and option)
 ###
@@ -2208,7 +2237,7 @@ test_expect_success 'R: cat-blob-fd must be a nonnegative integer' '
        test_must_fail git fast-import --cat-blob-fd=-1 </dev/null
 '
 
-test_expect_success 'R: print old blob' '
+test_expect_success NOT_MINGW 'R: print old blob' '
        blob=$(echo "yes it can" | git hash-object -w --stdin) &&
        cat >expect <<-EOF &&
        ${blob} blob 11
@@ -2220,7 +2249,7 @@ test_expect_success 'R: print old blob' '
        test_cmp expect actual
 '
 
-test_expect_success 'R: in-stream cat-blob-fd not respected' '
+test_expect_success NOT_MINGW 'R: in-stream cat-blob-fd not respected' '
        echo hello >greeting &&
        blob=$(git hash-object -w greeting) &&
        cat >expect <<-EOF &&
@@ -2241,7 +2270,7 @@ test_expect_success 'R: in-stream cat-blob-fd not respected' '
        test_cmp expect actual.1
 '
 
-test_expect_success 'R: print new blob' '
+test_expect_success NOT_MINGW 'R: print new blob' '
        blob=$(echo "yep yep yep" | git hash-object --stdin) &&
        cat >expect <<-EOF &&
        ${blob} blob 12
@@ -2259,7 +2288,7 @@ test_expect_success 'R: print new blob' '
        test_cmp expect actual
 '
 
-test_expect_success 'R: print new blob by sha1' '
+test_expect_success NOT_MINGW 'R: print new blob by sha1' '
        blob=$(echo "a new blob named by sha1" | git hash-object --stdin) &&
        cat >expect <<-EOF &&
        ${blob} blob 25
diff --git a/t/t9901-git-web--browse.sh b/t/t9901-git-web--browse.sh
new file mode 100755 (executable)
index 0000000..b0a6bad
--- /dev/null
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+
+test_description='git web--browse basic tests
+
+This test checks that git web--browse can handle various valid URLs.'
+
+. ./test-lib.sh
+
+test_web_browse () {
+       # browser=$1 url=$2
+       git web--browse --browser="$1" "$2" >actual &&
+       tr -d '\015' <actual >text &&
+       test_cmp expect text
+}
+
+test_expect_success \
+       'URL with an ampersand in it' '
+       echo http://example.com/foo\&bar >expect &&
+       git config browser.custom.cmd echo &&
+       test_web_browse custom http://example.com/foo\&bar
+'
+
+test_expect_success \
+       'URL with a semi-colon in it' '
+       echo http://example.com/foo\;bar >expect &&
+       git config browser.custom.cmd echo &&
+       test_web_browse custom http://example.com/foo\;bar
+'
+
+test_expect_success \
+       'URL with a hash in it' '
+       echo http://example.com/foo#bar >expect &&
+       git config browser.custom.cmd echo &&
+       test_web_browse custom http://example.com/foo#bar
+'
+
+test_expect_success \
+       'browser paths are properly quoted' '
+       echo fake: http://example.com/foo >expect &&
+       cat >"fake browser" <<-\EOF &&
+       #!/bin/sh
+       echo fake: "$@"
+       EOF
+       chmod +x "fake browser" &&
+       git config browser.w3m.path "`pwd`/fake browser" &&
+       test_web_browse w3m http://example.com/foo
+'
+
+test_expect_success \
+       'browser command allows arbitrary shell code' '
+       echo "arg: http://example.com/foo" >expect &&
+       git config browser.custom.cmd "
+               f() {
+                       for i in \"\$@\"; do
+                               echo arg: \$i
+                       done
+               }
+               f" &&
+       test_web_browse custom http://example.com/foo
+'
+
+test_done
index 237aed8c766638c55d8d6b870c86ef2ad13a74d3..8282f5e5f6c615460e1c340d66e395c2d57aef73 100644 (file)
@@ -1091,6 +1091,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                 */
                mark_new_skip_worktree(o->el, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
 
+               ret = 0;
                for (i = 0; i < o->result.cache_nr; i++) {
                        struct cache_entry *ce = o->result.cache[i];
 
@@ -1103,19 +1104,30 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                         * correct CE_NEW_SKIP_WORKTREE
                         */
                        if (ce->ce_flags & CE_ADDED &&
-                           verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
-                                       return -1;
+                           verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
+                               if (!o->show_all_errors)
+                                       goto return_failed;
+                               ret = -1;
+                       }
 
                        if (apply_sparse_checkout(ce, o)) {
+                               if (!o->show_all_errors)
+                                       goto return_failed;
                                ret = -1;
-                               goto done;
                        }
                        if (!ce_skip_worktree(ce))
                                empty_worktree = 0;
 
                }
+               if (ret < 0)
+                       goto return_failed;
+               /*
+                * Sparse checkout is meant to narrow down checkout area
+                * but it does not make sense to narrow down to empty working
+                * tree. This is usually a mistake in sparse checkout rules.
+                * Do not allow users to do that.
+                */
                if (o->result.cache_nr && empty_worktree) {
-                       /* dubious---why should this fail??? */
                        ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory");
                        goto done;
                }
diff --git a/url.c b/url.c
index 3e06fd34c46a00b41f4843ea87a151314ce0789c..335d97d3f74e5b7d7139e223fbe1d19837a72e81 100644 (file)
--- a/url.c
+++ b/url.c
@@ -18,35 +18,15 @@ int is_urlschemechar(int first_flag, int ch)
 
 int is_url(const char *url)
 {
-       const char *url2, *first_slash;
-
-       if (!url)
-               return 0;
-       url2 = url;
-       first_slash = strchr(url, '/');
-
-       /* Input with no slash at all or slash first can't be URL. */
-       if (!first_slash || first_slash == url)
+       /* Is "scheme" part reasonable? */
+       if (!url || !is_urlschemechar(1, *url++))
                return 0;
-       /* Character before must be : and next must be /. */
-       if (first_slash[-1] != ':' || first_slash[1] != '/')
-               return 0;
-       /* There must be something before the :// */
-       if (first_slash == url + 1)
-               return 0;
-       /*
-        * Check all characters up to first slash - 1. Only alphanum
-        * is allowed.
-        */
-       url2 = url;
-       while (url2 < first_slash - 1) {
-               if (!is_urlschemechar(url2 == url, (unsigned char)*url2))
+       while (*url && *url != ':') {
+               if (!is_urlschemechar(0, *url++))
                        return 0;
-               url2++;
        }
-
-       /* Valid enough. */
-       return 1;
+       /* We've seen "scheme"; we want colon-slash-slash */
+       return (url[0] == ':' && url[1] == '/' && url[2] == '/');
 }
 
 static int url_decode_char(const char *q)
@@ -68,18 +48,20 @@ static int url_decode_char(const char *q)
        return val;
 }
 
-static char *url_decode_internal(const char **query, const char *stop_at,
-                                struct strbuf *out, int decode_plus)
+static char *url_decode_internal(const char **query, int len,
+                                const char *stop_at, struct strbuf *out,
+                                int decode_plus)
 {
        const char *q = *query;
 
-       do {
+       while (len) {
                unsigned char c = *q;
 
                if (!c)
                        break;
                if (stop_at && strchr(stop_at, c)) {
                        q++;
+                       len--;
                        break;
                }
 
@@ -88,6 +70,7 @@ static char *url_decode_internal(const char **query, const char *stop_at,
                        if (0 <= val) {
                                strbuf_addch(out, val);
                                q += 3;
+                               len -= 3;
                                continue;
                        }
                }
@@ -97,34 +80,41 @@ static char *url_decode_internal(const char **query, const char *stop_at,
                else
                        strbuf_addch(out, c);
                q++;
-       } while (1);
+               len--;
+       }
        *query = q;
        return strbuf_detach(out, NULL);
 }
 
 char *url_decode(const char *url)
+{
+       return url_decode_mem(url, strlen(url));
+}
+
+char *url_decode_mem(const char *url, int len)
 {
        struct strbuf out = STRBUF_INIT;
-       const char *colon = strchr(url, ':');
+       const char *colon = memchr(url, ':', len);
 
        /* Skip protocol part if present */
        if (colon && url < colon) {
                strbuf_add(&out, url, colon - url);
+               len -= colon - url;
                url = colon;
        }
-       return url_decode_internal(&url, NULL, &out, 0);
+       return url_decode_internal(&url, len, NULL, &out, 0);
 }
 
 char *url_decode_parameter_name(const char **query)
 {
        struct strbuf out = STRBUF_INIT;
-       return url_decode_internal(query, "&=", &out, 1);
+       return url_decode_internal(query, -1, "&=", &out, 1);
 }
 
 char *url_decode_parameter_value(const char **query)
 {
        struct strbuf out = STRBUF_INIT;
-       return url_decode_internal(query, "&", &out, 1);
+       return url_decode_internal(query, -1, "&", &out, 1);
 }
 
 void end_url_with_slash(struct strbuf *buf, const char *url)
diff --git a/url.h b/url.h
index 7100e3215a97b234c8ab93b76f7f86518f7c3382..abdaf6fa30b68767f48b056c977e498f9cfe7de2 100644 (file)
--- a/url.h
+++ b/url.h
@@ -4,6 +4,7 @@
 extern int is_url(const char *url);
 extern int is_urlschemechar(int first_flag, int ch);
 extern char *url_decode(const char *url);
+extern char *url_decode_mem(const char *url, int len);
 extern char *url_decode_parameter_name(const char **query);
 extern char *url_decode_parameter_value(const char **query);
 
index 5a33d1a86964472a82a63f18ab3c9b4da9b23165..e419f4f726019a5b0365c589285439fb3bfb8db2 100644 (file)
@@ -383,7 +383,7 @@ static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
  * might be potentially discarded if they happear in a run of discardable.
  */
 static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
-       long i, nm, nreff;
+       long i, nm, nreff, mlim;
        xrecord_t **recs;
        xdlclass_t *rcrec;
        char *dis, *dis1, *dis2;
@@ -396,16 +396,20 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xd
        dis1 = dis;
        dis2 = dis1 + xdf1->nrec + 1;
 
+       if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT)
+               mlim = XDL_MAX_EQLIMIT;
        for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) {
                rcrec = cf->rcrecs[(*recs)->ha];
                nm = rcrec ? rcrec->len2 : 0;
-               dis1[i] = (nm == 0) ? 0: 1;
+               dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
        }
 
+       if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT)
+               mlim = XDL_MAX_EQLIMIT;
        for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) {
                rcrec = cf->rcrecs[(*recs)->ha];
                nm = rcrec ? rcrec->len1 : 0;
-               dis2[i] = (nm == 0) ? 0: 1;
+               dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
        }
 
        for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart];