Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Tue, 8 Jan 2013 21:23:46 +0000 (13:23 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 8 Jan 2013 21:23:46 +0000 (13:23 -0800)
* maint:
t1402: work around shell quoting issue on NetBSD
remote-hg: Fix biridectionality -> bidirectionality typos

108 files changed:
.gitignore
Documentation/RelNotes/1.8.2.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/git-bundle.txt
Documentation/git-config.txt
Documentation/git-fast-import.txt
Documentation/git-log.txt
Documentation/git-push.txt
Documentation/git-remote-testgit.txt
Documentation/git-submodule.txt
Documentation/git.txt
Documentation/gitmodules.txt
Documentation/mailmap.txt
Documentation/pretty-formats.txt
Documentation/pt_BR/gittutorial.txt [deleted file]
Documentation/technical/api-history-graph.txt
Documentation/technical/api-string-list.txt
GIT-VERSION-GEN
Makefile
RelNotes
abspath.c
advice.c
advice.h
archive.c
attr.c
builtin/apply.c
builtin/fast-export.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/push.c
builtin/send-pack.c
builtin/shortlog.c
cache-tree.c
cache-tree.h
cache.h
commit.h
config.c
configure.ac
contrib/completion/git-completion.bash
dir.c
dir.h
editor.c
fetch-pack.c
fsck.c
git-compat-util.h
git-remote-testgit [new file with mode: 0755]
git-remote-testgit.py [deleted file]
git-remote-testpy.py [new file with mode: 0644]
git-submodule.sh
git.c
git_remote_helpers/git/importer.py
gitweb/gitweb.perl
graph.c
http-push.c
http.c
imap-send.c
log-tree.c
mailmap.c
mergetools/p4merge
parse-options.c
parse-options.h
path.c
perl/Git.pm
perl/Git/SVN/Prompt.pm
pretty.c
refs.c
remote.c
run-command.c
send-pack.c
setup.c
strbuf.c
strbuf.h
string-list.c
string-list.h
t/t0000-basic.sh
t/t0060-path-utils.sh
t/t0063-string-list.sh
t/t1020-subdirectory.sh
t/t1450-fsck.sh
t/t2203-add-intent.sh
t/t4201-shortlog.sh
t/t4202-log.sh
t/t4203-mailmap.sh
t/t5002-archive-attr-pattern.sh [new file with mode: 0755]
t/t5516-fetch-push.sh
t/t5535-fetch-push-symref.sh [new file with mode: 0755]
t/t5800-remote-helpers.sh [deleted file]
t/t5800-remote-testpy.sh [new file with mode: 0755]
t/t5801-remote-helpers.sh [new file with mode: 0755]
t/t6006-rev-list-format.sh
t/t6130-pathspec-noglob.sh [new file with mode: 0755]
t/t7400-submodule-basic.sh
t/t7406-submodule-update.sh
t/t9020-remote-svn.sh
t/t9350-fast-export.sh
t/t9810-git-p4-rcs.sh
t/test-lib.sh
test-path-utils.c
test-string-list.c
transport-helper.c
transport.c
transport.h
tree-walk.c
unpack-trees.c
usage.c
utf8.c
utf8.h
wrapper.c
index f702415c12c5a4a66180f7ffd697347e5343ac4a..8e8dc275db9bcc1155e42daea5a6589b4802bc9c 100644 (file)
@@ -1,8 +1,8 @@
 /GIT-BUILD-OPTIONS
 /GIT-CFLAGS
 /GIT-LDFLAGS
-/GIT-GUI-VARS
 /GIT-PREFIX
+/GIT-PYTHON-VARS
 /GIT-SCRIPT-DEFINES
 /GIT-USER-AGENT
 /GIT-VERSION-FILE
 /git-remote-ftps
 /git-remote-fd
 /git-remote-ext
-/git-remote-testgit
+/git-remote-testpy
 /git-remote-testsvn
 /git-repack
 /git-replace
 /git-whatchanged
 /git-write-tree
 /git-core-*/?*
-/gitk-git/gitk-wish
 /gitweb/GITWEB-BUILD-OPTIONS
 /gitweb/gitweb.cgi
 /gitweb/static/gitweb.js
diff --git a/Documentation/RelNotes/1.8.2.txt b/Documentation/RelNotes/1.8.2.txt
new file mode 100644 (file)
index 0000000..92de751
--- /dev/null
@@ -0,0 +1,147 @@
+Git v1.8.2 Release Notes
+========================
+
+Backward compatibility notes
+----------------------------
+
+In the upcoming major release (tentatively called 1.8.2), we will
+change the behavior of the "git push" command.
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  We will use the "simple" semantics that pushes the
+current branch to the branch with the same name, only when the current
+branch is set to integrate with that remote branch.  There is a user
+preference configuration variable "push.default" to change this.
+
+
+Updates since v1.8.1
+--------------------
+
+UI, Workflows & Features
+
+ * Initial ports to QNX and z/OS UNIX System Services have started.
+
+ * Output from the tests is coloured using "green is okay, yellow is
+   questionable, red is bad and blue is informative" scheme.
+
+ * In bare repositories, "git shortlog" and other commands now read
+   mailmap files from the tip of the history, to help running these
+   tools in server settings.
+
+ * Color specifiers, e.g. "%C(blue)Hello%C(reset)", used in the
+   "--format=" option of "git log" and friends can be disabled when
+   the output is not sent to a terminal by prefixing them with
+   "auto,", e.g. "%C(auto,blue)Hello%C(auto,reset)".
+
+ * Scripts can ask Git that wildcard patterns in pathspecs they give do
+   not have any significance, i.e. take them as literal strings.
+
+ * "git fetch --mirror" and fetch that uses other forms of refspec
+   with wildcard used to attempt to update a symbolic ref that match
+   the wildcard on the receiving end, which made little sense (the
+   real ref that is pointed at by the symbolic ref would be updated
+   anyway).  Symbolic refs no longer are affected by such a fetch.
+
+ * "git push" now requires "-f" to update a tag, even if it is a
+   fast-forward, as tags are meant to be fixed points.
+
+ * "git submodule" started learning a new mode to integrate with the
+   tip of the remote branch (as opposed to integrating with the commit
+   recorded in the superproject's gitlink).
+
+
+Foreign Interface
+
+ * "git fast-export" has been updated for its use in the context of
+   the remote helper interface.
+
+
+Performance, Internal Implementation, etc.
+
+ * "git fsck" has been taught to be pickier about entries in tree
+   objects that should not be there, e.g. ".", ".git", and "..".
+
+ * Matching paths with common forms of pathspecs that contain wildcard
+   characters has been optimized further.
+
+ * The implementation of "imap-send" has been updated to reuse xml
+   quoting code from http-push codepath.
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.8.1
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.1 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * An element on GIT_CEILING_DIRECTORIES list that does not name the
+   real path to a directory (i.e. a symbolic link) could have caused
+   the GIT_DIR discovery logic to escape the ceiling.
+   (merge 059b379 mh/ceiling later to maint).
+
+ * t4014, t9502 and t0200 tests had various portability issues that
+   broke on OpenBSD.
+   (merge 27f6342 jc/maint-test-portability later to maint).
+
+ * t9020 and t3600 tests had various portability issues.
+   (merge 5a02966 jc/test-portability later to maint).
+
+ * t9200 runs "cvs init" on a directory that already exists, but a
+   platform can configure this fail for the current user (e.g. you
+   need to be in the cvsadmin group on NetBSD 6.0).
+   (merge 8666df0 jc/test-cvs-no-init-in-existing-dir later to maint).
+
+ * The behaviour visible to the end users was confusing, when they
+   attempt to kill a process spawned in the editor that was in turn
+   launched by Git with SIGINT (or SIGQUIT), as Git would catch that
+   signal and die.  We ignore these signals now.
+   (merge 1250857 pf/editor-ignore-sigint later to maint).
+
+ * After failing to create a temporary file using mkstemp(), failing
+   pathname was not reported correctly on some platforms.
+   (merge f7be59b jc/mkstemp-more-careful-error-reporting later to maint).
+
+ * The attribute mechanism didn't allow limiting attributes to be
+   applied to only a single directory itself with "path/" like the
+   exclude mechanism does.
+   (merge 94bc671 ja/directory-attrs later to maint).
+
+ * The way "git svn" asked for password using SSH_ASKPASS and
+   GIT_ASKPASS was not in line with the rest of the system.
+   (merge e9263e4 ss/svn-prompt later to maint).
+
+ * The --graph code fell into infinite loop when asked to do what the
+   code did not expect.
+   (merge 656197a mk/maint-graph-infinity-loop later to maint).
+
+ * http transport was wrong to ask for the username when the
+   authentication is done by certificate identity.
+   (merge 75e9a40 rb/http-cert-cred-no-username-prompt later to maint).
+
+ * "git pack-refs" that ran in parallel to another process that
+   created new refs had a nasty race.
+   (merge b3f1280 jk/repack-ref-racefix later to maint).
+
+ * After "git add -N" and then writing a tree object out of the
+   index, the cache-tree data structure got corrupted.
+   (merge eec3e7e nd/invalidate-i-t-a-cache-tree later to maint).
+
+ * "gitweb", when sorting by age to show repositories with new
+   activities first, used to sort repositories with absolutely
+   nothing in it early, which was not very useful.
+   (merge 28dae18 md/gitweb-sort-by-age later to maint).
+
+ * When a line to be wrapped has a solid run of non space characters
+   whose length exactly is the wrap width, "git shortlog -w" failed
+   to add a newline after such a line.
+   (merge e0db176 sp/shortlog-missing-lf later to maint).
+
+ * Some shells do not behave correctly when IFS is unset; work it
+   around by explicitly setting it to the default value.
+   (merge 393050c jc/maint-fbsd-sh-ifs-workaround later to maint).
index bf8f911e1ffe7820a8e903ec669c690d39612150..53c4ca1d7a0f7441a3ff84d50574efabce5a79f5 100644 (file)
@@ -140,10 +140,11 @@ advice.*::
        can tell Git that you do not need help by setting these to 'false':
 +
 --
-       pushNonFastForward::
+       pushUpdateRejected::
                Set this variable to 'false' if you want to disable
-               'pushNonFFCurrent', 'pushNonFFDefault', and
-               'pushNonFFMatching' simultaneously.
+               'pushNonFFCurrent', 'pushNonFFDefault',
+               'pushNonFFMatching', and 'pushAlreadyExists'
+               simultaneously.
        pushNonFFCurrent::
                Advice shown when linkgit:git-push[1] fails due to a
                non-fast-forward update to the current branch.
@@ -158,6 +159,9 @@ advice.*::
                'matching refs' explicitly (i.e. you used ':', or
                specified a refspec that isn't your current branch) and
                it resulted in a non-fast-forward error.
+       pushAlreadyExists::
+               Shown when linkgit:git-push[1] rejects an update that
+               does not qualify for fast-forwarding (e.g., a tag.)
        statusHints::
                Show directions on how to proceed from the current
                state in the output of linkgit:git-status[1], in
@@ -1517,6 +1521,14 @@ mailmap.file::
        subdirectory, or somewhere outside of the repository itself.
        See linkgit:git-shortlog[1] and linkgit:git-blame[1].
 
+mailmap.blob::
+       Like `mailmap.file`, but consider the value as a reference to a
+       blob in the repository. If both `mailmap.file` and
+       `mailmap.blob` are given, both are parsed, with entries from
+       `mailmap.file` taking precedence. In a bare repository, this
+       defaults to `HEAD:.mailmap`. In a non-bare repository, it
+       defaults to empty.
+
 man.viewer::
        Specify the programs that may be used to display help in the
        'man' format. See linkgit:git-help[1].
@@ -1995,6 +2007,12 @@ submodule.<name>.update::
        URL and other values found in the `.gitmodules` file.  See
        linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
 
+submodule.<name>.branch::
+       The remote branch name for a submodule, used by `git submodule
+       update --remote`.  Set this option to override the value found in
+       the `.gitmodules` file.  See linkgit:git-submodule[1] and
+       linkgit:gitmodules[5] for details.
+
 submodule.<name>.fetchRecurseSubmodules::
        This option can be used to control recursive fetching of this
        submodule. It can be overridden by using the --[no-]recurse-submodules
index 16a6b0acebc7e15bfae0850d6d6c716fd5a32eaa..bc023cc5f3bb6be8cd664ec6a74743f46b396283 100644 (file)
@@ -112,13 +112,12 @@ machineA$ git bundle create file.bundle master
 machineA$ git tag -f lastR2bundle master
 ----------------
 
-Then you transfer file.bundle to the target machine B. If you are creating
-the repository on machine B, then you can clone from the bundle as if it
-were a remote repository instead of creating an empty repository and then
-pulling or fetching objects from the bundle:
+Then you transfer file.bundle to the target machine B. Because this
+bundle does not require any existing object to be extracted, you can
+create a new repository on machine B by cloning from it:
 
 ----------------
-machineB$ git clone /home/me/tmp/file.bundle R2
+machineB$ git clone -b master /home/me/tmp/file.bundle R2
 ----------------
 
 This will define a remote called "origin" in the resulting repository that
index eaea0791657386469e448def614b949c0a1f45e9..9ae2508f3fb79b9da5fb4481a4fe2120f4a082b1 100644 (file)
@@ -240,6 +240,10 @@ GIT_CONFIG::
        Using the "--global" option forces this to ~/.gitconfig. Using the
        "--system" option forces this to $(prefix)/etc/gitconfig.
 
+GIT_CONFIG_NOSYSTEM::
+       Whether to skip reading settings from the system-wide
+       $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
+
 See also <<FILES>>.
 
 
index 68bca1a29de51995881edae077c8232bcdb1f07a..3da5cc272a7aac921017fead83c271b5d35fd977 100644 (file)
@@ -39,10 +39,6 @@ OPTIONS
        See ``Date Formats'' below for details about which formats
        are supported, and their syntax.
 
--- done::
-       Terminate with error if there is no 'done' command at the
-       end of the stream.
-
 --force::
        Force updating modified existing branches, even if doing
        so would cause commits to be lost (as the new commit does
@@ -108,7 +104,8 @@ OPTIONS
        output.
 
 --done::
-       Require a `done` command at the end of the stream.
+       Terminate with error if there is no `done` command at the
+       end of the stream.
        This option might be useful for detecting errors that
        cause the frontend to terminate before it has started to
        write a stream.
index 585dac40baabbee291f43a6e7c59c36340286e43..08a185db7fb7192b4e94c83ae6781893e119c6cf 100644 (file)
@@ -167,7 +167,7 @@ log.showroot::
        `git log -p` output would be shown without a diff attached.
        The default is `true`.
 
-mailmap.file::
+mailmap.*::
        See linkgit:git-shortlog[1].
 
 notes.displayRef::
index 8b637d339f522e9dd6f3310efdc0691c5bcb14bf..c964b796be742f01aa974ee4d770891b6a65b2cb 100644 (file)
@@ -51,10 +51,11 @@ be named. If `:`<dst> is omitted, the same ref as <src> will be
 updated.
 +
 The object referenced by <src> is used to update the <dst> reference
-on the remote side, but by default this is only allowed if the
-update can fast-forward <dst>.  By having the optional leading `+`,
-you can tell git to update the <dst> ref even when the update is not a
-fast-forward.  This does *not* attempt to merge <src> into <dst>.  See
+on the remote side.  By default this is only allowed if <dst> is not
+a tag (annotated or lightweight), and then only if it can fast-forward
+<dst>.  By having the optional leading `+`, you can tell git to update
+the <dst> ref even if it is not allowed by default (e.g., it is not a
+fast-forward.)  This does *not* attempt to merge <src> into <dst>.  See
 EXAMPLES below for details.
 +
 `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
index 2a67d456a3d2e278d924e792760dfd90f77a680c..612a625ced88919b106c28b79b8d6598f5c5e57c 100644 (file)
@@ -19,7 +19,7 @@ testcase for the remote-helper functionality, and as an example to
 show remote-helper authors one possible implementation.
 
 The best way to learn more is to read the comments and source code in
-'git-remote-testgit.py'.
+'git-remote-testgit'.
 
 SEE ALSO
 --------
index b1de3bade751f34b9629e3d4c0d8f654fca86a91..b1996f1a6311f99e2d583a1ad6cb839dd4efc7aa 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
              [--reference <repository>] [--] <repository> [<path>]
 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
-'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
+'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch] [--rebase]
              [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
              [commit] [--] [<path>...]
@@ -208,6 +208,8 @@ OPTIONS
 -b::
 --branch::
        Branch of repository to add as submodule.
+       The name of the branch is recorded as `submodule.<path>.branch` in
+       `.gitmodules` for `update --remote`.
 
 -f::
 --force::
@@ -236,6 +238,27 @@ OPTIONS
        (the default). This limit only applies to modified submodules. The
        size is always limited to 1 for added/deleted/typechanged submodules.
 
+--remote::
+       This option is only valid for the update command.  Instead of using
+       the superproject's recorded SHA-1 to update the submodule, use the
+       status of the submodule's remote tracking branch.  The remote used
+       is branch's remote (`branch.<name>.remote`), defaulting to `origin`.
+       The remote branch used defaults to `master`, but the branch name may
+       be overridden by setting the `submodule.<name>.branch` option in
+       either `.gitmodules` or `.git/config` (with `.git/config` taking
+       precedence).
++
+This works for any of the supported update procedures (`--checkout`,
+`--rebase`, etc.).  The only change is the source of the target SHA-1.
+For example, `submodule update --remote --merge` will merge upstream
+submodule changes into the submodules, while `submodule update
+--merge` will merge superproject gitlink changes into the submodules.
++
+In order to ensure a current tracking branch state, `update --remote`
+fetches the submodule's remote repository before calculating the
+SHA-1.  If you don't want to fetch, you should use `submodule update
+--remote --no-fetch`.
+
 -N::
 --no-fetch::
        This option is only valid for the update command.
index 7a3f03b5ce28eca6b8803a842d44465a2104144e..c03b7adc97a98b41f6f4c709fa5e0a1ee4e71cd5 100644 (file)
@@ -428,6 +428,11 @@ help ...`.
        Do not use replacement refs to replace git objects. See
        linkgit:git-replace[1] for more information.
 
+--literal-pathspecs::
+       Treat pathspecs literally, rather than as glob patterns. This is
+       equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
+       variable to `1`.
+
 
 GIT COMMANDS
 ------------
@@ -772,6 +777,14 @@ for further details.
        and read the password from its STDOUT. See also the 'core.askpass'
        option in linkgit:git-config[1].
 
+'GIT_CONFIG_NOSYSTEM'::
+       Whether to skip reading settings from the system-wide
+       `$(prefix)/etc/gitconfig` file.  This environment variable can
+       be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a
+       predictable environment for a picky script, or you can set it
+       temporarily to avoid using a buggy `/etc/gitconfig` file while
+       waiting for someone with sufficient permissions to fix it.
+
 'GIT_FLUSH'::
        If this environment variable is set to "1", then commands such
        as 'git blame' (in incremental mode), 'git rev-list', 'git log',
@@ -796,6 +809,16 @@ for further details.
        as a file path and will try to write the trace messages
        into it.
 
+GIT_LITERAL_PATHSPECS::
+       Setting this variable to `1` will cause git to treat all
+       pathspecs literally, rather than as glob patterns. For example,
+       running `GIT_LITERAL_PATHSPECS=1 git log -- '*.c'` will search
+       for commits that touch the path `*.c`, not any paths that the
+       glob `*.c` matches. You might want this if you are feeding
+       literal paths to git (e.g., paths previously given to you by
+       `git ls-tree`, `--raw` diff output, etc).
+
+
 Discussion[[Discussion]]
 ------------------------
 
index ab3e91c054ca7b4dcf7373b0aac839c18275a791..52d7ae4313389b1766862d3df5d9874a4ac97b36 100644 (file)
@@ -49,6 +49,11 @@ submodule.<name>.update::
        This config option is overridden if 'git submodule update' is given
        the '--merge', '--rebase' or '--checkout' options.
 
+submodule.<name>.branch::
+       A remote branch name for tracking updates in the upstream submodule.
+       If the option is not specified, it defaults to 'master'.  See the
+       `--remote` documentation in linkgit:git-submodule[1] for details.
+
 submodule.<name>.fetchRecurseSubmodules::
        This option can be used to control recursive fetching of this
        submodule. If this option is also present in the submodules entry in
index dd89fca3f8996e119ce9d0cec0a6d9fc6616525d..4a8c276529a574355185adf3c77dede6fbd94267 100644 (file)
@@ -1,5 +1,6 @@
 If the file `.mailmap` exists at the toplevel of the repository, or at
-the location pointed to by the mailmap.file configuration option, it
+the location pointed to by the mailmap.file or mailmap.blob
+configuration options, it
 is used to map author and committer names and email addresses to
 canonical real names and email addresses.
 
index d9eddedc72a5e6362d68df1b126b76804b9676e1..105f18a6f9fd9f4a5a388cb3ec8a0e6a99f7abe3 100644 (file)
@@ -144,7 +144,11 @@ The placeholders are:
 - '%Cgreen': switch color to green
 - '%Cblue': switch color to blue
 - '%Creset': reset color
-- '%C(...)': color specification, as described in color.branch.* config option
+- '%C(...)': color specification, as described in color.branch.* config option;
+  adding `auto,` at the beginning will emit color only when colors are
+  enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
+  respecting the `auto` settings of the former if we are going to a
+  terminal)
 - '%m': left, right or boundary mark
 - '%n': newline
 - '%%': a raw '%'
diff --git a/Documentation/pt_BR/gittutorial.txt b/Documentation/pt_BR/gittutorial.txt
deleted file mode 100644 (file)
index beba065..0000000
+++ /dev/null
@@ -1,675 +0,0 @@
-gittutorial(7)
-==============
-
-NOME
-----
-gittutorial - Um tutorial de introdução ao git (para versão 1.5.1 ou mais nova)
-
-SINOPSE
---------
-git *
-
-DESCRIÇÃO
------------
-
-Este tutorial explica como importar um novo projeto para o git,
-adicionar mudanças a ele, e compartilhar mudanças com outros
-desenvolvedores.
-
-Se, ao invés disso, você está interessado primariamente em usar git para
-obter um projeto, por exemplo, para testar a Ãºltima versão, você pode
-preferir começar com os primeiros dois capítulos de
-link:user-manual.html[O Manual do Usuário Git].
-
-Primeiro, note que você pode obter documentação para um comando como
-`git log --graph` com:
-
-------------------------------------------------
-$ man git-log
-------------------------------------------------
-
-ou:
-
-------------------------------------------------
-$ git help log
-------------------------------------------------
-
-Com a Ãºltima forma, você pode usar o visualizador de manual de sua
-escolha; veja linkgit:git-help[1] para maior informação.
-
-É uma boa idéia informar ao git seu nome e endereço público de email
-antes de fazer qualquer operação. A maneira mais fácil de fazê-lo Ã©:
-
-------------------------------------------------
-$ git config --global user.name "Seu Nome Vem Aqui"
-$ git config --global user.email voce@seudominio.exemplo.com
-------------------------------------------------
-
-
-Importando um novo projeto
------------------------
-
-Assuma que você tem um tarball project.tar.gz com seu trabalho inicial.
-Você pode colocá-lo sob controle de revisão git da seguinte forma:
-
-------------------------------------------------
-$ tar xzf project.tar.gz
-$ cd project
-$ git init
-------------------------------------------------
-
-Git irá responder
-
-------------------------------------------------
-Initialized empty Git repository in .git/
-------------------------------------------------
-
-Agora que você iniciou seu diretório de trabalho, você deve ter notado que um
-novo diretório foi criado com o nome de ".git".
-
-A seguir, diga ao git para gravar um instantâneo do conteúdo de todos os
-arquivos sob o diretório atual (note o '.'), com 'git-add':
-
-------------------------------------------------
-$ git add .
-------------------------------------------------
-
-Este instantâneo está agora armazenado em uma Ã¡rea temporária que o git
-chama de "index" ou Ã­ndice. Você pode armazenar permanentemente o
-conteúdo do Ã­ndice no repositório com 'git-commit':
-
-------------------------------------------------
-$ git commit
-------------------------------------------------
-
-Isto vai te pedir por uma mensagem de commit. Você agora gravou sua
-primeira versão de seu projeto no git.
-
-Fazendo mudanças
---------------
-
-Modifique alguns arquivos, e, então, adicione seu conteúdo atualizado ao
-índice:
-
-------------------------------------------------
-$ git add file1 file2 file3
-------------------------------------------------
-
-Você está agora pronto para fazer o commit. Você pode ver o que está
-para ser gravado usando 'git-diff' com a opção --cached:
-
-------------------------------------------------
-$ git diff --cached
-------------------------------------------------
-
-(Sem --cached, o comando 'git-diff' irá te mostrar quaisquer mudanças
-que você tenha feito mas ainda não adicionou ao Ã­ndice.) Você também
-pode obter um breve sumário da situação com 'git-status':
-
-------------------------------------------------
-$ git status
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      modified:   file1
-#      modified:   file2
-#      modified:   file3
-#
-------------------------------------------------
-
-Se você precisar fazer qualquer outro ajuste, faça-o agora, e, então,
-adicione qualquer conteúdo modificado ao Ã­ndice. Finalmente, grave suas
-mudanças com:
-
-------------------------------------------------
-$ git commit
-------------------------------------------------
-
-Ao executar esse comando, ele irá te pedir uma mensagem descrevendo a mudança,
-e, então, irá gravar a nova versão do projeto.
-
-Alternativamente, ao invés de executar 'git-add' antes, você pode usar
-
-------------------------------------------------
-$ git commit -a
-------------------------------------------------
-
-o que irá automaticamente notar quaisquer arquivos modificados (mas não
-novos), adicioná-los ao Ã­ndices, e gravar, tudo em um Ãºnico passo.
-
-Uma nota em mensagens de commit: Apesar de não ser exigido, Ã© uma boa
-idéia começar a mensagem com uma simples e curta (menos de 50
-caracteres) linha sumarizando a mudança, seguida de uma linha em branco
-e, então, uma descrição mais detalhada. Ferramentas que transformam
-commits em email, por exemplo, usam a primeira linha no campo de
-cabeçalho "Subject:" e o resto no corpo.
-
-Git rastreia conteúdo, não arquivos
-----------------------------
-
-Muitos sistemas de controle de revisão provêem um comando `add` que diz
-ao sistema para começar a rastrear mudanças em um novo arquivo. O
-comando `add` do git faz algo mais simples e mais poderoso: 'git-add' Ã©
-usado tanto para arquivos novos e arquivos recentemente modificados, e
-em ambos os casos, ele tira o instantâneo dos arquivos dados e armazena
-o conteúdo no Ã­ndice, pronto para inclusão do próximo commit.
-
-Visualizando a história do projeto
------------------------
-
-Em qualquer ponto você pode visualizar a história das suas mudanças
-usando
-
-------------------------------------------------
-$ git log
-------------------------------------------------
-
-Se você também quiser ver a diferença completa a cada passo, use
-
-------------------------------------------------
-$ git log -p
-------------------------------------------------
-
-Geralmente, uma visão geral da mudança Ã© Ãºtil para ter a sensação de
-cada passo
-
-------------------------------------------------
-$ git log --stat --summary
-------------------------------------------------
-
-Gerenciando "branches"/ramos
------------------
-
-Um simples repositório git pode manter múltiplos ramos de
-desenvolvimento. Para criar um novo ramo chamado "experimental", use
-
-------------------------------------------------
-$ git branch experimental
-------------------------------------------------
-
-Se você executar agora
-
-------------------------------------------------
-$ git branch
-------------------------------------------------
-
-você vai obter uma lista de todos os ramos existentes:
-
-------------------------------------------------
-  experimental
-* master
-------------------------------------------------
-
-O ramo "experimental" Ã© o que você acaba de criar, e o ramo "master" Ã© o
-ramo padrão que foi criado pra você automaticamente. O asterisco marca
-o ramo em que você está atualmente; digite
-
-------------------------------------------------
-$ git checkout experimental
-------------------------------------------------
-
-para mudar para o ramo experimental. Agora edite um arquivo, grave a
-mudança, e mude de volta para o ramo master:
-
-------------------------------------------------
-(edita arquivo)
-$ git commit -a
-$ git checkout master
-------------------------------------------------
-
-Verifique que a mudança que você fez não está mais visível, já que ela
-foi feita no ramo experimental e você está de volta ao ramo master.
-
-Você pode fazer uma mudança diferente no ramo master:
-
-------------------------------------------------
-(edit file)
-$ git commit -a
-------------------------------------------------
-
-neste ponto, os dois ramos divergiram, com diferentes mudanças feitas em
-cada um. Para unificar as mudanças feitas no experimental para o
-master, execute
-
-------------------------------------------------
-$ git merge experimental
-------------------------------------------------
-
-Se as mudanças não conflitarem, estará pronto. Se existirem conflitos,
-marcadores serão deixados nos arquivos problemáticos exibindo o
-conflito;
-
-------------------------------------------------
-$ git diff
-------------------------------------------------
-
-vai exibir isto. Após você editar os arquivos para resolver os
-conflitos,
-
-------------------------------------------------
-$ git commit -a
-------------------------------------------------
-
-irá gravar o resultado da unificação. Finalmente,
-
-------------------------------------------------
-$ gitk
-------------------------------------------------
-
-vai mostrar uma bela representação gráfica da história resultante.
-
-Neste ponto você pode remover seu ramo experimental com
-
-------------------------------------------------
-$ git branch -d experimental
-------------------------------------------------
-
-Este comando garante que as mudanças no ramo experimental já estão no
-ramo atual.
-
-Se você desenvolve em um ramo ideia-louca, e se arrepende, você pode
-sempre remover o ramo com
-
--------------------------------------
-$ git branch -D ideia-louca
--------------------------------------
-
-Ramos são baratos e fáceis, então isto Ã© uma boa maneira de experimentar
-alguma coisa.
-
-Usando git para colaboração
----------------------------
-
-Suponha que Alice começou um novo projeto com um repositório git em
-/home/alice/project, e que Bob, que tem um diretório home na mesma
-máquina, quer contribuir.
-
-Bob começa com:
-
-------------------------------------------------
-bob$ git clone /home/alice/project myrepo
-------------------------------------------------
-
-Isso cria um novo diretório "myrepo" contendo um clone do repositório de
-Alice. O clone está no mesmo pé que o projeto original, possuindo sua
-própria cópia da história do projeto original.
-
-Bob então faz algumas mudanças e as grava:
-
-------------------------------------------------
-(editar arquivos)
-bob$ git commit -a
-(repetir conforme necessário)
-------------------------------------------------
-
-Quanto está pronto, ele diz a Alice para puxar as mudanças do
-repositório em /home/bob/myrepo. Ela o faz com:
-
-------------------------------------------------
-alice$ cd /home/alice/project
-alice$ git pull /home/bob/myrepo master
-------------------------------------------------
-
-Isto unifica as mudanças do ramo "master" do Bob ao ramo atual de Alice.
-Se Alice fez suas próprias mudanças no intervalo, ela, então, pode
-precisar corrigir manualmente quaisquer conflitos. (Note que o argumento
-"master" no comando acima Ã©, de fato, desnecessário, já que Ã© o padrão.)
-
-O comando "pull" executa, então, duas operações: ele obtém mudanças de
-um ramo remoto, e, então, as unifica no ramo atual.
-
-Note que, em geral, Alice gostaria que suas mudanças locais fossem
-gravadas antes de iniciar este "pull". Se o trabalho de Bob conflita
-com o que Alice fez desde que suas histórias se ramificaram, Alice irá
-usar seu diretório de trabalho e o Ã­ndice para resolver conflitos, e
-mudanças locais existentes irão interferir com o processo de resolução
-de conflitos (git ainda irá realizar a obtenção mas irá se recusar a
-unificar --- Alice terá que se livrar de suas mudanças locais de alguma
-forma e puxar de novo quando isso acontecer).
-
-Alice pode espiar o que Bob fez sem unificar primeiro, usando o comando
-"fetch"; isto permite Alice inspecionar o que Bob fez, usando um símbolo
-especial "FETCH_HEAD", com o fim de determinar se ele tem alguma coisa
-que vale puxar, assim:
-
-------------------------------------------------
-alice$ git fetch /home/bob/myrepo master
-alice$ git log -p HEAD..FETCH_HEAD
-------------------------------------------------
-
-Esta operação Ã© segura mesmo se Alice tem mudanças locais não gravadas.
-A notação de intervalo "HEAD..FETCH_HEAD" significa mostrar tudo que Ã©
-alcançável de FETCH_HEAD mas exclua tudo o que Ã© alcançável de HEAD.
-Alice já sabe tudo que leva a seu estado atual (HEAD), e revisa o que Bob
-tem em seu estado (FETCH_HEAD) que ela ainda não viu com esse comando.
-
-Se Alice quer visualizar o que Bob fez desde que suas histórias se
-ramificaram, ela pode disparar o seguinte comando:
-
-------------------------------------------------
-$ gitk HEAD..FETCH_HEAD
-------------------------------------------------
-
-Isto usa a mesma notação de intervalo que vimos antes com 'git log'.
-
-Alice pode querer ver o que ambos fizeram desde que ramificaram. Ela
-pode usar a forma com três pontos ao invés da forma com dois pontos:
-
-------------------------------------------------
-$ gitk HEAD...FETCH_HEAD
-------------------------------------------------
-
-Isto significa "mostre tudo que Ã© alcançável de qualquer um deles, mas
-exclua tudo que Ã© alcançável a partir de ambos".
-
-Por favor, note que essas notações de intervalo podem ser usadas tanto
-com gitk quanto com "git log".
-
-Após inspecionar o que Bob fez, se não há nada urgente, Alice pode
-decidir continuar trabalhando sem puxar de Bob. Se a história de Bob
-tem alguma coisa que Alice precisa imediatamente, Alice pode optar por
-separar seu trabalho em progresso primeiro, fazer um "pull", e, então,
-finalmente, retomar seu trabalho em progresso em cima da história
-resultante.
-
-Quando você está trabalhando em um pequeno grupo unido, não Ã© incomum
-interagir com o mesmo repositório várias e várias vezes. Definindo um
-repositório remoto antes de tudo, você pode fazê-lo mais facilmente:
-
-------------------------------------------------
-alice$ git remote add bob /home/bob/myrepo
-------------------------------------------------
-
-Com isso, Alice pode executar a primeira parte da operação "pull" usando
-o comando 'git-fetch' sem unificar suas mudanças com seu próprio ramo,
-usando:
-
--------------------------------------
-alice$ git fetch bob
--------------------------------------
-
-Diferente da forma longa, quando Alice obteve de Bob usando um
-repositório remoto antes definido com 'git-remote', o que foi obtido Ã©
-armazenado em um ramo remoto, neste caso `bob/master`. Então, após isso:
-
--------------------------------------
-alice$ git log -p master..bob/master
--------------------------------------
-
-mostra uma lista de todas as mudanças que Bob fez desde que ramificou do
-ramo master de Alice.
-
-Após examinar essas mudanças, Alice pode unificá-las em seu ramo master:
-
--------------------------------------
-alice$ git merge bob/master
--------------------------------------
-
-Esse `merge` pode também ser feito puxando de seu próprio ramo remoto,
-assim:
-
--------------------------------------
-alice$ git pull . remotes/bob/master
--------------------------------------
-
-Note que 'git pull' sempre unifica ao ramo atual, independente do que
-mais foi passado na linha de comando.
-
-Depois, Bob pode atualizar seu repositório com as Ãºltimas mudanças de
-Alice, usando
-
--------------------------------------
-bob$ git pull
--------------------------------------
-
-Note que ele não precisa dar o caminho do repositório de Alice; quando
-Bob clonou seu repositório, o git armazenou a localização de seu
-repositório na configuração do mesmo, e essa localização Ã© usada
-para puxar:
-
--------------------------------------
-bob$ git config --get remote.origin.url
-/home/alice/project
--------------------------------------
-
-(A configuração completa criada por 'git-clone' Ã© visível usando `git
-config -l`, e a página de manual linkgit:git-config[1] explica o
-significado de cada opção.)
-
-Git também mantém uma cópia limpa do ramo master de Alice sob o nome
-"origin/master":
-
--------------------------------------
-bob$ git branch -r
-  origin/master
--------------------------------------
-
-Se Bob decidir depois em trabalhar em um host diferente, ele ainda pode
-executar clones e puxar usando o protocolo ssh:
-
--------------------------------------
-bob$ git clone alice.org:/home/alice/project myrepo
--------------------------------------
-
-Alternativamente, o git tem um protocolo nativo, ou pode usar rsync ou
-http; veja linkgit:git-pull[1] para detalhes.
-
-Git pode também ser usado em um modo parecido com CVS, com um
-repositório central para o qual vários usuários empurram modificações;
-veja linkgit:git-push[1] e linkgit:gitcvs-migration[7].
-
-Explorando história
------------------
-
-A história no git Ã© representada como uma série de commits
-interrelacionados. Nós já vimos que o comando 'git-log' pode listar
-esses commits. Note que a primeira linha de cada entrada no log também
-dá o nome para o commit:
-
--------------------------------------
-$ git log
-commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
-Author: Junio C Hamano <junkio@cox.net>
-Date:   Tue May 16 17:18:22 2006 -0700
-
-    merge-base: Clarify the comments on post processing.
--------------------------------------
-
-Nós podemos dar este nome ao 'git-show' para ver os detalhes sobre este
-commit.
-
--------------------------------------
-$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
--------------------------------------
-
-Mas há outras formas de se referir aos commits. Você pode usar qualquer
-parte inicial do nome que seja longo o bastante para identificar
-unicamente o commit:
-
--------------------------------------
-$ git show c82a22c39c  # os primeiros caracteres do nome são o bastante
-                       # usualmente
-$ git show HEAD                # a ponta do ramo atual
-$ git show experimental        # a ponta do ramo "experimental"
--------------------------------------
-
-Todo commit normalmente tem um commit "pai" que aponta para o estado
-anterior do projeto:
-
--------------------------------------
-$ git show HEAD^  # para ver o pai de HEAD
-$ git show HEAD^^ # para ver o avô de HEAD
-$ git show HEAD~4 # para ver o trisavô de HEAD
--------------------------------------
-
-Note que commits de unificação podem ter mais de um pai:
-
--------------------------------------
-$ git show HEAD^1 # mostra o primeiro pai de HEAD (o mesmo que HEAD^)
-$ git show HEAD^2 # mostra o segundo pai de HEAD
--------------------------------------
-
-Você também pode dar aos commits nomes Ã  sua escolha; após executar
-
--------------------------------------
-$ git tag v2.5 1b2e1d63ff
--------------------------------------
-
-você pode se referir a 1b2e1d63ff pelo nome "v2.5". Se você pretende
-compartilhar esse nome com outras pessoas (por exemplo, para identificar
-uma versão de lançamento), você deveria criar um objeto "tag", e talvez
-assiná-lo; veja linkgit:git-tag[1] para detalhes.
-
-Qualquer comando git que precise conhecer um commit pode receber
-quaisquer desses nomes. Por exemplo:
-
--------------------------------------
-$ git diff v2.5 HEAD    # compara o HEAD atual com v2.5
-$ git branch stable v2.5 # inicia um novo ramo chamado "stable" baseado
-                        # em v2.5
-$ git reset --hard HEAD^ # reseta seu ramo atual e seu diretório de
-                        # trabalho a seu estado em HEAD^
--------------------------------------
-
-Seja cuidadoso com o Ãºltimo comando: além de perder quaisquer mudanças
-em seu diretório de trabalho, ele também remove todos os commits
-posteriores desse ramo. Se esse ramo Ã© o Ãºnico ramo contendo esses
-commits, eles serão perdidos. Também, não use 'git-reset' num ramo
-publicamente visível de onde outros desenvolvedores puxam, já que vai
-forçar unificações desnecessárias para que outros desenvolvedores limpem
-a história. Se você precisa desfazer mudanças que você empurrou, use
-'git-revert' no lugar.
-
-O comando 'git-grep' pode buscar strings em qualquer versão de seu
-projeto, então
-
--------------------------------------
-$ git grep "hello" v2.5
--------------------------------------
-
-procura por todas as ocorrências de "hello" em v2.5.
-
-Se você deixar de fora o nome do commit, 'git-grep' irá procurar
-quaisquer dos arquivos que ele gerencia no diretório corrente. Então
-
--------------------------------------
-$ git grep "hello"
--------------------------------------
-
-é uma forma rápida de buscar somente os arquivos que são rastreados pelo
-git.
-
-Muitos comandos git também recebem um conjunto de commits, o que pode
-ser especificado de várias formas. Aqui estão alguns exemplos com 'git-log':
-
--------------------------------------
-$ git log v2.5..v2.6            # commits entre v2.5 e v2.6
-$ git log v2.5..                # commits desde v2.5
-$ git log --since="2 weeks ago" # commits das Ãºltimas 2 semanas
-$ git log v2.5.. Makefile       # commits desde v2.5 que modificam
-                               # Makefile
--------------------------------------
-
-Você também pode dar ao 'git-log' um "intervalo" de commits onde o
-primeiro não Ã© necessariamente um ancestral do segundo; por exemplo, se
-as pontas dos ramos "stable" e "master" divergiram de um commit
-comum algum tempo atrás, então
-
--------------------------------------
-$ git log stable..master
--------------------------------------
-
-irá listar os commits feitos no ramo "master" mas não no ramo
-"stable", enquanto
-
--------------------------------------
-$ git log master..stable
--------------------------------------
-
-irá listar a lista de commits feitos no ramo "stable" mas não no ramo
-"master".
-
-O comando 'git-log' tem uma fraqueza: ele precisa mostrar os commits em
-uma lista. Quando a história tem linhas de desenvolvimento que
-divergiram e então foram unificadas novamente, a ordem em que 'git-log'
-apresenta essas mudanças Ã© irrelevante.
-
-A maioria dos projetos com múltiplos contribuidores (como o kernel
-Linux, ou o próprio git) tem unificações frequentes, e 'gitk' faz um
-trabalho melhor de visualizar sua história. Por exemplo,
-
--------------------------------------
-$ gitk --since="2 weeks ago" drivers/
--------------------------------------
-
-permite a você navegar em quaisquer commits desde as Ãºltimas duas semanas
-de commits que modificaram arquivos sob o diretório "drivers". (Nota:
-você pode ajustar as fontes do gitk segurando a tecla control enquanto
-pressiona "-" ou "+".)
-
-Finalmente, a maioria dos comandos que recebem nomes de arquivo permitirão
-também, opcionalmente, preceder qualquer nome de arquivo por um
-commit, para especificar uma versão particular do arquivo:
-
--------------------------------------
-$ git diff v2.5:Makefile HEAD:Makefile.in
--------------------------------------
-
-Você pode usar 'git-show' para ver tal arquivo:
-
--------------------------------------
-$ git show v2.5:Makefile
--------------------------------------
-
-Próximos passos
-----------
-
-Este tutorial deve ser o bastante para operar controle de revisão
-distribuído básico para seus projetos. No entanto, para entender
-plenamente a profundidade e o poder do git você precisa entender duas
-idéias simples nas quais ele se baseia:
-
-  * A base de objetos Ã© um sistema bem elegante usado para armazenar a
-    história de seu projeto--arquivos, diretórios, e commits.
-
-  * O arquivo de Ã­ndice Ã© um cache do estado de uma Ã¡rvore de diretório,
-    usado para criar commits, restaurar diretórios de trabalho, e
-    armazenar as várias Ã¡rvores envolvidas em uma unificação.
-
-A parte dois deste tutorial explica a base de objetos, o arquivo de
-índice, e algumas outras coisinhas que você vai precisar pra usar o
-máximo do git. Você pode encontrá-la em linkgit:gittutorial-2[7].
-
-Se você não quiser continuar com o tutorial agora nesse momento, algumas
-outras digressões que podem ser interessantes neste ponto são:
-
-  * linkgit:git-format-patch[1], linkgit:git-am[1]: Estes convertem
-    séries de commits em patches para email, e vice-versa, Ãºteis para
-    projetos como o kernel Linux que dependem fortemente de patches
-    enviados por email.
-
-  * linkgit:git-bisect[1]: Quando há uma regressão em seu projeto, uma
-    forma de rastrear um bug Ã© procurando pela história para encontrar o
-    commit culpado. Git bisect pode ajudar a executar uma busca binária
-    por esse commit. Ele Ã© inteligente o bastante para executar uma
-    busca próxima da Ã³tima mesmo no caso de uma história complexa
-    não-linear com muitos ramos unificados.
-
-  * link:everyday.html[GIT diariamente com 20 e tantos comandos]
-
-  * linkgit:gitcvs-migration[7]: Git para usuários de CVS.
-
-VEJA TAMBÉM
---------
-linkgit:gittutorial-2[7],
-linkgit:gitcvs-migration[7],
-linkgit:gitcore-tutorial[7],
-linkgit:gitglossary[7],
-linkgit:git-help[1],
-link:everyday.html[git diariamente],
-link:user-manual.html[O Manual do Usuário git]
-
-GIT
----
-Parte da suite linkgit:git[1].
index d6fc90ac7eb210bd492057422748817a59cfc2a3..18142b6d29283bbf6e325ce71d50761a3f50a227 100644 (file)
@@ -33,11 +33,11 @@ The following utility functions are wrappers around `graph_next_line()` and
 They can all be called with a NULL graph argument, in which case no graph
 output will be printed.
 
-* `graph_show_commit()` calls `graph_next_line()` until it returns non-zero.
-  This prints all graph lines up to, and including, the line containing this
-  commit.  Output is printed to stdout.  The last line printed does not contain
-  a terminating newline.  This should not be called if the commit line has
-  already been printed, or it will loop forever.
+* `graph_show_commit()` calls `graph_next_line()` and
+  `graph_is_commit_finished()` until one of them return non-zero.  This prints
+  all graph lines up to, and including, the line containing this commit.
+  Output is printed to stdout.  The last line printed does not contain a
+  terminating newline.
 
 * `graph_show_oneline()` calls `graph_next_line()` and prints the result to
   stdout.  The line printed does not contain a terminating newline.
index 7386bcab3ec30a06f4663c953fa46e78ed26c07b..20be3488349c2ddbafbd90c0200f2a7d3862a12f 100644 (file)
@@ -82,14 +82,6 @@ Functions
        call free() on the util members of any items that have to be
        deleted.  Preserve the order of the items that are retained.
 
-`string_list_longest_prefix`::
-
-       Return the longest string within a string_list that is a
-       prefix (in the sense of prefixcmp()) of the specified string,
-       or NULL if no such prefix exists.  This function does not
-       require the string_list to be sorted (it does a linear
-       search).
-
 `print_string_list`::
 
        Dump a string_list to stdout, useful mainly for debugging purposes. It
index 72e37c9bfe3e897635f8c211569d9e6f5658a980..e9f7abca91b96c2f9c99744c49adefe04a4daf56 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.1
+DEF_VER=v1.8.1.GIT
 
 LF='
 '
index 736ecd45b58da32575cc20019d41a2b178843a09..56424b48b0b6c801ee74780718eab3014a3aeaa5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -74,10 +74,14 @@ all::
 # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
 # d_type in struct dirent (Cygwin 1.5, fixed in Cygwin 1.7).
 #
+# Define HAVE_STRINGS_H if you have strings.h and need it for strcasecmp.
+#
 # Define NO_STRCASESTR if you don't have strcasestr.
 #
 # Define NO_MEMMEM if you don't have memmem.
 #
+# Define NO_GETPAGESIZE if you don't have getpagesize.
+#
 # Define NO_STRLCPY if you don't have strlcpy.
 #
 # Define NO_STRTOUMAX if you don't have both strtoimax and strtoumax in the
@@ -165,6 +169,10 @@ all::
 # Define NO_POLL if you do not have or don't want to use poll().
 # This also implies NO_SYS_POLL_H.
 #
+# Define NEEDS_SYS_PARAM_H if you need to include sys/param.h to compile,
+# *PLEASE* REPORT to git@vger.kernel.org if your platform needs this;
+# we want to know more about the issue.
+#
 # Define NO_PTHREADS if you do not have or do not want to use Pthreads.
 #
 # Define NO_PREAD if you have a problem with pread() system call (e.g.
@@ -470,7 +478,7 @@ SCRIPT_PERL += git-relink.perl
 SCRIPT_PERL += git-send-email.perl
 SCRIPT_PERL += git-svn.perl
 
-SCRIPT_PYTHON += git-remote-testgit.py
+SCRIPT_PYTHON += git-remote-testpy.py
 SCRIPT_PYTHON += git-p4.py
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
@@ -1353,6 +1361,7 @@ ifeq ($(uname_S),NONSTOP_KERNEL)
        # Added manually, see above.
        NEEDS_SSL_WITH_CURL = YesPlease
        HAVE_LIBCHARSET_H = YesPlease
+       HAVE_STRINGS_H = YesPlease
        NEEDS_LIBICONV = YesPlease
        NEEDS_LIBINTL_BEFORE_LIBICONV = YesPlease
        NO_SYS_SELECT_H = UnfortunatelyYes
@@ -1448,6 +1457,22 @@ else
        NO_CURL = YesPlease
 endif
 endif
+ifeq ($(uname_S),QNX)
+       COMPAT_CFLAGS += -DSA_RESTART=0
+       HAVE_STRINGS_H = YesPlease
+       NEEDS_SOCKET = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
+       NO_GETPAGESIZE = YesPlease
+       NO_ICONV = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_MKSTEMPS = YesPlease
+       NO_NSEC = YesPlease
+       NO_PTHREADS = YesPlease
+       NO_R_TO_GCC_LINKER = YesPlease
+       NO_STRCASESTR = YesPlease
+       NO_STRLCPY = YesPlease
+endif
 
 -include config.mak.autogen
 -include config.mak
@@ -1655,6 +1680,9 @@ endif
 ifdef NO_D_INO_IN_DIRENT
        BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
 endif
+ifdef NO_GECOS_IN_PWENT
+       BASIC_CFLAGS += -DNO_GECOS_IN_PWENT
+endif
 ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
        BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
 endif
@@ -1748,6 +1776,9 @@ endif
 ifdef NO_SYS_POLL_H
        BASIC_CFLAGS += -DNO_SYS_POLL_H
 endif
+ifdef NEEDS_SYS_PARAM_H
+       BASIC_CFLAGS += -DNEEDS_SYS_PARAM_H
+endif
 ifdef NO_INTTYPES_H
        BASIC_CFLAGS += -DNO_INTTYPES_H
 endif
@@ -1859,6 +1890,9 @@ ifdef NO_MEMMEM
        COMPAT_CFLAGS += -DNO_MEMMEM
        COMPAT_OBJS += compat/memmem.o
 endif
+ifdef NO_GETPAGESIZE
+       COMPAT_CFLAGS += -DNO_GETPAGESIZE
+endif
 ifdef INTERNAL_QSORT
        COMPAT_CFLAGS += -DINTERNAL_QSORT
        COMPAT_OBJS += compat/qsort.o
@@ -1884,6 +1918,10 @@ ifdef HAVE_LIBCHARSET_H
        EXTLIBS += $(CHARSET_LIB)
 endif
 
+ifdef HAVE_STRINGS_H
+       BASIC_CFLAGS += -DHAVE_STRINGS_H
+endif
+
 ifdef HAVE_DEV_TTY
        BASIC_CFLAGS += -DHAVE_DEV_TTY
 endif
@@ -2183,7 +2221,7 @@ endef
 GIT-SCRIPT-DEFINES: FORCE
        @FLAGS='$(SCRIPT_DEFINES)'; \
            if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
-               echo 1>&2 "    * new script parameters"; \
+               echo >&2 "    * new script parameters"; \
                echo "$$FLAGS" >$@; \
             fi
 
@@ -2245,7 +2283,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
 endif # NO_PERL
 
 ifndef NO_PYTHON
-$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX
+$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
 $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
        $(QUIET_GEN)$(RM) $@ $@+ && \
        INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
@@ -2564,7 +2602,7 @@ TRACK_PREFIX = $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
 GIT-PREFIX: FORCE
        @FLAGS='$(TRACK_PREFIX)'; \
        if test x"$$FLAGS" != x"`cat GIT-PREFIX 2>/dev/null`" ; then \
-               echo 1>&2 "    * new prefix flags"; \
+               echo >&2 "    * new prefix flags"; \
                echo "$$FLAGS" >GIT-PREFIX; \
        fi
 
@@ -2573,7 +2611,7 @@ TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):$(USE_GETTEXT_SCHEME)
 GIT-CFLAGS: FORCE
        @FLAGS='$(TRACK_CFLAGS)'; \
            if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
-               echo 1>&2 "    * new build flags"; \
+               echo >&2 "    * new build flags"; \
                echo "$$FLAGS" >GIT-CFLAGS; \
             fi
 
@@ -2582,7 +2620,7 @@ TRACK_LDFLAGS = $(subst ','\'',$(ALL_LDFLAGS))
 GIT-LDFLAGS: FORCE
        @FLAGS='$(TRACK_LDFLAGS)'; \
            if test x"$$FLAGS" != x"`cat GIT-LDFLAGS 2>/dev/null`" ; then \
-               echo 1>&2 "    * new link flags"; \
+               echo >&2 "    * new link flags"; \
                echo "$$FLAGS" >GIT-LDFLAGS; \
             fi
 
@@ -2624,14 +2662,14 @@ ifdef GIT_PERF_MAKE_OPTS
        @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@
 endif
 
-### Detect Tck/Tk interpreter path changes
-ifndef NO_TCLTK
-TRACK_VARS = $(subst ','\'',-DTCLTK_PATH='$(TCLTK_PATH_SQ)')
+### Detect Python interpreter path changes
+ifndef NO_PYTHON
+TRACK_PYTHON = $(subst ','\'',-DPYTHON_PATH='$(PYTHON_PATH_SQ)')
 
-GIT-GUI-VARS: FORCE
-       @VARS='$(TRACK_VARS)'; \
+GIT-PYTHON-VARS: FORCE
+       @VARS='$(TRACK_PYTHON)'; \
            if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
-               echo 1>&2 "    * new Tcl/Tk interpreter location"; \
+               echo >&2 "    * new Python interpreter location"; \
                echo "$$VARS" >$@; \
             fi
 endif
@@ -2910,8 +2948,8 @@ ifndef NO_TCLTK
        $(MAKE) -C gitk-git clean
        $(MAKE) -C git-gui clean
 endif
-       $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
-       $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES
+       $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
+       $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES GIT-PYTHON-VARS
 
 .PHONY: all install profile-clean clean strip
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
index 28607146f3fec3b69cf5edacf2727e37ca2c89de..bdce3136ea5164d82f0d25d0a7a8b50181f572f7 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.1.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.2.txt
\ No newline at end of file
index 05f2d7934878a832f5a2efdf4222c16223050853..40cdc46219d4eba87ba947d9f5556eb80dfdfa9b 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -15,16 +15,34 @@ int is_directory(const char *path)
 #define MAXDEPTH 5
 
 /*
- * Use this to get the real path, i.e. resolve links. If you want an
- * absolute path but don't mind links, use absolute_path.
+ * Return the real path (i.e., absolute path, with symlinks resolved
+ * and extra slashes removed) equivalent to the specified path.  (If
+ * you want an absolute path but don't mind links, use
+ * absolute_path().)  The return value is a pointer to a static
+ * buffer.
+ *
+ * The input and all intermediate paths must be shorter than MAX_PATH.
+ * The directory part of path (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist.  If die_on_error is set, then die with an
+ * informative error message if there is a problem.  Otherwise, return
+ * NULL on errors (without generating any output).
  *
  * If path is our buffer, then return path, as it's already what the
  * user wants.
  */
-const char *real_path(const char *path)
+static const char *real_path_internal(const char *path, int die_on_error)
 {
        static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
+       char *retval = NULL;
+
+       /*
+        * If we have to temporarily chdir(), store the original CWD
+        * here so that we can chdir() back to it at the end of the
+        * function:
+        */
        char cwd[1024] = "";
+
        int buf_index = 1;
 
        int depth = MAXDEPTH;
@@ -35,11 +53,19 @@ const char *real_path(const char *path)
        if (path == buf || path == next_buf)
                return path;
 
-       if (!*path)
-               die("The empty string is not a valid path");
+       if (!*path) {
+               if (die_on_error)
+                       die("The empty string is not a valid path");
+               else
+                       goto error_out;
+       }
 
-       if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
-               die ("Too long path: %.*s", 60, path);
+       if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) {
+               if (die_on_error)
+                       die("Too long path: %.*s", 60, path);
+               else
+                       goto error_out;
+       }
 
        while (depth--) {
                if (!is_directory(buf)) {
@@ -54,20 +80,36 @@ const char *real_path(const char *path)
                }
 
                if (*buf) {
-                       if (!*cwd && !getcwd(cwd, sizeof(cwd)))
-                               die_errno ("Could not get current working directory");
+                       if (!*cwd && !getcwd(cwd, sizeof(cwd))) {
+                               if (die_on_error)
+                                       die_errno("Could not get current working directory");
+                               else
+                                       goto error_out;
+                       }
 
-                       if (chdir(buf))
-                               die_errno ("Could not switch to '%s'", buf);
+                       if (chdir(buf)) {
+                               if (die_on_error)
+                                       die_errno("Could not switch to '%s'", buf);
+                               else
+                                       goto error_out;
+                       }
+               }
+               if (!getcwd(buf, PATH_MAX)) {
+                       if (die_on_error)
+                               die_errno("Could not get current working directory");
+                       else
+                               goto error_out;
                }
-               if (!getcwd(buf, PATH_MAX))
-                       die_errno ("Could not get current working directory");
 
                if (last_elem) {
                        size_t len = strlen(buf);
-                       if (len + strlen(last_elem) + 2 > PATH_MAX)
-                               die ("Too long path name: '%s/%s'",
-                                               buf, last_elem);
+                       if (len + strlen(last_elem) + 2 > PATH_MAX) {
+                               if (die_on_error)
+                                       die("Too long path name: '%s/%s'",
+                                           buf, last_elem);
+                               else
+                                       goto error_out;
+                       }
                        if (len && !is_dir_sep(buf[len-1]))
                                buf[len++] = '/';
                        strcpy(buf + len, last_elem);
@@ -77,10 +119,18 @@ const char *real_path(const char *path)
 
                if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
                        ssize_t len = readlink(buf, next_buf, PATH_MAX);
-                       if (len < 0)
-                               die_errno ("Invalid symlink '%s'", buf);
-                       if (PATH_MAX <= len)
-                               die("symbolic link too long: %s", buf);
+                       if (len < 0) {
+                               if (die_on_error)
+                                       die_errno("Invalid symlink '%s'", buf);
+                               else
+                                       goto error_out;
+                       }
+                       if (PATH_MAX <= len) {
+                               if (die_on_error)
+                                       die("symbolic link too long: %s", buf);
+                               else
+                                       goto error_out;
+                       }
                        next_buf[len] = '\0';
                        buf = next_buf;
                        buf_index = 1 - buf_index;
@@ -89,10 +139,23 @@ const char *real_path(const char *path)
                        break;
        }
 
+       retval = buf;
+error_out:
+       free(last_elem);
        if (*cwd && chdir(cwd))
                die_errno ("Could not change back to '%s'", cwd);
 
-       return buf;
+       return retval;
+}
+
+const char *real_path(const char *path)
+{
+       return real_path_internal(path, 1);
+}
+
+const char *real_path_if_valid(const char *path)
+{
+       return real_path_internal(path, 0);
 }
 
 static const char *get_pwd_cwd(void)
index edfbd4a6fb01a6905671d6d842d22c4869fad729..d2879272802cb3477dd6b47a78098ffdc26dcb37 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -1,9 +1,10 @@
 #include "cache.h"
 
-int advice_push_nonfastforward = 1;
+int advice_push_update_rejected = 1;
 int advice_push_non_ff_current = 1;
 int advice_push_non_ff_default = 1;
 int advice_push_non_ff_matching = 1;
+int advice_push_already_exists = 1;
 int advice_status_hints = 1;
 int advice_commit_before_merge = 1;
 int advice_resolve_conflict = 1;
@@ -14,15 +15,19 @@ static struct {
        const char *name;
        int *preference;
 } advice_config[] = {
-       { "pushnonfastforward", &advice_push_nonfastforward },
+       { "pushupdaterejected", &advice_push_update_rejected },
        { "pushnonffcurrent", &advice_push_non_ff_current },
        { "pushnonffdefault", &advice_push_non_ff_default },
        { "pushnonffmatching", &advice_push_non_ff_matching },
+       { "pushalreadyexists", &advice_push_already_exists },
        { "statushints", &advice_status_hints },
        { "commitbeforemerge", &advice_commit_before_merge },
        { "resolveconflict", &advice_resolve_conflict },
        { "implicitidentity", &advice_implicit_identity },
        { "detachedhead", &advice_detached_head },
+
+       /* make this an alias for backward compatibility */
+       { "pushnonfastforward", &advice_push_update_rejected }
 };
 
 void advise(const char *advice, ...)
index f3cdbbf29e570e151b2b6b329ee9a9940ae59a98..8bf63563a5cf1573e0e6bf7ffcd5c55643d3f439 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -3,10 +3,11 @@
 
 #include "git-compat-util.h"
 
-extern int advice_push_nonfastforward;
+extern int advice_push_update_rejected;
 extern int advice_push_non_ff_current;
 extern int advice_push_non_ff_default;
 extern int advice_push_non_ff_matching;
+extern int advice_push_already_exists;
 extern int advice_status_hints;
 extern int advice_commit_before_merge;
 extern int advice_resolve_conflict;
index 466640479ecb332d8d06f6f26254023eb6e22c85..93e00bb4ae8ff9637be9e55fd41536b8837c3ba2 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -120,6 +120,8 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
        strbuf_add(&path, args->base, args->baselen);
        strbuf_add(&path, base, baselen);
        strbuf_addstr(&path, filename);
+       if (S_ISDIR(mode) || S_ISGITLINK(mode))
+               strbuf_addch(&path, '/');
        path_without_prefix = path.buf + args->baselen;
 
        setup_archive_check(check);
@@ -130,7 +132,6 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
        }
 
        if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
-               strbuf_addch(&path, '/');
                if (args->verbose)
                        fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
                err = write_entry(args, sha1, path.buf, path.len, mode);
diff --git a/attr.c b/attr.c
index 097ae87f3c2b4093fffe6586f036918367fa672e..466c93fa50976dc6a1a3019bdf47accc406acc32 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -564,17 +564,24 @@ static void bootstrap_attr_stack(void)
        attr_stack = elem;
 }
 
+static const char *find_basename(const char *path)
+{
+       const char *cp, *last_slash = NULL;
+
+       for (cp = path; *cp; cp++) {
+               if (*cp == '/' && cp[1])
+                       last_slash = cp;
+       }
+       return last_slash ? last_slash + 1 : path;
+}
+
 static void prepare_attr_stack(const char *path)
 {
        struct attr_stack *elem, *info;
        int dirlen, len;
        const char *cp;
 
-       cp = strrchr(path, '/');
-       if (!cp)
-               dirlen = 0;
-       else
-               dirlen = cp - path;
+       dirlen = find_basename(path) - path;
 
        /*
         * At the bottom of the attribute stack is the built-in
@@ -668,6 +675,10 @@ static int path_matches(const char *pathname, int pathlen,
        const char *pattern = pat->pattern;
        int prefix = pat->nowildcardlen;
 
+       if ((pat->flags & EXC_FLAG_MUSTBEDIR) &&
+           ((!pathlen) || (pathname[pathlen-1] != '/')))
+               return 0;
+
        if (pat->flags & EXC_FLAG_NODIR) {
                return match_basename(basename,
                                      pathlen - (basename - pathname),
@@ -758,9 +769,7 @@ static void collect_all_attrs(const char *path)
        for (i = 0; i < attr_nr; i++)
                check_all_attr[i].value = ATTR__UNKNOWN;
 
-       basename = strrchr(path, '/');
-       basename = basename ? basename + 1 : path;
-
+       basename = find_basename(path);
        pathlen = strlen(path);
        rem = attr_nr;
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
index 156b3ce3b72f51013baacff0a8ffd37ac97e6158..6c11e8bc73892b15f91fcb65d65e18ee05956ec8 100644 (file)
@@ -2095,7 +2095,7 @@ static void update_pre_post_images(struct image *preimage,
                                   char *buf,
                                   size_t len, size_t postlen)
 {
-       int i, ctx;
+       int i, ctx, reduced;
        char *new, *old, *fixed;
        struct image fixed_preimage;
 
@@ -2105,8 +2105,10 @@ static void update_pre_post_images(struct image *preimage,
         * free "oldlines".
         */
        prepare_image(&fixed_preimage, buf, len, 1);
-       assert(fixed_preimage.nr == preimage->nr);
-       for (i = 0; i < preimage->nr; i++)
+       assert(postlen
+              ? fixed_preimage.nr == preimage->nr
+              : fixed_preimage.nr <= preimage->nr);
+       for (i = 0; i < fixed_preimage.nr; i++)
                fixed_preimage.line[i].flag = preimage->line[i].flag;
        free(preimage->line_allocated);
        *preimage = fixed_preimage;
@@ -2126,7 +2128,8 @@ static void update_pre_post_images(struct image *preimage,
        else
                new = old;
        fixed = preimage->buf;
-       for (i = ctx = 0; i < postimage->nr; i++) {
+
+       for (i = reduced = ctx = 0; i < postimage->nr; i++) {
                size_t len = postimage->line[i].len;
                if (!(postimage->line[i].flag & LINE_COMMON)) {
                        /* an added line -- no counterparts in preimage */
@@ -2145,8 +2148,15 @@ static void update_pre_post_images(struct image *preimage,
                        fixed += preimage->line[ctx].len;
                        ctx++;
                }
-               if (preimage->nr <= ctx)
-                       die(_("oops"));
+
+               /*
+                * preimage is expected to run out, if the caller
+                * fixed addition of trailing blank lines.
+                */
+               if (preimage->nr <= ctx) {
+                       reduced++;
+                       continue;
+               }
 
                /* and copy it in, while fixing the line length */
                len = preimage->line[ctx].len;
@@ -2159,6 +2169,7 @@ static void update_pre_post_images(struct image *preimage,
 
        /* Fix the length of the whole thing */
        postimage->len = new - postimage->buf;
+       postimage->nr -= reduced;
 }
 
 static int match_fragment(struct image *img,
index 12220ad8dac65acaa556c6524310d5540709f324..77dffd1ce3a5f809a81793f67b9297a555bab1fa 100644 (file)
@@ -474,18 +474,21 @@ static void handle_tag(const char *name, struct tag *tag)
               (int)message_size, (int)message_size, message ? message : "");
 }
 
-static void get_tags_and_duplicates(struct object_array *pending,
+static void get_tags_and_duplicates(struct rev_cmdline_info *info,
                                    struct string_list *extra_refs)
 {
        struct tag *tag;
        int i;
 
-       for (i = 0; i < pending->nr; i++) {
-               struct object_array_entry *e = pending->objects + i;
+       for (i = 0; i < info->nr; i++) {
+               struct rev_cmdline_entry *e = info->rev + i;
                unsigned char sha1[20];
-               struct commit *commit = commit;
+               struct commit *commit;
                char *full_name;
 
+               if (e->flags & UNINTERESTING)
+                       continue;
+
                if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
                        continue;
 
@@ -523,10 +526,14 @@ static void get_tags_and_duplicates(struct object_array *pending,
                                typename(e->item->type));
                        continue;
                }
-               if (commit->util)
-                       /* more than one name for the same object */
+
+               /*
+                * This ref will not be updated through a commit, lets make
+                * sure it gets properly updated eventually.
+                */
+               if (commit->util || commit->object.flags & SHOWN)
                        string_list_append(extra_refs, full_name)->util = commit;
-               else
+               if (!commit->util)
                        commit->util = full_name;
        }
 }
@@ -614,6 +621,10 @@ static void import_marks(char *input_file)
                if (object->flags & SHOWN)
                        error("Object %s already has a mark", sha1_to_hex(sha1));
 
+               if (object->type != OBJ_COMMIT)
+                       /* only commits */
+                       continue;
+
                mark_object(object, mark);
                if (last_idnum < mark)
                        last_idnum = mark;
@@ -677,7 +688,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
        if (import_filename && revs.prune_data.nr)
                full_tree = 1;
 
-       get_tags_and_duplicates(&revs.pending, &extra_refs);
+       get_tags_and_duplicates(&revs.cmdline, &extra_refs);
 
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
index b5434af0c87741f3160388cf86904c6e3f903527..4a9ee690c7dcbaaf90f9511489b8f3b7b17b3c87 100644 (file)
@@ -337,7 +337,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
                matchbuf[0] = prefix;
                matchbuf[1] = NULL;
                init_pathspec(&pathspec, matchbuf);
-               pathspec.items[0].use_wildcard = 0;
+               pathspec.items[0].nowildcard_len = pathspec.items[0].len;
        } else
                init_pathspec(&pathspec, NULL);
        if (read_tree(tree, 1, &pathspec))
index 235c17cc015acfb73358bc5ee5bde712fa2b0fa9..fb76e38d849fc6f7b9cc1a534f62efb605a3655c 100644 (file)
@@ -168,7 +168,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 
        init_pathspec(&pathspec, get_pathspec(prefix, argv + 1));
        for (i = 0; i < pathspec.nr; i++)
-               pathspec.items[i].use_wildcard = 0;
+               pathspec.items[i].nowildcard_len = pathspec.items[i].len;
        pathspec.has_wildcard = 0;
        tree = parse_tree_indirect(sha1);
        if (!tree)
index db9ba30b08c221ac2290b1ffc939713fe378e666..8491e431e41aaff32c76ab0c61f528682b3babdb 100644 (file)
@@ -220,31 +220,42 @@ static const char message_advice_checkout_pull_push[] =
           "(e.g. 'git pull') before pushing again.\n"
           "See the 'Note about fast-forwards' in 'git push --help' for details.");
 
+static const char message_advice_ref_already_exists[] =
+       N_("Updates were rejected because the destination reference already exists\n"
+          "in the remote.");
+
 static void advise_pull_before_push(void)
 {
-       if (!advice_push_non_ff_current || !advice_push_nonfastforward)
+       if (!advice_push_non_ff_current || !advice_push_update_rejected)
                return;
        advise(_(message_advice_pull_before_push));
 }
 
 static void advise_use_upstream(void)
 {
-       if (!advice_push_non_ff_default || !advice_push_nonfastforward)
+       if (!advice_push_non_ff_default || !advice_push_update_rejected)
                return;
        advise(_(message_advice_use_upstream));
 }
 
 static void advise_checkout_pull_push(void)
 {
-       if (!advice_push_non_ff_matching || !advice_push_nonfastforward)
+       if (!advice_push_non_ff_matching || !advice_push_update_rejected)
                return;
        advise(_(message_advice_checkout_pull_push));
 }
 
+static void advise_ref_already_exists(void)
+{
+       if (!advice_push_already_exists || !advice_push_update_rejected)
+               return;
+       advise(_(message_advice_ref_already_exists));
+}
+
 static int push_with_options(struct transport *transport, int flags)
 {
        int err;
-       int nonfastforward;
+       unsigned int reject_reasons;
 
        transport_set_verbosity(transport, verbosity, progress);
 
@@ -257,7 +268,7 @@ static int push_with_options(struct transport *transport, int flags)
        if (verbosity > 0)
                fprintf(stderr, _("Pushing to %s\n"), transport->url);
        err = transport_push(transport, refspec_nr, refspec, flags,
-                            &nonfastforward);
+                            &reject_reasons);
        if (err != 0)
                error(_("failed to push some refs to '%s'"), transport->url);
 
@@ -265,18 +276,15 @@ static int push_with_options(struct transport *transport, int flags)
        if (!err)
                return 0;
 
-       switch (nonfastforward) {
-       default:
-               break;
-       case NON_FF_HEAD:
+       if (reject_reasons & REJECT_NON_FF_HEAD) {
                advise_pull_before_push();
-               break;
-       case NON_FF_OTHER:
+       } else if (reject_reasons & REJECT_NON_FF_OTHER) {
                if (default_matching_used)
                        advise_use_upstream();
                else
                        advise_checkout_pull_push();
-               break;
+       } else if (reject_reasons & REJECT_ALREADY_EXISTS) {
+               advise_ref_already_exists();
        }
 
        return 1;
index d34201372d71d0c5683d4d01fe162bd9b7182aa4..f849e0a4a041610dc258a9dc56cc8a357cff31b6 100644 (file)
@@ -44,6 +44,11 @@ static void print_helper_status(struct ref *ref)
                        msg = "non-fast forward";
                        break;
 
+               case REF_STATUS_REJECT_ALREADY_EXISTS:
+                       res = "error";
+                       msg = "already exists";
+                       break;
+
                case REF_STATUS_REJECT_NODELETE:
                case REF_STATUS_REMOTE_REJECT:
                        res = "error";
@@ -85,7 +90,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        int send_all = 0;
        const char *receivepack = "git-receive-pack";
        int flags;
-       int nonfastforward = 0;
+       unsigned int reject_reasons;
        int progress = -1;
 
        argv++;
@@ -223,7 +228,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        ret |= finish_connect(conn);
 
        if (!helper_status)
-               transport_print_push_status(dest, remote_refs, args.verbose, 0, &nonfastforward);
+               transport_print_push_status(dest, remote_refs, args.verbose, 0, &reject_reasons);
 
        if (!args.dry_run && remote) {
                struct ref *ref;
index b316cf37ca768f1502c5d0cfa64372a9b322a572..83605143ac0cea68b421dd9a3c056d3a27f66be9 100644 (file)
@@ -306,9 +306,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s,
                                     const struct shortlog *log)
 {
-       int col = strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
-       if (col != log->wrap)
-               strbuf_addch(sb, '\n');
+       strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
+       strbuf_addch(sb, '\n');
 }
 
 void shortlog_output(struct shortlog *log)
index 28ed6574a2faf3151056aa20e681e06a157e4a2d..37e4d008b59420338ce97f1b2cf2eb660dab8a34 100644 (file)
@@ -166,12 +166,8 @@ static int verify_cache(struct cache_entry **cache,
                                fprintf(stderr, "...\n");
                                break;
                        }
-                       if (ce_stage(ce))
-                               fprintf(stderr, "%s: unmerged (%s)\n",
-                                       ce->name, sha1_to_hex(ce->sha1));
-                       else
-                               fprintf(stderr, "%s: not added yet\n",
-                                       ce->name);
+                       fprintf(stderr, "%s: unmerged (%s)\n",
+                               ce->name, sha1_to_hex(ce->sha1));
                }
        }
        if (funny)
@@ -242,13 +238,17 @@ static int update_one(struct cache_tree *it,
                      int entries,
                      const char *base,
                      int baselen,
+                     int *skip_count,
                      int flags)
 {
        struct strbuf buffer;
        int missing_ok = flags & WRITE_TREE_MISSING_OK;
        int dryrun = flags & WRITE_TREE_DRY_RUN;
+       int to_invalidate = 0;
        int i;
 
+       *skip_count = 0;
+
        if (0 <= it->entry_count && has_sha1_file(it->sha1))
                return it->entry_count;
 
@@ -263,11 +263,12 @@ static int update_one(struct cache_tree *it,
        /*
         * Find the subtrees and update them.
         */
-       for (i = 0; i < entries; i++) {
+       i = 0;
+       while (i < entries) {
                struct cache_entry *ce = cache[i];
                struct cache_tree_sub *sub;
                const char *path, *slash;
-               int pathlen, sublen, subcnt;
+               int pathlen, sublen, subcnt, subskip;
 
                path = ce->name;
                pathlen = ce_namelen(ce);
@@ -275,8 +276,10 @@ static int update_one(struct cache_tree *it,
                        break; /* at the end of this level */
 
                slash = strchr(path + baselen, '/');
-               if (!slash)
+               if (!slash) {
+                       i++;
                        continue;
+               }
                /*
                 * a/bbb/c (base = a/, slash = /c)
                 * ==>
@@ -290,10 +293,13 @@ static int update_one(struct cache_tree *it,
                                    cache + i, entries - i,
                                    path,
                                    baselen + sublen + 1,
+                                   &subskip,
                                    flags);
                if (subcnt < 0)
                        return subcnt;
-               i += subcnt - 1;
+               i += subcnt;
+               sub->count = subcnt; /* to be used in the next loop */
+               *skip_count += subskip;
                sub->used = 1;
        }
 
@@ -304,7 +310,8 @@ static int update_one(struct cache_tree *it,
         */
        strbuf_init(&buffer, 8192);
 
-       for (i = 0; i < entries; i++) {
+       i = 0;
+       while (i < entries) {
                struct cache_entry *ce = cache[i];
                struct cache_tree_sub *sub;
                const char *path, *slash;
@@ -324,14 +331,17 @@ static int update_one(struct cache_tree *it,
                        if (!sub)
                                die("cache-tree.c: '%.*s' in '%s' not found",
                                    entlen, path + baselen, path);
-                       i += sub->cache_tree->entry_count - 1;
+                       i += sub->count;
                        sha1 = sub->cache_tree->sha1;
                        mode = S_IFDIR;
+                       if (sub->cache_tree->entry_count < 0)
+                               to_invalidate = 1;
                }
                else {
                        sha1 = ce->sha1;
                        mode = ce->ce_mode;
                        entlen = pathlen - baselen;
+                       i++;
                }
                if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) {
                        strbuf_release(&buffer);
@@ -339,8 +349,25 @@ static int update_one(struct cache_tree *it,
                                mode, sha1_to_hex(sha1), entlen+baselen, path);
                }
 
-               if (ce->ce_flags & (CE_REMOVE | CE_INTENT_TO_ADD))
-                       continue; /* entry being removed or placeholder */
+               /*
+                * CE_REMOVE entries are removed before the index is
+                * written to disk. Skip them to remain consistent
+                * with the future on-disk index.
+                */
+               if (ce->ce_flags & CE_REMOVE) {
+                       *skip_count = *skip_count + 1;
+                       continue;
+               }
+
+               /*
+                * CE_INTENT_TO_ADD entries exist on on-disk index but
+                * they are not part of generated trees. Invalidate up
+                * to root to force cache-tree users to read elsewhere.
+                */
+               if (ce->ce_flags & CE_INTENT_TO_ADD) {
+                       to_invalidate = 1;
+                       continue;
+               }
 
                strbuf_grow(&buffer, entlen + 100);
                strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
@@ -360,7 +387,7 @@ static int update_one(struct cache_tree *it,
        }
 
        strbuf_release(&buffer);
-       it->entry_count = i;
+       it->entry_count = to_invalidate ? -1 : i - *skip_count;
 #if DEBUG
        fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
                it->entry_count, it->subtree_nr,
@@ -374,11 +401,11 @@ int cache_tree_update(struct cache_tree *it,
                      int entries,
                      int flags)
 {
-       int i;
+       int i, skip;
        i = verify_cache(cache, entries, flags);
        if (i)
                return i;
-       i = update_one(it, cache, entries, "", 0, flags);
+       i = update_one(it, cache, entries, "", 0, &skip, flags);
        if (i < 0)
                return i;
        return 0;
index d8cb2e9e39d2be9c4dad67db44a464c2a1004d2f..55d0f59f2b7a42b40fe4be32297b56656206983d 100644 (file)
@@ -7,6 +7,7 @@
 struct cache_tree;
 struct cache_tree_sub {
        struct cache_tree *cache_tree;
+       int count;              /* internally used by update_one() */
        int namelen;
        int used;
        char name[FLEX_ARRAY];
diff --git a/cache.h b/cache.h
index 18fdd18f3674b1d7c62de65509bdb7bc57743395..c257953fa798110e0f4be9258f4f88f2d7952bdb 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -362,6 +362,7 @@ static inline enum object_type object_type(unsigned int mode)
 #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
 #define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
 #define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
+#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
 
 /*
  * Repository-local GIT_* environment variables
@@ -473,6 +474,8 @@ extern int index_name_is_other(const struct index_state *, const char *, int);
 extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
 extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
 
+#define PATHSPEC_ONESTAR 1     /* the pathspec pattern sastisfies GFNM_ONESTAR */
+
 struct pathspec {
        const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
        int nr;
@@ -482,7 +485,8 @@ struct pathspec {
        struct pathspec_item {
                const char *match;
                int len;
-               unsigned int use_wildcard:1;
+               int nowildcard_len;
+               int flags;
        } *items;
 };
 
@@ -490,6 +494,8 @@ extern int init_pathspec(struct pathspec *, const char **);
 extern void free_pathspec(struct pathspec *);
 extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
 
+extern int limit_pathspec_to_literal(void);
+
 #define HASH_WRITE_OBJECT 1
 #define HASH_FORMAT_CHECK 2
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
@@ -714,10 +720,11 @@ static inline int is_absolute_path(const char *path)
 }
 int is_directory(const char *);
 const char *real_path(const char *path);
+const char *real_path_if_valid(const char *path);
 const char *absolute_path(const char *path);
 const char *relative_path(const char *abs, const char *base);
 int normalize_path_copy(char *dst, const char *src);
-int longest_ancestor_length(const char *path, const char *prefix_list);
+int longest_ancestor_length(const char *path, struct string_list *prefixes);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
 int offset_1st_component(const char *path);
@@ -999,14 +1006,19 @@ struct ref {
        unsigned char old_sha1[20];
        unsigned char new_sha1[20];
        char *symref;
-       unsigned int force:1,
+       unsigned int
+               force:1,
+               requires_force:1,
                merge:1,
                nonfastforward:1,
+               not_forwardable:1,
+               update:1,
                deletion:1;
        enum {
                REF_STATUS_NONE = 0,
                REF_STATUS_OK,
                REF_STATUS_REJECT_NONFASTFORWARD,
+               REF_STATUS_REJECT_ALREADY_EXISTS,
                REF_STATUS_REJECT_NODELETE,
                REF_STATUS_UPTODATE,
                REF_STATUS_REMOTE_REJECT,
@@ -1136,6 +1148,9 @@ extern int check_repository_format_version(const char *var, const char *value, v
 extern int git_env_bool(const char *, int);
 extern int git_config_system(void);
 extern int config_error_nonbool(const char *);
+#ifdef __GNUC__
+#define config_error_nonbool(s) (config_error_nonbool(s), -1)
+#endif
 extern const char *get_log_output_encoding(void);
 extern const char *get_commit_output_encoding(void);
 
@@ -1155,6 +1170,7 @@ extern int author_ident_sufficiently_given(void);
 extern const char *git_commit_encoding;
 extern const char *git_log_output_encoding;
 extern const char *git_mailmap_file;
+extern const char *git_mailmap_blob;
 
 /* IO helper functions */
 extern void maybe_flush_or_die(FILE *, const char *);
index b6ad8f3f307a46cd5a0555ab346abaa20013b13a..0f469e507db7b8517e4f37107d855b7877176085 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -89,6 +89,7 @@ struct pretty_print_context {
        char *notes_message;
        struct reflog_walk_info *reflog_info;
        const char *output_encoding;
+       int color;
 };
 
 struct userformat_want {
index fb3f8681eed21ee81cfe36296c438ed135b98485..7b444b68abcebb5829a5628ee5b74cf3f0020c0b 100644 (file)
--- a/config.c
+++ b/config.c
@@ -58,7 +58,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
                path = buf.buf;
        }
 
-       if (!access_or_warn(path, R_OK)) {
+       if (!access_or_die(path, R_OK)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
                        die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
                            cf && cf->name ? cf->name : "the command line");
@@ -839,6 +839,8 @@ static int git_default_mailmap_config(const char *var, const char *value)
 {
        if (!strcmp(var, "mailmap.file"))
                return git_config_string(&git_mailmap_file, var, value);
+       if (!strcmp(var, "mailmap.blob"))
+               return git_config_string(&git_mailmap_blob, var, value);
 
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
@@ -938,23 +940,23 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
        home_config_paths(&user_config, &xdg_config, "config");
 
-       if (git_config_system() && !access_or_warn(git_etc_gitconfig(), R_OK)) {
+       if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK)) {
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                                            data);
                found += 1;
        }
 
-       if (xdg_config && !access_or_warn(xdg_config, R_OK)) {
+       if (xdg_config && !access_or_die(xdg_config, R_OK)) {
                ret += git_config_from_file(fn, xdg_config, data);
                found += 1;
        }
 
-       if (user_config && !access_or_warn(user_config, R_OK)) {
+       if (user_config && !access_or_die(user_config, R_OK)) {
                ret += git_config_from_file(fn, user_config, data);
                found += 1;
        }
 
-       if (repo_config && !access_or_warn(repo_config, R_OK)) {
+       if (repo_config && !access_or_die(repo_config, R_OK)) {
                ret += git_config_from_file(fn, repo_config, data);
                found += 1;
        }
@@ -1660,6 +1662,7 @@ int git_config_rename_section(const char *old_name, const char *new_name)
  * Call this to report error for your variable that should not
  * get a boolean value (i.e. "[my] var" means "true").
  */
+#undef config_error_nonbool
 int config_error_nonbool(const char *var)
 {
        return error("Missing value for '%s'", var);
index ad215cc4a10ed95804e7cec929f003c985d25a3d..1991258ae031cd656a8b599fda16ec73695216cb 100644 (file)
@@ -753,6 +753,14 @@ AC_CHECK_MEMBER(struct dirent.d_type,
 [#include <dirent.h>])
 GIT_CONF_SUBST([NO_D_TYPE_IN_DIRENT])
 #
+# Define NO_GECOS_IN_PWENT if you don't have pw_gecos in struct passwd
+# in the C library.
+AC_CHECK_MEMBER(struct passwd.pw_gecos,
+[NO_GECOS_IN_PWENT=],
+[NO_GECOS_IN_PWENT=YesPlease],
+[#include <pwd.h>])
+GIT_CONF_SUBST([NO_GECOS_IN_PWENT])
+#
 # Define NO_SOCKADDR_STORAGE if your platform does not have struct
 # sockaddr_storage.
 AC_CHECK_TYPE(struct sockaddr_storage,
@@ -872,6 +880,12 @@ AC_CHECK_HEADER([libcharset.h],
 [HAVE_LIBCHARSET_H=YesPlease],
 [HAVE_LIBCHARSET_H=])
 GIT_CONF_SUBST([HAVE_LIBCHARSET_H])
+#
+# Define HAVE_STRINGS_H if you have strings.h
+AC_CHECK_HEADER([strings.h],
+[HAVE_STRINGS_H=YesPlease],
+[HAVE_STRINGS_H=])
+GIT_CONF_SUBST([HAVE_STRINGS_H])
 # Define CHARSET_LIB if libiconv does not export the locale_charset symbol
 # and libcharset does
 CHARSET_LIB=
@@ -1021,7 +1035,17 @@ if test -n "$USER_NOPTHREAD"; then
 # -D_REENTRANT' or some such.
 elif test -z "$PTHREAD_CFLAGS"; then
   threads_found=no
-  for opt in -mt -pthread -lpthread; do
+  # Attempt to compile and link some code using pthreads to determine
+  # required linker flags. The order is somewhat important here: We
+  # first try it without any extra flags, to catch systems where
+  # pthreads are part of the C library, then go on testing various other
+  # flags. We do so to avoid false positives. For example, on Mac OS X
+  # pthreads are part of the C library; moreover, the compiler allows us
+  # to add "-mt" to the CFLAGS (although it will do nothing except
+  # trigger a warning about an unused flag). Hence if we checked for
+  # "-mt" before "" we would end up picking it. But unfortunately this
+  # would then trigger compiler warnings on every single file we compile.
+  for opt in "" -mt -pthread -lpthread; do
      old_CFLAGS="$CFLAGS"
      CFLAGS="$opt $CFLAGS"
      AC_MSG_CHECKING([for POSIX Threads with '$opt'])
index 0b77eb1fa4074fb8ed5ef4cd4c37513f49804e7e..a4c48e179eb778077462a812b491e762e284486c 100644 (file)
@@ -971,6 +971,13 @@ _git_commit ()
 {
        __git_has_doubledash && return
 
+       case "$prev" in
+       -c|-C)
+               __gitcomp_nl "$(__git_refs)" "" "${cur}"
+               return
+               ;;
+       esac
+
        case "$cur" in
        --cleanup=*)
                __gitcomp "default strip verbatim whitespace
diff --git a/dir.c b/dir.c
index 5a83aa7897f270279c403778f43aea6db1efc5af..095ea7ebabfa25f1ff1aba199c09daaac984dbaa 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -34,10 +34,33 @@ int fnmatch_icase(const char *pattern, const char *string, int flags)
        return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));
 }
 
+inline int git_fnmatch(const char *pattern, const char *string,
+                      int flags, int prefix)
+{
+       int fnm_flags = 0;
+       if (flags & GFNM_PATHNAME)
+               fnm_flags |= FNM_PATHNAME;
+       if (prefix > 0) {
+               if (strncmp(pattern, string, prefix))
+                       return FNM_NOMATCH;
+               pattern += prefix;
+               string += prefix;
+       }
+       if (flags & GFNM_ONESTAR) {
+               int pattern_len = strlen(++pattern);
+               int string_len = strlen(string);
+               return string_len < pattern_len ||
+                      strcmp(pattern,
+                             string + string_len - pattern_len);
+       }
+       return fnmatch(pattern, string, fnm_flags);
+}
+
 static size_t common_prefix_len(const char **pathspec)
 {
        const char *n, *first;
        size_t max = 0;
+       int literal = limit_pathspec_to_literal();
 
        if (!pathspec)
                return max;
@@ -47,7 +70,7 @@ static size_t common_prefix_len(const char **pathspec)
                size_t i, len = 0;
                for (i = 0; first == n || i < max; i++) {
                        char c = n[i];
-                       if (!c || c != first[i] || is_glob_special(c))
+                       if (!c || c != first[i] || (!literal && is_glob_special(c)))
                                break;
                        if (c == '/')
                                len = i + 1;
@@ -117,6 +140,7 @@ int within_depth(const char *name, int namelen,
 static int match_one(const char *match, const char *name, int namelen)
 {
        int matchlen;
+       int literal = limit_pathspec_to_literal();
 
        /* If the match was just the prefix, we matched */
        if (!*match)
@@ -126,7 +150,7 @@ static int match_one(const char *match, const char *name, int namelen)
                for (;;) {
                        unsigned char c1 = tolower(*match);
                        unsigned char c2 = tolower(*name);
-                       if (c1 == '\0' || is_glob_special(c1))
+                       if (c1 == '\0' || (!literal && is_glob_special(c1)))
                                break;
                        if (c1 != c2)
                                return 0;
@@ -138,7 +162,7 @@ static int match_one(const char *match, const char *name, int namelen)
                for (;;) {
                        unsigned char c1 = *match;
                        unsigned char c2 = *name;
-                       if (c1 == '\0' || is_glob_special(c1))
+                       if (c1 == '\0' || (!literal && is_glob_special(c1)))
                                break;
                        if (c1 != c2)
                                return 0;
@@ -148,14 +172,16 @@ static int match_one(const char *match, const char *name, int namelen)
                }
        }
 
-
        /*
         * If we don't match the matchstring exactly,
         * we need to match by fnmatch
         */
        matchlen = strlen(match);
-       if (strncmp_icase(match, name, matchlen))
+       if (strncmp_icase(match, name, matchlen)) {
+               if (literal)
+                       return 0;
                return !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0;
+       }
 
        if (namelen == matchlen)
                return MATCHED_EXACTLY;
@@ -230,7 +256,10 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
                        return MATCHED_RECURSIVELY;
        }
 
-       if (item->use_wildcard && !fnmatch(match, name, 0))
+       if (item->nowildcard_len < item->len &&
+           !git_fnmatch(match, name,
+                        item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+                        item->nowildcard_len - prefix))
                return MATCHED_FNMATCH;
 
        return 0;
@@ -1429,9 +1458,18 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)
 
                item->match = path;
                item->len = strlen(path);
-               item->use_wildcard = !no_wildcard(path);
-               if (item->use_wildcard)
-                       pathspec->has_wildcard = 1;
+               item->flags = 0;
+               if (limit_pathspec_to_literal()) {
+                       item->nowildcard_len = item->len;
+               } else {
+                       item->nowildcard_len = simple_length(path);
+                       if (item->nowildcard_len < item->len) {
+                               pathspec->has_wildcard = 1;
+                               if (path[item->nowildcard_len] == '*' &&
+                                   no_wildcard(path + item->nowildcard_len + 1))
+                                       item->flags |= PATHSPEC_ONESTAR;
+                       }
+               }
        }
 
        qsort(pathspec->items, pathspec->nr,
@@ -1445,3 +1483,11 @@ void free_pathspec(struct pathspec *pathspec)
        free(pathspec->items);
        pathspec->items = NULL;
 }
+
+int limit_pathspec_to_literal(void)
+{
+       static int flag = -1;
+       if (flag < 0)
+               flag = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
+       return flag;
+}
diff --git a/dir.h b/dir.h
index f5c89e3b80143f2508ac5b69d432aa82a4254751..ab5af42b2eedcf7045abd0b6029e84ba804f6057 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -139,4 +139,13 @@ extern int strcmp_icase(const char *a, const char *b);
 extern int strncmp_icase(const char *a, const char *b, size_t count);
 extern int fnmatch_icase(const char *pattern, const char *string, int flags);
 
+/*
+ * The prefix part of pattern must not contains wildcards.
+ */
+#define GFNM_PATHNAME 1                /* similar to FNM_PATHNAME */
+#define GFNM_ONESTAR  2                /* there is only _one_ wildcard, a star */
+
+extern int git_fnmatch(const char *pattern, const char *string,
+                      int flags, int prefix);
+
 #endif
index d8340031d24828483697c10257806efedfe041f5..065a7abf2ffc0df61c35e0740e95caa5af14b229 100644 (file)
--- a/editor.c
+++ b/editor.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "strbuf.h"
 #include "run-command.h"
+#include "sigchain.h"
 
 #ifndef DEFAULT_EDITOR
 #define DEFAULT_EDITOR "vi"
@@ -37,8 +38,25 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en
 
        if (strcmp(editor, ":")) {
                const char *args[] = { editor, path, NULL };
+               struct child_process p;
+               int ret, sig;
 
-               if (run_command_v_opt_cd_env(args, RUN_USING_SHELL, NULL, env))
+               memset(&p, 0, sizeof(p));
+               p.argv = args;
+               p.env = env;
+               p.use_shell = 1;
+               if (start_command(&p) < 0)
+                       return error("unable to start editor '%s'", editor);
+
+               sigchain_push(SIGINT, SIG_IGN);
+               sigchain_push(SIGQUIT, SIG_IGN);
+               ret = finish_command(&p);
+               sig = ret + 128;
+               sigchain_pop(SIGINT);
+               sigchain_pop(SIGQUIT);
+               if (sig == SIGINT || sig == SIGQUIT)
+                       raise(sig);
+               if (ret)
                        return error("There was a problem with the editor '%s'.",
                                        editor);
        }
index 099ff4ddffecee85d964bfa9f03795ed168edf5f..f0acdf7331eeaf7a55ad09309a788c5971fe9b7f 100644 (file)
@@ -874,8 +874,6 @@ static int fetch_pack_config(const char *var, const char *value, void *cb)
        return git_default_config(var, value, cb);
 }
 
-static struct lock_file lock;
-
 static void fetch_pack_setup(void)
 {
        static int did_setup;
@@ -917,6 +915,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
        ref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);
 
        if (args->depth > 0) {
+               static struct lock_file lock;
                struct cache_time mtime;
                struct strbuf sb = STRBUF_INIT;
                char *shallow = git_path("shallow");
diff --git a/fsck.c b/fsck.c
index 7395ef6a425f5c7725767f34a0383f61907fce93..99c049767484288f273f036b57683df04c1ef0df 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -142,6 +142,9 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        int has_null_sha1 = 0;
        int has_full_path = 0;
        int has_empty_name = 0;
+       int has_dot = 0;
+       int has_dotdot = 0;
+       int has_dotgit = 0;
        int has_zero_pad = 0;
        int has_bad_modes = 0;
        int has_dup_entries = 0;
@@ -168,6 +171,12 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
                        has_full_path = 1;
                if (!*name)
                        has_empty_name = 1;
+               if (!strcmp(name, "."))
+                       has_dot = 1;
+               if (!strcmp(name, ".."))
+                       has_dotdot = 1;
+               if (!strcmp(name, ".git"))
+                       has_dotgit = 1;
                has_zero_pad |= *(char *)desc.buffer == '0';
                update_tree_entry(&desc);
 
@@ -217,6 +226,12 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
                retval += error_func(&item->object, FSCK_WARN, "contains full pathnames");
        if (has_empty_name)
                retval += error_func(&item->object, FSCK_WARN, "contains empty pathname");
+       if (has_dot)
+               retval += error_func(&item->object, FSCK_WARN, "contains '.'");
+       if (has_dotdot)
+               retval += error_func(&item->object, FSCK_WARN, "contains '..'");
+       if (has_dotgit)
+               retval += error_func(&item->object, FSCK_WARN, "contains '.git'");
        if (has_zero_pad)
                retval += error_func(&item->object, FSCK_WARN, "contains zero-padded file modes");
        if (has_bad_modes)
index 2e79b8a2f379d7c72a0934b36c7538db2143c722..2cecf56eb367ccd866250b7634c738187d6e2261 100644 (file)
@@ -75,7 +75,7 @@
 # endif
 #elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
       !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
-      !defined(__TANDEM)
+      !defined(__TANDEM) && !defined(__QNX__)
 #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
 #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
 #endif
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
-#ifdef __TANDEM /* or HAVE_STRINGS_H or !NO_STRINGS_H? */
+#ifdef HAVE_STRINGS_H
 #include <strings.h> /* for strcasecmp() */
 #endif
 #include <errno.h>
 #include <limits.h>
+#ifdef NEEDS_SYS_PARAM_H
 #include <sys/param.h>
+#endif
 #include <sys/types.h>
 #include <dirent.h>
 #include <sys/time.h>
@@ -288,6 +290,17 @@ extern NORETURN void die_errno(const char *err, ...) __attribute__((format (prin
 extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
 extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
 
+/*
+ * Let callers be aware of the constant return value; this can help
+ * gcc with -Wuninitialized analysis. We have to restrict this trick to
+ * gcc, though, because of the variadic macro and the magic ## comma pasting
+ * behavior. But since we're only trying to help gcc, anyway, it's OK; other
+ * compilers will fall back to using the function as usual.
+ */
+#ifdef __GNUC__
+#define error(fmt, ...) (error((fmt), ##__VA_ARGS__), -1)
+#endif
+
 extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params));
 extern void set_error_routine(void (*routine)(const char *err, va_list params));
 
@@ -411,6 +424,10 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
+#ifdef NO_GETPAGESIZE
+#define getpagesize() sysconf(_SC_PAGESIZE)
+#endif
+
 #ifdef FREAD_READS_DIRECTORIES
 #ifdef fopen
 #undef fopen
@@ -637,8 +654,12 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
-/* Call access(2), but warn for any error besides ENOENT. */
+/*
+ * Call access(2), but warn for any error except "missing file"
+ * (ENOENT or ENOTDIR).
+ */
 int access_or_warn(const char *path, int mode);
+int access_or_die(const char *path, int mode);
 
 /* Warn on an inaccessible file that ought to be accessible */
 void warn_on_inaccessible(const char *path);
diff --git a/git-remote-testgit b/git-remote-testgit
new file mode 100755 (executable)
index 0000000..b395c8d
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012 Felipe Contreras
+
+alias=$1
+url=$2
+
+dir="$GIT_DIR/testgit/$alias"
+prefix="refs/testgit/$alias"
+
+default_refspec="refs/heads/*:${prefix}/heads/*"
+
+refspec="${GIT_REMOTE_TESTGIT_REFSPEC-$default_refspec}"
+
+test -z "$refspec" && prefix="refs"
+
+export GIT_DIR="$url/.git"
+
+mkdir -p "$dir"
+
+if test -z "$GIT_REMOTE_TESTGIT_NO_MARKS"
+then
+       gitmarks="$dir/git.marks"
+       testgitmarks="$dir/testgit.marks"
+       test -e "$gitmarks" || >"$gitmarks"
+       test -e "$testgitmarks" || >"$testgitmarks"
+       testgitmarks_args=( "--"{import,export}"-marks=$testgitmarks" )
+fi
+
+while read line
+do
+       case $line in
+       capabilities)
+               echo 'import'
+               echo 'export'
+               test -n "$refspec" && echo "refspec $refspec"
+               if test -n "$gitmarks"
+               then
+                       echo "*import-marks $gitmarks"
+                       echo "*export-marks $gitmarks"
+               fi
+               echo
+               ;;
+       list)
+               git for-each-ref --format='? %(refname)' 'refs/heads/'
+               head=$(git symbolic-ref HEAD)
+               echo "@$head HEAD"
+               echo
+               ;;
+       import*)
+               # read all import lines
+               while true
+               do
+                       ref="${line#* }"
+                       refs="$refs $ref"
+                       read line
+                       test "${line%% *}" != "import" && break
+               done
+
+               if test -n "$gitmarks"
+               then
+                       echo "feature import-marks=$gitmarks"
+                       echo "feature export-marks=$gitmarks"
+               fi
+               echo "feature done"
+               git fast-export "${testgitmarks_args[@]}" $refs |
+               sed -e "s#refs/heads/#${prefix}/heads/#g"
+               echo "done"
+               ;;
+       export)
+               before=$(git for-each-ref --format='%(refname) %(objectname)')
+
+               git fast-import "${testgitmarks_args[@]}" --quiet
+
+               after=$(git for-each-ref --format='%(refname) %(objectname)')
+
+               # figure out which refs were updated
+               join -e 0 -o '0 1.2 2.2' -a 2 <(echo "$before") <(echo "$after") |
+               while read ref a b
+               do
+                       test $a == $b && continue
+                       echo "ok $ref"
+               done
+
+               echo
+               ;;
+       '')
+               exit
+               ;;
+       esac
+done
diff --git a/git-remote-testgit.py b/git-remote-testgit.py
deleted file mode 100644 (file)
index 5f3ebd2..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-#!/usr/bin/env python
-
-# This command is a simple remote-helper, that is used both as a
-# testcase for the remote-helper functionality, and as an example to
-# show remote-helper authors one possible implementation.
-#
-# This is a Git <-> Git importer/exporter, that simply uses git
-# fast-import and git fast-export to consume and produce fast-import
-# streams.
-#
-# To understand better the way things work, one can activate debug
-# traces by setting (to any value) the environment variables
-# GIT_TRANSPORT_HELPER_DEBUG and GIT_DEBUG_TESTGIT, to see messages
-# from the transport-helper side, or from this example remote-helper.
-
-# hashlib is only available in python >= 2.5
-try:
-    import hashlib
-    _digest = hashlib.sha1
-except ImportError:
-    import sha
-    _digest = sha.new
-import sys
-import os
-import time
-sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
-
-from git_remote_helpers.util import die, debug, warn
-from git_remote_helpers.git.repo import GitRepo
-from git_remote_helpers.git.exporter import GitExporter
-from git_remote_helpers.git.importer import GitImporter
-from git_remote_helpers.git.non_local import NonLocalGit
-
-def get_repo(alias, url):
-    """Returns a git repository object initialized for usage.
-    """
-
-    repo = GitRepo(url)
-    repo.get_revs()
-    repo.get_head()
-
-    hasher = _digest()
-    hasher.update(repo.path)
-    repo.hash = hasher.hexdigest()
-
-    repo.get_base_path = lambda base: os.path.join(
-        base, 'info', 'fast-import', repo.hash)
-
-    prefix = 'refs/testgit/%s/' % alias
-    debug("prefix: '%s'", prefix)
-
-    repo.gitdir = os.environ["GIT_DIR"]
-    repo.alias = alias
-    repo.prefix = prefix
-
-    repo.exporter = GitExporter(repo)
-    repo.importer = GitImporter(repo)
-    repo.non_local = NonLocalGit(repo)
-
-    return repo
-
-
-def local_repo(repo, path):
-    """Returns a git repository object initalized for usage.
-    """
-
-    local = GitRepo(path)
-
-    local.non_local = None
-    local.gitdir = repo.gitdir
-    local.alias = repo.alias
-    local.prefix = repo.prefix
-    local.hash = repo.hash
-    local.get_base_path = repo.get_base_path
-    local.exporter = GitExporter(local)
-    local.importer = GitImporter(local)
-
-    return local
-
-
-def do_capabilities(repo, args):
-    """Prints the supported capabilities.
-    """
-
-    print "import"
-    print "export"
-    print "refspec refs/heads/*:%s*" % repo.prefix
-
-    dirname = repo.get_base_path(repo.gitdir)
-
-    if not os.path.exists(dirname):
-        os.makedirs(dirname)
-
-    path = os.path.join(dirname, 'testgit.marks')
-
-    print "*export-marks %s" % path
-    if os.path.exists(path):
-        print "*import-marks %s" % path
-
-    print # end capabilities
-
-
-def do_list(repo, args):
-    """Lists all known references.
-
-    Bug: This will always set the remote head to master for non-local
-    repositories, since we have no way of determining what the remote
-    head is at clone time.
-    """
-
-    for ref in repo.revs:
-        debug("? refs/heads/%s", ref)
-        print "? refs/heads/%s" % ref
-
-    if repo.head:
-        debug("@refs/heads/%s HEAD" % repo.head)
-        print "@refs/heads/%s HEAD" % repo.head
-    else:
-        debug("@refs/heads/master HEAD")
-        print "@refs/heads/master HEAD"
-
-    print # end list
-
-
-def update_local_repo(repo):
-    """Updates (or clones) a local repo.
-    """
-
-    if repo.local:
-        return repo
-
-    path = repo.non_local.clone(repo.gitdir)
-    repo.non_local.update(repo.gitdir)
-    repo = local_repo(repo, path)
-    return repo
-
-
-def do_import(repo, args):
-    """Exports a fast-import stream from testgit for git to import.
-    """
-
-    if len(args) != 1:
-        die("Import needs exactly one ref")
-
-    if not repo.gitdir:
-        die("Need gitdir to import")
-
-    ref = args[0]
-    refs = [ref]
-
-    while True:
-        line = sys.stdin.readline()
-        if line == '\n':
-            break
-        if not line.startswith('import '):
-            die("Expected import line.")
-
-        # strip of leading 'import '
-        ref = line[7:].strip()
-        refs.append(ref)
-
-    repo = update_local_repo(repo)
-    repo.exporter.export_repo(repo.gitdir, refs)
-
-    print "done"
-
-
-def do_export(repo, args):
-    """Imports a fast-import stream from git to testgit.
-    """
-
-    if not repo.gitdir:
-        die("Need gitdir to export")
-
-    update_local_repo(repo)
-    changed = repo.importer.do_import(repo.gitdir)
-
-    if not repo.local:
-        repo.non_local.push(repo.gitdir)
-
-    for ref in changed:
-        print "ok %s" % ref
-    print
-
-
-COMMANDS = {
-    'capabilities': do_capabilities,
-    'list': do_list,
-    'import': do_import,
-    'export': do_export,
-}
-
-
-def sanitize(value):
-    """Cleans up the url.
-    """
-
-    if value.startswith('testgit::'):
-        value = value[9:]
-
-    return value
-
-
-def read_one_line(repo):
-    """Reads and processes one command.
-    """
-
-    sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
-    if sleepy:
-        debug("Sleeping %d sec before readline" % int(sleepy))
-        time.sleep(int(sleepy))
-
-    line = sys.stdin.readline()
-
-    cmdline = line
-
-    if not cmdline:
-        warn("Unexpected EOF")
-        return False
-
-    cmdline = cmdline.strip().split()
-    if not cmdline:
-        # Blank line means we're about to quit
-        return False
-
-    cmd = cmdline.pop(0)
-    debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
-
-    if cmd not in COMMANDS:
-        die("Unknown command, %s", cmd)
-
-    func = COMMANDS[cmd]
-    func(repo, cmdline)
-    sys.stdout.flush()
-
-    return True
-
-
-def main(args):
-    """Starts a new remote helper for the specified repository.
-    """
-
-    if len(args) != 3:
-        die("Expecting exactly three arguments.")
-        sys.exit(1)
-
-    if os.getenv("GIT_DEBUG_TESTGIT"):
-        import git_remote_helpers.util
-        git_remote_helpers.util.DEBUG = True
-
-    alias = sanitize(args[1])
-    url = sanitize(args[2])
-
-    if not alias.isalnum():
-        warn("non-alnum alias '%s'", alias)
-        alias = "tmp"
-
-    args[1] = alias
-    args[2] = url
-
-    repo = get_repo(alias, url)
-
-    debug("Got arguments %s", args[1:])
-
-    more = True
-
-    sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
-    while (more):
-        more = read_one_line(repo)
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
diff --git a/git-remote-testpy.py b/git-remote-testpy.py
new file mode 100644 (file)
index 0000000..ade797b
--- /dev/null
@@ -0,0 +1,272 @@
+#!/usr/bin/env python
+
+# This command is a simple remote-helper, that is used both as a
+# testcase for the remote-helper functionality, and as an example to
+# show remote-helper authors one possible implementation.
+#
+# This is a Git <-> Git importer/exporter, that simply uses git
+# fast-import and git fast-export to consume and produce fast-import
+# streams.
+#
+# To understand better the way things work, one can activate debug
+# traces by setting (to any value) the environment variables
+# GIT_TRANSPORT_HELPER_DEBUG and GIT_DEBUG_TESTGIT, to see messages
+# from the transport-helper side, or from this example remote-helper.
+
+# hashlib is only available in python >= 2.5
+try:
+    import hashlib
+    _digest = hashlib.sha1
+except ImportError:
+    import sha
+    _digest = sha.new
+import sys
+import os
+import time
+sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
+
+from git_remote_helpers.util import die, debug, warn
+from git_remote_helpers.git.repo import GitRepo
+from git_remote_helpers.git.exporter import GitExporter
+from git_remote_helpers.git.importer import GitImporter
+from git_remote_helpers.git.non_local import NonLocalGit
+
+def get_repo(alias, url):
+    """Returns a git repository object initialized for usage.
+    """
+
+    repo = GitRepo(url)
+    repo.get_revs()
+    repo.get_head()
+
+    hasher = _digest()
+    hasher.update(repo.path)
+    repo.hash = hasher.hexdigest()
+
+    repo.get_base_path = lambda base: os.path.join(
+        base, 'info', 'fast-import', repo.hash)
+
+    prefix = 'refs/testgit/%s/' % alias
+    debug("prefix: '%s'", prefix)
+
+    repo.gitdir = os.environ["GIT_DIR"]
+    repo.alias = alias
+    repo.prefix = prefix
+
+    repo.exporter = GitExporter(repo)
+    repo.importer = GitImporter(repo)
+    repo.non_local = NonLocalGit(repo)
+
+    return repo
+
+
+def local_repo(repo, path):
+    """Returns a git repository object initalized for usage.
+    """
+
+    local = GitRepo(path)
+
+    local.non_local = None
+    local.gitdir = repo.gitdir
+    local.alias = repo.alias
+    local.prefix = repo.prefix
+    local.hash = repo.hash
+    local.get_base_path = repo.get_base_path
+    local.exporter = GitExporter(local)
+    local.importer = GitImporter(local)
+
+    return local
+
+
+def do_capabilities(repo, args):
+    """Prints the supported capabilities.
+    """
+
+    print "import"
+    print "export"
+    print "refspec refs/heads/*:%s*" % repo.prefix
+
+    dirname = repo.get_base_path(repo.gitdir)
+
+    if not os.path.exists(dirname):
+        os.makedirs(dirname)
+
+    path = os.path.join(dirname, 'git.marks')
+
+    print "*export-marks %s" % path
+    if os.path.exists(path):
+        print "*import-marks %s" % path
+
+    print # end capabilities
+
+
+def do_list(repo, args):
+    """Lists all known references.
+
+    Bug: This will always set the remote head to master for non-local
+    repositories, since we have no way of determining what the remote
+    head is at clone time.
+    """
+
+    for ref in repo.revs:
+        debug("? refs/heads/%s", ref)
+        print "? refs/heads/%s" % ref
+
+    if repo.head:
+        debug("@refs/heads/%s HEAD" % repo.head)
+        print "@refs/heads/%s HEAD" % repo.head
+    else:
+        debug("@refs/heads/master HEAD")
+        print "@refs/heads/master HEAD"
+
+    print # end list
+
+
+def update_local_repo(repo):
+    """Updates (or clones) a local repo.
+    """
+
+    if repo.local:
+        return repo
+
+    path = repo.non_local.clone(repo.gitdir)
+    repo.non_local.update(repo.gitdir)
+    repo = local_repo(repo, path)
+    return repo
+
+
+def do_import(repo, args):
+    """Exports a fast-import stream from testgit for git to import.
+    """
+
+    if len(args) != 1:
+        die("Import needs exactly one ref")
+
+    if not repo.gitdir:
+        die("Need gitdir to import")
+
+    ref = args[0]
+    refs = [ref]
+
+    while True:
+        line = sys.stdin.readline()
+        if line == '\n':
+            break
+        if not line.startswith('import '):
+            die("Expected import line.")
+
+        # strip of leading 'import '
+        ref = line[7:].strip()
+        refs.append(ref)
+
+    repo = update_local_repo(repo)
+    repo.exporter.export_repo(repo.gitdir, refs)
+
+    print "done"
+
+
+def do_export(repo, args):
+    """Imports a fast-import stream from git to testgit.
+    """
+
+    if not repo.gitdir:
+        die("Need gitdir to export")
+
+    update_local_repo(repo)
+    changed = repo.importer.do_import(repo.gitdir)
+
+    if not repo.local:
+        repo.non_local.push(repo.gitdir)
+
+    for ref in changed:
+        print "ok %s" % ref
+    print
+
+
+COMMANDS = {
+    'capabilities': do_capabilities,
+    'list': do_list,
+    'import': do_import,
+    'export': do_export,
+}
+
+
+def sanitize(value):
+    """Cleans up the url.
+    """
+
+    if value.startswith('testgit::'):
+        value = value[9:]
+
+    return value
+
+
+def read_one_line(repo):
+    """Reads and processes one command.
+    """
+
+    sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
+    if sleepy:
+        debug("Sleeping %d sec before readline" % int(sleepy))
+        time.sleep(int(sleepy))
+
+    line = sys.stdin.readline()
+
+    cmdline = line
+
+    if not cmdline:
+        warn("Unexpected EOF")
+        return False
+
+    cmdline = cmdline.strip().split()
+    if not cmdline:
+        # Blank line means we're about to quit
+        return False
+
+    cmd = cmdline.pop(0)
+    debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
+
+    if cmd not in COMMANDS:
+        die("Unknown command, %s", cmd)
+
+    func = COMMANDS[cmd]
+    func(repo, cmdline)
+    sys.stdout.flush()
+
+    return True
+
+
+def main(args):
+    """Starts a new remote helper for the specified repository.
+    """
+
+    if len(args) != 3:
+        die("Expecting exactly three arguments.")
+        sys.exit(1)
+
+    if os.getenv("GIT_DEBUG_TESTGIT"):
+        import git_remote_helpers.util
+        git_remote_helpers.util.DEBUG = True
+
+    alias = sanitize(args[1])
+    url = sanitize(args[2])
+
+    if not alias.isalnum():
+        warn("non-alnum alias '%s'", alias)
+        alias = "tmp"
+
+    args[1] = alias
+    args[2] = url
+
+    repo = get_repo(alias, url)
+
+    debug("Got arguments %s", args[1:])
+
+    more = True
+
+    sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
+    while (more):
+        more = read_one_line(repo)
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
index 2365149d0b920ece4d076dafbebf23fef6888df1..22ec5b63b4cd36dd10277e842970f9534a623a2f 100755 (executable)
@@ -8,7 +8,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /')
 USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
    or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] init [--] [<path>...]
-   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
+   or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
    or: $dashless [--quiet] foreach [--recursive] <command>
    or: $dashless [--quiet] sync [--recursive] [--] [<path>...]"
@@ -26,6 +26,7 @@ cached=
 recursive=
 init=
 files=
+remote=
 nofetch=
 update=
 prefix=
@@ -152,6 +153,32 @@ die_if_unmatched ()
        fi
 }
 
+#
+# Print a submodule configuration setting
+#
+# $1 = submodule name
+# $2 = option name
+# $3 = default value
+#
+# Checks in the usual git-config places first (for overrides),
+# otherwise it falls back on .gitmodules.  This allows you to
+# distribute project-wide defaults in .gitmodules, while still
+# customizing individual repositories if necessary.  If the option is
+# not in .gitmodules either, print a default value.
+#
+get_submodule_config () {
+       name="$1"
+       option="$2"
+       default="$3"
+       value=$(git config submodule."$name"."$option")
+       if test -z "$value"
+       then
+               value=$(git config -f .gitmodules submodule."$name"."$option")
+       fi
+       printf '%s' "${value:-$default}"
+}
+
+
 #
 # Map submodule path to submodule name
 #
@@ -390,6 +417,10 @@ Use -f if you really want to add it." >&2
 
        git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
        git config -f .gitmodules submodule."$sm_name".url "$repo" &&
+       if test -n "$branch"
+       then
+               git config -f .gitmodules submodule."$sm_name".branch "$branch"
+       fi &&
        git add --force .gitmodules ||
        die "$(eval_gettext "Failed to register submodule '\$sm_path'")"
 }
@@ -533,6 +564,9 @@ cmd_update()
                -i|--init)
                        init=1
                        ;;
+               --remote)
+                       remote=1
+                       ;;
                -N|--no-fetch)
                        nofetch=1
                        ;;
@@ -593,6 +627,7 @@ cmd_update()
                fi
                name=$(module_name "$sm_path") || exit
                url=$(git config submodule."$name".url)
+               branch=$(get_submodule_config "$name" branch master)
                if ! test -z "$update"
                then
                        update_module=$update
@@ -627,6 +662,20 @@ Maybe you want to use 'update --init'?")"
                        die "$(eval_gettext "Unable to find current revision in submodule path '\$sm_path'")"
                fi
 
+               if test -n "$remote"
+               then
+                       if test -z "$nofetch"
+                       then
+                               # Fetch remote before determining tracking $sha1
+                               (clear_local_git_env; cd "$sm_path" && git-fetch) ||
+                               die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
+                       fi
+                       remote_name=$(clear_local_git_env; cd "$sm_path" && get_default_remote)
+                       sha1=$(clear_local_git_env; cd "$sm_path" &&
+                               git rev-parse --verify "${remote_name}/${branch}") ||
+                       die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
+               fi
+
                if test "$subsha1" != "$sha1" -o -n "$force"
                then
                        subforce=$force
diff --git a/git.c b/git.c
index d33f9b32a2895ef9f062f9fda487588daac6f5bc..ed66c660d15010af9a8b0c2ea1da8839e316e1db 100644 (file)
--- a/git.c
+++ b/git.c
@@ -135,6 +135,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                        git_config_push_parameter((*argv)[1]);
                        (*argv)++;
                        (*argc)--;
+               } else if (!strcmp(cmd, "--literal-pathspecs")) {
+                       setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "1", 1);
+                       if (envchanged)
+                               *envchanged = 1;
+               } else if (!strcmp(cmd, "--no-literal-pathspecs")) {
+                       setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "0", 1);
+                       if (envchanged)
+                               *envchanged = 1;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(git_usage_string);
index 5c6b595e16665bc508625ab0e96c95776bacba1a..e28cc8f98655b16e5930c9c623a1f3098ae0ca93 100644 (file)
@@ -39,7 +39,7 @@ def do_import(self, base):
             gitdir = self.repo.gitpath
         else:
             gitdir = os.path.abspath(os.path.join(dirname, '.git'))
-        path = os.path.abspath(os.path.join(dirname, 'git.marks'))
+        path = os.path.abspath(os.path.join(dirname, 'testgit.marks'))
 
         if not os.path.exists(dirname):
             os.makedirs(dirname)
index 0f207f2e20b0c3c30e62c1fd6f0526d38868776f..656b324fb7f82c7f65c71075f57e909843c50cce 100755 (executable)
@@ -5528,23 +5528,30 @@ sub fill_project_list_info {
 
 sub sort_projects_list {
        my ($projlist, $order) = @_;
-       my @projects;
 
-       my %order_info = (
-               project => { key => 'path', type => 'str' },
-               descr => { key => 'descr_long', type => 'str' },
-               owner => { key => 'owner', type => 'str' },
-               age => { key => 'age', type => 'num' }
-       );
-       my $oi = $order_info{$order};
-       return @$projlist unless defined $oi;
-       if ($oi->{'type'} eq 'str') {
-               @projects = sort {$a->{$oi->{'key'}} cmp $b->{$oi->{'key'}}} @$projlist;
-       } else {
-               @projects = sort {$a->{$oi->{'key'}} <=> $b->{$oi->{'key'}}} @$projlist;
+       sub order_str {
+               my $key = shift;
+               return sub { $a->{$key} cmp $b->{$key} };
        }
 
-       return @projects;
+       sub order_num_then_undef {
+               my $key = shift;
+               return sub {
+                       defined $a->{$key} ?
+                               (defined $b->{$key} ? $a->{$key} <=> $b->{$key} : -1) :
+                               (defined $b->{$key} ? 1 : 0)
+               };
+       }
+
+       my %orderings = (
+               project => order_str('path'),
+               descr => order_str('descr_long'),
+               owner => order_str('owner'),
+               age => order_num_then_undef('age'),
+       );
+
+       my $ordering = $orderings{$order};
+       return defined $ordering ? sort $ordering @$projlist : @$projlist;
 }
 
 # returns a hash of categories, containing the list of project
diff --git a/graph.c b/graph.c
index e864fe2c6a21379398e454e60627e78a63a09462..391a712e5eafbc05b8d4b739d96aaca0dd481460 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -1227,7 +1227,7 @@ void graph_show_commit(struct git_graph *graph)
        if (!graph)
                return;
 
-       while (!shown_commit_line) {
+       while (!shown_commit_line && !graph_is_commit_finished(graph)) {
                shown_commit_line = graph_next_line(graph, &msgbuf);
                fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
                if (!shown_commit_line)
index 8701c1215d21cd0413c1d69be91b309984cf6b1f..9923441a4ec74cfdfd3c36b1be41762c04697bdd 100644 (file)
@@ -172,28 +172,7 @@ enum dav_header_flag {
 static char *xml_entities(const char *s)
 {
        struct strbuf buf = STRBUF_INIT;
-       while (*s) {
-               size_t len = strcspn(s, "\"<>&");
-               strbuf_add(&buf, s, len);
-               s += len;
-               switch (*s) {
-               case '"':
-                       strbuf_addstr(&buf, "&quot;");
-                       break;
-               case '<':
-                       strbuf_addstr(&buf, "&lt;");
-                       break;
-               case '>':
-                       strbuf_addstr(&buf, "&gt;");
-                       break;
-               case '&':
-                       strbuf_addstr(&buf, "&amp;");
-                       break;
-               case 0:
-                       return strbuf_detach(&buf, NULL);
-               }
-               s++;
-       }
+       strbuf_addstr_xml_quoted(&buf, s);
        return strbuf_detach(&buf, NULL);
 }
 
diff --git a/http.c b/http.c
index 0a8abf3be369a18fae8e743d4cc9b5f2c2f63f03..44f35256e44ffdda2ffb0ce67825008bef89700f 100644 (file)
--- a/http.c
+++ b/http.c
@@ -236,6 +236,7 @@ static int has_cert_password(void)
                return 0;
        if (!cert_auth.password) {
                cert_auth.protocol = xstrdup("cert");
+               cert_auth.username = xstrdup("");
                cert_auth.path = xstrdup(ssl_cert);
                credential_fill(&cert_auth);
        }
index d42e4712972794f055aec6630ba86797d7e5343c..e521e2fd223766eee22705674dd3becbb3d52a57 100644 (file)
@@ -69,8 +69,7 @@ struct store {
 };
 
 struct msg_data {
-       char *data;
-       int len;
+       struct strbuf data;
        unsigned char flags;
 };
 
@@ -1264,45 +1263,49 @@ static int imap_make_flags(int flags, char *buf)
        return d;
 }
 
-static void lf_to_crlf(struct msg_data *msg)
+static void lf_to_crlf(struct strbuf *msg)
 {
+       size_t new_len;
        char *new;
        int i, j, lfnum = 0;
 
-       if (msg->data[0] == '\n')
+       if (msg->buf[0] == '\n')
                lfnum++;
        for (i = 1; i < msg->len; i++) {
-               if (msg->data[i - 1] != '\r' && msg->data[i] == '\n')
+               if (msg->buf[i - 1] != '\r' && msg->buf[i] == '\n')
                        lfnum++;
        }
 
-       new = xmalloc(msg->len + lfnum);
-       if (msg->data[0] == '\n') {
+       new_len = msg->len + lfnum;
+       new = xmalloc(new_len + 1);
+       if (msg->buf[0] == '\n') {
                new[0] = '\r';
                new[1] = '\n';
                i = 1;
                j = 2;
        } else {
-               new[0] = msg->data[0];
+               new[0] = msg->buf[0];
                i = 1;
                j = 1;
        }
        for ( ; i < msg->len; i++) {
-               if (msg->data[i] != '\n') {
-                       new[j++] = msg->data[i];
+               if (msg->buf[i] != '\n') {
+                       new[j++] = msg->buf[i];
                        continue;
                }
-               if (msg->data[i - 1] != '\r')
+               if (msg->buf[i - 1] != '\r')
                        new[j++] = '\r';
                /* otherwise it already had CR before */
                new[j++] = '\n';
        }
-       msg->len += lfnum;
-       free(msg->data);
-       msg->data = new;
+       strbuf_attach(msg, new, new_len, new_len + 1);
 }
 
-static int imap_store_msg(struct store *gctx, struct msg_data *data)
+/*
+ * Store msg to IMAP.  Also detach and free the data from msg->data,
+ * leaving msg->data empty.
+ */
+static int imap_store_msg(struct store *gctx, struct msg_data *msg)
 {
        struct imap_store *ctx = (struct imap_store *)gctx;
        struct imap *imap = ctx->imap;
@@ -1311,16 +1314,15 @@ static int imap_store_msg(struct store *gctx, struct msg_data *data)
        int ret, d;
        char flagstr[128];
 
-       lf_to_crlf(data);
+       lf_to_crlf(&msg->data);
        memset(&cb, 0, sizeof(cb));
 
-       cb.dlen = data->len;
-       cb.data = xmalloc(cb.dlen);
-       memcpy(cb.data, data->data, data->len);
+       cb.dlen = msg->data.len;
+       cb.data = strbuf_detach(&msg->data, NULL);
 
        d = 0;
-       if (data->flags) {
-               d = imap_make_flags(data->flags, flagstr);
+       if (msg->flags) {
+               d = imap_make_flags(msg->flags, flagstr);
                flagstr[d++] = ' ';
        }
        flagstr[d] = 0;
@@ -1337,75 +1339,46 @@ static int imap_store_msg(struct store *gctx, struct msg_data *data)
        return DRV_OK;
 }
 
-static void encode_html_chars(struct strbuf *p)
-{
-       int i;
-       for (i = 0; i < p->len; i++) {
-               if (p->buf[i] == '&')
-                       strbuf_splice(p, i, 1, "&amp;", 5);
-               if (p->buf[i] == '<')
-                       strbuf_splice(p, i, 1, "&lt;", 4);
-               if (p->buf[i] == '>')
-                       strbuf_splice(p, i, 1, "&gt;", 4);
-               if (p->buf[i] == '"')
-                       strbuf_splice(p, i, 1, "&quot;", 6);
-       }
-}
-static void wrap_in_html(struct msg_data *msg)
+static void wrap_in_html(struct strbuf *msg)
 {
        struct strbuf buf = STRBUF_INIT;
-       struct strbuf **lines;
-       struct strbuf **p;
        static char *content_type = "Content-Type: text/html;\n";
        static char *pre_open = "<pre>\n";
        static char *pre_close = "</pre>\n";
-       int added_header = 0;
-
-       strbuf_attach(&buf, msg->data, msg->len, msg->len);
-       lines = strbuf_split(&buf, '\n');
-       strbuf_release(&buf);
-       for (p = lines; *p; p++) {
-               if (! added_header) {
-                       if ((*p)->len == 1 && *((*p)->buf) == '\n') {
-                               strbuf_addstr(&buf, content_type);
-                               strbuf_addbuf(&buf, *p);
-                               strbuf_addstr(&buf, pre_open);
-                               added_header = 1;
-                               continue;
-                       }
-               }
-               else
-                       encode_html_chars(*p);
-               strbuf_addbuf(&buf, *p);
-       }
+       const char *body = strstr(msg->buf, "\n\n");
+
+       if (!body)
+               return; /* Headers but no body; no wrapping needed */
+
+       body += 2;
+
+       strbuf_add(&buf, msg->buf, body - msg->buf - 1);
+       strbuf_addstr(&buf, content_type);
+       strbuf_addch(&buf, '\n');
+       strbuf_addstr(&buf, pre_open);
+       strbuf_addstr_xml_quoted(&buf, body);
        strbuf_addstr(&buf, pre_close);
-       strbuf_list_free(lines);
-       msg->len  = buf.len;
-       msg->data = strbuf_detach(&buf, NULL);
+
+       strbuf_release(msg);
+       *msg = buf;
 }
 
 #define CHUNKSIZE 0x1000
 
-static int read_message(FILE *f, struct msg_data *msg)
+static int read_message(FILE *f, struct strbuf *all_msgs)
 {
-       struct strbuf buf = STRBUF_INIT;
-
-       memset(msg, 0, sizeof(*msg));
-
        do {
-               if (strbuf_fread(&buf, CHUNKSIZE, f) <= 0)
+               if (strbuf_fread(all_msgs, CHUNKSIZE, f) <= 0)
                        break;
        } while (!feof(f));
 
-       msg->len  = buf.len;
-       msg->data = strbuf_detach(&buf, NULL);
-       return msg->len;
+       return ferror(f) ? -1 : 0;
 }
 
-static int count_messages(struct msg_data *msg)
+static int count_messages(struct strbuf *all_msgs)
 {
        int count = 0;
-       char *p = msg->data;
+       char *p = all_msgs->buf;
 
        while (1) {
                if (!prefixcmp(p, "From ")) {
@@ -1426,34 +1399,39 @@ static int count_messages(struct msg_data *msg)
        return count;
 }
 
-static int split_msg(struct msg_data *all_msgs, struct msg_data *msg, int *ofs)
+/*
+ * Copy the next message from all_msgs, starting at offset *ofs, to
+ * msg.  Update *ofs to the start of the following message.  Return
+ * true iff a message was successfully copied.
+ */
+static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
 {
        char *p, *data;
+       size_t len;
 
-       memset(msg, 0, sizeof *msg);
        if (*ofs >= all_msgs->len)
                return 0;
 
-       data = &all_msgs->data[*ofs];
-       msg->len = all_msgs->len - *ofs;
+       data = &all_msgs->buf[*ofs];
+       len = all_msgs->len - *ofs;
 
-       if (msg->len < 5 || prefixcmp(data, "From "))
+       if (len < 5 || prefixcmp(data, "From "))
                return 0;
 
        p = strchr(data, '\n');
        if (p) {
-               p = &p[1];
-               msg->len -= p-data;
-               *ofs += p-data;
+               p++;
+               len -= p - data;
+               *ofs += p - data;
                data = p;
        }
 
        p = strstr(data, "\nFrom ");
        if (p)
-               msg->len = &p[1] - data;
+               len = &p[1] - data;
 
-       msg->data = xmemdupz(data, msg->len);
-       *ofs += msg->len;
+       strbuf_add(msg, data, len);
+       *ofs += len;
        return 1;
 }
 
@@ -1504,7 +1482,8 @@ static int git_imap_config(const char *key, const char *val, void *cb)
 
 int main(int argc, char **argv)
 {
-       struct msg_data all_msgs, msg;
+       struct strbuf all_msgs = STRBUF_INIT;
+       struct msg_data msg = {STRBUF_INIT, 0};
        struct store *ctx = NULL;
        int ofs = 0;
        int r;
@@ -1537,7 +1516,12 @@ int main(int argc, char **argv)
        }
 
        /* read the messages */
-       if (!read_message(stdin, &all_msgs)) {
+       if (read_message(stdin, &all_msgs)) {
+               fprintf(stderr, "error reading input\n");
+               return 1;
+       }
+
+       if (all_msgs.len == 0) {
                fprintf(stderr, "nothing to send\n");
                return 1;
        }
@@ -1559,11 +1543,12 @@ int main(int argc, char **argv)
        ctx->name = imap_folder;
        while (1) {
                unsigned percent = n * 100 / total;
+
                fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
-               if (!split_msg(&all_msgs, &msg, &ofs))
+               if (!split_msg(&all_msgs, &msg.data, &ofs))
                        break;
                if (server.use_html)
-                       wrap_in_html(&msg);
+                       wrap_in_html(&msg.data);
                r = imap_store_msg(ctx, &msg);
                if (r != DRV_OK)
                        break;
index 4f86defe324bac8374585df5d9e8ef7b5f9a3524..8876c736d4afbb92d862598861145abe0f408cec 100644 (file)
@@ -671,6 +671,7 @@ void show_log(struct rev_info *opt)
        ctx.preserve_subject = opt->preserve_subject;
        ctx.reflog_info = opt->reflog_info;
        ctx.fmt = opt->commit_format;
+       ctx.color = opt->diffopt.use_color;
        pretty_print_commit(&ctx, commit, &msgbuf);
 
        if (opt->add_signoff)
index ea4b471edeb5ca9b29a8138f6f831a5e6a15a9e8..b16542febec14ed86fd7ef21ba19899d08c95a64 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -10,6 +10,7 @@ static inline void debug_mm(const char *format, ...) {}
 #endif
 
 const char *git_mailmap_file;
+const char *git_mailmap_blob;
 
 struct mailmap_info {
        char *name;
@@ -129,54 +130,119 @@ static char *parse_name_and_email(char *buffer, char **name,
        return (*right == '\0' ? NULL : right);
 }
 
-static int read_single_mailmap(struct string_list *map, const char *filename, char **repo_abbrev)
+static void read_mailmap_line(struct string_list *map, char *buffer,
+                             char **repo_abbrev)
+{
+       char *name1 = NULL, *email1 = NULL, *name2 = NULL, *email2 = NULL;
+       if (buffer[0] == '#') {
+               static const char abbrev[] = "# repo-abbrev:";
+               int abblen = sizeof(abbrev) - 1;
+               int len = strlen(buffer);
+
+               if (!repo_abbrev)
+                       return;
+
+               if (len && buffer[len - 1] == '\n')
+                       buffer[--len] = 0;
+               if (!strncmp(buffer, abbrev, abblen)) {
+                       char *cp;
+
+                       if (repo_abbrev)
+                               free(*repo_abbrev);
+                       *repo_abbrev = xmalloc(len);
+
+                       for (cp = buffer + abblen; isspace(*cp); cp++)
+                               ; /* nothing */
+                       strcpy(*repo_abbrev, cp);
+               }
+               return;
+       }
+       if ((name2 = parse_name_and_email(buffer, &name1, &email1, 0)) != NULL)
+               parse_name_and_email(name2, &name2, &email2, 1);
+
+       if (email1)
+               add_mapping(map, name1, email1, name2, email2);
+}
+
+static int read_mailmap_file(struct string_list *map, const char *filename,
+                            char **repo_abbrev)
 {
        char buffer[1024];
-       FILE *f = (filename == NULL ? NULL : fopen(filename, "r"));
+       FILE *f;
 
-       if (f == NULL)
-               return 1;
-       while (fgets(buffer, sizeof(buffer), f) != NULL) {
-               char *name1 = NULL, *email1 = NULL, *name2 = NULL, *email2 = NULL;
-               if (buffer[0] == '#') {
-                       static const char abbrev[] = "# repo-abbrev:";
-                       int abblen = sizeof(abbrev) - 1;
-                       int len = strlen(buffer);
-
-                       if (!repo_abbrev)
-                               continue;
-
-                       if (len && buffer[len - 1] == '\n')
-                               buffer[--len] = 0;
-                       if (!strncmp(buffer, abbrev, abblen)) {
-                               char *cp;
-
-                               if (repo_abbrev)
-                                       free(*repo_abbrev);
-                               *repo_abbrev = xmalloc(len);
-
-                               for (cp = buffer + abblen; isspace(*cp); cp++)
-                                       ; /* nothing */
-                               strcpy(*repo_abbrev, cp);
-                       }
-                       continue;
-               }
-               if ((name2 = parse_name_and_email(buffer, &name1, &email1, 0)) != NULL)
-                       parse_name_and_email(name2, &name2, &email2, 1);
+       if (!filename)
+               return 0;
 
-               if (email1)
-                       add_mapping(map, name1, email1, name2, email2);
+       f = fopen(filename, "r");
+       if (!f) {
+               if (errno == ENOENT)
+                       return 0;
+               return error("unable to open mailmap at %s: %s",
+                            filename, strerror(errno));
        }
+
+       while (fgets(buffer, sizeof(buffer), f) != NULL)
+               read_mailmap_line(map, buffer, repo_abbrev);
        fclose(f);
        return 0;
 }
 
+static void read_mailmap_buf(struct string_list *map,
+                            const char *buf, unsigned long len,
+                            char **repo_abbrev)
+{
+       while (len) {
+               const char *end = strchrnul(buf, '\n');
+               unsigned long linelen = end - buf + 1;
+               char *line = xmemdupz(buf, linelen);
+
+               read_mailmap_line(map, line, repo_abbrev);
+
+               free(line);
+               buf += linelen;
+               len -= linelen;
+       }
+}
+
+static int read_mailmap_blob(struct string_list *map,
+                            const char *name,
+                            char **repo_abbrev)
+{
+       unsigned char sha1[20];
+       char *buf;
+       unsigned long size;
+       enum object_type type;
+
+       if (!name)
+               return 0;
+       if (get_sha1(name, sha1) < 0)
+               return 0;
+
+       buf = read_sha1_file(sha1, &type, &size);
+       if (!buf)
+               return error("unable to read mailmap object at %s", name);
+       if (type != OBJ_BLOB)
+               return error("mailmap is not a blob: %s", name);
+
+       read_mailmap_buf(map, buf, size, repo_abbrev);
+
+       free(buf);
+       return 0;
+}
+
 int read_mailmap(struct string_list *map, char **repo_abbrev)
 {
+       int err = 0;
+
        map->strdup_strings = 1;
-       /* each failure returns 1, so >1 means both calls failed */
-       return read_single_mailmap(map, ".mailmap", repo_abbrev) +
-              read_single_mailmap(map, git_mailmap_file, repo_abbrev) > 1;
+
+       if (!git_mailmap_blob && is_bare_repository())
+               git_mailmap_blob = "HEAD:.mailmap";
+
+       err |= read_mailmap_file(map, ".mailmap", repo_abbrev);
+       err |= read_mailmap_blob(map, git_mailmap_blob, repo_abbrev);
+       err |= read_mailmap_file(map, git_mailmap_file, repo_abbrev);
+       return err;
 }
 
 void clear_mailmap(struct string_list *map)
index 295361a8aa7d075bbb9fdb8173858e37f9a43211..52f7c8f70578929432becdd58a7fb423398f8de8 100644 (file)
@@ -1,29 +1,21 @@
 diff_cmd () {
+       empty_file=
+
        # p4merge does not like /dev/null
-       rm_local=
-       rm_remote=
        if test "/dev/null" = "$LOCAL"
        then
-               LOCAL="./p4merge-dev-null.LOCAL.$$"
-               >"$LOCAL"
-               rm_local=true
+               LOCAL="$(create_empty_file)"
        fi
        if test "/dev/null" = "$REMOTE"
        then
-               REMOTE="./p4merge-dev-null.REMOTE.$$"
-               >"$REMOTE"
-               rm_remote=true
+               REMOTE="$(create_empty_file)"
        fi
 
        "$merge_tool_path" "$LOCAL" "$REMOTE"
 
-       if test -n "$rm_local"
-       then
-               rm -f "$LOCAL"
-       fi
-       if test -n "$rm_remote"
+       if test -n "$empty_file"
        then
-               rm -f "$REMOTE"
+               rm -f "$empty_file"
        fi
 }
 
@@ -33,3 +25,10 @@ merge_cmd () {
        "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
        check_unchanged
 }
+
+create_empty_file () {
+       empty_file="${TMPDIR:-/tmp}/git-difftool-p4merge-empty-file.$$"
+       >"$empty_file"
+
+       printf "$empty_file"
+}
index c1c66bd408c50685c06fe7ff1e1c6a78c26be1b1..67e98a6323e2dd4e3b4b8003806f7dffaff29a64 100644 (file)
@@ -18,15 +18,6 @@ int optbug(const struct option *opt, const char *reason)
        return error("BUG: switch '%c' %s", opt->short_name, reason);
 }
 
-int opterror(const struct option *opt, const char *reason, int flags)
-{
-       if (flags & OPT_SHORT)
-               return error("switch `%c' %s", opt->short_name, reason);
-       if (flags & OPT_UNSET)
-               return error("option `no-%s' %s", opt->long_name, reason);
-       return error("option `%s' %s", opt->long_name, reason);
-}
-
 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
                   int flags, const char **arg)
 {
@@ -594,3 +585,12 @@ static int parse_options_usage(struct parse_opt_ctx_t *ctx,
        return usage_with_options_internal(ctx, usagestr, opts, 0, err);
 }
 
+#undef opterror
+int opterror(const struct option *opt, const char *reason, int flags)
+{
+       if (flags & OPT_SHORT)
+               return error("switch `%c' %s", opt->short_name, reason);
+       if (flags & OPT_UNSET)
+               return error("option `no-%s' %s", opt->long_name, reason);
+       return error("option `%s' %s", opt->long_name, reason);
+}
index 71a39c60d942601a1cf30e218df56777742d5580..e703853749f0949c58cde0a27ff1d01991609400 100644 (file)
@@ -177,6 +177,10 @@ extern NORETURN void usage_msg_opt(const char *msg,
 
 extern int optbug(const struct option *opt, const char *reason);
 extern int opterror(const struct option *opt, const char *reason, int flags);
+#ifdef __GNUC__
+#define opterror(o,r,f) (opterror((o),(r),(f)), -1)
+#endif
+
 /*----- incremental advanced APIs -----*/
 
 enum {
diff --git a/path.c b/path.c
index cbbdf7d6ba68160a3a9936976e53d773d181ceac..d3d3f8b8ad75b9817df3014296aabc34b6a4eb14 100644 (file)
--- a/path.c
+++ b/path.c
@@ -12,6 +12,7 @@
  */
 #include "cache.h"
 #include "strbuf.h"
+#include "string-list.h"
 
 static char bad_path[] = "/bad-path/";
 
@@ -569,43 +570,38 @@ int normalize_path_copy(char *dst, const char *src)
 
 /*
  * path = Canonical absolute path
- * prefix_list = Colon-separated list of absolute paths
+ * prefixes = string_list containing normalized, absolute paths without
+ * trailing slashes (except for the root directory, which is denoted by "/").
  *
- * Determines, for each path in prefix_list, whether the "prefix" really
+ * Determines, for each path in prefixes, whether the "prefix"
  * is an ancestor directory of path.  Returns the length of the longest
  * ancestor directory, excluding any trailing slashes, or -1 if no prefix
- * is an ancestor.  (Note that this means 0 is returned if prefix_list is
- * "/".) "/foo" is not considered an ancestor of "/foobar".  Directories
+ * is an ancestor.  (Note that this means 0 is returned if prefixes is
+ * ["/"].) "/foo" is not considered an ancestor of "/foobar".  Directories
  * are not considered to be their own ancestors.  path must be in a
  * canonical form: empty components, or "." or ".." components are not
- * allowed.  prefix_list may be null, which is like "".
+ * allowed.
  */
-int longest_ancestor_length(const char *path, const char *prefix_list)
+int longest_ancestor_length(const char *path, struct string_list *prefixes)
 {
-       char buf[PATH_MAX+1];
-       const char *ceil, *colon;
-       int len, max_len = -1;
+       int i, max_len = -1;
 
-       if (prefix_list == NULL || !strcmp(path, "/"))
+       if (!strcmp(path, "/"))
                return -1;
 
-       for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
-               for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
-               len = colon - ceil;
-               if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
-                       continue;
-               strlcpy(buf, ceil, len+1);
-               if (normalize_path_copy(buf, buf) < 0)
-                       continue;
-               len = strlen(buf);
-               if (len > 0 && buf[len-1] == '/')
-                       buf[--len] = '\0';
+       for (i = 0; i < prefixes->nr; i++) {
+               const char *ceil = prefixes->items[i].string;
+               int len = strlen(ceil);
 
-               if (!strncmp(path, buf, len) &&
-                   path[len] == '/' &&
-                   len > max_len) {
+               if (len == 1 && ceil[0] == '/')
+                       len = 0; /* root matches anything, with length 0 */
+               else if (!strncmp(path, ceil, len) && path[len] == '/')
+                       ; /* match of length len */
+               else
+                       continue; /* no match */
+
+               if (len > max_len)
                        max_len = len;
-               }
        }
 
        return max_len;
index 497f420178a73061901393f8c21a9feb17054b6d..931047c51da22cddefe0eab08d0fdaa595daefef 100644 (file)
@@ -58,7 +58,7 @@ =head1 SYNOPSIS
                 command_output_pipe command_input_pipe command_close_pipe
                 command_bidi_pipe command_close_bidi_pipe
                 version exec_path html_path hash_object git_cmd_try
-                remote_refs
+                remote_refs prompt
                 temp_acquire temp_release temp_reset temp_path);
 
 
@@ -511,6 +511,58 @@ sub version {
 
 sub html_path { command_oneline('--html-path') }
 
+=item prompt ( PROMPT , ISPASSWORD  )
+
+Query user C<PROMPT> and return answer from user.
+
+Honours GIT_ASKPASS and SSH_ASKPASS environment variables for querying
+the user. If no *_ASKPASS variable is set or an error occoured,
+the terminal is tried as a fallback.
+If C<ISPASSWORD> is set and true, the terminal disables echo.
+
+=cut
+
+sub prompt {
+       my ($prompt, $isPassword) = @_;
+       my $ret;
+       if (exists $ENV{'GIT_ASKPASS'}) {
+               $ret = _prompt($ENV{'GIT_ASKPASS'}, $prompt);
+       }
+       if (!defined $ret && exists $ENV{'SSH_ASKPASS'}) {
+               $ret = _prompt($ENV{'SSH_ASKPASS'}, $prompt);
+       }
+       if (!defined $ret) {
+               print STDERR $prompt;
+               STDERR->flush;
+               if (defined $isPassword && $isPassword) {
+                       require Term::ReadKey;
+                       Term::ReadKey::ReadMode('noecho');
+                       $ret = '';
+                       while (defined(my $key = Term::ReadKey::ReadKey(0))) {
+                               last if $key =~ /[\012\015]/; # \n\r
+                               $ret .= $key;
+                       }
+                       Term::ReadKey::ReadMode('restore');
+                       print STDERR "\n";
+                       STDERR->flush;
+               } else {
+                       chomp($ret = <STDIN>);
+               }
+       }
+       return $ret;
+}
+
+sub _prompt {
+       my ($askpass, $prompt) = @_;
+       return unless length $askpass;
+       $prompt =~ s/\n/ /g;
+       my $ret;
+       open my $fh, "-|", $askpass, $prompt or return;
+       $ret = <$fh>;
+       $ret =~ s/[\015\012]//g; # strip \r\n, chomp does not work on all systems (i.e. windows) as expected
+       close ($fh);
+       return $ret;
+}
 
 =item repo_path ()
 
index 3a6f8af0d9849c5f2fc886f8fc3ac9a8575e271e..74daa7a597fcf55a649a4e90367b1e783a74fcd5 100644 (file)
@@ -62,16 +62,16 @@ sub ssl_server_trust {
                                       issuer_dname fingerprint);
        my $choice;
 prompt:
-       print STDERR $may_save ?
+       my $options = $may_save ?
              "(R)eject, accept (t)emporarily or accept (p)ermanently? " :
              "(R)eject or accept (t)emporarily? ";
        STDERR->flush;
-       $choice = lc(substr(<STDIN> || 'R', 0, 1));
-       if ($choice =~ /^t$/i) {
+       $choice = lc(substr(Git::prompt("Certificate problem.\n" . $options) || 'R', 0, 1));
+       if ($choice eq 't') {
                $cred->may_save(undef);
-       } elsif ($choice =~ /^r$/i) {
+       } elsif ($choice eq 'r') {
                return -1;
-       } elsif ($may_save && $choice =~ /^p$/i) {
+       } elsif ($may_save && $choice eq 'p') {
                $cred->may_save($may_save);
        } else {
                goto prompt;
@@ -109,9 +109,7 @@ sub username {
        if (defined $_username) {
                $username = $_username;
        } else {
-               print STDERR "Username: ";
-               STDERR->flush;
-               chomp($username = <STDIN>);
+               $username = Git::prompt("Username: ");
        }
        $cred->username($username);
        $cred->may_save($may_save);
@@ -120,25 +118,7 @@ sub username {
 
 sub _read_password {
        my ($prompt, $realm) = @_;
-       my $password = '';
-       if (exists $ENV{GIT_ASKPASS}) {
-               open(PH, "-|", $ENV{GIT_ASKPASS}, $prompt);
-               $password = <PH>;
-               $password =~ s/[\012\015]//; # \n\r
-               close(PH);
-       } else {
-               print STDERR $prompt;
-               STDERR->flush;
-               require Term::ReadKey;
-               Term::ReadKey::ReadMode('noecho');
-               while (defined(my $key = Term::ReadKey::ReadKey(0))) {
-                       last if $key =~ /[\012\015]/; # \n\r
-                       $password .= $key;
-               }
-               Term::ReadKey::ReadMode('restore');
-               print STDERR "\n";
-               STDERR->flush;
-       }
+       my $password = Git::prompt($prompt, 1);
        $password;
 }
 
index 5bdc2e70bcd1e8fc0c7e625c3eac26397d8c96d2..92c839fe641da15d05c2afe2b498a9fe390624c8 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -567,7 +567,7 @@ char *logmsg_reencode(const struct commit *commit,
        char *encoding;
        char *out;
 
-       if (!*output_encoding)
+       if (!output_encoding || !*output_encoding)
                return NULL;
        encoding = get_header(commit, "encoding");
        use_encoding = encoding ? encoding : utf8;
@@ -960,12 +960,19 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
        switch (placeholder[0]) {
        case 'C':
                if (placeholder[1] == '(') {
-                       const char *end = strchr(placeholder + 2, ')');
+                       const char *begin = placeholder + 2;
+                       const char *end = strchr(begin, ')');
                        char color[COLOR_MAXLEN];
+
                        if (!end)
                                return 0;
-                       color_parse_mem(placeholder + 2,
-                                       end - (placeholder + 2),
+                       if (!memcmp(begin, "auto,", 5)) {
+                               if (!want_color(c->pretty_ctx->color))
+                                       return end - placeholder + 1;
+                               begin += 5;
+                       }
+                       color_parse_mem(begin,
+                                       end - begin,
                                        "--pretty format", color);
                        strbuf_addstr(sb, color);
                        return end - placeholder + 1;
@@ -1250,23 +1257,15 @@ void format_commit_message(const struct commit *commit,
                           const struct pretty_print_context *pretty_ctx)
 {
        struct format_commit_context context;
-       static const char utf8[] = "UTF-8";
        const char *output_enc = pretty_ctx->output_encoding;
 
        memset(&context, 0, sizeof(context));
        context.commit = commit;
        context.pretty_ctx = pretty_ctx;
        context.wrap_start = sb->len;
-       context.message = commit->buffer;
-       if (output_enc) {
-               char *enc = get_header(commit, "encoding");
-               if (strcmp(enc ? enc : utf8, output_enc)) {
-                       context.message = logmsg_reencode(commit, output_enc);
-                       if (!context.message)
-                               context.message = commit->buffer;
-               }
-               free(enc);
-       }
+       context.message = logmsg_reencode(commit, output_enc);
+       if (!context.message)
+               context.message = commit->buffer;
 
        strbuf_expand(sb, format, format_commit_item, &context);
        rewrap_message_tail(sb, &context, 0, 0, 0);
diff --git a/refs.c b/refs.c
index 6cec1c8bdf70589a41c2ace4ba4f21f4035e4ed4..541fec20658082f13ef4b73b621787512b300ba6 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1744,7 +1744,8 @@ static struct lock_file packlock;
 static int repack_without_ref(const char *refname)
 {
        struct repack_without_ref_sb data;
-       struct ref_dir *packed = get_packed_refs(get_ref_cache(NULL));
+       struct ref_cache *refs = get_ref_cache(NULL);
+       struct ref_dir *packed = get_packed_refs(refs);
        if (find_ref(packed, refname) == NULL)
                return 0;
        data.refname = refname;
@@ -1753,6 +1754,8 @@ static int repack_without_ref(const char *refname)
                unable_to_lock_error(git_path("packed-refs"), errno);
                return error("cannot delete '%s' from packed refs", refname);
        }
+       clear_packed_ref_cache(refs);
+       packed = get_packed_refs(refs);
        do_for_each_ref_in_dir(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
        return commit_lock_file(&packlock);
 }
index 6aa49c03df13245486b20b04315437811b260882..4b1153f02c715ac0c441110bf5aa83aceb081aa0 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1279,12 +1279,34 @@ int match_push_refs(struct ref *src, struct ref **dst,
        return 0;
 }
 
+static inline int is_forwardable(struct ref* ref)
+{
+       struct object *o;
+
+       if (!prefixcmp(ref->name, "refs/tags/"))
+               return 0;
+
+       /* old object must be a commit */
+       o = parse_object(ref->old_sha1);
+       if (!o || o->type != OBJ_COMMIT)
+               return 0;
+
+       /* new object must be commit-ish */
+       o = deref_tag(parse_object(ref->new_sha1), NULL, 0);
+       if (!o || o->type != OBJ_COMMIT)
+               return 0;
+
+       return 1;
+}
+
 void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
        int force_update)
 {
        struct ref *ref;
 
        for (ref = remote_refs; ref; ref = ref->next) {
+               int force_ref_update = ref->force || force_update;
+
                if (ref->peer_ref)
                        hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
                else if (!send_mirror)
@@ -1297,34 +1319,55 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                        continue;
                }
 
-               /* This part determines what can overwrite what.
-                * The rules are:
+               /*
+                * The below logic determines whether an individual
+                * refspec A:B can be pushed.  The push will succeed
+                * if any of the following are true:
                 *
-                * (0) you can always use --force or +A:B notation to
-                *     selectively force individual ref pairs.
+                * (1) the remote reference B does not exist
                 *
-                * (1) if the old thing does not exist, it is OK.
+                * (2) the remote reference B is being removed (i.e.,
+                *     pushing :B where no source is specified)
                 *
-                * (2) if you do not have the old thing, you are not allowed
-                *     to overwrite it; you would not know what you are losing
-                *     otherwise.
+                * (3) the update meets all fast-forwarding criteria:
                 *
-                * (3) if both new and old are commit-ish, and new is a
-                *     descendant of old, it is OK.
+                *     (a) the destination is not under refs/tags/
+                *     (b) the old is a commit
+                *     (c) the new is a descendant of the old
                 *
-                * (4) regardless of all of the above, removing :B is
-                *     always allowed.
+                *     NOTE: We must actually have the old object in
+                *     order to overwrite it in the remote reference,
+                *     and the new object must be commit-ish.  These are
+                *     implied by (b) and (c) respectively.
+                *
+                * (4) it is forced using the +A:B notation, or by
+                *     passing the --force argument
                 */
 
-               ref->nonfastforward =
-                       !ref->deletion &&
-                       !is_null_sha1(ref->old_sha1) &&
-                       (!has_sha1_file(ref->old_sha1)
-                         || !ref_newer(ref->new_sha1, ref->old_sha1));
+               ref->not_forwardable = !is_forwardable(ref);
 
-               if (ref->nonfastforward && !ref->force && !force_update) {
-                       ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
-                       continue;
+               ref->update =
+                       !ref->deletion &&
+                       !is_null_sha1(ref->old_sha1);
+
+               if (ref->update) {
+                       ref->nonfastforward =
+                               !has_sha1_file(ref->old_sha1)
+                                 || !ref_newer(ref->new_sha1, ref->old_sha1);
+
+                       if (ref->not_forwardable) {
+                               ref->requires_force = 1;
+                               if (!force_ref_update) {
+                                       ref->status = REF_STATUS_REJECT_ALREADY_EXISTS;
+                                       continue;
+                               }
+                       } else if (ref->nonfastforward) {
+                               ref->requires_force = 1;
+                               if (!force_ref_update) {
+                                       ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
+                                       continue;
+                               }
+                       }
                }
        }
 }
@@ -1370,6 +1413,16 @@ int branch_merge_matches(struct branch *branch,
        return refname_match(branch->merge[i]->src, refname, ref_fetch_rules);
 }
 
+static int ignore_symref_update(const char *refname)
+{
+       unsigned char sha1[20];
+       int flag;
+
+       if (!resolve_ref_unsafe(refname, sha1, 0, &flag))
+               return 0; /* non-existing refs are OK */
+       return (flag & REF_ISSYMREF);
+}
+
 static struct ref *get_expanded_map(const struct ref *remote_refs,
                                    const struct refspec *refspec)
 {
@@ -1383,7 +1436,8 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
                if (strchr(ref->name, '^'))
                        continue; /* a dereference item */
                if (match_name_with_pattern(refspec->src, ref->name,
-                                           refspec->dst, &expn_name)) {
+                                           refspec->dst, &expn_name) &&
+                   !ignore_symref_update(expn_name)) {
                        struct ref *cpy = copy_ref(ref);
 
                        cpy->peer_ref = alloc_ref(expn_name);
index 3b982e4d55274ebe87c5751fa198bee53e371d9b..24eaad5c66c1742602347c42c71d279297aabc2a 100644 (file)
@@ -226,7 +226,7 @@ static inline void set_cloexec(int fd)
                fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
 }
 
-static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
+static int wait_or_whine(pid_t pid, const char *argv0)
 {
        int status, code = -1;
        pid_t waiting;
@@ -242,7 +242,8 @@ static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
                error("waitpid is confused (%s)", argv0);
        } else if (WIFSIGNALED(status)) {
                code = WTERMSIG(status);
-               error("%s died of signal %d", argv0, code);
+               if (code != SIGINT && code != SIGQUIT)
+                       error("%s died of signal %d", argv0, code);
                /*
                 * This return value is chosen so that code & 0xff
                 * mimics the exit code that a POSIX shell would report for
@@ -432,8 +433,7 @@ int start_command(struct child_process *cmd)
                 * At this point we know that fork() succeeded, but execvp()
                 * failed. Errors have been reported to our stderr.
                 */
-               wait_or_whine(cmd->pid, cmd->argv[0],
-                             cmd->silent_exec_failure);
+               wait_or_whine(cmd->pid, cmd->argv[0]);
                failed_errno = errno;
                cmd->pid = -1;
        }
@@ -538,7 +538,7 @@ int start_command(struct child_process *cmd)
 
 int finish_command(struct child_process *cmd)
 {
-       return wait_or_whine(cmd->pid, cmd->argv[0], cmd->silent_exec_failure);
+       return wait_or_whine(cmd->pid, cmd->argv[0]);
 }
 
 int run_command(struct child_process *cmd)
@@ -725,7 +725,7 @@ int start_async(struct async *async)
 int finish_async(struct async *async)
 {
 #ifdef NO_PTHREADS
-       return wait_or_whine(async->pid, "child process", 0);
+       return wait_or_whine(async->pid, "child process");
 #else
        void *ret = (void *)(intptr_t)(-1);
 
index f50dfd9f488821e6b052affb19c0048afd11109c..1c375f0a28c6417f1f6cb48afbde681f458c544d 100644 (file)
@@ -229,6 +229,7 @@ int send_pack(struct send_pack_args *args,
                /* Check for statuses set by set_ref_status_for_push() */
                switch (ref->status) {
                case REF_STATUS_REJECT_NONFASTFORWARD:
+               case REF_STATUS_REJECT_ALREADY_EXISTS:
                case REF_STATUS_UPTODATE:
                        continue;
                default:
diff --git a/setup.c b/setup.c
index 3a1b2fd45580cad7ecd55efa755872efc81075ad..f108c4b990c0e4f6a98c1fe34d3031040c84195a 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "dir.h"
+#include "string-list.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -620,6 +621,27 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
        return buf.st_dev;
 }
 
+/*
+ * A "string_list_each_func_t" function that canonicalizes an entry
+ * from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
+ * discards it if unusable.
+ */
+static int canonicalize_ceiling_entry(struct string_list_item *item,
+                                     void *unused)
+{
+       char *ceil = item->string;
+       const char *real_path;
+
+       if (!*ceil || !is_absolute_path(ceil))
+               return 0;
+       real_path = real_path_if_valid(ceil);
+       if (!real_path)
+               return 0;
+       free(item->string);
+       item->string = xstrdup(real_path);
+       return 1;
+}
+
 /*
  * We cannot decide in this function whether we are in the work tree or
  * not, since the config can only be read _after_ this function was called.
@@ -627,10 +649,11 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
 static const char *setup_git_directory_gently_1(int *nongit_ok)
 {
        const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
+       struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
        static char cwd[PATH_MAX+1];
        const char *gitdirenv, *ret;
        char *gitfile;
-       int len, offset, offset_parent, ceil_offset;
+       int len, offset, offset_parent, ceil_offset = -1;
        dev_t current_device = 0;
        int one_filesystem = 1;
 
@@ -655,7 +678,14 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
        if (gitdirenv)
                return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
 
-       ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
+       if (env_ceiling_dirs) {
+               string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
+               filter_string_list(&ceiling_dirs, 0,
+                                  canonicalize_ceiling_entry, NULL);
+               ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
+               string_list_clear(&ceiling_dirs, 0);
+       }
+
        if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
                ceil_offset = 1;
 
index 05d0693eba1eba4e2f21057388368c0890e668fe..9a373bef70b7fdd434c02d1ca753fcc8f799ecc2 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -425,6 +425,32 @@ void strbuf_add_lines(struct strbuf *out, const char *prefix,
        strbuf_complete_line(out);
 }
 
+void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
+{
+       while (*s) {
+               size_t len = strcspn(s, "\"<>&");
+               strbuf_add(buf, s, len);
+               s += len;
+               switch (*s) {
+               case '"':
+                       strbuf_addstr(buf, "&quot;");
+                       break;
+               case '<':
+                       strbuf_addstr(buf, "&lt;");
+                       break;
+               case '>':
+                       strbuf_addstr(buf, "&gt;");
+                       break;
+               case '&':
+                       strbuf_addstr(buf, "&amp;");
+                       break;
+               case 0:
+                       return;
+               }
+               s++;
+       }
+}
+
 static int is_rfc3986_reserved(char ch)
 {
        switch (ch) {
index aa386c6074ec0006acbd1067b561a9b2695e29f0..ecae4e215f6377702c2b33e78ca1a0e454ebd819 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -136,6 +136,12 @@ extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
 
 extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);
 
+/*
+ * Append s to sb, with the characters '<', '>', '&' and '"' converted
+ * into XML entities.
+ */
+extern void strbuf_addstr_xml_quoted(struct strbuf *sb, const char *s);
+
 static inline void strbuf_complete_line(struct strbuf *sb)
 {
        if (sb->len && sb->buf[sb->len - 1] != '\n')
index 397e6cfa7db82bdb17f7cdbe4662a1607c0773af..480173fe6dbee5428e3b135ff27ba7551c527ad8 100644 (file)
@@ -145,26 +145,6 @@ void string_list_remove_empty_items(struct string_list *list, int free_util) {
        filter_string_list(list, free_util, item_is_not_empty, NULL);
 }
 
-char *string_list_longest_prefix(const struct string_list *prefixes,
-                                const char *string)
-{
-       int i, max_len = -1;
-       char *retval = NULL;
-
-       for (i = 0; i < prefixes->nr; i++) {
-               char *prefix = prefixes->items[i].string;
-               if (!prefixcmp(string, prefix)) {
-                       int len = strlen(prefix);
-                       if (len > max_len) {
-                               retval = prefix;
-                               max_len = len;
-                       }
-               }
-       }
-
-       return retval;
-}
-
 void string_list_clear(struct string_list *list, int free_util)
 {
        if (list->items) {
index c50b0d0deac086cd5a50a5c021103a5f5e76c1cd..db1284861adb707b675714edc1ecacf9357f6661 100644 (file)
@@ -45,15 +45,6 @@ void filter_string_list(struct string_list *list, int free_util,
  */
 void string_list_remove_empty_items(struct string_list *list, int free_util);
 
-/*
- * Return the longest string in prefixes that is a prefix (in the
- * sense of prefixcmp()) of string, or NULL if no such prefix exists.
- * This function does not require the string_list to be sorted (it
- * does a linear search).
- */
-char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);
-
-
 /* Use these functions only on sorted lists: */
 int string_list_has_string(const struct string_list *list, const char *string);
 int string_list_find_insert_index(const struct string_list *list, const char *string,
index 562cf41cad7b0532ab4a15625950720c71549742..cefe33d6d1976e4017569507a6f76ad89c83e4ff 100755 (executable)
@@ -45,39 +45,176 @@ test_expect_failure 'pretend we have a known breakage' '
        false
 '
 
-test_expect_success 'pretend we have fixed a known breakage (run in sub test-lib)' "
-       mkdir passing-todo &&
-       (cd passing-todo &&
-       cat >passing-todo.sh <<-EOF &&
-       #!$SHELL_PATH
-
-       test_description='A passing TODO test
+run_sub_test_lib_test () {
+       name="$1" descr="$2" # stdin is the body of the test code
+       mkdir "$name" &&
+       (
+               cd "$name" &&
+               cat >"$name.sh" <<-EOF &&
+               #!$SHELL_PATH
+
+               test_description='$descr (run in sub test-lib)
+
+               This is run in a sub test-lib so that we do not get incorrect
+               passing metrics
+               '
+
+               # Point to the t/test-lib.sh, which isn't in ../ as usual
+               . "\$TEST_DIRECTORY"/test-lib.sh
+               EOF
+               cat >>"$name.sh" &&
+               chmod +x "$name.sh" &&
+               export TEST_DIRECTORY &&
+               ./"$name.sh" >out 2>err
+       )
+}
 
-       This is run in a sub test-lib so that we do not get incorrect
-       passing metrics
-       '
+check_sub_test_lib_test () {
+       name="$1" # stdin is the expected output from the test
+       (
+               cd "$name" &&
+               ! test -s err &&
+               sed -e 's/^> //' -e 's/Z$//' >expect &&
+               test_cmp expect out
+       )
+}
+
+test_expect_success 'pretend we have a fully passing test suite' "
+       run_sub_test_lib_test full-pass '3 passing tests' <<-\\EOF &&
+       for i in 1 2 3
+       do
+               test_expect_success \"passing test #\$i\" 'true'
+       done
+       test_done
+       EOF
+       check_sub_test_lib_test full-pass <<-\\EOF
+       > ok 1 - passing test #1
+       > ok 2 - passing test #2
+       > ok 3 - passing test #3
+       > # passed all 3 test(s)
+       > 1..3
+       EOF
+"
 
-       # Point to the t/test-lib.sh, which isn't in ../ as usual
-       TEST_DIRECTORY=\"$TEST_DIRECTORY\"
-       . \"\$TEST_DIRECTORY\"/test-lib.sh
+test_expect_success 'pretend we have a partially passing test suite' "
+       test_must_fail run_sub_test_lib_test \
+               partial-pass '2/3 tests passing' <<-\\EOF &&
+       test_expect_success 'passing test #1' 'true'
+       test_expect_success 'failing test #2' 'false'
+       test_expect_success 'passing test #3' 'true'
+       test_done
+       EOF
+       check_sub_test_lib_test partial-pass <<-\\EOF
+       > ok 1 - passing test #1
+       > not ok 2 - failing test #2
+       #       false
+       > ok 3 - passing test #3
+       > # failed 1 among 3 test(s)
+       > 1..3
+       EOF
+"
 
-       test_expect_failure 'pretend we have fixed a known breakage' '
-               :
-       '
+test_expect_success 'pretend we have a known breakage' "
+       run_sub_test_lib_test failing-todo 'A failing TODO test' <<-\\EOF &&
+       test_expect_success 'passing test' 'true'
+       test_expect_failure 'pretend we have a known breakage' 'false'
+       test_done
+       EOF
+       check_sub_test_lib_test failing-todo <<-\\EOF
+       > ok 1 - passing test
+       > not ok 2 - pretend we have a known breakage # TODO known breakage
+       > # still have 1 known breakage(s)
+       > # passed all remaining 1 test(s)
+       > 1..2
+       EOF
+"
 
+test_expect_success 'pretend we have fixed a known breakage' "
+       run_sub_test_lib_test passing-todo 'A passing TODO test' <<-\\EOF &&
+       test_expect_failure 'pretend we have fixed a known breakage' 'true'
        test_done
        EOF
-       chmod +x passing-todo.sh &&
-       ./passing-todo.sh >out 2>err &&
-       ! test -s err &&
-       sed -e 's/^> //' >expect <<-\\EOF &&
-       > ok 1 - pretend we have fixed a known breakage # TODO known breakage
-       > # fixed 1 known breakage(s)
-       > # passed all 1 test(s)
+       check_sub_test_lib_test passing-todo <<-\\EOF
+       > ok 1 - pretend we have fixed a known breakage # TODO known breakage vanished
+       > # 1 known breakage(s) vanished; please update test(s)
        > 1..1
        EOF
-       test_cmp expect out)
 "
+
+test_expect_success 'pretend we have fixed one of two known breakages (run in sub test-lib)' "
+       run_sub_test_lib_test partially-passing-todos \
+               '2 TODO tests, one passing' <<-\\EOF &&
+       test_expect_failure 'pretend we have a known breakage' 'false'
+       test_expect_success 'pretend we have a passing test' 'true'
+       test_expect_failure 'pretend we have fixed another known breakage' 'true'
+       test_done
+       EOF
+       check_sub_test_lib_test partially-passing-todos <<-\\EOF
+       > not ok 1 - pretend we have a known breakage # TODO known breakage
+       > ok 2 - pretend we have a passing test
+       > ok 3 - pretend we have fixed another known breakage # TODO known breakage vanished
+       > # 1 known breakage(s) vanished; please update test(s)
+       > # still have 1 known breakage(s)
+       > # passed all remaining 1 test(s)
+       > 1..3
+       EOF
+"
+
+test_expect_success 'pretend we have a pass, fail, and known breakage' "
+       test_must_fail run_sub_test_lib_test \
+               mixed-results1 'mixed results #1' <<-\\EOF &&
+       test_expect_success 'passing test' 'true'
+       test_expect_success 'failing test' 'false'
+       test_expect_failure 'pretend we have a known breakage' 'false'
+       test_done
+       EOF
+       check_sub_test_lib_test mixed-results1 <<-\\EOF
+       > ok 1 - passing test
+       > not ok 2 - failing test
+       > #     false
+       > not ok 3 - pretend we have a known breakage # TODO known breakage
+       > # still have 1 known breakage(s)
+       > # failed 1 among remaining 2 test(s)
+       > 1..3
+       EOF
+"
+
+test_expect_success 'pretend we have a mix of all possible results' "
+       test_must_fail run_sub_test_lib_test \
+               mixed-results2 'mixed results #2' <<-\\EOF &&
+       test_expect_success 'passing test' 'true'
+       test_expect_success 'passing test' 'true'
+       test_expect_success 'passing test' 'true'
+       test_expect_success 'passing test' 'true'
+       test_expect_success 'failing test' 'false'
+       test_expect_success 'failing test' 'false'
+       test_expect_success 'failing test' 'false'
+       test_expect_failure 'pretend we have a known breakage' 'false'
+       test_expect_failure 'pretend we have a known breakage' 'false'
+       test_expect_failure 'pretend we have fixed a known breakage' 'true'
+       test_done
+       EOF
+       check_sub_test_lib_test mixed-results2 <<-\\EOF
+       > ok 1 - passing test
+       > ok 2 - passing test
+       > ok 3 - passing test
+       > ok 4 - passing test
+       > not ok 5 - failing test
+       > #     false
+       > not ok 6 - failing test
+       > #     false
+       > not ok 7 - failing test
+       > #     false
+       > not ok 8 - pretend we have a known breakage # TODO known breakage
+       > not ok 9 - pretend we have a known breakage # TODO known breakage
+       > ok 10 - pretend we have fixed a known breakage # TODO known breakage vanished
+       > # 1 known breakage(s) vanished; please update test(s)
+       > # still have 2 known breakage(s)
+       > # failed 3 among remaining 7 test(s)
+       > 1..10
+       EOF
+"
+
 test_set_prereq HAVEIT
 haveit=no
 test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
@@ -159,19 +296,8 @@ then
 fi
 
 test_expect_success 'tests clean up even on failures' "
-       mkdir failing-cleanup &&
-       (
-       cd failing-cleanup &&
-
-       cat >failing-cleanup.sh <<-EOF &&
-       #!$SHELL_PATH
-
-       test_description='Failing tests with cleanup commands'
-
-       # Point to the t/test-lib.sh, which isn't in ../ as usual
-       TEST_DIRECTORY=\"$TEST_DIRECTORY\"
-       . \"\$TEST_DIRECTORY\"/test-lib.sh
-
+       test_must_fail run_sub_test_lib_test \
+               failing-cleanup 'Failing tests with cleanup commands' <<-\\EOF &&
        test_expect_success 'tests clean up even after a failure' '
                touch clean-after-failure &&
                test_when_finished rm clean-after-failure &&
@@ -181,29 +307,21 @@ test_expect_success 'tests clean up even on failures' "
                test_when_finished \"(exit 2)\"
        '
        test_done
-
        EOF
-
-       chmod +x failing-cleanup.sh &&
-       test_must_fail ./failing-cleanup.sh >out 2>err &&
-       ! test -s err &&
-       ! test -f \"trash directory.failing-cleanup/clean-after-failure\" &&
-       sed -e 's/Z$//' -e 's/^> //' >expect <<-\\EOF &&
-       > not ok - 1 tests clean up even after a failure
+       check_sub_test_lib_test failing-cleanup <<-\\EOF
+       > not ok 1 - tests clean up even after a failure
        > #     Z
        > #     touch clean-after-failure &&
        > #     test_when_finished rm clean-after-failure &&
        > #     (exit 1)
        > #     Z
-       > not ok - 2 failure to clean up causes the test to fail
+       > not ok 2 - failure to clean up causes the test to fail
        > #     Z
        > #     test_when_finished \"(exit 2)\"
        > #     Z
        > # failed 2 among 2 test(s)
        > 1..2
        EOF
-       test_cmp expect out
-       )
 "
 
 ################################################################
index 4ef2345982fe0e0c175ed67edcb20b04c81b9680..09a42a428e1d286c5ab9e1003d49481ef6df3e44 100755 (executable)
@@ -93,47 +93,32 @@ norm_path /d1/s1//../s2/../../d2 /d2 POSIX
 norm_path /d1/.../d2 /d1/.../d2 POSIX
 norm_path /d1/..././../d2 /d1/d2 POSIX
 
-ancestor / "" -1
 ancestor / / -1
-ancestor /foo "" -1
-ancestor /foo : -1
-ancestor /foo ::. -1
-ancestor /foo ::..:: -1
 ancestor /foo / 0
 ancestor /foo /fo -1
 ancestor /foo /foo -1
-ancestor /foo /foo/ -1
 ancestor /foo /bar -1
-ancestor /foo /bar/ -1
 ancestor /foo /foo/bar -1
-ancestor /foo /foo:/bar/ -1
-ancestor /foo /foo/:/bar/ -1
-ancestor /foo /foo::/bar/ -1
-ancestor /foo /:/foo:/bar/ 0
-ancestor /foo /foo:/:/bar/ 0
-ancestor /foo /:/bar/:/foo 0
-ancestor /foo/bar "" -1
+ancestor /foo /foo:/bar -1
+ancestor /foo /:/foo:/bar 0
+ancestor /foo /foo:/:/bar 0
+ancestor /foo /:/bar:/foo 0
 ancestor /foo/bar / 0
 ancestor /foo/bar /fo -1
-ancestor /foo/bar foo -1
 ancestor /foo/bar /foo 4
-ancestor /foo/bar /foo/ 4
 ancestor /foo/bar /foo/ba -1
 ancestor /foo/bar /:/fo 0
 ancestor /foo/bar /foo:/foo/ba 4
 ancestor /foo/bar /bar -1
-ancestor /foo/bar /bar/ -1
-ancestor /foo/bar /fo: -1
-ancestor /foo/bar :/fo -1
-ancestor /foo/bar /foo:/bar/ 4
-ancestor /foo/bar /:/foo:/bar/ 4
-ancestor /foo/bar /foo:/:/bar/ 4
-ancestor /foo/bar /:/bar/:/fo 0
-ancestor /foo/bar /:/bar/ 0
-ancestor /foo/bar .:/foo/. 4
-ancestor /foo/bar .:/foo/.:.: 4
-ancestor /foo/bar /foo/./:.:/bar 4
-ancestor /foo/bar .:/bar -1
+ancestor /foo/bar /fo -1
+ancestor /foo/bar /foo:/bar 4
+ancestor /foo/bar /:/foo:/bar 4
+ancestor /foo/bar /foo:/:/bar 4
+ancestor /foo/bar /:/bar:/fo 0
+ancestor /foo/bar /:/bar 0
+ancestor /foo/bar /foo 4
+ancestor /foo/bar /foo:/bar 4
+ancestor /foo/bar /bar -1
 
 test_expect_success 'strip_path_suffix' '
        test c:/msysgit = $(test-path-utils strip_path_suffix \
index 41c8826a74db9a5c34ad3365f4875f6317a5bca0..dbfc05ebdc3990bf4ea5b0163afb4c6a9e698fa7 100755 (executable)
@@ -17,14 +17,6 @@ test_split () {
        "
 }
 
-test_longest_prefix () {
-       test "$(test-string-list longest_prefix "$1" "$2")" = "$3"
-}
-
-test_no_longest_prefix () {
-       test_must_fail test-string-list longest_prefix "$1" "$2"
-}
-
 test_split "foo:bar:baz" ":" "-1" <<EOF
 3
 [0]: "foo"
@@ -96,26 +88,4 @@ test_expect_success "test remove_duplicates" '
        test a:b:c = "$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)"
 '
 
-test_expect_success "test longest_prefix" '
-       test_no_longest_prefix - '' &&
-       test_no_longest_prefix - x &&
-       test_longest_prefix "" x "" &&
-       test_longest_prefix x x x &&
-       test_longest_prefix "" foo "" &&
-       test_longest_prefix : foo "" &&
-       test_longest_prefix f foo f &&
-       test_longest_prefix foo foobar foo &&
-       test_longest_prefix foo foo foo &&
-       test_no_longest_prefix bar foo &&
-       test_no_longest_prefix bar:bar foo &&
-       test_no_longest_prefix foobar foo &&
-       test_longest_prefix foo:bar foo foo &&
-       test_longest_prefix foo:bar bar bar &&
-       test_longest_prefix foo::bar foo foo &&
-       test_longest_prefix foo:foobar foo foo &&
-       test_longest_prefix foobar:foo foo foo &&
-       test_longest_prefix foo: bar "" &&
-       test_longest_prefix :foo bar ""
-'
-
 test_done
index e23ac0e69da8d3dba32f0d256a249a987356e825..1e2945ec7e397cf6b2e3b00bee0ca1df40a0e6a9 100755 (executable)
@@ -111,19 +111,19 @@ test_expect_success 'read-tree' '
 
 test_expect_success 'alias expansion' '
        (
-               git config alias.ss status &&
+               git config alias.test-status-alias status &&
                cd dir &&
                git status &&
-               git ss
+               git test-status-alias
        )
 '
 
 test_expect_success NOT_MINGW '!alias expansion' '
        pwd >expect &&
        (
-               git config alias.test !pwd &&
+               git config alias.test-alias-directory !pwd &&
                cd dir &&
-               git test >../actual
+               git test-alias-directory >../actual
        ) &&
        test_cmp expect actual
 '
@@ -131,9 +131,9 @@ test_expect_success NOT_MINGW '!alias expansion' '
 test_expect_success 'GIT_PREFIX for !alias' '
        printf "dir/" >expect &&
        (
-               git config alias.test "!sh -c \"printf \$GIT_PREFIX\"" &&
+               git config alias.test-alias-directory "!sh -c \"printf \$GIT_PREFIX\"" &&
                cd dir &&
-               git test >../actual
+               git test-alias-directory >../actual
        ) &&
        test_cmp expect actual
 '
index 08aa24ca15a377826b9e1cdad73fb232853aea7f..d730734fde8e4de69fdf2662915bc67342198fc8 100755 (executable)
@@ -237,4 +237,35 @@ test_expect_success 'fsck notices submodule entry pointing to null sha1' '
        )
 '
 
+test_expect_success 'fsck notices "." and ".." in trees' '
+       (
+               git init dots &&
+               cd dots &&
+               blob=$(echo foo | git hash-object -w --stdin) &&
+               tab=$(printf "\\t") &&
+               git mktree <<-EOF &&
+               100644 blob $blob$tab.
+               100644 blob $blob$tab..
+               EOF
+               git fsck 2>out &&
+               cat out &&
+               grep "warning.*\\." out
+       )
+'
+
+test_expect_success 'fsck notices ".git" in trees' '
+       (
+               git init dotgit &&
+               cd dotgit &&
+               blob=$(echo foo | git hash-object -w --stdin) &&
+               tab=$(printf "\\t") &&
+               git mktree <<-EOF &&
+               100644 blob $blob$tab.git
+               EOF
+               git fsck 2>out &&
+               cat out &&
+               grep "warning.*\\.git" out
+       )
+'
+
 test_done
index ec35409f9cbe9bcdd3d21a6a5a15996b165d2fff..2a4a749b4fa3b07963a18b645d29ef774c01bbd1 100755 (executable)
@@ -62,5 +62,25 @@ test_expect_success 'can "commit -a" with an i-t-a entry' '
        git commit -a -m all
 '
 
+test_expect_success 'cache-tree invalidates i-t-a paths' '
+       git reset --hard &&
+       mkdir dir &&
+       : >dir/foo &&
+       git add dir/foo &&
+       git commit -m foo &&
+
+       : >dir/bar &&
+       git add -N dir/bar &&
+       git diff --cached --name-only >actual &&
+       echo dir/bar >expect &&
+       test_cmp expect actual &&
+
+       git write-tree >/dev/null &&
+
+       git diff --cached --name-only >actual &&
+       echo dir/bar >expect &&
+       test_cmp expect actual
+'
+
 test_done
 
index 6872ba1a42ce289c0983b1ed62f05defb493bf49..5493500ef15d2f561bd14ca0bdf5f519ec6f49be 100755 (executable)
@@ -120,6 +120,30 @@ test_expect_success 'shortlog from non-git directory' '
        test_cmp expect out
 '
 
+test_expect_success 'shortlog should add newline when input line matches wraplen' '
+       cat >expect <<\EOF &&
+A U Thor (2):
+      bbbbbbbbbbbbbbbbbb: bbbbbbbb bbb bbbb bbbbbbb bb bbbb bbb bbbbb bbbbbb
+      aaaaaaaaaaaaaaaaaaaaaa: aaaaaa aaaaaaaaaa aaaa aaaaaaaa aa aaaa aa aaa
+
+EOF
+       git shortlog -w >out <<\EOF &&
+commit 0000000000000000000000000000000000000001
+Author: A U Thor <author@example.com>
+Date:   Thu Apr 7 15:14:13 2005 -0700
+
+    aaaaaaaaaaaaaaaaaaaaaa: aaaaaa aaaaaaaaaa aaaa aaaaaaaa aa aaaa aa aaa
+
+commit 0000000000000000000000000000000000000002
+Author: A U Thor <author@example.com>
+Date:   Thu Apr 7 15:14:13 2005 -0700
+
+    bbbbbbbbbbbbbbbbbb: bbbbbbbb bbb bbbb bbbbbbb bb bbbb bbb bbbbb bbbbbb
+
+EOF
+       test_cmp expect out
+'
+
 iconvfromutf8toiso88591() {
        printf "%s" "$*" | iconv -f UTF-8 -t ISO8859-1
 }
index a343bf6c629f8e6acaf7559d3168a97fcce9d286..fa686b887d6b49ab8e6d30893501744645f72a91 100755 (executable)
@@ -280,6 +280,16 @@ test_expect_success 'log --graph with merge' '
        test_cmp expect actual
 '
 
+test_expect_success 'log --raw --graph -m with merge' '
+       git log --raw --graph --oneline -m master | head -n 500 >actual &&
+       grep "initial" actual
+'
+
+test_expect_success 'diff-tree --graph' '
+       git diff-tree --graph master^ | head -n 500 >actual &&
+       grep "one" actual
+'
+
 cat > expect <<\EOF
 *   commit master
 |\  Merge: A B
index 1f182f612c7e2376b503cf0b9cf7389e37903239..aae30d97b1a0b95f9cae5c2659f77cf2cb9c3947 100755 (executable)
@@ -149,6 +149,104 @@ test_expect_success 'No mailmap files, but configured' '
        test_cmp expect actual
 '
 
+test_expect_success 'setup mailmap blob tests' '
+       git checkout -b map &&
+       test_when_finished "git checkout master" &&
+       cat >just-bugs <<-\EOF &&
+       Blob Guy <bugs@company.xx>
+       EOF
+       cat >both <<-\EOF &&
+       Blob Guy <author@example.com>
+       Blob Guy <bugs@company.xx>
+       EOF
+       git add just-bugs both &&
+       git commit -m "my mailmaps" &&
+       echo "Repo Guy <author@example.com>" >.mailmap &&
+       echo "Internal Guy <author@example.com>" >internal.map
+'
+
+test_expect_success 'mailmap.blob set' '
+       cat >expect <<-\EOF &&
+       Blob Guy (1):
+             second
+
+       Repo Guy (1):
+             initial
+
+       EOF
+       git -c mailmap.blob=map:just-bugs shortlog HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'mailmap.blob overrides .mailmap' '
+       cat >expect <<-\EOF &&
+       Blob Guy (2):
+             initial
+             second
+
+       EOF
+       git -c mailmap.blob=map:both shortlog HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'mailmap.file overrides mailmap.blob' '
+       cat >expect <<-\EOF &&
+       Blob Guy (1):
+             second
+
+       Internal Guy (1):
+             initial
+
+       EOF
+       git \
+         -c mailmap.blob=map:both \
+         -c mailmap.file=internal.map \
+         shortlog HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'mailmap.blob can be missing' '
+       cat >expect <<-\EOF &&
+       Repo Guy (1):
+             initial
+
+       nick1 (1):
+             second
+
+       EOF
+       git -c mailmap.blob=map:nonexistent shortlog HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'mailmap.blob defaults to off in non-bare repo' '
+       git init non-bare &&
+       (
+               cd non-bare &&
+               test_commit one .mailmap "Fake Name <author@example.com>" &&
+               echo "     1    Fake Name" >expect &&
+               git shortlog -ns HEAD >actual &&
+               test_cmp expect actual &&
+               rm .mailmap &&
+               echo "     1    A U Thor" >expect &&
+               git shortlog -ns HEAD >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'mailmap.blob defaults to HEAD:.mailmap in bare repo' '
+       git clone --bare non-bare bare &&
+       (
+               cd bare &&
+               echo "     1    Fake Name" >expect &&
+               git shortlog -ns HEAD >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'cleanup after mailmap.blob tests' '
+       rm -f .mailmap
+'
+
 # Extended mailmap configurations should give us the following output for shortlog
 cat >expect <<\EOF
 A U Thor <author@example.com> (1):
diff --git a/t/t5002-archive-attr-pattern.sh b/t/t5002-archive-attr-pattern.sh
new file mode 100755 (executable)
index 0000000..0c847fb
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='git archive attribute pattern tests'
+
+. ./test-lib.sh
+
+test_expect_exists() {
+       test_expect_success " $1 exists" "test -e $1"
+}
+
+test_expect_missing() {
+       test_expect_success " $1 does not exist" "test ! -e $1"
+}
+
+test_expect_success 'setup' '
+       echo ignored >ignored &&
+       echo ignored export-ignore >>.git/info/attributes &&
+       git add ignored &&
+
+       mkdir not-ignored-dir &&
+       echo ignored-in-tree >not-ignored-dir/ignored &&
+       echo not-ignored-in-tree >not-ignored-dir/ignored-only-if-dir &&
+       git add not-ignored-dir &&
+
+       mkdir ignored-only-if-dir &&
+       echo ignored by ignored dir >ignored-only-if-dir/ignored-by-ignored-dir &&
+       echo ignored-only-if-dir/ export-ignore >>.git/info/attributes &&
+       git add ignored-only-if-dir &&
+
+
+       mkdir -p one-level-lower/two-levels-lower/ignored-only-if-dir &&
+       echo ignored by ignored dir >one-level-lower/two-levels-lower/ignored-only-if-dir/ignored-by-ignored-dir &&
+       git add one-level-lower &&
+
+       git commit -m. &&
+
+       git clone --bare . bare &&
+       cp .git/info/attributes bare/info/attributes
+'
+
+test_expect_success 'git archive' '
+       git archive HEAD >archive.tar &&
+       (mkdir archive && cd archive && "$TAR" xf -) <archive.tar
+'
+
+test_expect_missing    archive/ignored
+test_expect_missing    archive/not-ignored-dir/ignored
+test_expect_exists     archive/not-ignored-dir/ignored-only-if-dir
+test_expect_exists     archive/not-ignored-dir/
+test_expect_missing    archive/ignored-only-if-dir/
+test_expect_missing    archive/ignored-ony-if-dir/ignored-by-ignored-dir
+test_expect_exists     archive/one-level-lower/
+test_expect_missing    archive/one-level-lower/two-levels-lower/ignored-only-if-dir/
+test_expect_missing    archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir
+
+
+test_done
index b5417cc951b1cecbbde613fa572387f362e889d1..60093728fecd626ae5e005c4d41cee330ac1112c 100755 (executable)
@@ -368,7 +368,7 @@ test_expect_success 'push with colon-less refspec (2)' '
                git branch -D frotz
        fi &&
        git tag -f frotz &&
-       git push testrepo frotz &&
+       git push -f testrepo frotz &&
        check_push_result $the_commit tags/frotz &&
        check_push_result $the_first_commit heads/frotz
 
@@ -929,6 +929,48 @@ test_expect_success 'push into aliased refs (inconsistent)' '
        )
 '
 
+test_expect_success 'push requires --force to update lightweight tag' '
+       mk_test heads/master &&
+       mk_child child1 &&
+       mk_child child2 &&
+       (
+               cd child1 &&
+               git tag Tag &&
+               git push ../child2 Tag &&
+               git push ../child2 Tag &&
+               >file1 &&
+               git add file1 &&
+               git commit -m "file1" &&
+               git tag -f Tag &&
+               test_must_fail git push ../child2 Tag &&
+               git push --force ../child2 Tag &&
+               git tag -f Tag &&
+               test_must_fail git push ../child2 Tag HEAD~ &&
+               git push --force ../child2 Tag
+       )
+'
+
+test_expect_success 'push requires --force to update annotated tag' '
+       mk_test heads/master &&
+       mk_child child1 &&
+       mk_child child2 &&
+       (
+               cd child1 &&
+               git tag -a -m "message 1" Tag &&
+               git push ../child2 Tag:refs/tmp/Tag &&
+               git push ../child2 Tag:refs/tmp/Tag &&
+               >file1 &&
+               git add file1 &&
+               git commit -m "file1" &&
+               git tag -f -a -m "message 2" Tag &&
+               test_must_fail git push ../child2 Tag:refs/tmp/Tag &&
+               git push --force ../child2 Tag:refs/tmp/Tag &&
+               git tag -f -a -m "message 3" Tag HEAD~ &&
+               test_must_fail git push ../child2 Tag:refs/tmp/Tag &&
+               git push --force ../child2 Tag:refs/tmp/Tag
+       )
+'
+
 test_expect_success 'push --porcelain' '
        mk_empty &&
        echo >.git/foo  "To testrepo" &&
diff --git a/t/t5535-fetch-push-symref.sh b/t/t5535-fetch-push-symref.sh
new file mode 100755 (executable)
index 0000000..8ed58d2
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+test_description='avoiding conflicting update thru symref aliasing'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit one &&
+       git clone . src &&
+       git clone src dst1 &&
+       git clone src dst2 &&
+       test_commit two &&
+       ( cd src && git pull )
+'
+
+test_expect_success 'push' '
+       (
+               cd src &&
+               git push ../dst1 "refs/remotes/*:refs/remotes/*"
+       ) &&
+       git ls-remote src "refs/remotes/*" >expect &&
+       git ls-remote dst1 "refs/remotes/*" >actual &&
+       test_cmp expect actual &&
+       ( cd src && git symbolic-ref refs/remotes/origin/HEAD ) >expect &&
+       ( cd dst1 && git symbolic-ref refs/remotes/origin/HEAD ) >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'fetch' '
+       (
+               cd dst2 &&
+               git fetch ../src "refs/remotes/*:refs/remotes/*"
+       ) &&
+       git ls-remote src "refs/remotes/*" >expect &&
+       git ls-remote dst2 "refs/remotes/*" >actual &&
+       test_cmp expect actual &&
+       ( cd src && git symbolic-ref refs/remotes/origin/HEAD ) >expect &&
+       ( cd dst2 && git symbolic-ref refs/remotes/origin/HEAD ) >actual &&
+       test_cmp expect actual
+'
+
+test_done
diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
deleted file mode 100755 (executable)
index e7dc668..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2010 Sverre Rabbelier
-#
-
-test_description='Test remote-helper import and export commands'
-
-. ./test-lib.sh
-
-if ! test_have_prereq PYTHON ; then
-       skip_all='skipping git-remote-hg tests, python not available'
-       test_done
-fi
-
-"$PYTHON_PATH" -c '
-import sys
-if sys.hexversion < 0x02040000:
-    sys.exit(1)
-' || {
-       skip_all='skipping git-remote-hg tests, python version < 2.4'
-       test_done
-}
-
-compare_refs() {
-       git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
-       git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
-       test_cmp expect actual
-}
-
-test_expect_success 'setup repository' '
-       git init --bare server/.git &&
-       git clone server public &&
-       (cd public &&
-        echo content >file &&
-        git add file &&
-        git commit -m one &&
-        git push origin master)
-'
-
-test_expect_success 'cloning from local repo' '
-       git clone "testgit::${PWD}/server" localclone &&
-       test_cmp public/file localclone/file
-'
-
-test_expect_success 'cloning from remote repo' '
-       git clone "testgit::file://${PWD}/server" clone &&
-       test_cmp public/file clone/file
-'
-
-test_expect_success 'create new commit on remote' '
-       (cd public &&
-        echo content >>file &&
-        git commit -a -m two &&
-        git push)
-'
-
-test_expect_success 'pulling from local repo' '
-       (cd localclone && git pull) &&
-       test_cmp public/file localclone/file
-'
-
-test_expect_success 'pulling from remote remote' '
-       (cd clone && git pull) &&
-       test_cmp public/file clone/file
-'
-
-test_expect_success 'pushing to local repo' '
-       (cd localclone &&
-       echo content >>file &&
-       git commit -a -m three &&
-       git push) &&
-       compare_refs localclone HEAD server HEAD
-'
-
-# Generally, skip this test.  It demonstrates a now-fixed race in
-# git-remote-testgit, but is too slow to leave in for general use.
-: test_expect_success 'racily pushing to local repo' '
-       test_when_finished "rm -rf server2 localclone2" &&
-       cp -R server server2 &&
-       git clone "testgit::${PWD}/server2" localclone2 &&
-       (cd localclone2 &&
-       echo content >>file &&
-       git commit -a -m three &&
-       GIT_REMOTE_TESTGIT_SLEEPY=2 git push) &&
-       compare_refs localclone2 HEAD server2 HEAD
-'
-
-test_expect_success 'synch with changes from localclone' '
-       (cd clone &&
-        git pull)
-'
-
-test_expect_success 'pushing remote local repo' '
-       (cd clone &&
-       echo content >>file &&
-       git commit -a -m four &&
-       git push) &&
-       compare_refs clone HEAD server HEAD
-'
-
-test_expect_success 'fetch new branch' '
-       (cd public &&
-        git checkout -b new &&
-        echo content >>file &&
-        git commit -a -m five &&
-        git push origin new
-       ) &&
-       (cd localclone &&
-        git fetch origin new
-       ) &&
-       compare_refs public HEAD localclone FETCH_HEAD
-'
-
-test_expect_success 'fetch multiple branches' '
-       (cd localclone &&
-        git fetch
-       ) &&
-       compare_refs server master localclone refs/remotes/origin/master &&
-       compare_refs server new localclone refs/remotes/origin/new
-'
-
-test_expect_success 'push when remote has extra refs' '
-       (cd clone &&
-        echo content >>file &&
-        git commit -a -m six &&
-        git push
-       ) &&
-       compare_refs clone master server master
-'
-
-test_expect_success 'push new branch by name' '
-       (cd clone &&
-        git checkout -b new-name  &&
-        echo content >>file &&
-        git commit -a -m seven &&
-        git push origin new-name
-       ) &&
-       compare_refs clone HEAD server refs/heads/new-name
-'
-
-test_expect_failure 'push new branch with old:new refspec' '
-       (cd clone &&
-        git push origin new-name:new-refspec
-       ) &&
-       compare_refs clone HEAD server refs/heads/new-refspec
-'
-
-test_done
diff --git a/t/t5800-remote-testpy.sh b/t/t5800-remote-testpy.sh
new file mode 100755 (executable)
index 0000000..6750961
--- /dev/null
@@ -0,0 +1,148 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Sverre Rabbelier
+#
+
+test_description='Test python remote-helper framework'
+
+. ./test-lib.sh
+
+if ! test_have_prereq PYTHON ; then
+       skip_all='skipping python remote-helper tests, python not available'
+       test_done
+fi
+
+"$PYTHON_PATH" -c '
+import sys
+if sys.hexversion < 0x02040000:
+    sys.exit(1)
+' || {
+       skip_all='skipping python remote-helper tests, python version < 2.4'
+       test_done
+}
+
+compare_refs() {
+       git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
+       git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'setup repository' '
+       git init --bare server/.git &&
+       git clone server public &&
+       (cd public &&
+        echo content >file &&
+        git add file &&
+        git commit -m one &&
+        git push origin master)
+'
+
+test_expect_success 'cloning from local repo' '
+       git clone "testpy::${PWD}/server" localclone &&
+       test_cmp public/file localclone/file
+'
+
+test_expect_success 'cloning from remote repo' '
+       git clone "testpy::file://${PWD}/server" clone &&
+       test_cmp public/file clone/file
+'
+
+test_expect_success 'create new commit on remote' '
+       (cd public &&
+        echo content >>file &&
+        git commit -a -m two &&
+        git push)
+'
+
+test_expect_success 'pulling from local repo' '
+       (cd localclone && git pull) &&
+       test_cmp public/file localclone/file
+'
+
+test_expect_success 'pulling from remote remote' '
+       (cd clone && git pull) &&
+       test_cmp public/file clone/file
+'
+
+test_expect_success 'pushing to local repo' '
+       (cd localclone &&
+       echo content >>file &&
+       git commit -a -m three &&
+       git push) &&
+       compare_refs localclone HEAD server HEAD
+'
+
+# Generally, skip this test.  It demonstrates a now-fixed race in
+# git-remote-testpy, but is too slow to leave in for general use.
+: test_expect_success 'racily pushing to local repo' '
+       test_when_finished "rm -rf server2 localclone2" &&
+       cp -R server server2 &&
+       git clone "testpy::${PWD}/server2" localclone2 &&
+       (cd localclone2 &&
+       echo content >>file &&
+       git commit -a -m three &&
+       GIT_REMOTE_TESTGIT_SLEEPY=2 git push) &&
+       compare_refs localclone2 HEAD server2 HEAD
+'
+
+test_expect_success 'synch with changes from localclone' '
+       (cd clone &&
+        git pull)
+'
+
+test_expect_success 'pushing remote local repo' '
+       (cd clone &&
+       echo content >>file &&
+       git commit -a -m four &&
+       git push) &&
+       compare_refs clone HEAD server HEAD
+'
+
+test_expect_success 'fetch new branch' '
+       (cd public &&
+        git checkout -b new &&
+        echo content >>file &&
+        git commit -a -m five &&
+        git push origin new
+       ) &&
+       (cd localclone &&
+        git fetch origin new
+       ) &&
+       compare_refs public HEAD localclone FETCH_HEAD
+'
+
+test_expect_success 'fetch multiple branches' '
+       (cd localclone &&
+        git fetch
+       ) &&
+       compare_refs server master localclone refs/remotes/origin/master &&
+       compare_refs server new localclone refs/remotes/origin/new
+'
+
+test_expect_success 'push when remote has extra refs' '
+       (cd clone &&
+        echo content >>file &&
+        git commit -a -m six &&
+        git push
+       ) &&
+       compare_refs clone master server master
+'
+
+test_expect_success 'push new branch by name' '
+       (cd clone &&
+        git checkout -b new-name  &&
+        echo content >>file &&
+        git commit -a -m seven &&
+        git push origin new-name
+       ) &&
+       compare_refs clone HEAD server refs/heads/new-name
+'
+
+test_expect_failure 'push new branch with old:new refspec' '
+       (cd clone &&
+        git push origin new-name:new-refspec
+       ) &&
+       compare_refs clone HEAD server refs/heads/new-refspec
+'
+
+test_done
diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh
new file mode 100755 (executable)
index 0000000..f387027
--- /dev/null
@@ -0,0 +1,169 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Sverre Rabbelier
+#
+
+test_description='Test remote-helper import and export commands'
+
+. ./test-lib.sh
+
+if ! type "${BASH-bash}" >/dev/null 2>&1; then
+       skip_all='skipping remote-testgit tests, bash not available'
+       test_done
+fi
+
+compare_refs() {
+       git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
+       git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'setup repository' '
+       git init server &&
+       (cd server &&
+        echo content >file &&
+        git add file &&
+        git commit -m one)
+'
+
+test_expect_success 'cloning from local repo' '
+       git clone "testgit::${PWD}/server" local &&
+       test_cmp server/file local/file
+'
+
+test_expect_success 'create new commit on remote' '
+       (cd server &&
+        echo content >>file &&
+        git commit -a -m two)
+'
+
+test_expect_success 'pulling from local repo' '
+       (cd local && git pull) &&
+       test_cmp server/file local/file
+'
+
+test_expect_success 'pushing to local repo' '
+       (cd local &&
+       echo content >>file &&
+       git commit -a -m three &&
+       git push) &&
+       compare_refs local HEAD server HEAD
+'
+
+test_expect_success 'fetch new branch' '
+       (cd server &&
+        git reset --hard &&
+        git checkout -b new &&
+        echo content >>file &&
+        git commit -a -m five
+       ) &&
+       (cd local &&
+        git fetch origin new
+       ) &&
+       compare_refs server HEAD local FETCH_HEAD
+'
+
+test_expect_success 'fetch multiple branches' '
+       (cd local &&
+        git fetch
+       ) &&
+       compare_refs server master local refs/remotes/origin/master &&
+       compare_refs server new local refs/remotes/origin/new
+'
+
+test_expect_success 'push when remote has extra refs' '
+       (cd local &&
+        git reset --hard origin/master &&
+        echo content >>file &&
+        git commit -a -m six &&
+        git push
+       ) &&
+       compare_refs local master server master
+'
+
+test_expect_success 'push new branch by name' '
+       (cd local &&
+        git checkout -b new-name  &&
+        echo content >>file &&
+        git commit -a -m seven &&
+        git push origin new-name
+       ) &&
+       compare_refs local HEAD server refs/heads/new-name
+'
+
+test_expect_failure 'push new branch with old:new refspec' '
+       (cd local &&
+        git push origin new-name:new-refspec
+       ) &&
+       compare_refs local HEAD server refs/heads/new-refspec
+'
+
+test_expect_success 'cloning without refspec' '
+       GIT_REMOTE_TESTGIT_REFSPEC="" \
+       git clone "testgit::${PWD}/server" local2 &&
+       compare_refs local2 HEAD server HEAD
+'
+
+test_expect_success 'pulling without refspecs' '
+       (cd local2 &&
+       git reset --hard &&
+       GIT_REMOTE_TESTGIT_REFSPEC="" git pull) &&
+       compare_refs local2 HEAD server HEAD
+'
+
+test_expect_failure 'pushing without refspecs' '
+       test_when_finished "(cd local2 && git reset --hard origin)" &&
+       (cd local2 &&
+       echo content >>file &&
+       git commit -a -m ten &&
+       GIT_REMOTE_TESTGIT_REFSPEC="" git push) &&
+       compare_refs local2 HEAD server HEAD
+'
+
+test_expect_success 'pulling with straight refspec' '
+       (cd local2 &&
+       GIT_REMOTE_TESTGIT_REFSPEC="*:*" git pull) &&
+       compare_refs local2 HEAD server HEAD
+'
+
+test_expect_failure 'pushing with straight refspec' '
+       test_when_finished "(cd local2 && git reset --hard origin)" &&
+       (cd local2 &&
+       echo content >>file &&
+       git commit -a -m eleven &&
+       GIT_REMOTE_TESTGIT_REFSPEC="*:*" git push) &&
+       compare_refs local2 HEAD server HEAD
+'
+
+test_expect_success 'pulling without marks' '
+       (cd local2 &&
+       GIT_REMOTE_TESTGIT_NO_MARKS=1 git pull) &&
+       compare_refs local2 HEAD server HEAD
+'
+
+test_expect_failure 'pushing without marks' '
+       test_when_finished "(cd local2 && git reset --hard origin)" &&
+       (cd local2 &&
+       echo content >>file &&
+       git commit -a -m twelve &&
+       GIT_REMOTE_TESTGIT_NO_MARKS=1 git push) &&
+       compare_refs local2 HEAD server HEAD
+'
+
+test_expect_success 'push all with existing object' '
+       (cd local &&
+       git branch dup2 master &&
+       git push origin --all
+       ) &&
+       compare_refs local dup2 server dup2
+'
+
+test_expect_success 'push ref with existing object' '
+       (cd local &&
+       git branch dup master &&
+       git push origin dup
+       ) &&
+       compare_refs local dup server dup
+'
+
+test_done
index f94f0c48e6337f6bd718b4fc6859a52411e09326..3fc3b74c8efa4e5092e36e6a6fbd2a15bc862d77 100755 (executable)
@@ -3,6 +3,7 @@
 test_description='git rev-list --pretty=format test'
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
 
 test_tick
 test_expect_success 'setup' '
@@ -11,12 +12,24 @@ touch foo && git add foo && git commit -m "added foo" &&
 '
 
 # usage: test_format name format_string <expected_output
-test_format() {
+test_format () {
        cat >expect.$1
        test_expect_success "format $1" "
-git rev-list --pretty=format:'$2' master >output.$1 &&
-test_cmp expect.$1 output.$1
-"
+               git rev-list --pretty=format:'$2' master >output.$1 &&
+               test_cmp expect.$1 output.$1
+       "
+}
+
+# Feed to --format to provide predictable colored sequences.
+AUTO_COLOR='%C(auto,red)foo%C(auto,reset)'
+has_color () {
+       printf '\033[31mfoo\033[m\n' >expect &&
+       test_cmp expect "$1"
+}
+
+has_no_color () {
+       echo foo >expect &&
+       test_cmp expect "$1"
 }
 
 test_format percent %%h <<'EOF'
@@ -124,6 +137,48 @@ commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 \e[1;31;43mfoo\e[m
 EOF
 
+test_expect_success '%C(auto) does not enable color by default' '
+       git log --format=$AUTO_COLOR -1 >actual &&
+       has_no_color actual
+'
+
+test_expect_success '%C(auto) enables colors for color.diff' '
+       git -c color.diff=always log --format=$AUTO_COLOR -1 >actual &&
+       has_color actual
+'
+
+test_expect_success '%C(auto) enables colors for color.ui' '
+       git -c color.ui=always log --format=$AUTO_COLOR -1 >actual &&
+       has_color actual
+'
+
+test_expect_success '%C(auto) respects --color' '
+       git log --format=$AUTO_COLOR -1 --color >actual &&
+       has_color actual
+'
+
+test_expect_success '%C(auto) respects --no-color' '
+       git -c color.ui=always log --format=$AUTO_COLOR -1 --no-color >actual &&
+       has_no_color actual
+'
+
+test_expect_success TTY '%C(auto) respects --color=auto (stdout is tty)' '
+       (
+               TERM=vt100 && export TERM &&
+               test_terminal \
+                       git log --format=$AUTO_COLOR -1 --color=auto >actual &&
+               has_color actual
+       )
+'
+
+test_expect_success '%C(auto) respects --color=auto (stdout not tty)' '
+       (
+               TERM=vt100 && export TERM &&
+               git log --format=$AUTO_COLOR -1 --color=auto >actual &&
+               has_no_color actual
+       )
+'
+
 cat >commit-msg <<'EOF'
 Test printing of complex bodies
 
diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh
new file mode 100755 (executable)
index 0000000..39ef619
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+test_description='test globbing (and noglob) of pathspec limiting'
+. ./test-lib.sh
+
+test_expect_success 'create commits with glob characters' '
+       test_commit unrelated bar &&
+       test_commit vanilla foo &&
+       # insert file "f*" in the commit, but in a way that avoids
+       # the name "f*" in the worktree, because it is not allowed
+       # on Windows (the tests below do not depend on the presence
+       # of the file in the worktree)
+       git update-index --add --cacheinfo 100644 "$(git rev-parse HEAD:foo)" "f*" &&
+       test_tick &&
+       git commit -m star &&
+       test_commit bracket "f[o][o]"
+'
+
+test_expect_success 'vanilla pathspec matches literally' '
+       echo vanilla >expect &&
+       git log --format=%s -- foo >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'star pathspec globs' '
+       cat >expect <<-\EOF &&
+       bracket
+       star
+       vanilla
+       EOF
+       git log --format=%s -- "f*" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'bracket pathspec globs and matches literal brackets' '
+       cat >expect <<-\EOF &&
+       bracket
+       vanilla
+       EOF
+       git log --format=%s -- "f[o][o]" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'no-glob option matches literally (vanilla)' '
+       echo vanilla >expect &&
+       git --literal-pathspecs log --format=%s -- foo >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'no-glob option matches literally (star)' '
+       echo star >expect &&
+       git --literal-pathspecs log --format=%s -- "f*" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'no-glob option matches literally (bracket)' '
+       echo bracket >expect &&
+       git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'no-glob environment variable works' '
+       echo star >expect &&
+       GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&
+       test_cmp expect actual
+'
+
+test_done
index de7d45352e001d3c1b2c7f24361dc38dd9e0ea0a..2683cba7e3f0ba7fbb7ea1752a39a6068fc91718 100755 (executable)
@@ -133,6 +133,7 @@ test_expect_success 'submodule add --branch' '
        (
                cd addtest &&
                git submodule add -b initial "$submodurl" submod-branch &&
+               test "initial" = "$(git config -f .gitmodules submodule.submod-branch.branch)" &&
                git submodule init
        ) &&
 
index feaec6cdf4b8c7eac348ea1de61887c93c69244d..4975ec07ce614c8473f7f5638a008d7058730f06 100755 (executable)
@@ -135,6 +135,37 @@ test_expect_success 'submodule update --force forcibly checks out submodules' '
        )
 '
 
+test_expect_success 'submodule update --remote should fetch upstream changes' '
+       (cd submodule &&
+        echo line4 >> file &&
+        git add file &&
+        test_tick &&
+        git commit -m "upstream line4"
+       ) &&
+       (cd super &&
+        git submodule update --remote --force submodule &&
+        cd submodule &&
+        test "$(git log -1 --oneline)" = "$(GIT_DIR=../../submodule/.git git log -1 --oneline)"
+       )
+'
+
+test_expect_success 'local config should override .gitmodules branch' '
+       (cd submodule &&
+        git checkout -b test-branch &&
+        echo line5 >> file &&
+        git add file &&
+        test_tick &&
+        git commit -m "upstream line5" &&
+        git checkout master
+       ) &&
+       (cd super &&
+        git config submodule.submodule.branch test-branch &&
+        git submodule update --remote --force submodule &&
+        cd submodule &&
+        test "$(git log -1 --oneline)" = "$(GIT_DIR=../../submodule/.git git log -1 --oneline test-branch)"
+       )
+'
+
 test_expect_success 'submodule update --rebase staying on master' '
        (cd super/submodule &&
          git checkout master
index d7be66a1d66006b099ff98225efb3ed1849f7b30..2d2f016f6f8b151f10b08e4419dc6d3bdef3d0a8 100755 (executable)
@@ -36,8 +36,8 @@ fi
 
 test_debug '
        git --version
-       which git
-       which svnrdump
+       type git
+       type svnrdump
 '
 
 test_expect_success REMOTE_SVN 'simple fetch' '
index 3e821f958bf10afc739e014ed854254a625affd9..9320b4f94c25bf376a004c2c0d4451c0fd96f969 100755 (executable)
@@ -303,7 +303,7 @@ test_expect_success 'dropping tag of filtered out object' '
 (
        cd limit-by-paths &&
        git fast-export --tag-of-filtered-object=drop mytag -- there > output &&
-       test_cmp output expected
+       test_cmp expected output
 )
 '
 
@@ -320,7 +320,7 @@ test_expect_success 'rewriting tag of filtered out object' '
 (
        cd limit-by-paths &&
        git fast-export --tag-of-filtered-object=rewrite mytag -- there > output &&
-       test_cmp output expected
+       test_cmp expected output
 )
 '
 
@@ -351,7 +351,7 @@ test_expect_failure 'no exact-ref revisions included' '
        (
                cd limit-by-paths &&
                git fast-export master~2..master~1 > output &&
-               test_cmp output expected
+               test_cmp expected output
        )
 '
 
@@ -440,4 +440,63 @@ test_expect_success 'fast-export quotes pathnames' '
        )
 '
 
+test_expect_success 'test bidirectionality' '
+       >marks-cur &&
+       >marks-new &&
+       git init marks-test &&
+       git fast-export --export-marks=marks-cur --import-marks=marks-cur --branches | \
+       git --git-dir=marks-test/.git fast-import --export-marks=marks-new --import-marks=marks-new &&
+       (cd marks-test &&
+       git reset --hard &&
+       echo Wohlauf > file &&
+       git commit -a -m "back in time") &&
+       git --git-dir=marks-test/.git fast-export --export-marks=marks-new --import-marks=marks-new --branches | \
+       git fast-import --export-marks=marks-cur --import-marks=marks-cur
+'
+
+cat > expected << EOF
+blob
+mark :13
+data 5
+bump
+
+commit refs/heads/master
+mark :14
+author A U Thor <author@example.com> 1112912773 -0700
+committer C O Mitter <committer@example.com> 1112912773 -0700
+data 5
+bump
+from :12
+M 100644 :13 file
+
+EOF
+
+test_expect_success 'avoid uninteresting refs' '
+       > tmp-marks &&
+       git fast-export --import-marks=tmp-marks \
+               --export-marks=tmp-marks master > /dev/null &&
+       git tag v1.0 &&
+       git branch uninteresting &&
+       echo bump > file &&
+       git commit -a -m bump &&
+       git fast-export --import-marks=tmp-marks \
+               --export-marks=tmp-marks ^uninteresting ^v1.0 master > actual &&
+       test_cmp expected actual
+'
+
+cat > expected << EOF
+reset refs/heads/master
+from :14
+
+EOF
+
+test_expect_success 'refs are updated even if no commits need to be exported' '
+       > tmp-marks &&
+       git fast-export --import-marks=tmp-marks \
+               --export-marks=tmp-marks master > /dev/null &&
+       git fast-export --import-marks=tmp-marks \
+               --export-marks=tmp-marks master > actual &&
+       test_cmp expected actual
+'
+
 test_done
index 0c2fc3ea1a28268e216a3a93ed12b09f0cf55ef2..34fbc900055d9bbaa9e533063b7c69e384e07e5a 100755 (executable)
@@ -26,10 +26,8 @@ test_expect_success 'init depot' '
                line7
                line8
                EOF
-               cp filek fileko &&
-               sed -i "s/Revision/Revision: do not scrub me/" fileko
-               cp fileko file_text &&
-               sed -i "s/Id/Id: do not scrub me/" file_text
+               sed "s/Revision/Revision: do not scrub me/" <filek >fileko &&
+               sed "s/Id/Id: do not scrub me/" <fileko >file_text &&
                p4 add -t text+k filek &&
                p4 submit -d "filek" &&
                p4 add -t text+ko fileko &&
@@ -88,7 +86,8 @@ test_expect_success 'edit far away from RCS lines' '
        (
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
-               sed -i "s/^line7/line7 edit/" filek &&
+               sed "s/^line7/line7 edit/" <filek >filek.tmp &&
+               mv -f filek.tmp filek &&
                git commit -m "filek line7 edit" filek &&
                git p4 submit &&
                scrub_k_check filek
@@ -105,7 +104,8 @@ test_expect_success 'edit near RCS lines' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               sed -i "s/^line4/line4 edit/" filek &&
+               sed "s/^line4/line4 edit/" <filek >filek.tmp &&
+               mv -f filek.tmp filek &&
                git commit -m "filek line4 edit" filek &&
                git p4 submit &&
                scrub_k_check filek
@@ -122,7 +122,8 @@ test_expect_success 'edit keyword lines' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               sed -i "/Revision/d" filek &&
+               sed "/Revision/d" <filek >filek.tmp &&
+               mv -f filek.tmp filek &&
                git commit -m "filek remove Revision line" filek &&
                git p4 submit &&
                scrub_k_check filek
@@ -139,7 +140,8 @@ test_expect_success 'scrub ko files differently' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               sed -i "s/^line4/line4 edit/" fileko &&
+               sed "s/^line4/line4 edit/" <fileko >fileko.tmp &&
+               mv -f fileko.tmp fileko &&
                git commit -m "fileko line4 edit" fileko &&
                git p4 submit &&
                scrub_ko_check fileko &&
@@ -189,12 +191,14 @@ test_expect_success 'do not scrub plain text' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               sed -i "s/^line4/line4 edit/" file_text &&
+               sed "s/^line4/line4 edit/" <file_text >file_text.tmp &&
+               mv -f file_text.tmp file_text &&
                git commit -m "file_text line4 edit" file_text &&
                (
                        cd "$cli" &&
                        p4 open file_text &&
-                       sed -i "s/^line5/line5 p4 edit/" file_text &&
+                       sed "s/^line5/line5 p4 edit/" <file_text >file_text.tmp &&
+                       mv -f file_text.tmp file_text &&
                        p4 submit -d "file5 p4 edit"
                ) &&
                echo s | test_expect_code 1 git p4 submit &&
index f50f8341d40c6ec87565d01a263d97209fb68680..8a12cbb86a0222f8adc05ba8c77faa4cd05e1cad 100644 (file)
@@ -212,11 +212,13 @@ then
                error)
                        tput bold; tput setaf 1;; # bold red
                skip)
-                       tput bold; tput setaf 2;; # bold green
+                       tput setaf 4;; # blue
+               warn)
+                       tput setaf 3;; # brown/yellow
                pass)
-                       tput setaf 2;;            # green
+                       tput setaf 2;; # green
                info)
-                       tput setaf 3;;            # brown
+                       tput setaf 6;; # cyan
                *)
                        test -n "$quiet" && return;;
                esac
@@ -298,7 +300,7 @@ test_ok_ () {
 
 test_failure_ () {
        test_failure=$(($test_failure + 1))
-       say_color error "not ok - $test_count $1"
+       say_color error "not ok $test_count - $1"
        shift
        echo "$@" | sed -e 's/^/#       /'
        test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; }
@@ -306,12 +308,12 @@ test_failure_ () {
 
 test_known_broken_ok_ () {
        test_fixed=$(($test_fixed+1))
-       say_color "" "ok $test_count - $@ # TODO known breakage"
+       say_color error "ok $test_count - $@ # TODO known breakage vanished"
 }
 
 test_known_broken_failure_ () {
        test_broken=$(($test_broken+1))
-       say_color skip "not ok $test_count - $@ # TODO known breakage"
+       say_color warn "not ok $test_count - $@ # TODO known breakage"
 }
 
 test_debug () {
@@ -404,13 +406,18 @@ test_done () {
 
        if test "$test_fixed" != 0
        then
-               say_color pass "# fixed $test_fixed known breakage(s)"
+               say_color error "# $test_fixed known breakage(s) vanished; please update test(s)"
        fi
        if test "$test_broken" != 0
        then
-               say_color error "# still have $test_broken known breakage(s)"
-               msg="remaining $(($test_count-$test_broken)) test(s)"
+               say_color warn "# still have $test_broken known breakage(s)"
+       fi
+       if test "$test_broken" != 0 || test "$test_fixed" != 0
+       then
+               test_remaining=$(( $test_count - $test_broken - $test_fixed ))
+               msg="remaining $test_remaining test(s)"
        else
+               test_remaining=$test_count
                msg="$test_count test(s)"
        fi
        case "$test_failure" in
@@ -424,7 +431,7 @@ test_done () {
 
                if test $test_external_has_tap -eq 0
                then
-                       if test $test_count -gt 0
+                       if test $test_remaining -gt 0
                        then
                                say_color pass "# passed all $msg"
                        fi
@@ -615,7 +622,7 @@ for skp in $GIT_SKIP_TESTS
 do
        case "$this_test" in
        $skp)
-               say_color skip >&3 "skipping test $this_test altogether"
+               say_color info >&3 "skipping test $this_test altogether"
                skip_all="skip all tests in $this_test"
                test_done
        esac
index 3bc20e91da561f4edd5c3eddb0988735759234e4..0092cbf3540e2fdfd2e882461ba39ba2a833b672 100644 (file)
@@ -1,4 +1,32 @@
 #include "cache.h"
+#include "string-list.h"
+
+/*
+ * A "string_list_each_func_t" function that normalizes an entry from
+ * GIT_CEILING_DIRECTORIES.  If the path is unusable for some reason,
+ * die with an explanation.
+ */
+static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
+{
+       const char *ceil = item->string;
+       int len = strlen(ceil);
+       char buf[PATH_MAX+1];
+
+       if (len == 0)
+               die("Empty path is not supported");
+       if (len > PATH_MAX)
+               die("Path \"%s\" is too long", ceil);
+       if (!is_absolute_path(ceil))
+               die("Path \"%s\" is not absolute", ceil);
+       if (normalize_path_copy(buf, ceil) < 0)
+               die("Path \"%s\" could not be normalized", ceil);
+       len = strlen(buf);
+       if (len > 1 && buf[len-1] == '/')
+               die("Normalized path \"%s\" ended with slash", buf);
+       free(item->string);
+       item->string = xstrdup(buf);
+       return 1;
+}
 
 int main(int argc, char **argv)
 {
@@ -30,7 +58,28 @@ int main(int argc, char **argv)
        }
 
        if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) {
-               int len = longest_ancestor_length(argv[2], argv[3]);
+               int len;
+               struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
+               char *path = xstrdup(argv[2]);
+
+               /*
+                * We have to normalize the arguments because under
+                * Windows, bash mangles arguments that look like
+                * absolute POSIX paths or colon-separate lists of
+                * absolute POSIX paths into DOS paths (e.g.,
+                * "/foo:/foo/bar" might be converted to
+                * "D:\Src\msysgit\foo;D:\Src\msysgit\foo\bar"),
+                * whereas longest_ancestor_length() requires paths
+                * that use forward slashes.
+                */
+               if (normalize_path_copy(path, path))
+                       die("Path \"%s\" could not be normalized", argv[2]);
+               string_list_split(&ceiling_dirs, argv[3], PATH_SEP, -1);
+               filter_string_list(&ceiling_dirs, 0,
+                                  normalize_ceiling_entry, NULL);
+               len = longest_ancestor_length(path, &ceiling_dirs);
+               string_list_clear(&ceiling_dirs, 0);
+               free(path);
                printf("%d\n", len);
                return 0;
        }
index 4693295a98ca713fa65eb9b67d50113ec97ecf71..00ce6c9a129674c1922e0c388366592c5ae7c8c7 100644 (file)
@@ -97,26 +97,6 @@ int main(int argc, char **argv)
                return 0;
        }
 
-       if (argc == 4 && !strcmp(argv[1], "longest_prefix")) {
-               /* arguments: <colon-separated-prefixes>|- <string> */
-               struct string_list prefixes = STRING_LIST_INIT_DUP;
-               int retval;
-               const char *prefix_string = argv[2];
-               const char *string = argv[3];
-               const char *match;
-
-               parse_string_list(&prefixes, prefix_string);
-               match = string_list_longest_prefix(&prefixes, string);
-               if (match) {
-                       printf("%s\n", match);
-                       retval = 0;
-               }
-               else
-                       retval = 1;
-               string_list_clear(&prefixes, 0);
-               return retval;
-       }
-
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
        return 1;
index 4713b6930248d961824c9f867b10340e6278132f..965b778cb3bb6fdd8068dbc7f9603cf9815c028d 100644 (file)
@@ -661,6 +661,11 @@ static void push_update_ref_status(struct strbuf *buf,
                        free(msg);
                        msg = NULL;
                }
+               else if (!strcmp(msg, "already exists")) {
+                       status = REF_STATUS_REJECT_ALREADY_EXISTS;
+                       free(msg);
+                       msg = NULL;
+               }
        }
 
        if (*ref)
@@ -720,6 +725,7 @@ static int push_refs_with_push(struct transport *transport,
                /* Check for statuses set by set_ref_status_for_push() */
                switch (ref->status) {
                case REF_STATUS_REJECT_NONFASTFORWARD:
+               case REF_STATUS_REJECT_ALREADY_EXISTS:
                case REF_STATUS_UPTODATE:
                        continue;
                default:
index 9932f402dfee2605dbb498b120813aebaa3961f8..2673d273ff3aa5530ee57e8a3916bbbbc802466d 100644 (file)
@@ -659,7 +659,7 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
                const char *msg;
 
                strcpy(quickref, status_abbrev(ref->old_sha1));
-               if (ref->nonfastforward) {
+               if (ref->requires_force) {
                        strcat(quickref, "...");
                        type = '+';
                        msg = "forced update";
@@ -695,6 +695,10 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
                                                 "non-fast-forward", porcelain);
                break;
+       case REF_STATUS_REJECT_ALREADY_EXISTS:
+               print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+                                                "already exists", porcelain);
+               break;
        case REF_STATUS_REMOTE_REJECT:
                print_ref_status('!', "[remote rejected]", ref,
                                                 ref->deletion ? NULL : ref->peer_ref,
@@ -714,7 +718,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
 }
 
 void transport_print_push_status(const char *dest, struct ref *refs,
-                                 int verbose, int porcelain, int *nonfastforward)
+                                 int verbose, int porcelain, unsigned int *reject_reasons)
 {
        struct ref *ref;
        int n = 0;
@@ -733,18 +737,19 @@ void transport_print_push_status(const char *dest, struct ref *refs,
                if (ref->status == REF_STATUS_OK)
                        n += print_one_push_status(ref, dest, n, porcelain);
 
-       *nonfastforward = 0;
+       *reject_reasons = 0;
        for (ref = refs; ref; ref = ref->next) {
                if (ref->status != REF_STATUS_NONE &&
                    ref->status != REF_STATUS_UPTODATE &&
                    ref->status != REF_STATUS_OK)
                        n += print_one_push_status(ref, dest, n, porcelain);
-               if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD &&
-                   *nonfastforward != NON_FF_HEAD) {
+               if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD) {
                        if (!strcmp(head, ref->name))
-                               *nonfastforward = NON_FF_HEAD;
+                               *reject_reasons |= REJECT_NON_FF_HEAD;
                        else
-                               *nonfastforward = NON_FF_OTHER;
+                               *reject_reasons |= REJECT_NON_FF_OTHER;
+               } else if (ref->status == REF_STATUS_REJECT_ALREADY_EXISTS) {
+                       *reject_reasons |= REJECT_ALREADY_EXISTS;
                }
        }
 }
@@ -1031,9 +1036,9 @@ static void die_with_unpushed_submodules(struct string_list *needs_pushing)
 
 int transport_push(struct transport *transport,
                   int refspec_nr, const char **refspec, int flags,
-                  int *nonfastforward)
+                  unsigned int *reject_reasons)
 {
-       *nonfastforward = 0;
+       *reject_reasons = 0;
        transport_verify_remote_names(refspec_nr, refspec);
 
        if (transport->push) {
@@ -1099,7 +1104,7 @@ int transport_push(struct transport *transport,
                if (!quiet || err)
                        transport_print_push_status(transport->url, remote_refs,
                                        verbose | porcelain, porcelain,
-                                       nonfastforward);
+                                       reject_reasons);
 
                if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
                        set_upstreams(transport, remote_refs, pretend);
index 4a61c0c3f2d9efa8daf228b20f5d57d96e72e261..bfd2df5823aac55e4ce8674b7980cccabf0fed5f 100644 (file)
@@ -140,11 +140,13 @@ int transport_set_option(struct transport *transport, const char *name,
 void transport_set_verbosity(struct transport *transport, int verbosity,
        int force_progress);
 
-#define NON_FF_HEAD 1
-#define NON_FF_OTHER 2
+#define REJECT_NON_FF_HEAD     0x01
+#define REJECT_NON_FF_OTHER    0x02
+#define REJECT_ALREADY_EXISTS  0x04
+
 int transport_push(struct transport *connection,
                   int refspec_nr, const char **refspec, int flags,
-                  int * nonfastforward);
+                  unsigned int * reject_reasons);
 
 const struct ref *transport_get_remote_refs(struct transport *transport);
 
@@ -170,7 +172,7 @@ void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int v
 int transport_refs_pushed(struct ref *ref);
 
 void transport_print_push_status(const char *dest, struct ref *refs,
-                 int verbose, int porcelain, int *nonfastforward);
+                 int verbose, int porcelain, unsigned int *reject_reasons);
 
 typedef void alternate_ref_fn(const struct ref *, void *);
 extern void for_each_alternate_ref(alternate_ref_fn, void *);
index 3f54c02d7624c26632e3a0f81b8bb970c6ac307f..6e30ef9d048c62c11a92aa5b0ee6df2d227776e6 100644 (file)
@@ -572,6 +572,54 @@ static int match_dir_prefix(const char *base,
        return 0;
 }
 
+/*
+ * Perform matching on the leading non-wildcard part of
+ * pathspec. item->nowildcard_len must be greater than zero. Return
+ * non-zero if base is matched.
+ */
+static int match_wildcard_base(const struct pathspec_item *item,
+                              const char *base, int baselen,
+                              int *matched)
+{
+       const char *match = item->match;
+       /* the wildcard part is not considered in this function */
+       int matchlen = item->nowildcard_len;
+
+       if (baselen) {
+               int dirlen;
+               /*
+                * Return early if base is longer than the
+                * non-wildcard part but it does not match.
+                */
+               if (baselen >= matchlen) {
+                       *matched = matchlen;
+                       return !strncmp(base, match, matchlen);
+               }
+
+               dirlen = matchlen;
+               while (dirlen && match[dirlen - 1] != '/')
+                       dirlen--;
+
+               /*
+                * Return early if base is shorter than the
+                * non-wildcard part but it does not match. Note that
+                * base ends with '/' so we are sure it really matches
+                * directory
+                */
+               if (strncmp(base, match, baselen))
+                       return 0;
+               *matched = baselen;
+       } else
+               *matched = 0;
+       /*
+        * we could have checked entry against the non-wildcard part
+        * that is not in base and does similar never_interesting
+        * optimization as in match_entry. For now just be happy with
+        * base comparison.
+        */
+       return entry_interesting;
+}
+
 /*
  * Is a tree entry interesting given the pathspec we have?
  *
@@ -602,7 +650,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
                const struct pathspec_item *item = ps->items+i;
                const char *match = item->match;
                const char *base_str = base->buf + base_offset;
-               int matchlen = item->len;
+               int matchlen = item->len, matched = 0;
 
                if (baselen >= matchlen) {
                        /* If it doesn't match, move along... */
@@ -626,8 +674,10 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
                                        &never_interesting))
                                return entry_interesting;
 
-                       if (item->use_wildcard) {
-                               if (!fnmatch(match + baselen, entry->path, 0))
+                       if (item->nowildcard_len < item->len) {
+                               if (!git_fnmatch(match + baselen, entry->path,
+                                                item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+                                                item->nowildcard_len - baselen))
                                        return entry_interesting;
 
                                /*
@@ -642,17 +692,34 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
                }
 
 match_wildcards:
-               if (!item->use_wildcard)
+               if (item->nowildcard_len == item->len)
                        continue;
 
+               if (item->nowildcard_len &&
+                   !match_wildcard_base(item, base_str, baselen, &matched))
+                       return entry_not_interesting;
+
                /*
                 * Concatenate base and entry->path into one and do
                 * fnmatch() on it.
+                *
+                * While we could avoid concatenation in certain cases
+                * [1], which saves a memcpy and potentially a
+                * realloc, it turns out not worth it. Measurement on
+                * linux-2.6 does not show any clear improvements,
+                * partly because of the nowildcard_len optimization
+                * in git_fnmatch(). Avoid micro-optimizations here.
+                *
+                * [1] if match_wildcard_base() says the base
+                * directory is already matched, we only need to match
+                * the rest, which is shorter so _in theory_ faster.
                 */
 
                strbuf_add(base, entry->path, pathlen);
 
-               if (!fnmatch(match, base->buf + base_offset, 0)) {
+               if (!git_fnmatch(match, base->buf + base_offset,
+                                item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+                                item->nowildcard_len)) {
                        strbuf_setlen(base, base_offset + baselen);
                        return entry_interesting;
                }
index 6d9636623a2cbb5d5a38eb58d625ef0164d953c0..61acc5e5646f0082c8e24a9587280c5fd2f5704e 100644 (file)
@@ -1834,7 +1834,7 @@ int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)
 
        if (old && same(old, a)) {
                int update = 0;
-               if (o->reset && !ce_uptodate(old) && !ce_skip_worktree(old)) {
+               if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old)) {
                        struct stat st;
                        if (lstat(old->name, &st) ||
                            ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
diff --git a/usage.c b/usage.c
index 8eab28113a970a3f1bc7b9b430aa50341c2667e2..40b3de51c7dfa3fdaaeb44e1c64a2208560414c5 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -130,6 +130,7 @@ void NORETURN die_errno(const char *fmt, ...)
        va_end(params);
 }
 
+#undef error
 int error(const char *err, ...)
 {
        va_list params;
diff --git a/utf8.c b/utf8.c
index 5c61bbe1131e7bbdd939c8b815bd5222b872e3fb..a4ee6650ef6c4c487c083aabf0a950b8ec317b09 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -323,7 +323,7 @@ static size_t display_mode_esc_sequence_len(const char *s)
  * If indent is negative, assume that already -indent columns have been
  * consumed (and no extra indent is necessary for the first line).
  */
-int strbuf_add_wrapped_text(struct strbuf *buf,
+void strbuf_add_wrapped_text(struct strbuf *buf,
                const char *text, int indent1, int indent2, int width)
 {
        int indent, w, assume_utf8 = 1;
@@ -332,7 +332,7 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
 
        if (width <= 0) {
                strbuf_add_indented_text(buf, text, indent1, indent2);
-               return 1;
+               return;
        }
 
 retry:
@@ -356,14 +356,14 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
                        if (w <= width || !space) {
                                const char *start = bol;
                                if (!c && text == start)
-                                       return w;
+                                       return;
                                if (space)
                                        start = space;
                                else
                                        strbuf_addchars(buf, ' ', indent);
                                strbuf_add(buf, start, text - start);
                                if (!c)
-                                       return w;
+                                       return;
                                space = text;
                                if (c == '\t')
                                        w |= 0x07;
@@ -405,13 +405,12 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
        }
 }
 
-int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
                             int indent, int indent2, int width)
 {
        char *tmp = xstrndup(data, len);
-       int r = strbuf_add_wrapped_text(buf, tmp, indent, indent2, width);
+       strbuf_add_wrapped_text(buf, tmp, indent, indent2, width);
        free(tmp);
-       return r;
 }
 
 int is_encoding_utf8(const char *name)
diff --git a/utf8.h b/utf8.h
index 93ef60042c2fad93184b573f30e771ecddc842be..a214238bdd70c6b4eb41edf6626c5b396489ab50 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -9,9 +9,9 @@ int is_utf8(const char *text);
 int is_encoding_utf8(const char *name);
 int same_encoding(const char *, const char *);
 
-int strbuf_add_wrapped_text(struct strbuf *buf,
+void strbuf_add_wrapped_text(struct strbuf *buf,
                const char *text, int indent, int indent2, int width);
-int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
                             int indent, int indent2, int width);
 
 #ifndef NO_ICONV
index a066e2ee9e2cc90ad77547ee9f2267e255cf7d23..bac59d2c41bae7441038b30728c696b6280f4c2d 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -411,11 +411,19 @@ void warn_on_inaccessible(const char *path)
 int access_or_warn(const char *path, int mode)
 {
        int ret = access(path, mode);
-       if (ret && errno != ENOENT)
+       if (ret && errno != ENOENT && errno != ENOTDIR)
                warn_on_inaccessible(path);
        return ret;
 }
 
+int access_or_die(const char *path, int mode)
+{
+       int ret = access(path, mode);
+       if (ret && errno != ENOENT && errno != ENOTDIR)
+               die_errno(_("unable to access '%s'"), path);
+       return ret;
+}
+
 struct passwd *xgetpwuid_self(void)
 {
        struct passwd *pw;