Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Thu, 10 Jan 2013 22:38:00 +0000 (14:38 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 10 Jan 2013 22:38:00 +0000 (14:38 -0800)
* maint:
Prepare for 1.8.1.1
Makefile: detect when PYTHON_PATH changes (cherry-picked)

144 files changed:
.gitignore
Documentation/RelNotes/1.8.2.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/git-bundle.txt
Documentation/git-config.txt
Documentation/git-cvsimport.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/gitignore.txt
Documentation/gitmodules.txt
Documentation/mailmap.txt
Documentation/pretty-formats.txt
Documentation/technical/api-allocation-growing.txt
Documentation/technical/api-directory-listing.txt
Documentation/technical/api-history-graph.txt
Documentation/technical/api-string-list.txt
GIT-VERSION-GEN
Makefile
RelNotes
abspath.c
advice.c
advice.h
archive-tar.c
archive.c
attr.c
builtin.h
builtin/add.c
builtin/apply.c
builtin/branch.c
builtin/clone.c
builtin/fast-export.c
builtin/fmt-merge-msg.c
builtin/log.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/merge.c
builtin/push.c
builtin/send-pack.c
cache.h
commit.h
compat/fnmatch/fnmatch.c
config.c
config.mak.uname [new file with mode: 0644]
configure.ac
contrib/ciabot/ciabot.py
contrib/completion/git-completion.bash
contrib/fast-import/import-zips.py
contrib/hg-to-git/hg-to-git.py
contrib/p4import/git-p4import.py
contrib/remote-helpers/git-remote-bzr [new file with mode: 0755]
contrib/remote-helpers/test-bzr.sh [new file with mode: 0755]
contrib/svn-fe/svnrdump_sim.py
ctype.c
dir.c
dir.h
editor.c
fetch-pack.c
fsck.c
git-compat-util.h
git-p4.py
git-rebase--am.sh
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/__init__.py
git_remote_helpers/git/importer.py
gitweb/gitweb.perl
graph.c
http-push.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
po/de.po
pretty.c
remote.c
run-command.c
send-pack.c
sequencer.c
setup.c
strbuf.c
strbuf.h
string-list.c
string-list.h
t/Makefile
t/check-non-portable-shell.pl [new file with mode: 0755]
t/t0000-basic.sh
t/t0003-attributes.sh
t/t0060-path-utils.sh
t/t0063-string-list.sh
t/t1020-subdirectory.sh
t/t1450-fsck.sh
t/t1505-rev-parse-last.sh
t/t3001-ls-files-others-exclude.sh
t/t3070-wildmatch.sh [new file with mode: 0755]
t/t3404-rebase-interactive.sh
t/t3501-revert-cherry-pick.sh
t/t3506-cherry-pick-ff.sh
t/t3507-cherry-pick-conflict.sh
t/t3508-cherry-pick-many-commits.sh
t/t3510-cherry-pick-sequence.sh
t/t4014-format-patch.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/t5600-clone-fail-cleanup.sh
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/t6030-bisect-porcelain.sh
t/t6130-pathspec-noglob.sh [new file with mode: 0755]
t/t7400-submodule-basic.sh
t/t7406-submodule-update.sh
t/t7505-prepare-commit-msg-hook.sh
t/t9350-fast-export.sh
t/test-lib-functions.sh
t/test-lib.sh
test-path-utils.c
test-string-list.c
test-wildmatch.c [new file with mode: 0644]
transport-helper.c
transport.c
transport.h
tree-walk.c
unpack-trees.c
usage.c
wildmatch.c [new file with mode: 0644]
wildmatch.h [new file with mode: 0644]
wrapper.c
index 726db73450189ccd1ab6975ba9ca872f53a79c44..aa258a6bcfe105cdb872c6d77cd9bd19c84e8dc5 100644 (file)
@@ -1,7 +1,6 @@
 /GIT-BUILD-OPTIONS
 /GIT-CFLAGS
 /GIT-LDFLAGS
-/GIT-GUI-VARS
 /GIT-PREFIX
 /GIT-PYTHON-VARS
 /GIT-SCRIPT-DEFINES
 /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
 /test-string-list
 /test-subprocess
 /test-svn-fe
+/test-wildmatch
 /common-cmds.h
 *.tar.gz
 *.dsc
diff --git a/Documentation/RelNotes/1.8.2.txt b/Documentation/RelNotes/1.8.2.txt
new file mode 100644 (file)
index 0000000..a6eb139
--- /dev/null
@@ -0,0 +1,219 @@
+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.
+
+ * The pathspec code learned to grok "foo/**/bar" as a pattern that
+   matches "bar" in 0-or-more levels of subdirectory in "foo".
+
+ * "git cherry-pick" can be used to replay a root commit to an unborn
+   branch.
+
+ * "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 format-patch" now detects more cases in which a whole branch
+   is being exported, and uses the description for the branch, when
+   asked to write a cover letter for the series.
+
+ * "git push" now requires "-f" to update a tag, even if it is a
+   fast-forward, as tags are meant to be fixed points.
+
+ * When "git rebase" fails to generate patches to be applied (e.g. due
+   to oom), it failed to detect the failure and instead behaved as if
+   there were nothing to do.  A workaround to use a temporary file has
+   been applied, but we probably would want to revisit this later, as
+   it hurts the common case of not failing at all.
+
+ * "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.
+
+ * A new remote helper to interact with bzr has been added to contrib/.
+
+
+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.
+
+ * There is a simple-minded checker for the test scripts in t/
+   directory to catch most common mistakes (it is not enabled by
+   default).
+
+
+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).
+
+ * When attempting to read the XDG-style $HOME/.config/git/config and
+   finding that $HOME/.config/git is a file, we gave a wrong error
+   message, instead of treating the case as "a custom config file does
+   not exist there" and moving on.
+   (merge 8f2bbe4 jn/warn-on-inaccessible-loosen 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).
+
+ * "git apply" misbehaved when fixing whitespace breakages by removing
+   excess trailing blank lines.
+   (merge 5de7166 jc/apply-trailing-blank-removal later to maint).
+
+ * A tar archive created by "git archive" recorded a directory in a
+   way that made NetBSD's implementation of "tar" sometimes unhappy.
+   (merge 22f0dcd rs/leave-base-name-in-name-field-of-tar later to maint).
+
+ * When "git clone --separate-git-dir=$over_there" is interrupted, it
+   failed to remove the real location of the $GIT_DIR it created.
+   This was most visible when interrupting a submodule update.
+   (merge 9be1980 jl/interrupt-clone-remove-separate-git-dir 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).
+
+ * "git merge --no-edit" computed who were involved in the work done
+   on the side branch, even though that information is to be discarded
+   without getting seen in the editor.
+   (merge 9bcbb1c jc/maint-fmt-merge-msg-no-edit-lose-credit later to maint).
+
+ * "git merge" started calling prepare-commit-msg hook like "git
+   commit" does some time ago, but forgot to pay attention to the exit
+   status of the hook.
+   (merge 3e4141d ap/merge-stop-at-prepare-commit-msg-failure 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).
+
+ * "gitweb"'s code to sanitize control characters before passing it to
+   "highlight" filter lost known-to-be-safe control characters by
+   mistake.
+   (merge 0e901d2 os/gitweb-highlight-uncaptured 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).
+
+ * Some scripted programs written in Python did not get updated when
+   PYTHON_PATH changed.
+   (cherry-pick 96a4647fca54031974cd6ad1 later to maint).
+
+ * When autoconf is used, any build on a different commit always ran
+   "config.status --recheck" even when unnecessary.
+   (merge 1226504 jn/less-reconfigure later to maint).
+
+ * We have been carrying a translated and long-unmaintained copy of an
+   old version of the tutorial; removed.
+   (merge 0a85441 ta/remove-stale-translated-tut 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).
+
+ * t9020 and t9810 had a few non-portable shell script construct.
+   (merge 2797914 tb/test-t9020-no-which later to maint).
+   (merge 6f4e505 tb/test-t9810-no-sed-i later to maint).
index 75935d500dbde241675df0d31b7a75ee036d5468..90133d8c3b2ea7ea8af55a2bac0876b10aff8f3e 100644 (file)
@@ -1,73 +1,5 @@
-Checklist (and a short version for the impatient):
-
-       Commits:
-
-       - make commits of logical units
-       - check for unnecessary whitespace with "git diff --check"
-         before committing
-       - do not check in commented out code or unneeded files
-       - the first line of the commit message should be a short
-         description (50 characters is the soft limit, see DISCUSSION
-         in git-commit(1)), and should skip the full stop
-       - it is also conventional in most cases to prefix the
-         first line with "area: " where the area is a filename
-         or identifier for the general area of the code being
-         modified, e.g.
-         . archive: ustar header checksum is computed unsigned
-         . git-cherry-pick.txt: clarify the use of revision range notation
-         (if in doubt which identifier to use, run "git log --no-merges"
-         on the files you are modifying to see the current conventions)
-       - the body should provide a meaningful commit message, which:
-         . explains the problem the change tries to solve, iow, what
-           is wrong with the current code without the change.
-         . justifies the way the change solves the problem, iow, why
-           the result with the change is better.
-         . alternate solutions considered but discarded, if any.
-       - describe changes in imperative mood, e.g. "make xyzzy do frotz"
-         instead of "[This patch] makes xyzzy do frotz" or "[I] changed
-         xyzzy to do frotz", as if you are giving orders to the codebase
-         to change its behaviour.
-       - try to make sure your explanation can be understood without
-         external resources. Instead of giving a URL to a mailing list
-         archive, summarize the relevant points of the discussion.
-       - add a "Signed-off-by: Your Name <you@example.com>" line to the
-         commit message (or just use the option "-s" when committing)
-         to confirm that you agree to the Developer's Certificate of Origin
-       - make sure that you have tests for the bug you are fixing
-       - make sure that the test suite passes after your commit
-
-       Patch:
-
-       - use "git format-patch -M" to create the patch
-       - do not PGP sign your patch
-       - do not attach your patch, but read in the mail
-         body, unless you cannot teach your mailer to
-         leave the formatting of the patch alone.
-       - be careful doing cut & paste into your mailer, not to
-         corrupt whitespaces.
-       - provide additional information (which is unsuitable for
-         the commit message) between the "---" and the diffstat
-       - if you change, add, or remove a command line option or
-         make some other user interface change, the associated
-         documentation should be updated as well.
-       - if your name is not writable in ASCII, make sure that
-         you send off a message in the correct encoding.
-       - send the patch to the list (git@vger.kernel.org) and the
-         maintainer (gitster@pobox.com) if (and only if) the patch
-         is ready for inclusion. If you use git-send-email(1),
-         please test it first by sending email to yourself.
-       - see below for instructions specific to your mailer
-
-Long version:
-
-I started reading over the SubmittingPatches document for Linux
-kernel, primarily because I wanted to have a document similar to
-it for the core GIT to make sure people understand what they are
-doing when they write "Signed-off-by" line.
-
-But the patch submission requirements are a lot more relaxed
-here on the technical/contents front, because the core GIT is
-thousand times smaller ;-).  So here is only the relevant bits.
+Here are some guidelines for people who want to contribute their code
+to this software.
 
 (0) Decide what to base your work on.
 
@@ -94,6 +26,10 @@ change is relevant to.
    wait until some of the dependent topics graduate to 'master', and
    rebase your work.
 
+ - Some parts of the system have dedicated maintainers with their own
+   repositories (see the section "Subsystems" below).  Changes to
+   these parts should be based on their trees.
+
 To find the tip of a topic branch, run "git log --first-parent
 master..pu" and look for the merge commit. The second parent of this
 commit is the tip of the topic branch.
@@ -121,13 +57,53 @@ change, the approach taken by the change, and if relevant how this
 differs substantially from the prior version, are all good things
 to have.
 
+Make sure that you have tests for the bug you are fixing.
+
+When adding a new feature, make sure that you have new tests to show
+the feature triggers the new behaviour when it should, and to show the
+feature does not trigger when it shouldn't.  Also make sure that the
+test suite passes after your commit.  Do not forget to update the
+documentation to describe the updated behaviour.
+
 Oh, another thing.  I am picky about whitespaces.  Make sure your
 changes do not trigger errors with the sample pre-commit hook shipped
 in templates/hooks--pre-commit.  To help ensure this does not happen,
 run git diff --check on your changes before you commit.
 
 
-(2) Generate your patch using git tools out of your commits.
+(2) Describe your changes well.
+
+The first line of the commit message should be a short description (50
+characters is the soft limit, see DISCUSSION in git-commit(1)), and
+should skip the full stop.  It is also conventional in most cases to
+prefix the first line with "area: " where the area is a filename or
+identifier for the general area of the code being modified, e.g.
+
+  . archive: ustar header checksum is computed unsigned
+  . git-cherry-pick.txt: clarify the use of revision range notation
+
+If in doubt which identifier to use, run "git log --no-merges" on the
+files you are modifying to see the current conventions.
+
+The body should provide a meaningful commit message, which:
+
+  . explains the problem the change tries to solve, iow, what is wrong
+    with the current code without the change.
+
+  . justifies the way the change solves the problem, iow, why the
+    result with the change is better.
+
+  . alternate solutions considered but discarded, if any.
+
+Describe your changes in imperative mood, e.g. "make xyzzy do frotz"
+instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
+to do frotz", as if you are giving orders to the codebase to change
+its behaviour.  Try to make sure your explanation can be understood
+without external resources. Instead of giving a URL to a mailing list
+archive, summarize the relevant points of the discussion.
+
+
+(3) Generate your patch using git tools out of your commits.
 
 git based diff tools generate unidiff which is the preferred format.
 
@@ -135,22 +111,27 @@ You do not have to be afraid to use -M option to "git diff" or
 "git format-patch", if your patch involves file renames.  The
 receiving end can handle them just fine.
 
-Please make sure your patch does not include any extra files
-which do not belong in a patch submission.  Make sure to review
+Please make sure your patch does not add commented out debugging code,
+or include any extra files which do not relate to what your patch
+is trying to achieve. Make sure to review
 your patch after generating it, to ensure accuracy.  Before
 sending out, please make sure it cleanly applies to the "master"
 branch head.  If you are preparing a work based on "next" branch,
 that is fine, but please mark it as such.
 
 
-(3) Sending your patches.
+(4) Sending your patches.
 
 People on the git mailing list need to be able to read and
 comment on the changes you are submitting.  It is important for
 a developer to be able to "quote" your changes, using standard
 e-mail tools, so that they may comment on specific portions of
 your code.  For this reason, all patches should be submitted
-"inline".  WARNING: Be wary of your MUAs word-wrap
+"inline".  If your log message (including your name on the
+Signed-off-by line) is not writable in ASCII, make sure that
+you send off a message in the correct encoding.
+
+WARNING: Be wary of your MUAs word-wrap
 corrupting your patch.  Do not cut-n-paste your patch; you can
 lose tabs that way if you are not careful.
 
@@ -203,19 +184,25 @@ patch, format it as "multipart/signed", not a text/plain message
 that starts with '-----BEGIN PGP SIGNED MESSAGE-----'.  That is
 not a text/plain, it's something else.
 
-Unless your patch is a very trivial and an obviously correct one,
-first send it with "To:" set to the mailing list, with "cc:" listing
+Send your patch with "To:" set to the mailing list, with "cc:" listing
 people who are involved in the area you are touching (the output from
 "git blame $path" and "git shortlog --no-merges $path" would help to
-identify them), to solicit comments and reviews.  After the list
-reached a consensus that it is a good idea to apply the patch, re-send
-it with "To:" set to the maintainer and optionally "cc:" the list for
-inclusion.  Do not forget to add trailers such as "Acked-by:",
-"Reviewed-by:" and "Tested-by:" after your "Signed-off-by:" line as
-necessary.
+identify them), to solicit comments and reviews.
 
+After the list reached a consensus that it is a good idea to apply the
+patch, re-send it with "To:" set to the maintainer [*1*] and "cc:" the
+list [*2*] for inclusion.
 
-(4) Sign your work
+Do not forget to add trailers such as "Acked-by:", "Reviewed-by:" and
+"Tested-by:" lines as necessary to credit people who helped your
+patch.
+
+    [Addresses]
+     *1* The current maintainer: gitster@pobox.com
+     *2* The mailing list: git@vger.kernel.org
+
+
+(5) Sign your work
 
 To improve tracking of who did what, we've borrowed the
 "sign-off" procedure from the Linux kernel project on patches
@@ -285,6 +272,26 @@ If you like, you can put extra tags at the end:
 You can also create your own tag or use one that's in common usage
 such as "Thanks-to:", "Based-on-patch-by:", or "Mentored-by:".
 
+------------------------------------------------
+Subsystems with dedicated maintainers
+
+Some parts of the system have dedicated maintainers with their own
+repositories.
+
+ - git-gui/ comes from git-gui project, maintained by Pat Thoyts:
+
+        git://repo.or.cz/git-gui.git
+
+ - gitk-git/ comes from Paul Mackerras's gitk project:
+
+        git://ozlabs.org/~paulus/gitk
+
+ - po/ comes from the localization coordinator, Jiang Xin:
+
+       https://github.com/git-l10n/git-po/
+
+Patches to these parts should be based on their trees.
+
 ------------------------------------------------
 An ideal patch flow
 
index bf8f911e1ffe7820a8e903ec669c690d39612150..d5809e0e8c4dca414a863cfd019a6f8860c46c4d 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
@@ -735,6 +739,12 @@ branch.<name>.rebase::
 it unless you understand the implications (see linkgit:git-rebase[1]
 for details).
 
+branch.<name>.description::
+       Branch description, can be edited with
+       `git branch --edit-description`. Branch description is
+       automatically added in the format-patch cover letter or
+       request-pull summary.
+
 browser.<tool>.cmd::
        Specify the command to invoke the specified browser. The
        specified command is evaluated in shell with the URLs passed
@@ -1517,6 +1527,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 +2013,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 98d9881d7e891e4728c09f6536c3506b3688d145..9d5353e8be4a56cb92c1987e40a3695b23733d56 100644 (file)
@@ -213,11 +213,9 @@ Problems related to tags:
 * Multiple tags on the same revision are not imported.
 
 If you suspect that any of these issues may apply to the repository you
-want to import consider using these alternative tools which proved to be
-more stable in practice:
+want to imort, consider using cvs2git:
 
-* cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org`
-* parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs`
+* cvs2git (part of cvs2svn), `http://subversion.apache.org/`
 
 GIT
 ---
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 1b82fe1969ed1cf965d946178a423771dd3cfe5f..91a6438031949d83600abc791676bbf0397a0ddc 100644 (file)
@@ -108,6 +108,25 @@ PATTERN FORMAT
    For example, "/{asterisk}.c" matches "cat-file.c" but not
    "mozilla-sha1/sha1.c".
 
+Two consecutive asterisks ("`**`") in patterns matched against
+full pathname may have special meaning:
+
+ - A leading "`**`" followed by a slash means match in all
+   directories. For example, "`**/foo`" matches file or directory
+   "`foo`" anywhere, the same as pattern "`foo`". "**/foo/bar"
+   matches file or directory "`bar`" anywhere that is directly
+   under directory "`foo`".
+
+ - A trailing "/**" matches everything inside. For example,
+   "abc/**" matches all files inside directory "abc", relative
+   to the location of the `.gitignore` file, with infinite depth.
+
+ - A slash followed by two consecutive asterisks then a slash
+   matches zero or more directories. For example, "`a/**/b`"
+   matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
+
+ - Other consecutive asterisks are considered invalid.
+
 NOTES
 -----
 
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 '%'
index 43dbe09f735525b0a1549ccfb4de2f2ca87252a0..542946b1ba701069837b702cbd8fe8079cecf56d 100644 (file)
@@ -5,7 +5,9 @@ Dynamically growing an array using realloc() is error prone and boring.
 
 Define your array with:
 
-* a pointer (`ary`) that points at the array, initialized to `NULL`;
+* a pointer (`item`) that points at the array, initialized to `NULL`
+  (although please name the variable based on its contents, not on its
+  type);
 
 * an integer variable (`alloc`) that keeps track of how big the current
   allocation is, initialized to `0`;
@@ -13,22 +15,22 @@ Define your array with:
 * another integer variable (`nr`) to keep track of how many elements the
   array currently has, initialized to `0`.
 
-Then before adding `n`th element to the array, call `ALLOC_GROW(ary, n,
+Then before adding `n`th element to the item, call `ALLOC_GROW(item, n,
 alloc)`.  This ensures that the array can hold at least `n` elements by
 calling `realloc(3)` and adjusting `alloc` variable.
 
 ------------
-sometype *ary;
+sometype *item;
 size_t nr;
 size_t alloc
 
 for (i = 0; i < nr; i++)
-       if (we like ary[i] already)
+       if (we like item[i] already)
                return;
 
 /* we did not like any existing one, so add one */
-ALLOC_GROW(ary, nr + 1, alloc);
-ary[nr++] = value you like;
+ALLOC_GROW(item, nr + 1, alloc);
+item[nr++] = value you like;
 ------------
 
 You are responsible for updating the `nr` variable.
index add6f435b59e3df095e507d8a5d4f911cee9d3b2..944fc39fac8b26ceaee781fe4a18b9ba2d78ac9d 100644 (file)
@@ -9,37 +9,40 @@ Data structure
 --------------
 
 `struct dir_struct` structure is used to pass directory traversal
-options to the library and to record the paths discovered.  The notable
-options are:
+options to the library and to record the paths discovered.  A single
+`struct dir_struct` is used regardless of whether or not the traversal
+recursively descends into subdirectories.
+
+The notable options are:
 
 `exclude_per_dir`::
 
        The name of the file to be read in each directory for excluded
        files (typically `.gitignore`).
 
-`collect_ignored`::
+`flags`::
 
-       Include paths that are to be excluded in the result.
+       A bit-field of options:
 
-`show_ignored`::
+`DIR_SHOW_IGNORED`:::
 
        The traversal is for finding just ignored files, not unignored
        files.
 
-`show_other_directories`::
+`DIR_SHOW_OTHER_DIRECTORIES`:::
 
        Include a directory that is not tracked.
 
-`hide_empty_directories`::
+`DIR_HIDE_EMPTY_DIRECTORIES`:::
 
        Do not include a directory that is not tracked and is empty.
 
-`no_gitlinks`::
+`DIR_NO_GITLINKS`:::
 
        If set, recurse into a directory that looks like a git
        directory.  Otherwise it is shown as a directory.
 
-The result of the enumeration is left in these fields::
+The result of the enumeration is left in these fields:
 
 `entries[]`::
 
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 18023294d2fd698f53fcb436e6998ae3d17a3327..029bf39c9adecb9b5cd69b770a4daaf423ac6a5c 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.
@@ -273,6 +281,10 @@ all::
 #
 # Define NO_REGEX if you have no or inferior regex support in your C library.
 #
+# Define CYGWIN_V15_WIN32API if you are using Cygwin v1.7.x but are not
+# using the current w32api packages. The recommended approach, however,
+# is to update your installation if compilation errors occur.
+#
 # Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
 # user.
 #
@@ -326,19 +338,6 @@ GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
 -include GIT-VERSION-FILE
 
-uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
-uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
-uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
-uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
-uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
-uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
-
-ifdef MSVC
-       # avoid the MingW and Cygwin configuration sections
-       uname_S := Windows
-       uname_O := Windows
-endif
-
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
 CFLAGS = -g -O2 -Wall
@@ -470,7 +469,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)) \
@@ -524,6 +523,7 @@ TEST_PROGRAMS_NEED_X += test-sigchain
 TEST_PROGRAMS_NEED_X += test-string-list
 TEST_PROGRAMS_NEED_X += test-subprocess
 TEST_PROGRAMS_NEED_X += test-svn-fe
+TEST_PROGRAMS_NEED_X += test-wildmatch
 
 TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
 
@@ -696,6 +696,7 @@ LIB_H += userdiff.h
 LIB_H += utf8.h
 LIB_H += varint.h
 LIB_H += walker.h
+LIB_H += wildmatch.h
 LIB_H += wt-status.h
 LIB_H += xdiff-interface.h
 LIB_H += xdiff/xdiff.h
@@ -830,6 +831,7 @@ LIB_OBJS += utf8.o
 LIB_OBJS += varint.o
 LIB_OBJS += version.o
 LIB_OBJS += walker.o
+LIB_OBJS += wildmatch.o
 LIB_OBJS += wrapper.o
 LIB_OBJS += write_or_die.o
 LIB_OBJS += ws.o
@@ -937,518 +939,7 @@ EXTLIBS =
 
 GIT_USER_AGENT = git/$(GIT_VERSION)
 
-#
-# Platform specific tweaks
-#
-
-# We choose to avoid "if .. else if .. else .. endif endif"
-# because maintaining the nesting to match is a pain.  If
-# we had "elif" things would have been much nicer...
-
-ifeq ($(uname_M),x86_64)
-       XDL_FAST_HASH = YesPlease
-endif
-ifeq ($(uname_S),OSF1)
-       # Need this for u_short definitions et al
-       BASIC_CFLAGS += -D_OSF_SOURCE
-       SOCKLEN_T = int
-       NO_STRTOULL = YesPlease
-       NO_NSEC = YesPlease
-endif
-ifeq ($(uname_S),Linux)
-       NO_STRLCPY = YesPlease
-       NO_MKSTEMPS = YesPlease
-       HAVE_PATHS_H = YesPlease
-       LIBC_CONTAINS_LIBINTL = YesPlease
-       HAVE_DEV_TTY = YesPlease
-endif
-ifeq ($(uname_S),GNU/kFreeBSD)
-       NO_STRLCPY = YesPlease
-       NO_MKSTEMPS = YesPlease
-       HAVE_PATHS_H = YesPlease
-       DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
-       LIBC_CONTAINS_LIBINTL = YesPlease
-endif
-ifeq ($(uname_S),UnixWare)
-       CC = cc
-       NEEDS_SOCKET = YesPlease
-       NEEDS_NSL = YesPlease
-       NEEDS_SSL_WITH_CRYPTO = YesPlease
-       NEEDS_LIBICONV = YesPlease
-       SHELL_PATH = /usr/local/bin/bash
-       NO_IPV6 = YesPlease
-       NO_HSTRERROR = YesPlease
-       NO_MKSTEMPS = YesPlease
-       BASIC_CFLAGS += -Kthread
-       BASIC_CFLAGS += -I/usr/local/include
-       BASIC_LDFLAGS += -L/usr/local/lib
-       INSTALL = ginstall
-       TAR = gtar
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-endif
-ifeq ($(uname_S),SCO_SV)
-       ifeq ($(uname_R),3.2)
-               CFLAGS = -O2
-       endif
-       ifeq ($(uname_R),5)
-               CC = cc
-               BASIC_CFLAGS += -Kthread
-       endif
-       NEEDS_SOCKET = YesPlease
-       NEEDS_NSL = YesPlease
-       NEEDS_SSL_WITH_CRYPTO = YesPlease
-       NEEDS_LIBICONV = YesPlease
-       SHELL_PATH = /usr/bin/bash
-       NO_IPV6 = YesPlease
-       NO_HSTRERROR = YesPlease
-       NO_MKSTEMPS = YesPlease
-       BASIC_CFLAGS += -I/usr/local/include
-       BASIC_LDFLAGS += -L/usr/local/lib
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       INSTALL = ginstall
-       TAR = gtar
-endif
-ifeq ($(uname_S),Darwin)
-       NEEDS_CRYPTO_WITH_SSL = YesPlease
-       NEEDS_SSL_WITH_CRYPTO = YesPlease
-       NEEDS_LIBICONV = YesPlease
-       ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2)
-               OLD_ICONV = UnfortunatelyYes
-       endif
-       ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2)
-               NO_STRLCPY = YesPlease
-       endif
-       NO_MEMMEM = YesPlease
-       USE_ST_TIMESPEC = YesPlease
-       HAVE_DEV_TTY = YesPlease
-       COMPAT_OBJS += compat/precompose_utf8.o
-       BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
-endif
-ifeq ($(uname_S),SunOS)
-       NEEDS_SOCKET = YesPlease
-       NEEDS_NSL = YesPlease
-       SHELL_PATH = /bin/bash
-       SANE_TOOL_PATH = /usr/xpg6/bin:/usr/xpg4/bin
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_MKDTEMP = YesPlease
-       NO_MKSTEMPS = YesPlease
-       NO_REGEX = YesPlease
-       NO_FNMATCH_CASEFOLD = YesPlease
-       NO_MSGFMT_EXTENDED_OPTIONS = YesPlease
-       HAVE_DEV_TTY = YesPlease
-       ifeq ($(uname_R),5.6)
-               SOCKLEN_T = int
-               NO_HSTRERROR = YesPlease
-               NO_IPV6 = YesPlease
-               NO_SOCKADDR_STORAGE = YesPlease
-               NO_UNSETENV = YesPlease
-               NO_SETENV = YesPlease
-               NO_STRLCPY = YesPlease
-               NO_STRTOUMAX = YesPlease
-               GIT_TEST_CMP = cmp
-       endif
-       ifeq ($(uname_R),5.7)
-               NEEDS_RESOLV = YesPlease
-               NO_IPV6 = YesPlease
-               NO_SOCKADDR_STORAGE = YesPlease
-               NO_UNSETENV = YesPlease
-               NO_SETENV = YesPlease
-               NO_STRLCPY = YesPlease
-               NO_STRTOUMAX = YesPlease
-               GIT_TEST_CMP = cmp
-       endif
-       ifeq ($(uname_R),5.8)
-               NO_UNSETENV = YesPlease
-               NO_SETENV = YesPlease
-               NO_STRTOUMAX = YesPlease
-               GIT_TEST_CMP = cmp
-       endif
-       ifeq ($(uname_R),5.9)
-               NO_UNSETENV = YesPlease
-               NO_SETENV = YesPlease
-               NO_STRTOUMAX = YesPlease
-               GIT_TEST_CMP = cmp
-       endif
-       INSTALL = /usr/ucb/install
-       TAR = gtar
-       BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
-endif
-ifeq ($(uname_O),Cygwin)
-       ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4)
-               NO_D_TYPE_IN_DIRENT = YesPlease
-               NO_D_INO_IN_DIRENT = YesPlease
-               NO_STRCASESTR = YesPlease
-               NO_MEMMEM = YesPlease
-               NO_MKSTEMPS = YesPlease
-               NO_SYMLINK_HEAD = YesPlease
-               NO_IPV6 = YesPlease
-               OLD_ICONV = UnfortunatelyYes
-               CYGWIN_V15_WIN32API = YesPlease
-       endif
-       NO_THREAD_SAFE_PREAD = YesPlease
-       NEEDS_LIBICONV = YesPlease
-       NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
-       NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
-       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
-       # There are conflicting reports about this.
-       # On some boxes NO_MMAP is needed, and not so elsewhere.
-       # Try commenting this out if you suspect MMAP is more efficient
-       NO_MMAP = YesPlease
-       X = .exe
-       COMPAT_OBJS += compat/cygwin.o
-       UNRELIABLE_FSTAT = UnfortunatelyYes
-       SPARSE_FLAGS = -isystem /usr/include/w32api -Wno-one-bit-signed-bitfield
-endif
-ifeq ($(uname_S),FreeBSD)
-       NEEDS_LIBICONV = YesPlease
-       OLD_ICONV = YesPlease
-       NO_MEMMEM = YesPlease
-       BASIC_CFLAGS += -I/usr/local/include
-       BASIC_LDFLAGS += -L/usr/local/lib
-       DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
-       USE_ST_TIMESPEC = YesPlease
-       ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
-               PTHREAD_LIBS = -pthread
-               NO_UINTMAX_T = YesPlease
-               NO_STRTOUMAX = YesPlease
-       endif
-       PYTHON_PATH = /usr/local/bin/python
-       HAVE_PATHS_H = YesPlease
-endif
-ifeq ($(uname_S),OpenBSD)
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       USE_ST_TIMESPEC = YesPlease
-       NEEDS_LIBICONV = YesPlease
-       BASIC_CFLAGS += -I/usr/local/include
-       BASIC_LDFLAGS += -L/usr/local/lib
-       HAVE_PATHS_H = YesPlease
-endif
-ifeq ($(uname_S),NetBSD)
-       ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
-               NEEDS_LIBICONV = YesPlease
-       endif
-       BASIC_CFLAGS += -I/usr/pkg/include
-       BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
-       USE_ST_TIMESPEC = YesPlease
-       NO_MKSTEMPS = YesPlease
-       HAVE_PATHS_H = YesPlease
-endif
-ifeq ($(uname_S),AIX)
-       DEFAULT_PAGER = more
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_MKDTEMP = YesPlease
-       NO_MKSTEMPS = YesPlease
-       NO_STRLCPY = YesPlease
-       NO_NSEC = YesPlease
-       FREAD_READS_DIRECTORIES = UnfortunatelyYes
-       INTERNAL_QSORT = UnfortunatelyYes
-       NEEDS_LIBICONV = YesPlease
-       BASIC_CFLAGS += -D_LARGE_FILES
-       ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
-               NO_PTHREADS = YesPlease
-       else
-               PTHREAD_LIBS = -lpthread
-       endif
-       ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3)
-               INLINE = ''
-       endif
-       GIT_TEST_CMP = cmp
-endif
-ifeq ($(uname_S),GNU)
-       # GNU/Hurd
-       NO_STRLCPY = YesPlease
-       NO_MKSTEMPS = YesPlease
-       HAVE_PATHS_H = YesPlease
-       LIBC_CONTAINS_LIBINTL = YesPlease
-endif
-ifeq ($(uname_S),IRIX)
-       NO_SETENV = YesPlease
-       NO_UNSETENV = YesPlease
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_MKSTEMPS = YesPlease
-       NO_MKDTEMP = YesPlease
-       # When compiled with the MIPSpro 7.4.4m compiler, and without pthreads
-       # (i.e. NO_PTHREADS is set), and _with_ MMAP (i.e. NO_MMAP is not set),
-       # git dies with a segmentation fault when trying to access the first
-       # entry of a reflog.  The conservative choice is made to always set
-       # NO_MMAP.  If you suspect that your compiler is not affected by this
-       # issue, comment out the NO_MMAP statement.
-       NO_MMAP = YesPlease
-       NO_REGEX = YesPlease
-       NO_FNMATCH_CASEFOLD = YesPlease
-       SNPRINTF_RETURNS_BOGUS = YesPlease
-       SHELL_PATH = /usr/gnu/bin/bash
-       NEEDS_LIBGEN = YesPlease
-endif
-ifeq ($(uname_S),IRIX64)
-       NO_SETENV = YesPlease
-       NO_UNSETENV = YesPlease
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_MKSTEMPS = YesPlease
-       NO_MKDTEMP = YesPlease
-       # When compiled with the MIPSpro 7.4.4m compiler, and without pthreads
-       # (i.e. NO_PTHREADS is set), and _with_ MMAP (i.e. NO_MMAP is not set),
-       # git dies with a segmentation fault when trying to access the first
-       # entry of a reflog.  The conservative choice is made to always set
-       # NO_MMAP.  If you suspect that your compiler is not affected by this
-       # issue, comment out the NO_MMAP statement.
-       NO_MMAP = YesPlease
-       NO_REGEX = YesPlease
-       NO_FNMATCH_CASEFOLD = YesPlease
-       SNPRINTF_RETURNS_BOGUS = YesPlease
-       SHELL_PATH = /usr/gnu/bin/bash
-       NEEDS_LIBGEN = YesPlease
-endif
-ifeq ($(uname_S),HP-UX)
-       INLINE = __inline
-       NO_IPV6 = YesPlease
-       NO_SETENV = YesPlease
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_MKSTEMPS = YesPlease
-       NO_STRLCPY = YesPlease
-       NO_MKDTEMP = YesPlease
-       NO_UNSETENV = YesPlease
-       NO_HSTRERROR = YesPlease
-       NO_SYS_SELECT_H = YesPlease
-       NO_FNMATCH_CASEFOLD = YesPlease
-       SNPRINTF_RETURNS_BOGUS = YesPlease
-       NO_NSEC = YesPlease
-       ifeq ($(uname_R),B.11.00)
-               NO_INET_NTOP = YesPlease
-               NO_INET_PTON = YesPlease
-       endif
-       ifeq ($(uname_R),B.10.20)
-               # Override HP-UX 11.x setting:
-               INLINE =
-               SOCKLEN_T = size_t
-               NO_PREAD = YesPlease
-               NO_INET_NTOP = YesPlease
-               NO_INET_PTON = YesPlease
-       endif
-       GIT_TEST_CMP = cmp
-endif
-ifeq ($(uname_S),Windows)
-       GIT_VERSION := $(GIT_VERSION).MSVC
-       pathsep = ;
-       NO_PREAD = YesPlease
-       NEEDS_CRYPTO_WITH_SSL = YesPlease
-       NO_LIBGEN_H = YesPlease
-       NO_POLL = YesPlease
-       NO_SYMLINK_HEAD = YesPlease
-       NO_IPV6 = YesPlease
-       NO_UNIX_SOCKETS = YesPlease
-       NO_SETENV = YesPlease
-       NO_UNSETENV = YesPlease
-       NO_STRCASESTR = YesPlease
-       NO_STRLCPY = YesPlease
-       NO_STRTOK_R = YesPlease
-       NO_FNMATCH = YesPlease
-       NO_MEMMEM = YesPlease
-       # NEEDS_LIBICONV = YesPlease
-       NO_ICONV = YesPlease
-       NO_STRTOUMAX = YesPlease
-       NO_STRTOULL = YesPlease
-       NO_MKDTEMP = YesPlease
-       NO_MKSTEMPS = YesPlease
-       SNPRINTF_RETURNS_BOGUS = YesPlease
-       NO_SVN_TESTS = YesPlease
-       NO_PERL_MAKEMAKER = YesPlease
-       RUNTIME_PREFIX = YesPlease
-       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
-       NO_NSEC = YesPlease
-       USE_WIN32_MMAP = YesPlease
-       # USE_NED_ALLOCATOR = YesPlease
-       UNRELIABLE_FSTAT = UnfortunatelyYes
-       OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
-       NO_REGEX = YesPlease
-       NO_CURL = YesPlease
-       NO_PYTHON = YesPlease
-       BLK_SHA1 = YesPlease
-       NO_POSIX_GOODIES = UnfortunatelyYes
-       NATIVE_CRLF = YesPlease
-       DEFAULT_HELP_FORMAT = html
-
-       CC = compat/vcbuild/scripts/clink.pl
-       AR = compat/vcbuild/scripts/lib.pl
-       CFLAGS =
-       BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
-       COMPAT_OBJS = compat/msvc.o compat/winansi.o \
-               compat/win32/pthread.o compat/win32/syslog.o \
-               compat/win32/dirent.o
-       COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-       BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
-       EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
-       PTHREAD_LIBS =
-       lib =
-ifndef DEBUG
-       BASIC_CFLAGS += -GL -Os -MT
-       BASIC_LDFLAGS += -LTCG
-       AR += -LTCG
-else
-       BASIC_CFLAGS += -Zi -MTd
-endif
-       X = .exe
-endif
-ifeq ($(uname_S),Interix)
-       NO_INITGROUPS = YesPlease
-       NO_IPV6 = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_MKDTEMP = YesPlease
-       NO_STRTOUMAX = YesPlease
-       NO_NSEC = YesPlease
-       NO_MKSTEMPS = YesPlease
-       ifeq ($(uname_R),3.5)
-               NO_INET_NTOP = YesPlease
-               NO_INET_PTON = YesPlease
-               NO_SOCKADDR_STORAGE = YesPlease
-               NO_FNMATCH_CASEFOLD = YesPlease
-       endif
-       ifeq ($(uname_R),5.2)
-               NO_INET_NTOP = YesPlease
-               NO_INET_PTON = YesPlease
-               NO_SOCKADDR_STORAGE = YesPlease
-               NO_FNMATCH_CASEFOLD = YesPlease
-       endif
-endif
-ifeq ($(uname_S),Minix)
-       NO_IPV6 = YesPlease
-       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
-       NO_NSEC = YesPlease
-       NEEDS_LIBGEN =
-       NEEDS_CRYPTO_WITH_SSL = YesPlease
-       NEEDS_IDN_WITH_CURL = YesPlease
-       NEEDS_SSL_WITH_CURL = YesPlease
-       NEEDS_RESOLV =
-       NO_HSTRERROR = YesPlease
-       NO_MMAP = YesPlease
-       NO_CURL =
-       NO_EXPAT =
-endif
-ifeq ($(uname_S),NONSTOP_KERNEL)
-       # Needs some C99 features, "inline" is just one of them.
-       # INLINE='' would just replace one set of warnings with another and
-       # still not compile in c89 mode, due to non-const array initializations.
-       CC = cc -c99
-       # Disable all optimization, seems to result in bad code, with -O or -O2
-       # or even -O1 (default), /usr/local/libexec/git-core/git-pack-objects
-       # abends on "git push". Needs more investigation.
-       CFLAGS = -g -O0
-       # We'd want it to be here.
-       prefix = /usr/local
-       # Our's are in ${prefix}/bin (perl might also be in /usr/bin/perl).
-       PERL_PATH = ${prefix}/bin/perl
-       PYTHON_PATH = ${prefix}/bin/python
-
-       # As detected by './configure'.
-       # Missdetected, hence commented out, see below.
-       #NO_CURL = YesPlease
-       # Added manually, see above.
-       NEEDS_SSL_WITH_CURL = YesPlease
-       HAVE_LIBCHARSET_H = YesPlease
-       NEEDS_LIBICONV = YesPlease
-       NEEDS_LIBINTL_BEFORE_LIBICONV = YesPlease
-       NO_SYS_SELECT_H = UnfortunatelyYes
-       NO_D_TYPE_IN_DIRENT = YesPlease
-       NO_HSTRERROR = YesPlease
-       NO_STRCASESTR = YesPlease
-       NO_FNMATCH_CASEFOLD = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_STRLCPY = YesPlease
-       NO_SETENV = YesPlease
-       NO_UNSETENV = YesPlease
-       NO_MKDTEMP = YesPlease
-       NO_MKSTEMPS = YesPlease
-       # Currently libiconv-1.9.1.
-       OLD_ICONV = UnfortunatelyYes
-       NO_REGEX = YesPlease
-       NO_PTHREADS = UnfortunatelyYes
-
-       # Not detected (nor checked for) by './configure'.
-       # We don't have SA_RESTART on NonStop, unfortunalety.
-       COMPAT_CFLAGS += -DSA_RESTART=0
-       # Apparently needed in compat/fnmatch/fnmatch.c.
-       COMPAT_CFLAGS += -DHAVE_STRING_H=1
-       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
-       NO_NSEC = YesPlease
-       NO_PREAD = YesPlease
-       NO_MMAP = YesPlease
-       NO_POLL = YesPlease
-       NO_INTPTR_T = UnfortunatelyYes
-       # Bug report 10-120822-4477 submitted to HP NonStop development.
-       MKDIR_WO_TRAILING_SLASH = YesPlease
-       # RFE 10-120912-4693 submitted to HP NonStop development.
-       NO_SETITIMER = UnfortunatelyYes
-       SANE_TOOL_PATH = /usr/coreutils/bin:/usr/local/bin
-       SHELL_PATH = /usr/local/bin/bash
-       # as of H06.25/J06.14, we might better use this
-       #SHELL_PATH = /usr/coreutils/bin/bash
-endif
-ifneq (,$(findstring MINGW,$(uname_S)))
-       pathsep = ;
-       NO_PREAD = YesPlease
-       NEEDS_CRYPTO_WITH_SSL = YesPlease
-       NO_LIBGEN_H = YesPlease
-       NO_POLL = YesPlease
-       NO_SYMLINK_HEAD = YesPlease
-       NO_UNIX_SOCKETS = YesPlease
-       NO_SETENV = YesPlease
-       NO_UNSETENV = YesPlease
-       NO_STRCASESTR = YesPlease
-       NO_STRLCPY = YesPlease
-       NO_STRTOK_R = YesPlease
-       NO_FNMATCH = YesPlease
-       NO_MEMMEM = YesPlease
-       NEEDS_LIBICONV = YesPlease
-       OLD_ICONV = YesPlease
-       NO_STRTOUMAX = YesPlease
-       NO_MKDTEMP = YesPlease
-       NO_MKSTEMPS = YesPlease
-       NO_SVN_TESTS = YesPlease
-       NO_PERL_MAKEMAKER = YesPlease
-       RUNTIME_PREFIX = YesPlease
-       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
-       NO_NSEC = YesPlease
-       USE_WIN32_MMAP = YesPlease
-       USE_NED_ALLOCATOR = YesPlease
-       UNRELIABLE_FSTAT = UnfortunatelyYes
-       OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
-       NO_REGEX = YesPlease
-       NO_PYTHON = YesPlease
-       BLK_SHA1 = YesPlease
-       ETAGS_TARGET = ETAGS
-       NO_INET_PTON = YesPlease
-       NO_INET_NTOP = YesPlease
-       NO_POSIX_GOODIES = UnfortunatelyYes
-       COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
-       COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
-       COMPAT_OBJS += compat/mingw.o compat/winansi.o \
-               compat/win32/pthread.o compat/win32/syslog.o \
-               compat/win32/dirent.o
-       EXTLIBS += -lws2_32
-       PTHREAD_LIBS =
-       X = .exe
-       SPARSE_FLAGS = -Wno-one-bit-signed-bitfield
-ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
-       htmldir = doc/git/html/
-       prefix =
-       INSTALL = /bin/install
-       EXTLIBS += /mingw/lib/libz.a
-       NO_R_TO_GCC_LINKER = YesPlease
-       INTERNAL_QSORT = YesPlease
-       HAVE_LIBCHARSET_H = YesPlease
-else
-       NO_CURL = YesPlease
-endif
-endif
-
+include config.mak.uname
 -include config.mak.autogen
 -include config.mak
 
@@ -1655,6 +1146,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 +1242,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 +1356,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 +1384,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 +1687,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
 
@@ -2275,8 +1779,14 @@ configure: configure.ac GIT-VERSION-FILE
        $(RM) $<+
 
 ifdef AUTOCONFIGURED
-config.status: configure
-       $(QUIET_GEN)if test -f config.status; then \
+# We avoid depending on 'configure' here, because it gets rebuilt
+# every time GIT-VERSION-FILE is modified, only to update the embedded
+# version number string, which config.status does not care about.  We
+# do want to recheck when the platform/environment detection logic
+# changes, hence this depends on configure.ac.
+config.status: configure.ac
+       $(QUIET_GEN)$(MAKE) configure && \
+       if test -f config.status; then \
          ./config.status --recheck; \
        else \
          ./configure; \
@@ -2564,7 +2074,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 +2083,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 +2092,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,18 +2134,6 @@ 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)')
-
-GIT-GUI-VARS: FORCE
-       @VARS='$(TRACK_VARS)'; \
-           if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
-               echo 1>&2 "    * new Tcl/Tk interpreter location"; \
-               echo "$$VARS" >$@; \
-            fi
-endif
-
 ### Detect Python interpreter path changes
 ifndef NO_PYTHON
 TRACK_PYTHON = $(subst ','\'',-DPYTHON_PATH='$(PYTHON_PATH_SQ)')
@@ -2643,7 +2141,7 @@ TRACK_PYTHON = $(subst ','\'',-DPYTHON_PATH='$(PYTHON_PATH_SQ)')
 GIT-PYTHON-VARS: FORCE
        @VARS='$(TRACK_PYTHON)'; \
            if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
-               echo 1>&2 "    * new Python interpreter location"; \
+               echo >&2 "    * new Python interpreter location"; \
                echo "$$VARS" >$@; \
             fi
 endif
@@ -2922,7 +2420,7 @@ 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-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
index 5964e1c4ca69a74cffebfbd27f693acce5d26cbc..bdce3136ea5164d82f0d25d0a7a8b50181f572f7 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.1.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 0ba3f25cf579d6629566a39d4d5ac19b51293ed5..d1cce46e3310d64af32b231de697449ae90ddccf 100644 (file)
@@ -153,6 +153,8 @@ static unsigned int ustar_header_chksum(const struct ustar_header *header)
 static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen)
 {
        size_t i = pathlen;
+       if (i > 1 && path[i - 1] == '/')
+               i--;
        if (i > maxlen)
                i = maxlen;
        do {
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..d6d71901b24855a1d33ef2edeb8fbc6ce8e969dc 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -284,7 +284,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
  * (reading the file from top to bottom), .gitattribute of the root
  * directory (again, reading the file from top to bottom) down to the
  * current directory, and then scan the list backwards to find the first match.
- * This is exactly the same as what excluded() does in dir.c to deal with
+ * This is exactly the same as what is_excluded() does in dir.c to deal with
  * .gitignore
  */
 
@@ -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 3faf9d6691413c006f4c82702aa5e0c5e4bc88a0..7e7bbd665a905b0fdf9ce5351f6f09dfd3dd7e8a 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -15,7 +15,8 @@ extern const char git_more_info_string[];
 extern void prune_packed_objects(int);
 
 struct fmt_merge_msg_opts {
-       unsigned add_title:1;
+       unsigned add_title:1,
+               credit_people:1;
        int shortlog_len;
 };
 
index e664100c7122d6c4116763716c2260756feffac2..075312afcd8813c3a7dbf08f6be519a37498fe4f 100644 (file)
@@ -454,7 +454,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                            && !file_exists(pathspec[i])) {
                                if (ignore_missing) {
                                        int dtype = DT_UNKNOWN;
-                                       if (path_excluded(&check, pathspec[i], -1, &dtype))
+                                       if (is_path_excluded(&check, pathspec[i], -1, &dtype))
                                                dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
                                } else
                                        die(_("pathspec '%s' did not match any files"),
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 1ec9c02612d0391984b484a5850f45c277a3e804..873f624d1cc70e03da4c67b30f8c839b4afe099d 100644 (file)
@@ -725,7 +725,7 @@ static int edit_branch_description(const char *branch_name)
        stripspace(&buf, 1);
 
        strbuf_addf(&name, "branch.%s.description", branch_name);
-       status = git_config_set(name.buf, buf.buf);
+       status = git_config_set(name.buf, buf.len ? buf.buf : NULL);
        strbuf_release(&name);
        strbuf_release(&buf);
 
index ec2f75b4f3b9d9acfb8aa6b423f3b0fc7fbbafdf..8d23a62e8a1b875f1415f78a4c283f4cdefac011 100644 (file)
@@ -771,8 +771,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                die(_("could not create leading directories of '%s'"), git_dir);
 
        set_git_dir_init(git_dir, real_git_dir, 0);
-       if (real_git_dir)
+       if (real_git_dir) {
                git_dir = real_git_dir;
+               junk_git_dir = real_git_dir;
+       }
 
        if (0 <= option_verbosity) {
                if (option_bare)
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 e2e27b2c404a1c451a20e396a7aa03dece722dad..d9af43c257150c957bf3bc3c3b7a7e43e370174c 100644 (file)
@@ -232,8 +232,9 @@ static void record_person(int which, struct string_list *people,
 {
        char *name_buf, *name, *name_end;
        struct string_list_item *elem;
-       const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
+       const char *field;
 
+       field = (which == 'a') ? "\nauthor " : "\ncommitter ";
        name = strstr(commit->buffer, field);
        if (!name)
                return;
@@ -323,7 +324,8 @@ static void add_people_info(struct strbuf *out,
 static void shortlog(const char *name,
                     struct origin_data *origin_data,
                     struct commit *head,
-                    struct rev_info *rev, int limit,
+                    struct rev_info *rev,
+                    struct fmt_merge_msg_opts *opts,
                     struct strbuf *out)
 {
        int i, count = 0;
@@ -335,6 +337,7 @@ static void shortlog(const char *name,
        int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
        struct strbuf sb = STRBUF_INIT;
        const unsigned char *sha1 = origin_data->sha1;
+       int limit = opts->shortlog_len;
 
        branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
        if (!branch || branch->type != OBJ_COMMIT)
@@ -351,13 +354,15 @@ static void shortlog(const char *name,
 
                if (commit->parents && commit->parents->next) {
                        /* do not list a merge but count committer */
-                       record_person('c', &committers, commit);
+                       if (opts->credit_people)
+                               record_person('c', &committers, commit);
                        continue;
                }
-               if (!count)
+               if (!count && opts->credit_people)
                        /* the 'tip' committer */
                        record_person('c', &committers, commit);
-               record_person('a', &authors, commit);
+               if (opts->credit_people)
+                       record_person('a', &authors, commit);
                count++;
                if (subjects.nr > limit)
                        continue;
@@ -372,7 +377,8 @@ static void shortlog(const char *name,
                        string_list_append(&subjects, strbuf_detach(&sb, NULL));
        }
 
-       add_people_info(out, &authors, &committers);
+       if (opts->credit_people)
+               add_people_info(out, &authors, &committers);
        if (count > limit)
                strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
        else
@@ -635,7 +641,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                for (i = 0; i < origins.nr; i++)
                        shortlog(origins.items[i].string,
                                 origins.items[i].util,
-                                head, &rev, opts->shortlog_len, out);
+                                head, &rev, opts, out);
        }
 
        strbuf_complete_line(out);
@@ -690,6 +696,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 
        memset(&opts, 0, sizeof(opts));
        opts.add_title = !message;
+       opts.credit_people = 1;
        opts.shortlog_len = shortlog_len;
 
        ret = fmt_merge_msg(&input, &output, &opts);
index e7b7db1cacf1934a9bb0b96beb98ddda15a66074..3899b1d43acc8c51e7609be94469eac057116440 100644 (file)
@@ -1016,8 +1016,9 @@ static char *find_branch_name(struct rev_info *rev)
 {
        int i, positive = -1;
        unsigned char branch_sha1[20];
-       struct strbuf buf = STRBUF_INIT;
-       const char *branch;
+       const unsigned char *tip_sha1;
+       const char *ref;
+       char *full_ref, *branch = NULL;
 
        for (i = 0; i < rev->cmdline.nr; i++) {
                if (rev->cmdline.rev[i].flags & UNINTERESTING)
@@ -1027,18 +1028,27 @@ static char *find_branch_name(struct rev_info *rev)
                else
                        return NULL;
        }
-       if (positive < 0)
+       if (0 <= positive) {
+               ref = rev->cmdline.rev[positive].name;
+               tip_sha1 = rev->cmdline.rev[positive].item->sha1;
+       } else if (!rev->cmdline.nr && rev->pending.nr == 1 &&
+                  !strcmp(rev->pending.objects[0].name, "HEAD")) {
+               /*
+                * No actual ref from command line, but "HEAD" from
+                * rev->def was added in setup_revisions()
+                * e.g. format-patch --cover-letter -12
+                */
+               ref = "HEAD";
+               tip_sha1 = rev->pending.objects[0].item->sha1;
+       } else {
                return NULL;
-       strbuf_addf(&buf, "refs/heads/%s", rev->cmdline.rev[positive].name);
-       branch = resolve_ref_unsafe(buf.buf, branch_sha1, 1, NULL);
-       if (!branch ||
-           prefixcmp(branch, "refs/heads/") ||
-           hashcmp(rev->cmdline.rev[positive].item->sha1, branch_sha1))
-               branch = NULL;
-       strbuf_release(&buf);
-       if (branch)
-               return xstrdup(rev->cmdline.rev[positive].name);
-       return NULL;
+       }
+       if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
+           !prefixcmp(full_ref, "refs/heads/") &&
+           !hashcmp(tip_sha1, branch_sha1))
+               branch = xstrdup(full_ref + strlen("refs/heads/"));
+       free(full_ref);
+       return branch;
 }
 
 int cmd_format_patch(int argc, const char **argv, const char *prefix)
index b5434af0c87741f3160388cf86904c6e3f903527..373c573449b5771f9b56d7d4ce04e4c0b3957cd9 100644 (file)
@@ -203,7 +203,7 @@ static void show_ru_info(void)
 static int ce_excluded(struct path_exclude_check *check, struct cache_entry *ce)
 {
        int dtype = ce_to_dtype(ce);
-       return path_excluded(check, ce->name, ce_namelen(ce), &dtype);
+       return is_path_excluded(check, ce->name, ce_namelen(ce), &dtype);
 }
 
 static void show_files(struct dir_struct *dir)
@@ -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 a96e8eac19911c710f0f6870a53bda480b09747b..9307e9c726587461d002530938dbf2c0d74d55a1 100644 (file)
@@ -800,8 +800,9 @@ static void prepare_to_commit(struct commit_list *remoteheads)
        if (0 < option_edit)
                strbuf_add_lines(&msg, "# ", comment, strlen(comment));
        write_merge_msg(&msg);
-       run_hook(get_index_file(), "prepare-commit-msg",
-                git_path("MERGE_MSG"), "merge", NULL, NULL);
+       if (run_hook(get_index_file(), "prepare-commit-msg",
+                    git_path("MERGE_MSG"), "merge", NULL, NULL))
+               abort_commit(remoteheads, NULL);
        if (0 < option_edit) {
                if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
                        abort_commit(remoteheads, NULL);
@@ -1221,6 +1222,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        memset(&opts, 0, sizeof(opts));
                        opts.add_title = !have_message;
                        opts.shortlog_len = shortlog_len;
+                       opts.credit_people = (0 < option_edit);
 
                        fmt_merge_msg(&merge_names, &merge_msg, &opts);
                        if (merge_msg.len)
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;
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 b8b7dc254373fb0f7b2a7b16163fa72e1e8c5f7b..5ef0685135662e3cefc80eed5c5ae030fe1a5d49 100644 (file)
@@ -55,7 +55,8 @@
    program understand `configure --with-gnu-libc' and omit the object files,
    it is simpler to just do this in the source for each such file.  */
 
-#if defined _LIBC || !defined __GNU_LIBRARY__
+#if defined NO_FNMATCH || defined NO_FNMATCH_CASEFOLD || \
+    defined _LIBC || !defined __GNU_LIBRARY__
 
 
 # if defined STDC_HEADERS || !defined isascii
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);
diff --git a/config.mak.uname b/config.mak.uname
new file mode 100644 (file)
index 0000000..bea34f0
--- /dev/null
@@ -0,0 +1,539 @@
+# Platform specific Makefile tweaks based on uname detection
+
+uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
+uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
+uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
+uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
+uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
+uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
+
+ifdef MSVC
+       # avoid the MingW and Cygwin configuration sections
+       uname_S := Windows
+       uname_O := Windows
+endif
+
+# We choose to avoid "if .. else if .. else .. endif endif"
+# because maintaining the nesting to match is a pain.  If
+# we had "elif" things would have been much nicer...
+
+ifeq ($(uname_M),x86_64)
+       XDL_FAST_HASH = YesPlease
+endif
+ifeq ($(uname_S),OSF1)
+       # Need this for u_short definitions et al
+       BASIC_CFLAGS += -D_OSF_SOURCE
+       SOCKLEN_T = int
+       NO_STRTOULL = YesPlease
+       NO_NSEC = YesPlease
+endif
+ifeq ($(uname_S),Linux)
+       NO_STRLCPY = YesPlease
+       NO_MKSTEMPS = YesPlease
+       HAVE_PATHS_H = YesPlease
+       LIBC_CONTAINS_LIBINTL = YesPlease
+       HAVE_DEV_TTY = YesPlease
+endif
+ifeq ($(uname_S),GNU/kFreeBSD)
+       NO_STRLCPY = YesPlease
+       NO_MKSTEMPS = YesPlease
+       HAVE_PATHS_H = YesPlease
+       DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
+       LIBC_CONTAINS_LIBINTL = YesPlease
+endif
+ifeq ($(uname_S),UnixWare)
+       CC = cc
+       NEEDS_SOCKET = YesPlease
+       NEEDS_NSL = YesPlease
+       NEEDS_SSL_WITH_CRYPTO = YesPlease
+       NEEDS_LIBICONV = YesPlease
+       SHELL_PATH = /usr/local/bin/bash
+       NO_IPV6 = YesPlease
+       NO_HSTRERROR = YesPlease
+       NO_MKSTEMPS = YesPlease
+       BASIC_CFLAGS += -Kthread
+       BASIC_CFLAGS += -I/usr/local/include
+       BASIC_LDFLAGS += -L/usr/local/lib
+       INSTALL = ginstall
+       TAR = gtar
+       NO_STRCASESTR = YesPlease
+       NO_MEMMEM = YesPlease
+endif
+ifeq ($(uname_S),SCO_SV)
+       ifeq ($(uname_R),3.2)
+               CFLAGS = -O2
+       endif
+       ifeq ($(uname_R),5)
+               CC = cc
+               BASIC_CFLAGS += -Kthread
+       endif
+       NEEDS_SOCKET = YesPlease
+       NEEDS_NSL = YesPlease
+       NEEDS_SSL_WITH_CRYPTO = YesPlease
+       NEEDS_LIBICONV = YesPlease
+       SHELL_PATH = /usr/bin/bash
+       NO_IPV6 = YesPlease
+       NO_HSTRERROR = YesPlease
+       NO_MKSTEMPS = YesPlease
+       BASIC_CFLAGS += -I/usr/local/include
+       BASIC_LDFLAGS += -L/usr/local/lib
+       NO_STRCASESTR = YesPlease
+       NO_MEMMEM = YesPlease
+       INSTALL = ginstall
+       TAR = gtar
+endif
+ifeq ($(uname_S),Darwin)
+       NEEDS_CRYPTO_WITH_SSL = YesPlease
+       NEEDS_SSL_WITH_CRYPTO = YesPlease
+       NEEDS_LIBICONV = YesPlease
+       ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2)
+               OLD_ICONV = UnfortunatelyYes
+       endif
+       ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2)
+               NO_STRLCPY = YesPlease
+       endif
+       NO_MEMMEM = YesPlease
+       USE_ST_TIMESPEC = YesPlease
+       HAVE_DEV_TTY = YesPlease
+       COMPAT_OBJS += compat/precompose_utf8.o
+       BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
+endif
+ifeq ($(uname_S),SunOS)
+       NEEDS_SOCKET = YesPlease
+       NEEDS_NSL = YesPlease
+       SHELL_PATH = /bin/bash
+       SANE_TOOL_PATH = /usr/xpg6/bin:/usr/xpg4/bin
+       NO_STRCASESTR = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_MKSTEMPS = YesPlease
+       NO_REGEX = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
+       NO_MSGFMT_EXTENDED_OPTIONS = YesPlease
+       HAVE_DEV_TTY = YesPlease
+       ifeq ($(uname_R),5.6)
+               SOCKLEN_T = int
+               NO_HSTRERROR = YesPlease
+               NO_IPV6 = YesPlease
+               NO_SOCKADDR_STORAGE = YesPlease
+               NO_UNSETENV = YesPlease
+               NO_SETENV = YesPlease
+               NO_STRLCPY = YesPlease
+               NO_STRTOUMAX = YesPlease
+               GIT_TEST_CMP = cmp
+       endif
+       ifeq ($(uname_R),5.7)
+               NEEDS_RESOLV = YesPlease
+               NO_IPV6 = YesPlease
+               NO_SOCKADDR_STORAGE = YesPlease
+               NO_UNSETENV = YesPlease
+               NO_SETENV = YesPlease
+               NO_STRLCPY = YesPlease
+               NO_STRTOUMAX = YesPlease
+               GIT_TEST_CMP = cmp
+       endif
+       ifeq ($(uname_R),5.8)
+               NO_UNSETENV = YesPlease
+               NO_SETENV = YesPlease
+               NO_STRTOUMAX = YesPlease
+               GIT_TEST_CMP = cmp
+       endif
+       ifeq ($(uname_R),5.9)
+               NO_UNSETENV = YesPlease
+               NO_SETENV = YesPlease
+               NO_STRTOUMAX = YesPlease
+               GIT_TEST_CMP = cmp
+       endif
+       INSTALL = /usr/ucb/install
+       TAR = gtar
+       BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
+endif
+ifeq ($(uname_O),Cygwin)
+       ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4)
+               NO_D_TYPE_IN_DIRENT = YesPlease
+               NO_D_INO_IN_DIRENT = YesPlease
+               NO_STRCASESTR = YesPlease
+               NO_MEMMEM = YesPlease
+               NO_MKSTEMPS = YesPlease
+               NO_SYMLINK_HEAD = YesPlease
+               NO_IPV6 = YesPlease
+               OLD_ICONV = UnfortunatelyYes
+               CYGWIN_V15_WIN32API = YesPlease
+       endif
+       NO_THREAD_SAFE_PREAD = YesPlease
+       NEEDS_LIBICONV = YesPlease
+       NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
+       NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
+       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+       # There are conflicting reports about this.
+       # On some boxes NO_MMAP is needed, and not so elsewhere.
+       # Try commenting this out if you suspect MMAP is more efficient
+       NO_MMAP = YesPlease
+       X = .exe
+       COMPAT_OBJS += compat/cygwin.o
+       UNRELIABLE_FSTAT = UnfortunatelyYes
+       SPARSE_FLAGS = -isystem /usr/include/w32api -Wno-one-bit-signed-bitfield
+endif
+ifeq ($(uname_S),FreeBSD)
+       NEEDS_LIBICONV = YesPlease
+       OLD_ICONV = YesPlease
+       NO_MEMMEM = YesPlease
+       BASIC_CFLAGS += -I/usr/local/include
+       BASIC_LDFLAGS += -L/usr/local/lib
+       DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
+       USE_ST_TIMESPEC = YesPlease
+       ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
+               PTHREAD_LIBS = -pthread
+               NO_UINTMAX_T = YesPlease
+               NO_STRTOUMAX = YesPlease
+       endif
+       PYTHON_PATH = /usr/local/bin/python
+       HAVE_PATHS_H = YesPlease
+endif
+ifeq ($(uname_S),OpenBSD)
+       NO_STRCASESTR = YesPlease
+       NO_MEMMEM = YesPlease
+       USE_ST_TIMESPEC = YesPlease
+       NEEDS_LIBICONV = YesPlease
+       BASIC_CFLAGS += -I/usr/local/include
+       BASIC_LDFLAGS += -L/usr/local/lib
+       HAVE_PATHS_H = YesPlease
+endif
+ifeq ($(uname_S),NetBSD)
+       ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
+               NEEDS_LIBICONV = YesPlease
+       endif
+       BASIC_CFLAGS += -I/usr/pkg/include
+       BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
+       USE_ST_TIMESPEC = YesPlease
+       NO_MKSTEMPS = YesPlease
+       HAVE_PATHS_H = YesPlease
+endif
+ifeq ($(uname_S),AIX)
+       DEFAULT_PAGER = more
+       NO_STRCASESTR = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_MKSTEMPS = YesPlease
+       NO_STRLCPY = YesPlease
+       NO_NSEC = YesPlease
+       FREAD_READS_DIRECTORIES = UnfortunatelyYes
+       INTERNAL_QSORT = UnfortunatelyYes
+       NEEDS_LIBICONV = YesPlease
+       BASIC_CFLAGS += -D_LARGE_FILES
+       ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
+               NO_PTHREADS = YesPlease
+       else
+               PTHREAD_LIBS = -lpthread
+       endif
+       ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3)
+               INLINE = ''
+       endif
+       GIT_TEST_CMP = cmp
+endif
+ifeq ($(uname_S),GNU)
+       # GNU/Hurd
+       NO_STRLCPY = YesPlease
+       NO_MKSTEMPS = YesPlease
+       HAVE_PATHS_H = YesPlease
+       LIBC_CONTAINS_LIBINTL = YesPlease
+endif
+ifeq ($(uname_S),IRIX)
+       NO_SETENV = YesPlease
+       NO_UNSETENV = YesPlease
+       NO_STRCASESTR = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_MKSTEMPS = YesPlease
+       NO_MKDTEMP = YesPlease
+       # When compiled with the MIPSpro 7.4.4m compiler, and without pthreads
+       # (i.e. NO_PTHREADS is set), and _with_ MMAP (i.e. NO_MMAP is not set),
+       # git dies with a segmentation fault when trying to access the first
+       # entry of a reflog.  The conservative choice is made to always set
+       # NO_MMAP.  If you suspect that your compiler is not affected by this
+       # issue, comment out the NO_MMAP statement.
+       NO_MMAP = YesPlease
+       NO_REGEX = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
+       SNPRINTF_RETURNS_BOGUS = YesPlease
+       SHELL_PATH = /usr/gnu/bin/bash
+       NEEDS_LIBGEN = YesPlease
+endif
+ifeq ($(uname_S),IRIX64)
+       NO_SETENV = YesPlease
+       NO_UNSETENV = YesPlease
+       NO_STRCASESTR = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_MKSTEMPS = YesPlease
+       NO_MKDTEMP = YesPlease
+       # When compiled with the MIPSpro 7.4.4m compiler, and without pthreads
+       # (i.e. NO_PTHREADS is set), and _with_ MMAP (i.e. NO_MMAP is not set),
+       # git dies with a segmentation fault when trying to access the first
+       # entry of a reflog.  The conservative choice is made to always set
+       # NO_MMAP.  If you suspect that your compiler is not affected by this
+       # issue, comment out the NO_MMAP statement.
+       NO_MMAP = YesPlease
+       NO_REGEX = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
+       SNPRINTF_RETURNS_BOGUS = YesPlease
+       SHELL_PATH = /usr/gnu/bin/bash
+       NEEDS_LIBGEN = YesPlease
+endif
+ifeq ($(uname_S),HP-UX)
+       INLINE = __inline
+       NO_IPV6 = YesPlease
+       NO_SETENV = YesPlease
+       NO_STRCASESTR = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_MKSTEMPS = YesPlease
+       NO_STRLCPY = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_UNSETENV = YesPlease
+       NO_HSTRERROR = YesPlease
+       NO_SYS_SELECT_H = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
+       SNPRINTF_RETURNS_BOGUS = YesPlease
+       NO_NSEC = YesPlease
+       ifeq ($(uname_R),B.11.00)
+               NO_INET_NTOP = YesPlease
+               NO_INET_PTON = YesPlease
+       endif
+       ifeq ($(uname_R),B.10.20)
+               # Override HP-UX 11.x setting:
+               INLINE =
+               SOCKLEN_T = size_t
+               NO_PREAD = YesPlease
+               NO_INET_NTOP = YesPlease
+               NO_INET_PTON = YesPlease
+       endif
+       GIT_TEST_CMP = cmp
+endif
+ifeq ($(uname_S),Windows)
+       GIT_VERSION := $(GIT_VERSION).MSVC
+       pathsep = ;
+       NO_PREAD = YesPlease
+       NEEDS_CRYPTO_WITH_SSL = YesPlease
+       NO_LIBGEN_H = YesPlease
+       NO_POLL = YesPlease
+       NO_SYMLINK_HEAD = YesPlease
+       NO_IPV6 = YesPlease
+       NO_UNIX_SOCKETS = YesPlease
+       NO_SETENV = YesPlease
+       NO_UNSETENV = YesPlease
+       NO_STRCASESTR = YesPlease
+       NO_STRLCPY = YesPlease
+       NO_STRTOK_R = YesPlease
+       NO_FNMATCH = YesPlease
+       NO_MEMMEM = YesPlease
+       # NEEDS_LIBICONV = YesPlease
+       NO_ICONV = YesPlease
+       NO_STRTOUMAX = YesPlease
+       NO_STRTOULL = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_MKSTEMPS = YesPlease
+       SNPRINTF_RETURNS_BOGUS = YesPlease
+       NO_SVN_TESTS = YesPlease
+       NO_PERL_MAKEMAKER = YesPlease
+       RUNTIME_PREFIX = YesPlease
+       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+       NO_NSEC = YesPlease
+       USE_WIN32_MMAP = YesPlease
+       # USE_NED_ALLOCATOR = YesPlease
+       UNRELIABLE_FSTAT = UnfortunatelyYes
+       OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
+       NO_REGEX = YesPlease
+       NO_CURL = YesPlease
+       NO_PYTHON = YesPlease
+       BLK_SHA1 = YesPlease
+       NO_POSIX_GOODIES = UnfortunatelyYes
+       NATIVE_CRLF = YesPlease
+       DEFAULT_HELP_FORMAT = html
+
+       CC = compat/vcbuild/scripts/clink.pl
+       AR = compat/vcbuild/scripts/lib.pl
+       CFLAGS =
+       BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
+       COMPAT_OBJS = compat/msvc.o compat/winansi.o \
+               compat/win32/pthread.o compat/win32/syslog.o \
+               compat/win32/dirent.o
+       COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
+       BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+       EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
+       PTHREAD_LIBS =
+       lib =
+ifndef DEBUG
+       BASIC_CFLAGS += -GL -Os -MT
+       BASIC_LDFLAGS += -LTCG
+       AR += -LTCG
+else
+       BASIC_CFLAGS += -Zi -MTd
+endif
+       X = .exe
+endif
+ifeq ($(uname_S),Interix)
+       NO_INITGROUPS = YesPlease
+       NO_IPV6 = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_STRTOUMAX = YesPlease
+       NO_NSEC = YesPlease
+       NO_MKSTEMPS = YesPlease
+       ifeq ($(uname_R),3.5)
+               NO_INET_NTOP = YesPlease
+               NO_INET_PTON = YesPlease
+               NO_SOCKADDR_STORAGE = YesPlease
+               NO_FNMATCH_CASEFOLD = YesPlease
+       endif
+       ifeq ($(uname_R),5.2)
+               NO_INET_NTOP = YesPlease
+               NO_INET_PTON = YesPlease
+               NO_SOCKADDR_STORAGE = YesPlease
+               NO_FNMATCH_CASEFOLD = YesPlease
+       endif
+endif
+ifeq ($(uname_S),Minix)
+       NO_IPV6 = YesPlease
+       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+       NO_NSEC = YesPlease
+       NEEDS_LIBGEN =
+       NEEDS_CRYPTO_WITH_SSL = YesPlease
+       NEEDS_IDN_WITH_CURL = YesPlease
+       NEEDS_SSL_WITH_CURL = YesPlease
+       NEEDS_RESOLV =
+       NO_HSTRERROR = YesPlease
+       NO_MMAP = YesPlease
+       NO_CURL =
+       NO_EXPAT =
+endif
+ifeq ($(uname_S),NONSTOP_KERNEL)
+       # Needs some C99 features, "inline" is just one of them.
+       # INLINE='' would just replace one set of warnings with another and
+       # still not compile in c89 mode, due to non-const array initializations.
+       CC = cc -c99
+       # Disable all optimization, seems to result in bad code, with -O or -O2
+       # or even -O1 (default), /usr/local/libexec/git-core/git-pack-objects
+       # abends on "git push". Needs more investigation.
+       CFLAGS = -g -O0
+       # We'd want it to be here.
+       prefix = /usr/local
+       # Our's are in ${prefix}/bin (perl might also be in /usr/bin/perl).
+       PERL_PATH = ${prefix}/bin/perl
+       PYTHON_PATH = ${prefix}/bin/python
+
+       # As detected by './configure'.
+       # Missdetected, hence commented out, see below.
+       #NO_CURL = YesPlease
+       # 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
+       NO_D_TYPE_IN_DIRENT = YesPlease
+       NO_HSTRERROR = YesPlease
+       NO_STRCASESTR = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_STRLCPY = YesPlease
+       NO_SETENV = YesPlease
+       NO_UNSETENV = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_MKSTEMPS = YesPlease
+       # Currently libiconv-1.9.1.
+       OLD_ICONV = UnfortunatelyYes
+       NO_REGEX = YesPlease
+       NO_PTHREADS = UnfortunatelyYes
+
+       # Not detected (nor checked for) by './configure'.
+       # We don't have SA_RESTART on NonStop, unfortunalety.
+       COMPAT_CFLAGS += -DSA_RESTART=0
+       # Apparently needed in compat/fnmatch/fnmatch.c.
+       COMPAT_CFLAGS += -DHAVE_STRING_H=1
+       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+       NO_NSEC = YesPlease
+       NO_PREAD = YesPlease
+       NO_MMAP = YesPlease
+       NO_POLL = YesPlease
+       NO_INTPTR_T = UnfortunatelyYes
+       # Bug report 10-120822-4477 submitted to HP NonStop development.
+       MKDIR_WO_TRAILING_SLASH = YesPlease
+       # RFE 10-120912-4693 submitted to HP NonStop development.
+       NO_SETITIMER = UnfortunatelyYes
+       SANE_TOOL_PATH = /usr/coreutils/bin:/usr/local/bin
+       SHELL_PATH = /usr/local/bin/bash
+       # as of H06.25/J06.14, we might better use this
+       #SHELL_PATH = /usr/coreutils/bin/bash
+endif
+ifneq (,$(findstring MINGW,$(uname_S)))
+       pathsep = ;
+       NO_PREAD = YesPlease
+       NEEDS_CRYPTO_WITH_SSL = YesPlease
+       NO_LIBGEN_H = YesPlease
+       NO_POLL = YesPlease
+       NO_SYMLINK_HEAD = YesPlease
+       NO_UNIX_SOCKETS = YesPlease
+       NO_SETENV = YesPlease
+       NO_UNSETENV = YesPlease
+       NO_STRCASESTR = YesPlease
+       NO_STRLCPY = YesPlease
+       NO_STRTOK_R = YesPlease
+       NO_FNMATCH = YesPlease
+       NO_MEMMEM = YesPlease
+       NEEDS_LIBICONV = YesPlease
+       OLD_ICONV = YesPlease
+       NO_STRTOUMAX = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_MKSTEMPS = YesPlease
+       NO_SVN_TESTS = YesPlease
+       NO_PERL_MAKEMAKER = YesPlease
+       RUNTIME_PREFIX = YesPlease
+       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+       NO_NSEC = YesPlease
+       USE_WIN32_MMAP = YesPlease
+       USE_NED_ALLOCATOR = YesPlease
+       UNRELIABLE_FSTAT = UnfortunatelyYes
+       OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
+       NO_REGEX = YesPlease
+       NO_PYTHON = YesPlease
+       BLK_SHA1 = YesPlease
+       ETAGS_TARGET = ETAGS
+       NO_INET_PTON = YesPlease
+       NO_INET_NTOP = YesPlease
+       NO_POSIX_GOODIES = UnfortunatelyYes
+       COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
+       COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
+       COMPAT_OBJS += compat/mingw.o compat/winansi.o \
+               compat/win32/pthread.o compat/win32/syslog.o \
+               compat/win32/dirent.o
+       EXTLIBS += -lws2_32
+       PTHREAD_LIBS =
+       X = .exe
+       SPARSE_FLAGS = -Wno-one-bit-signed-bitfield
+ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
+       htmldir = doc/git/html/
+       prefix =
+       INSTALL = /bin/install
+       EXTLIBS += /mingw/lib/libz.a
+       NO_R_TO_GCC_LINKER = YesPlease
+       INTERNAL_QSORT = YesPlease
+       HAVE_LIBCHARSET_H = YesPlease
+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
index 41ac9a5e2d29b5f797a03052c3a17a8b42dac093..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=
index bd24395d4cf404f886803892d0be98c964a43ce7..36b5665ff81af1d52be5e926b029452d3e838c35 100755 (executable)
 # we default to that.
 #
 
-import os, sys, commands, socket, urllib
+import sys
+if sys.hexversion < 0x02000000:
+        # The limiter is the xml.sax module
+        sys.stderr.write("ciabot.py: requires Python 2.0.0 or later.\n")
+        sys.exit(1)
+
+import os, commands, socket, urllib
 from xml.sax.saxutils import escape
 
 # Changeset URL prefix for your repo: when the commit ID is appended
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
index 82f5ed3ddc8adb1b9b281c3912f4e67c53ef152f..5cec9b012994de61ba6ed1e4c17992edbfd8a07d 100755 (executable)
@@ -9,10 +9,15 @@
 ##  git log --stat import-zips
 
 from os import popen, path
-from sys import argv, exit
+from sys import argv, exit, hexversion, stderr
 from time import mktime
 from zipfile import ZipFile
 
+if hexversion < 0x01060000:
+        # The limiter is the zipfile module
+        sys.stderr.write("import-zips.py: requires Python 1.6.0 or later.\n")
+        sys.exit(1)
+
 if len(argv) < 2:
        print 'Usage:', argv[0], '<zipfile>...'
        exit(1)
index 046cb2b268a82358630e86bb55cf8b4e58c730fb..232625a7b72aef88ef9cc0285eb7208ce38a2138 100755 (executable)
 import tempfile, pickle, getopt
 import re
 
+if sys.hexversion < 0x02030000:
+   # The behavior of the pickle module changed significantly in 2.3
+   sys.stderr.write("hg-to-git.py: requires Python 2.3 or later.\n")
+   sys.exit(1)
+
 # Maps hg version -> git version
 hgvers = {}
 # List of children for each hg revision
index b6e534b65b687d955a878d902b9bb46cfa2e42ce..593d6a0682ba49e31e40e1b4e5c3e0af82fd9cda 100644 (file)
 import time
 import getopt
 
+if sys.hexversion < 0x02020000:
+   # The behavior of the marshal module changed significantly in 2.2
+   sys.stderr.write("git-p4import.py: requires Python 2.2 or later.\n")
+   sys.exit(1)
+
 from signal import signal, \
    SIGPIPE, SIGINT, SIG_DFL, \
    default_int_handler
diff --git a/contrib/remote-helpers/git-remote-bzr b/contrib/remote-helpers/git-remote-bzr
new file mode 100755 (executable)
index 0000000..c5822e4
--- /dev/null
@@ -0,0 +1,725 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012 Felipe Contreras
+#
+
+#
+# Just copy to your ~/bin, or anywhere in your $PATH.
+# Then you can clone with:
+# % git clone bzr::/path/to/bzr/repo/or/url
+#
+# For example:
+# % git clone bzr::$HOME/myrepo
+# or
+# % git clone bzr::lp:myrepo
+#
+
+import sys
+
+import bzrlib
+if hasattr(bzrlib, "initialize"):
+    bzrlib.initialize()
+
+import bzrlib.plugin
+bzrlib.plugin.load_plugins()
+
+import bzrlib.generate_ids
+import bzrlib.transport
+
+import sys
+import os
+import json
+import re
+import StringIO
+
+NAME_RE = re.compile('^([^<>]+)')
+AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')
+RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)')
+
+def die(msg, *args):
+    sys.stderr.write('ERROR: %s\n' % (msg % args))
+    sys.exit(1)
+
+def warn(msg, *args):
+    sys.stderr.write('WARNING: %s\n' % (msg % args))
+
+def gittz(tz):
+    return '%+03d%02d' % (tz / 3600, tz % 3600 / 60)
+
+class Marks:
+
+    def __init__(self, path):
+        self.path = path
+        self.tips = {}
+        self.marks = {}
+        self.rev_marks = {}
+        self.last_mark = 0
+        self.load()
+
+    def load(self):
+        if not os.path.exists(self.path):
+            return
+
+        tmp = json.load(open(self.path))
+        self.tips = tmp['tips']
+        self.marks = tmp['marks']
+        self.last_mark = tmp['last-mark']
+
+        for rev, mark in self.marks.iteritems():
+            self.rev_marks[mark] = rev
+
+    def dict(self):
+        return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
+
+    def store(self):
+        json.dump(self.dict(), open(self.path, 'w'))
+
+    def __str__(self):
+        return str(self.dict())
+
+    def from_rev(self, rev):
+        return self.marks[rev]
+
+    def to_rev(self, mark):
+        return self.rev_marks[mark]
+
+    def next_mark(self):
+        self.last_mark += 1
+        return self.last_mark
+
+    def get_mark(self, rev):
+        self.last_mark += 1
+        self.marks[rev] = self.last_mark
+        return self.last_mark
+
+    def is_marked(self, rev):
+        return self.marks.has_key(rev)
+
+    def new_mark(self, rev, mark):
+        self.marks[rev] = mark
+        self.rev_marks[mark] = rev
+        self.last_mark = mark
+
+    def get_tip(self, branch):
+        return self.tips.get(branch, None)
+
+    def set_tip(self, branch, tip):
+        self.tips[branch] = tip
+
+class Parser:
+
+    def __init__(self, repo):
+        self.repo = repo
+        self.line = self.get_line()
+
+    def get_line(self):
+        return sys.stdin.readline().strip()
+
+    def __getitem__(self, i):
+        return self.line.split()[i]
+
+    def check(self, word):
+        return self.line.startswith(word)
+
+    def each_block(self, separator):
+        while self.line != separator:
+            yield self.line
+            self.line = self.get_line()
+
+    def __iter__(self):
+        return self.each_block('')
+
+    def next(self):
+        self.line = self.get_line()
+        if self.line == 'done':
+            self.line = None
+
+    def get_mark(self):
+        i = self.line.index(':') + 1
+        return int(self.line[i:])
+
+    def get_data(self):
+        if not self.check('data'):
+            return None
+        i = self.line.index(' ') + 1
+        size = int(self.line[i:])
+        return sys.stdin.read(size)
+
+    def get_author(self):
+        m = RAW_AUTHOR_RE.match(self.line)
+        if not m:
+            return None
+        _, name, email, date, tz = m.groups()
+        committer = '%s <%s>' % (name, email)
+        tz = int(tz)
+        tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
+        return (committer, int(date), tz)
+
+def rev_to_mark(rev):
+    global marks
+    return marks.from_rev(rev)
+
+def mark_to_rev(mark):
+    global marks
+    return marks.to_rev(mark)
+
+def fixup_user(user):
+    name = mail = None
+    user = user.replace('"', '')
+    m = AUTHOR_RE.match(user)
+    if m:
+        name = m.group(1)
+        mail = m.group(2).strip()
+    else:
+        m = NAME_RE.match(user)
+        if m:
+            name = m.group(1).strip()
+
+    return '%s <%s>' % (name, mail)
+
+def get_filechanges(cur, prev):
+    modified = {}
+    removed = {}
+
+    changes = cur.changes_from(prev)
+
+    for path, fid, kind in changes.added:
+        modified[path] = fid
+    for path, fid, kind in changes.removed:
+        removed[path] = None
+    for path, fid, kind, mod, _ in changes.modified:
+        modified[path] = fid
+    for oldpath, newpath, fid, kind, mod, _ in changes.renamed:
+        removed[oldpath] = None
+        modified[newpath] = fid
+
+    return modified, removed
+
+def export_files(tree, files):
+    global marks, filenodes
+
+    final = []
+    for path, fid in files.iteritems():
+        kind = tree.kind(fid)
+
+        h = tree.get_file_sha1(fid)
+
+        if kind == 'symlink':
+            d = tree.get_symlink_target(fid)
+            mode = '120000'
+        elif kind == 'file':
+
+            if tree.is_executable(fid):
+                mode = '100755'
+            else:
+                mode = '100644'
+
+            # is the blog already exported?
+            if h in filenodes:
+                mark = filenodes[h]
+                final.append((mode, mark, path))
+                continue
+
+            d = tree.get_file_text(fid)
+        elif kind == 'directory':
+            continue
+        else:
+            die("Unhandled kind '%s' for path '%s'" % (kind, path))
+
+        mark = marks.next_mark()
+        filenodes[h] = mark
+
+        print "blob"
+        print "mark :%u" % mark
+        print "data %d" % len(d)
+        print d
+
+        final.append((mode, mark, path))
+
+    return final
+
+def export_branch(branch, name):
+    global prefix, dirname
+
+    ref = '%s/heads/%s' % (prefix, name)
+    tip = marks.get_tip(name)
+
+    repo = branch.repository
+    repo.lock_read()
+    revs = branch.iter_merge_sorted_revisions(None, tip, 'exclude', 'forward')
+    count = 0
+
+    revs = [revid for revid, _, _, _ in revs if not marks.is_marked(revid)]
+
+    for revid in revs:
+
+        rev = repo.get_revision(revid)
+
+        parents = rev.parent_ids
+        time = rev.timestamp
+        tz = rev.timezone
+        committer = rev.committer.encode('utf-8')
+        committer = "%s %u %s" % (fixup_user(committer), time, gittz(tz))
+        author = committer
+        msg = rev.message.encode('utf-8')
+
+        msg += '\n'
+
+        if len(parents) == 0:
+            parent = bzrlib.revision.NULL_REVISION
+        else:
+            parent = parents[0]
+
+        cur_tree = repo.revision_tree(revid)
+        prev = repo.revision_tree(parent)
+        modified, removed = get_filechanges(cur_tree, prev)
+
+        modified_final = export_files(cur_tree, modified)
+
+        if len(parents) == 0:
+            print 'reset %s' % ref
+
+        print "commit %s" % ref
+        print "mark :%d" % (marks.get_mark(revid))
+        print "author %s" % (author)
+        print "committer %s" % (committer)
+        print "data %d" % (len(msg))
+        print msg
+
+        for i, p in enumerate(parents):
+            try:
+                m = rev_to_mark(p)
+            except KeyError:
+                # ghost?
+                continue
+            if i == 0:
+                print "from :%s" % m
+            else:
+                print "merge :%s" % m
+
+        for f in modified_final:
+            print "M %s :%u %s" % f
+        for f in removed:
+            print "D %s" % (f)
+        print
+
+        count += 1
+        if (count % 100 == 0):
+            print "progress revision %s (%d/%d)" % (revid, count, len(revs))
+            print "#############################################################"
+
+    repo.unlock()
+
+    revid = branch.last_revision()
+
+    # make sure the ref is updated
+    print "reset %s" % ref
+    print "from :%u" % rev_to_mark(revid)
+    print
+
+    marks.set_tip(name, revid)
+
+def export_tag(repo, name):
+    global tags
+    try:
+        print "reset refs/tags/%s" % name
+        print "from :%u" % rev_to_mark(tags[name])
+        print
+    except KeyError:
+        warn("TODO: fetch tag '%s'" % name)
+
+def do_import(parser):
+    global dirname
+
+    branch = parser.repo
+    path = os.path.join(dirname, 'marks-git')
+
+    print "feature done"
+    if os.path.exists(path):
+        print "feature import-marks=%s" % path
+    print "feature export-marks=%s" % path
+    sys.stdout.flush()
+
+    while parser.check('import'):
+        ref = parser[1]
+        if ref.startswith('refs/heads/'):
+            name = ref[len('refs/heads/'):]
+            export_branch(branch, name)
+        if ref.startswith('refs/tags/'):
+            name = ref[len('refs/tags/'):]
+            export_tag(branch, name)
+        parser.next()
+
+    print 'done'
+
+    sys.stdout.flush()
+
+def parse_blob(parser):
+    global blob_marks
+
+    parser.next()
+    mark = parser.get_mark()
+    parser.next()
+    data = parser.get_data()
+    blob_marks[mark] = data
+    parser.next()
+
+class CustomTree():
+
+    def __init__(self, repo, revid, parents, files):
+        global files_cache
+
+        self.repo = repo
+        self.revid = revid
+        self.parents = parents
+        self.updates = {}
+
+        def copy_tree(revid):
+            files = files_cache[revid] = {}
+            tree = repo.repository.revision_tree(revid)
+            repo.lock_read()
+            try:
+                for path, entry in tree.iter_entries_by_dir():
+                    files[path] = entry.file_id
+            finally:
+                repo.unlock()
+            return files
+
+        if len(parents) == 0:
+            self.base_id = bzrlib.revision.NULL_REVISION
+            self.base_files = {}
+        else:
+            self.base_id = parents[0]
+            self.base_files = files_cache.get(self.base_id, None)
+            if not self.base_files:
+                self.base_files = copy_tree(self.base_id)
+
+        self.files = files_cache[revid] = self.base_files.copy()
+
+        for path, f in files.iteritems():
+            fid = self.files.get(path, None)
+            if not fid:
+                fid = bzrlib.generate_ids.gen_file_id(path)
+            f['path'] = path
+            self.updates[fid] = f
+
+    def last_revision(self):
+        return self.base_id
+
+    def iter_changes(self):
+        changes = []
+
+        def get_parent(dirname, basename):
+            parent_fid = self.base_files.get(dirname, None)
+            if parent_fid:
+                return parent_fid
+            parent_fid = self.files.get(dirname, None)
+            if parent_fid:
+                return parent_fid
+            if basename == '':
+                return None
+            fid = bzrlib.generate_ids.gen_file_id(path)
+            d = add_entry(fid, dirname, 'directory')
+            return fid
+
+        def add_entry(fid, path, kind, mode = None):
+            dirname, basename = os.path.split(path)
+            parent_fid = get_parent(dirname, basename)
+
+            executable = False
+            if mode == '100755':
+                executable = True
+            elif mode == '120000':
+                kind = 'symlink'
+
+            change = (fid,
+                    (None, path),
+                    True,
+                    (False, True),
+                    (None, parent_fid),
+                    (None, basename),
+                    (None, kind),
+                    (None, executable))
+            self.files[path] = change[0]
+            changes.append(change)
+            return change
+
+        def update_entry(fid, path, kind, mode = None):
+            dirname, basename = os.path.split(path)
+            parent_fid = get_parent(dirname, basename)
+
+            executable = False
+            if mode == '100755':
+                executable = True
+            elif mode == '120000':
+                kind = 'symlink'
+
+            change = (fid,
+                    (path, path),
+                    True,
+                    (True, True),
+                    (None, parent_fid),
+                    (None, basename),
+                    (None, kind),
+                    (None, executable))
+            self.files[path] = change[0]
+            changes.append(change)
+            return change
+
+        def remove_entry(fid, path, kind):
+            dirname, basename = os.path.split(path)
+            parent_fid = get_parent(dirname, basename)
+            change = (fid,
+                    (path, None),
+                    True,
+                    (True, False),
+                    (parent_fid, None),
+                    (None, None),
+                    (None, None),
+                    (None, None))
+            del self.files[path]
+            changes.append(change)
+            return change
+
+        for fid, f in self.updates.iteritems():
+            path = f['path']
+
+            if 'deleted' in f:
+                remove_entry(fid, path, 'file')
+                continue
+
+            if path in self.base_files:
+                update_entry(fid, path, 'file', f['mode'])
+            else:
+                add_entry(fid, path, 'file', f['mode'])
+
+        return changes
+
+    def get_file_with_stat(self, file_id, path=None):
+        return (StringIO.StringIO(self.updates[file_id]['data']), None)
+
+    def get_symlink_target(self, file_id):
+        return self.updates[file_id]['data']
+
+def parse_commit(parser):
+    global marks, blob_marks, bmarks, parsed_refs
+    global mode
+
+    parents = []
+
+    ref = parser[1]
+    parser.next()
+
+    if ref != 'refs/heads/master':
+        die("bzr doesn't support multiple branches; use 'master'")
+
+    commit_mark = parser.get_mark()
+    parser.next()
+    author = parser.get_author()
+    parser.next()
+    committer = parser.get_author()
+    parser.next()
+    data = parser.get_data()
+    parser.next()
+    if parser.check('from'):
+        parents.append(parser.get_mark())
+        parser.next()
+    while parser.check('merge'):
+        parents.append(parser.get_mark())
+        parser.next()
+
+    files = {}
+
+    for line in parser:
+        if parser.check('M'):
+            t, m, mark_ref, path = line.split(' ', 3)
+            mark = int(mark_ref[1:])
+            f = { 'mode' : m, 'data' : blob_marks[mark] }
+        elif parser.check('D'):
+            t, path = line.split(' ')
+            f = { 'deleted' : True }
+        else:
+            die('Unknown file command: %s' % line)
+        files[path] = f
+
+    repo = parser.repo
+
+    committer, date, tz = committer
+    parents = [str(mark_to_rev(p)) for p in parents]
+    revid = bzrlib.generate_ids.gen_revision_id(committer, date)
+    props = {}
+    props['branch-nick'] = repo.nick
+
+    mtree = CustomTree(repo, revid, parents, files)
+    changes = mtree.iter_changes()
+
+    repo.lock_write()
+    try:
+        builder = repo.get_commit_builder(parents, None, date, tz, committer, props, revid)
+        try:
+            list(builder.record_iter_changes(mtree, mtree.last_revision(), changes))
+            builder.finish_inventory()
+            builder.commit(data.decode('utf-8', 'replace'))
+        except Exception, e:
+            builder.abort()
+            raise
+    finally:
+        repo.unlock()
+
+    parsed_refs[ref] = revid
+    marks.new_mark(revid, commit_mark)
+
+def parse_reset(parser):
+    global parsed_refs
+
+    ref = parser[1]
+    parser.next()
+
+    if ref != 'refs/heads/master':
+        die("bzr doesn't support multiple branches; use 'master'")
+
+    # ugh
+    if parser.check('commit'):
+        parse_commit(parser)
+        return
+    if not parser.check('from'):
+        return
+    from_mark = parser.get_mark()
+    parser.next()
+
+    parsed_refs[ref] = mark_to_rev(from_mark)
+
+def do_export(parser):
+    global parsed_refs, dirname, peer
+
+    parser.next()
+
+    for line in parser.each_block('done'):
+        if parser.check('blob'):
+            parse_blob(parser)
+        elif parser.check('commit'):
+            parse_commit(parser)
+        elif parser.check('reset'):
+            parse_reset(parser)
+        elif parser.check('tag'):
+            pass
+        elif parser.check('feature'):
+            pass
+        else:
+            die('unhandled export command: %s' % line)
+
+    repo = parser.repo
+
+    for ref, revid in parsed_refs.iteritems():
+        if ref == 'refs/heads/master':
+            repo.generate_revision_history(revid, marks.get_tip('master'))
+            revno, revid = repo.last_revision_info()
+            if peer:
+                if hasattr(peer, "import_last_revision_info_and_tags"):
+                    peer.import_last_revision_info_and_tags(repo, revno, revid)
+                else:
+                    peer.import_last_revision_info(repo.repository, revno, revid)
+                wt = peer.bzrdir.open_workingtree()
+            else:
+                wt = repo.bzrdir.open_workingtree()
+            wt.update()
+        print "ok %s" % ref
+    print
+
+def do_capabilities(parser):
+    global dirname
+
+    print "import"
+    print "export"
+    print "refspec refs/heads/*:%s/heads/*" % prefix
+
+    path = os.path.join(dirname, 'marks-git')
+
+    if os.path.exists(path):
+        print "*import-marks %s" % path
+    print "*export-marks %s" % path
+
+    print
+
+def do_list(parser):
+    global tags
+    print "? refs/heads/%s" % 'master'
+    for tag, revid in parser.repo.tags.get_tag_dict().items():
+        print "? refs/tags/%s" % tag
+        tags[tag] = revid
+    print "@refs/heads/%s HEAD" % 'master'
+    print
+
+def get_repo(url, alias):
+    global dirname, peer
+
+    origin = bzrlib.bzrdir.BzrDir.open(url)
+    branch = origin.open_branch()
+
+    if not isinstance(origin.transport, bzrlib.transport.local.LocalTransport):
+        clone_path = os.path.join(dirname, 'clone')
+        remote_branch = branch
+        if os.path.exists(clone_path):
+            # pull
+            d = bzrlib.bzrdir.BzrDir.open(clone_path)
+            branch = d.open_branch()
+            result = branch.pull(remote_branch, [], None, False)
+        else:
+            # clone
+            d = origin.sprout(clone_path, None,
+                    hardlink=True, create_tree_if_local=False,
+                    source_branch=remote_branch)
+            branch = d.open_branch()
+            branch.bind(remote_branch)
+
+        peer = remote_branch
+    else:
+        peer = None
+
+    return branch
+
+def main(args):
+    global marks, prefix, dirname
+    global tags, filenodes
+    global blob_marks
+    global parsed_refs
+    global files_cache
+
+    alias = args[1]
+    url = args[2]
+
+    prefix = 'refs/bzr/%s' % alias
+    tags = {}
+    filenodes = {}
+    blob_marks = {}
+    parsed_refs = {}
+    files_cache = {}
+
+    gitdir = os.environ['GIT_DIR']
+    dirname = os.path.join(gitdir, 'bzr', alias)
+
+    if not os.path.exists(dirname):
+        os.makedirs(dirname)
+
+    repo = get_repo(url, alias)
+
+    marks_path = os.path.join(dirname, 'marks-int')
+    marks = Marks(marks_path)
+
+    parser = Parser(repo)
+    for line in parser:
+        if parser.check('capabilities'):
+            do_capabilities(parser)
+        elif parser.check('list'):
+            do_list(parser)
+        elif parser.check('import'):
+            do_import(parser)
+        elif parser.check('export'):
+            do_export(parser)
+        else:
+            die('unhandled command: %s' % line)
+        sys.stdout.flush()
+
+    marks.store()
+
+sys.exit(main(sys.argv))
diff --git a/contrib/remote-helpers/test-bzr.sh b/contrib/remote-helpers/test-bzr.sh
new file mode 100755 (executable)
index 0000000..70aa8a0
--- /dev/null
@@ -0,0 +1,143 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Felipe Contreras
+#
+
+test_description='Test remote-bzr'
+
+. ./test-lib.sh
+
+if ! test_have_prereq PYTHON; then
+       skip_all='skipping remote-bzr tests; python not available'
+       test_done
+fi
+
+if ! "$PYTHON_PATH" -c 'import bzrlib'; then
+       skip_all='skipping remote-bzr tests; bzr not available'
+       test_done
+fi
+
+cmd='
+import bzrlib
+bzrlib.initialize()
+import bzrlib.plugin
+bzrlib.plugin.load_plugins()
+import bzrlib.plugins.fastimport
+'
+
+if ! "$PYTHON_PATH" -c "$cmd"; then
+       echo "consider setting BZR_PLUGIN_PATH=$HOME/.bazaar/plugins" 1>&2
+       skip_all='skipping remote-bzr tests; bzr-fastimport not available'
+       test_done
+fi
+
+check () {
+       (cd $1 &&
+       git log --format='%s' -1 &&
+       git symbolic-ref HEAD) > actual &&
+       (echo $2 &&
+       echo "refs/heads/$3") > expected &&
+       test_cmp expected actual
+}
+
+bzr whoami "A U Thor <author@example.com>"
+
+test_expect_success 'cloning' '
+  (bzr init bzrrepo &&
+  cd bzrrepo &&
+  echo one > content &&
+  bzr add content &&
+  bzr commit -m one
+  ) &&
+
+  git clone "bzr::$PWD/bzrrepo" gitrepo &&
+  check gitrepo one master
+'
+
+test_expect_success 'pulling' '
+  (cd bzrrepo &&
+  echo two > content &&
+  bzr commit -m two
+  ) &&
+
+  (cd gitrepo && git pull) &&
+
+  check gitrepo two master
+'
+
+test_expect_success 'pushing' '
+  (cd gitrepo &&
+  echo three > content &&
+  git commit -a -m three &&
+  git push
+  ) &&
+
+  echo three > expected &&
+  cat bzrrepo/content > actual &&
+  test_cmp expected actual
+'
+
+test_expect_success 'roundtrip' '
+  (cd gitrepo &&
+  git pull &&
+  git log --format="%s" -1 origin/master > actual) &&
+  echo three > expected &&
+  test_cmp expected actual &&
+
+  (cd gitrepo && git push && git pull) &&
+
+  (cd bzrrepo &&
+  echo four > content &&
+  bzr commit -m four
+  ) &&
+
+  (cd gitrepo && git pull && git push) &&
+
+  check gitrepo four master &&
+
+  (cd gitrepo &&
+  echo five > content &&
+  git commit -a -m five &&
+  git push && git pull
+  ) &&
+
+  (cd bzrrepo && bzr revert) &&
+
+  echo five > expected &&
+  cat bzrrepo/content > actual &&
+  test_cmp expected actual
+'
+
+cat > expected <<EOF
+100644 blob 54f9d6da5c91d556e6b54340b1327573073030af   content
+100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb   executable
+120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea   link
+EOF
+
+test_expect_success 'special modes' '
+  (cd bzrrepo &&
+  echo exec > executable
+  chmod +x executable &&
+  bzr add executable
+  bzr commit -m exec &&
+  ln -s content link
+  bzr add link
+  bzr commit -m link &&
+  mkdir dir &&
+  bzr add dir &&
+  bzr commit -m dir) &&
+
+  (cd gitrepo &&
+  git pull
+  git ls-tree HEAD > ../actual) &&
+
+  test_cmp expected actual &&
+
+  (cd gitrepo &&
+  git cat-file -p HEAD:link > ../actual) &&
+
+  echo -n content > expected &&
+  test_cmp expected actual
+'
+
+test_done
index 1cfac4a6f84051d625ee2e1800ffd074b215eb86..17cf6f961f5fdf1e8f790acf7f498dc863e11e45 100755 (executable)
@@ -7,6 +7,10 @@
 """
 import sys, os
 
+if sys.hexversion < 0x02040000:
+        # The limiter is the ValueError() calls. This may be too conservative
+        sys.stderr.write("svnrdump-sim.py: requires Python 2.4 or later.\n")
+        sys.exit(1)
 
 def getrevlimit():
         var = 'SVNRMAX'
diff --git a/ctype.c b/ctype.c
index 935327164b1066ad011d11fdcd3fd1dc1a936c58..0bfebb4e75866ba0e97713fab5394490290831c0 100644 (file)
--- a/ctype.c
+++ b/ctype.c
@@ -11,18 +11,21 @@ enum {
        D = GIT_DIGIT,
        G = GIT_GLOB_SPECIAL,   /* *, ?, [, \\ */
        R = GIT_REGEX_SPECIAL,  /* $, (, ), +, ., ^, {, | */
-       P = GIT_PATHSPEC_MAGIC  /* other non-alnum, except for ] and } */
+       P = GIT_PATHSPEC_MAGIC, /* other non-alnum, except for ] and } */
+       X = GIT_CNTRL,
+       U = GIT_PUNCT,
+       Z = GIT_CNTRL | GIT_SPACE
 };
 
-unsigned char sane_ctype[256] = {
-       0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0,         /*   0.. 15 */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,         /*  16.. 31 */
+const unsigned char sane_ctype[256] = {
+       X, X, X, X, X, X, X, X, X, Z, Z, X, X, Z, X, X,         /*   0.. 15 */
+       X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,         /*  16.. 31 */
        S, P, P, P, R, P, P, P, R, R, G, R, P, P, R, P,         /*  32.. 47 */
        D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G,         /*  48.. 63 */
        P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,         /*  64.. 79 */
-       A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, P,         /*  80.. 95 */
+       A, A, A, A, A, A, A, A, A, A, A, G, G, U, R, P,         /*  80.. 95 */
        P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,         /*  96..111 */
-       A, A, A, A, A, A, A, A, A, A, A, R, R, 0, P, 0,         /* 112..127 */
+       A, A, A, A, A, A, A, A, A, A, A, R, R, U, P, X,         /* 112..127 */
        /* Nothing in the 128.. range */
 };
 
diff --git a/dir.c b/dir.c
index 5a83aa7897f270279c403778f43aea6db1efc5af..e883a91483981ad9e2da4841063c1c8bad6a25fd 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -2,12 +2,15 @@
  * This handles recursive filename detection with exclude
  * files, index knowledge etc..
  *
+ * See Documentation/technical/api-directory-listing.txt
+ *
  * Copyright (C) Linus Torvalds, 2005-2006
  *              Junio Hamano, 2005-2006
  */
 #include "cache.h"
 #include "dir.h"
 #include "refs.h"
+#include "wildmatch.h"
 
 struct path_simplify {
        int len;
@@ -34,10 +37,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 +73,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 +143,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 +153,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 +165,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 +175,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 +259,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;
@@ -347,7 +379,7 @@ void parse_exclude_pattern(const char **pattern,
 }
 
 void add_exclude(const char *string, const char *base,
-                int baselen, struct exclude_list *which)
+                int baselen, struct exclude_list *el)
 {
        struct exclude *x;
        int patternlen;
@@ -371,8 +403,8 @@ void add_exclude(const char *string, const char *base,
        x->base = base;
        x->baselen = baselen;
        x->flags = flags;
-       ALLOC_GROW(which->excludes, which->nr + 1, which->alloc);
-       which->excludes[which->nr++] = x;
+       ALLOC_GROW(el->excludes, el->nr + 1, el->alloc);
+       el->excludes[el->nr++] = x;
 }
 
 static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
@@ -398,7 +430,11 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
        return data;
 }
 
-void free_excludes(struct exclude_list *el)
+/*
+ * Frees memory within el which was allocated for exclude patterns and
+ * the file buffer.  Does not free el itself.
+ */
+void clear_exclude_list(struct exclude_list *el)
 {
        int i;
 
@@ -414,7 +450,7 @@ int add_excludes_from_file_to_list(const char *fname,
                                   const char *base,
                                   int baselen,
                                   char **buf_p,
-                                  struct exclude_list *which,
+                                  struct exclude_list *el,
                                   int check_index)
 {
        struct stat st;
@@ -463,7 +499,7 @@ int add_excludes_from_file_to_list(const char *fname,
                if (buf[i] == '\n') {
                        if (entry != buf + i && entry[0] != '#') {
                                buf[i - (i && buf[i-1] == '\r')] = 0;
-                               add_exclude(entry, base, baselen, which);
+                               add_exclude(entry, base, baselen, el);
                        }
                        entry = buf + i + 1;
                }
@@ -478,6 +514,10 @@ void add_excludes_from_file(struct dir_struct *dir, const char *fname)
                die("cannot use %s as an exclude file", fname);
 }
 
+/*
+ * Loads the per-directory exclude list for the substring of base
+ * which has a char length of baselen.
+ */
 static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 {
        struct exclude_list *el;
@@ -488,7 +528,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
            (baselen + strlen(dir->exclude_per_dir) >= PATH_MAX))
                return; /* too long a path -- ignore */
 
-       /* Pop the ones that are not the prefix of the path being checked. */
+       /* Pop the directories that are not the prefix of the path being checked. */
        el = &dir->exclude_list[EXC_DIRS];
        while ((stk = dir->exclude_stack) != NULL) {
                if (stk->baselen <= baselen &&
@@ -595,25 +635,30 @@ int match_pathname(const char *pathname, int pathlen,
                namelen -= prefix;
        }
 
-       return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0;
+       return wildmatch(pattern, name,
+                        ignore_case ? FNM_CASEFOLD : 0) == 0;
 }
 
-/* Scan the list and let the last match determine the fate.
- * Return 1 for exclude, 0 for include and -1 for undecided.
+/*
+ * Scan the given exclude list in reverse to see whether pathname
+ * should be ignored.  The first match (i.e. the last on the list), if
+ * any, determines the fate.  Returns the exclude_list element which
+ * matched, or NULL for undecided.
  */
-int excluded_from_list(const char *pathname,
-                      int pathlen, const char *basename, int *dtype,
-                      struct exclude_list *el)
+static struct exclude *last_exclude_matching_from_list(const char *pathname,
+                                                      int pathlen,
+                                                      const char *basename,
+                                                      int *dtype,
+                                                      struct exclude_list *el)
 {
        int i;
 
        if (!el->nr)
-               return -1;      /* undefined */
+               return NULL;    /* undefined */
 
        for (i = el->nr - 1; 0 <= i; i--) {
                struct exclude *x = el->excludes[i];
                const char *exclude = x->pattern;
-               int to_exclude = x->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
                int prefix = x->nowildcardlen;
 
                if (x->flags & EXC_FLAG_MUSTBEDIR) {
@@ -628,7 +673,7 @@ int excluded_from_list(const char *pathname,
                                           pathlen - (basename - pathname),
                                           exclude, prefix, x->patternlen,
                                           x->flags))
-                               return to_exclude;
+                               return x;
                        continue;
                }
 
@@ -636,28 +681,64 @@ int excluded_from_list(const char *pathname,
                if (match_pathname(pathname, pathlen,
                                   x->base, x->baselen ? x->baselen - 1 : 0,
                                   exclude, prefix, x->patternlen, x->flags))
-                       return to_exclude;
+                       return x;
        }
+       return NULL; /* undecided */
+}
+
+/*
+ * Scan the list and let the last match determine the fate.
+ * Return 1 for exclude, 0 for include and -1 for undecided.
+ */
+int is_excluded_from_list(const char *pathname,
+                         int pathlen, const char *basename, int *dtype,
+                         struct exclude_list *el)
+{
+       struct exclude *exclude;
+       exclude = last_exclude_matching_from_list(pathname, pathlen, basename, dtype, el);
+       if (exclude)
+               return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
        return -1; /* undecided */
 }
 
-static int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
+/*
+ * Loads the exclude lists for the directory containing pathname, then
+ * scans all exclude lists to determine whether pathname is excluded.
+ * Returns the exclude_list element which matched, or NULL for
+ * undecided.
+ */
+static struct exclude *last_exclude_matching(struct dir_struct *dir,
+                                            const char *pathname,
+                                            int *dtype_p)
 {
        int pathlen = strlen(pathname);
        int st;
+       struct exclude *exclude;
        const char *basename = strrchr(pathname, '/');
        basename = (basename) ? basename+1 : pathname;
 
        prep_exclude(dir, pathname, basename-pathname);
        for (st = EXC_CMDL; st <= EXC_FILE; st++) {
-               switch (excluded_from_list(pathname, pathlen, basename,
-                                          dtype_p, &dir->exclude_list[st])) {
-               case 0:
-                       return 0;
-               case 1:
-                       return 1;
-               }
+               exclude = last_exclude_matching_from_list(
+                       pathname, pathlen, basename, dtype_p,
+                       &dir->exclude_list[st]);
+               if (exclude)
+                       return exclude;
        }
+       return NULL;
+}
+
+/*
+ * Loads the exclude lists for the directory containing pathname, then
+ * scans all exclude lists to determine whether pathname is excluded.
+ * Returns 1 if true, otherwise 0.
+ */
+static int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
+{
+       struct exclude *exclude =
+               last_exclude_matching(dir, pathname, dtype_p);
+       if (exclude)
+               return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
        return 0;
 }
 
@@ -665,6 +746,7 @@ void path_exclude_check_init(struct path_exclude_check *check,
                             struct dir_struct *dir)
 {
        check->dir = dir;
+       check->exclude = NULL;
        strbuf_init(&check->path, 256);
 }
 
@@ -674,32 +756,41 @@ void path_exclude_check_clear(struct path_exclude_check *check)
 }
 
 /*
- * Is this name excluded?  This is for a caller like show_files() that
- * do not honor directory hierarchy and iterate through paths that are
- * possibly in an ignored directory.
+ * For each subdirectory in name, starting with the top-most, checks
+ * to see if that subdirectory is excluded, and if so, returns the
+ * corresponding exclude structure.  Otherwise, checks whether name
+ * itself (which is presumably a file) is excluded.
  *
  * A path to a directory known to be excluded is left in check->path to
  * optimize for repeated checks for files in the same excluded directory.
  */
-int path_excluded(struct path_exclude_check *check,
-                 const char *name, int namelen, int *dtype)
+struct exclude *last_exclude_matching_path(struct path_exclude_check *check,
+                                          const char *name, int namelen,
+                                          int *dtype)
 {
        int i;
        struct strbuf *path = &check->path;
+       struct exclude *exclude;
 
        /*
         * we allow the caller to pass namelen as an optimization; it
         * must match the length of the name, as we eventually call
-        * excluded() on the whole name string.
+        * is_excluded() on the whole name string.
         */
        if (namelen < 0)
                namelen = strlen(name);
 
+       /*
+        * If path is non-empty, and name is equal to path or a
+        * subdirectory of path, name should be excluded, because
+        * it's inside a directory which is already known to be
+        * excluded and was previously left in check->path.
+        */
        if (path->len &&
            path->len <= namelen &&
            !memcmp(name, path->buf, path->len) &&
            (!name[path->len] || name[path->len] == '/'))
-               return 1;
+               return check->exclude;
 
        strbuf_setlen(path, 0);
        for (i = 0; name[i]; i++) {
@@ -707,8 +798,12 @@ int path_excluded(struct path_exclude_check *check,
 
                if (ch == '/') {
                        int dt = DT_DIR;
-                       if (excluded(check->dir, path->buf, &dt))
-                               return 1;
+                       exclude = last_exclude_matching(check->dir,
+                                                       path->buf, &dt);
+                       if (exclude) {
+                               check->exclude = exclude;
+                               return exclude;
+                       }
                }
                strbuf_addch(path, ch);
        }
@@ -716,7 +811,22 @@ int path_excluded(struct path_exclude_check *check,
        /* An entry in the index; cannot be a directory with subentries */
        strbuf_setlen(path, 0);
 
-       return excluded(check->dir, name, dtype);
+       return last_exclude_matching(check->dir, name, dtype);
+}
+
+/*
+ * Is this name excluded?  This is for a caller like show_files() that
+ * do not honor directory hierarchy and iterate through paths that are
+ * possibly in an ignored directory.
+ */
+int is_path_excluded(struct path_exclude_check *check,
+                 const char *name, int namelen, int *dtype)
+{
+       struct exclude *exclude =
+               last_exclude_matching_path(check, name, namelen, dtype);
+       if (exclude)
+               return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
+       return 0;
 }
 
 static struct dir_entry *dir_entry_new(const char *pathname, int len)
@@ -1016,7 +1126,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
                                          const struct path_simplify *simplify,
                                          int dtype, struct dirent *de)
 {
-       int exclude = excluded(dir, path->buf, &dtype);
+       int exclude = is_excluded(dir, path->buf, &dtype);
        if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
            && exclude_matches_pathspec(path->buf, path->len, simplify))
                dir_add_ignored(dir, path->buf, path->len);
@@ -1429,9 +1539,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 +1564,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..ae1bc467ae909e6db151b055e212ded45fac34f6 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -1,6 +1,8 @@
 #ifndef DIR_H
 #define DIR_H
 
+/* See Documentation/technical/api-directory-listing.txt */
+
 #include "strbuf.h"
 
 struct dir_entry {
@@ -13,6 +15,12 @@ struct dir_entry {
 #define EXC_FLAG_MUSTBEDIR 8
 #define EXC_FLAG_NEGATIVE 16
 
+/*
+ * Each .gitignore file will be parsed into patterns which are then
+ * appended to the relevant exclude_list (either EXC_DIRS or
+ * EXC_FILE).  exclude_lists are also used to represent the list of
+ * --exclude values passed via CLI args (EXC_CMDL).
+ */
 struct exclude_list {
        int nr;
        int alloc;
@@ -26,9 +34,15 @@ struct exclude_list {
        } **excludes;
 };
 
+/*
+ * The contents of the per-directory exclude files are lazily read on
+ * demand and then cached in memory, one per exclude_stack struct, in
+ * order to avoid opening and parsing each one every time that
+ * directory is traversed.
+ */
 struct exclude_stack {
-       struct exclude_stack *prev;
-       char *filebuf;
+       struct exclude_stack *prev; /* the struct exclude_stack for the parent directory */
+       char *filebuf; /* remember pointer to per-directory exclude file contents so we can free() */
        int baselen;
        int exclude_ix;
 };
@@ -59,6 +73,14 @@ struct dir_struct {
 #define EXC_DIRS 1
 #define EXC_FILE 2
 
+       /*
+        * Temporary variables which are used during loading of the
+        * per-directory exclude lists.
+        *
+        * exclude_stack points to the top of the exclude_stack, and
+        * basebuf contains the full path to the current
+        * (sub)directory in the traversal.
+        */
        struct exclude_stack *exclude_stack;
        char basebuf[PATH_MAX];
 };
@@ -76,8 +98,8 @@ extern int within_depth(const char *name, int namelen, int depth, int max_depth)
 extern int fill_directory(struct dir_struct *dir, const char **pathspec);
 extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
 
-extern int excluded_from_list(const char *pathname, int pathlen, const char *basename,
-                             int *dtype, struct exclude_list *el);
+extern int is_excluded_from_list(const char *pathname, int pathlen, const char *basename,
+                                int *dtype, struct exclude_list *el);
 struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len);
 
 /*
@@ -91,26 +113,29 @@ extern int match_pathname(const char *, int,
                          const char *, int, int, int);
 
 /*
- * The excluded() API is meant for callers that check each level of leading
- * directory hierarchies with excluded() to avoid recursing into excluded
+ * The is_excluded() API is meant for callers that check each level of leading
+ * directory hierarchies with is_excluded() to avoid recursing into excluded
  * directories.  Callers that do not do so should use this API instead.
  */
 struct path_exclude_check {
        struct dir_struct *dir;
+       struct exclude *exclude;
        struct strbuf path;
 };
 extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *);
 extern void path_exclude_check_clear(struct path_exclude_check *);
-extern int path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);
+extern struct exclude *last_exclude_matching_path(struct path_exclude_check *, const char *,
+                                                 int namelen, int *dtype);
+extern int is_path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);
 
 
 extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
-                                         char **buf_p, struct exclude_list *which, int check_index);
+                                         char **buf_p, struct exclude_list *el, int check_index);
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen);
 extern void add_exclude(const char *string, const char *base,
-                       int baselen, struct exclude_list *which);
-extern void free_excludes(struct exclude_list *el);
+                       int baselen, struct exclude_list *el);
+extern void clear_exclude_list(struct exclude_list *el);
 extern int file_exists(const char *);
 
 extern int is_inside_dir(const char *dir);
@@ -139,4 +164,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..e5a4b7450bfa7a700ce1c76f597266a9724a19f5 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
@@ -511,13 +528,19 @@ extern const char tolower_trans_tbl[256];
 #undef isupper
 #undef tolower
 #undef toupper
-extern unsigned char sane_ctype[256];
+#undef iscntrl
+#undef ispunct
+#undef isxdigit
+
+extern const unsigned char sane_ctype[256];
 #define GIT_SPACE 0x01
 #define GIT_DIGIT 0x02
 #define GIT_ALPHA 0x04
 #define GIT_GLOB_SPECIAL 0x08
 #define GIT_REGEX_SPECIAL 0x10
 #define GIT_PATHSPEC_MAGIC 0x20
+#define GIT_CNTRL 0x40
+#define GIT_PUNCT 0x80
 #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
 #define isascii(x) (((x) & ~0x7f) == 0)
 #define isspace(x) sane_istest(x,GIT_SPACE)
@@ -529,6 +552,10 @@ extern unsigned char sane_ctype[256];
 #define isupper(x) sane_iscase(x, 0)
 #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
 #define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
+#define iscntrl(x) (sane_istest(x,GIT_CNTRL))
+#define ispunct(x) sane_istest(x, GIT_PUNCT | GIT_REGEX_SPECIAL | \
+               GIT_GLOB_SPECIAL | GIT_PATHSPEC_MAGIC)
+#define isxdigit(x) (hexval_table[x] != -1)
 #define tolower(x) sane_case((unsigned char)(x), 0x20)
 #define toupper(x) sane_case((unsigned char)(x), 0)
 #define is_pathspec_magic(x) sane_istest(x,GIT_PATHSPEC_MAGIC)
@@ -637,8 +664,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);
index 551aec9417401dcd7ef526dd6c9b554e5194f861..69f1452cf80066a002fe58bb1eeebda7fe63ba8b 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -8,7 +8,13 @@
 # License: MIT <http://www.opensource.org/licenses/mit-license.php>
 #
 
-import optparse, sys, os, marshal, subprocess, shelve
+import sys
+if sys.hexversion < 0x02040000:
+    # The limiter is the subprocess module
+    sys.stderr.write("git-p4: requires Python 2.4 or later.\n")
+    sys.exit(1)
+
+import optparse, os, marshal, subprocess, shelve
 import tempfile, getopt, os.path, time, platform
 import re, shutil
 
index 392ebc9790c88f9857fc4e943d1fe6351e953c7d..97f31dc7af43bafe36d3222ba2f78da861a4e620 100644 (file)
@@ -18,6 +18,7 @@ esac
 
 test -n "$rebase_root" && root_flag=--root
 
+ret=0
 if test -n "$keep_empty"
 then
        # we have to do this the hard way.  git format-patch completely squashes
@@ -25,13 +26,49 @@ then
        # itself well to recording empty patches.  fortunately, cherry-pick
        # makes this easy
        git cherry-pick --allow-empty "$revisions"
+       ret=$?
 else
+       rm -f "$GIT_DIR/rebased-patches"
+
        git format-patch -k --stdout --full-index --ignore-if-in-upstream \
                --src-prefix=a/ --dst-prefix=b/ \
-               --no-renames $root_flag "$revisions" |
-       git am $git_am_opt --rebasing --resolvemsg="$resolvemsg"
-fi && move_to_original_branch
+               --no-renames $root_flag "$revisions" >"$GIT_DIR/rebased-patches"
+       ret=$?
+
+       if test 0 != $ret
+       then
+               rm -f "$GIT_DIR/rebased-patches"
+               case "$head_name" in
+               refs/heads/*)
+                       git checkout -q "$head_name"
+                       ;;
+               *)
+                       git checkout -q "$orig_head"
+                       ;;
+               esac
+
+               cat >&2 <<-EOF
+
+               git encountered an error while preparing the patches to replay
+               these revisions:
+
+                   $revisions
+
+               As a result, git cannot rebase them.
+               EOF
+               exit $?
+       fi
+
+       git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" <"$GIT_DIR/rebased-patches"
+       ret=$?
+
+       rm -f "$GIT_DIR/rebased-patches"
+fi
+
+if test 0 != $ret
+then
+       test -d "$state_dir" && write_basic_state
+       exit $ret
+fi
 
-ret=$?
-test 0 != $ret -a -d "$state_dir" && write_basic_state
-exit $ret
+move_to_original_branch
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..e4533b1
--- /dev/null
@@ -0,0 +1,277 @@
+#!/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
+
+if sys.hexversion < 0x01050200:
+    # os.makedirs() is the limiter
+    sys.stderr.write("git-remote-testgit: requires Python 1.5.2 or later.\n")
+    sys.exit(1)
+
+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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1dbb1b0148074ac34fb4e4240c06f1042b12c10a 100644 (file)
@@ -0,0 +1,5 @@
+import sys
+if sys.hexversion < 0x02040000:
+    # The limiter is the subprocess module
+    sys.stderr.write("git_remote_helpers: requires Python 2.4 or later.\n")
+    sys.exit(1)
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 656b324fb7f82c7f65c71075f57e909843c50cce..c6bafe6ead815ece2e820d303e442270749c5c4b 100755 (executable)
@@ -1556,7 +1556,7 @@ sub sanitize {
        return undef unless defined $str;
 
        $str = to_utf8($str);
-       $str =~ s|([[:cntrl:]])|($1 =~ /[\t\n\r]/ ? $1 : quot_cec($1))|eg;
+       $str =~ s|([[:cntrl:]])|(index("\t\n\r", $1) != -1 ? $1 : quot_cec($1))|eg;
        return $str;
 }
 
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);
 }
 
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 0e8ed5437af275a4bb41a67debefe04bdc07a88e..c8ad2f01c91b2349bc0e778b3dff0da26070c00a 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -33,10 +33,10 @@ msgid ""
 "appropriate to mark resolution and make a commit,\n"
 "or use 'git commit -a'."
 msgstr ""
-"Korrigiere dies im Arbeitsbaum,\n"
-"und benutze dann 'git add/rm <Datei>'\n"
+"Korrigieren Sie dies im Arbeitsbaum,\n"
+"und benutzen Sie dann 'git add/rm <Datei>'\n"
 "um die Auflösung entsprechend zu markieren und einzutragen,\n"
-"oder benutze 'git commit -a'."
+"oder benutzen Sie 'git commit -a'."
 
 #: archive.c:10
 msgid "git archive [options] <tree-ish> [<path>...]"
@@ -131,7 +131,7 @@ msgid ""
 "Use '\\!' for literal leading exclamation."
 msgstr ""
 "Verneinende Muster sind in Git-Attributen verboten.\n"
-"Benutze '\\!' für führende Ausrufezeichen."
+"Benutzen Sie '\\!' für führende Ausrufezeichen."
 
 #: bundle.c:36
 #, c-format
@@ -381,7 +381,7 @@ msgstr "Vorhandene Git-Kommandos in '%s'"
 
 #: help.c:219
 msgid "git commands available from elsewhere on your $PATH"
-msgstr "Vorhandene Git-Kommandos irgendwo in deinem $PATH"
+msgstr "Vorhandene Git-Kommandos irgendwo in Ihrem $PATH"
 
 #: help.c:275
 #, c-format
@@ -394,7 +394,7 @@ msgstr ""
 
 #: help.c:332
 msgid "Uh oh. Your system reports no Git commands at all."
-msgstr "Uh oh. Keine Git-Kommandos auf deinem System vorhanden."
+msgstr "Uh oh. Keine Git-Kommandos auf Ihrem System vorhanden."
 
 #: help.c:354
 #, c-format
@@ -402,8 +402,8 @@ msgid ""
 "WARNING: You called a Git command named '%s', which does not exist.\n"
 "Continuing under the assumption that you meant '%s'"
 msgstr ""
-"Warnung: Du hast das nicht existierende Git-Kommando '%s' ausgeführt.\n"
-"Setze fort unter der Annahme das du '%s' gemeint hast"
+"Warnung: Sie haben das nicht existierende Git-Kommando '%s' ausgeführt.\n"
+"Setze fort unter der Annahme, dass Sie '%s' gemeint haben"
 
 #: help.c:359
 #, c-format
@@ -424,10 +424,10 @@ msgid_plural ""
 "Did you mean one of these?"
 msgstr[0] ""
 "\n"
-"Hast du das gemeint?"
+"Haben Sie das gemeint?"
 msgstr[1] ""
 "\n"
-"Hast du eines von diesen gemeint?"
+"Haben Sie eines von diesen gemeint?"
 
 #: merge.c:56
 msgid "failed to read the cache"
@@ -721,12 +721,12 @@ msgstr "    %s"
 #, c-format
 msgid "Your branch is ahead of '%s' by %d commit.\n"
 msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
-msgstr[0] "Dein Zweig ist vor '%s' um %d Version.\n"
-msgstr[1] "Dein Zweig ist vor '%s' um %d Versionen.\n"
+msgstr[0] "Ihr Zweig ist vor '%s' um %d Version.\n"
+msgstr[1] "Ihr Zweig ist vor '%s' um %d Versionen.\n"
 
 #: remote.c:1637
 msgid "  (use \"git push\" to publish your local commits)\n"
-msgstr "  (benutze \"git push\" um deine lokalen Versionen herauszubringen)\n"
+msgstr "  (benutzen Sie \"git push\" um lokalen Versionen herauszubringen)\n"
 
 #: remote.c:1640
 #, c-format
@@ -734,15 +734,15 @@ msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
 "Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n"
 msgstr[0] ""
-"Dein Zweig ist zu '%s' um %d Version hinterher, und kann vorgespult werden.\n"
+"Ihr Zweig ist zu '%s' um %d Version hinterher, und kann vorgespult werden.\n"
 msgstr[1] ""
-"Dein Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult "
+"Ihr Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult "
 "werden.\n"
 
 #: remote.c:1647
 msgid "  (use \"git pull\" to update your local branch)\n"
 msgstr ""
-"  (benutze \"git pull\" um deinen lokalen Zweig zu aktualisieren)\n"
+"  (benutzen Sie \"git pull\" um Ihren lokalen Zweig zu aktualisieren)\n"
 
 #: remote.c:1650
 #, c-format
@@ -753,16 +753,16 @@ msgid_plural ""
 "Your branch and '%s' have diverged,\n"
 "and have %d and %d different commits each, respectively.\n"
 msgstr[0] ""
-"Dein Zweig und '%s' sind divergiert,\n"
+"Ihr Zweig und '%s' sind divergiert,\n"
 "und haben jeweils %d und %d unterschiedliche Versionen.\n"
 msgstr[1] ""
-"Dein Zweig und '%s' sind divergiert,\n"
+"Ihr Zweig und '%s' sind divergiert,\n"
 "und haben jeweils %d und %d unterschiedliche Versionen.\n"
 
 #: remote.c:1659
 msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
 msgstr ""
-"  (benutze \"git pull\" um deinen Zweig mit dem externen zusammenzuführen)\n"
+"  (benutzen Sie \"git pull\" um Ihren Zweig mit dem externen zusammenzuführen)\n"
 
 #: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
 #: builtin/merge.c:994
@@ -781,7 +781,7 @@ msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
 msgstr ""
-"nach Auflösung der Konflikte, markiere die korrigierten Pfade\n"
+"nach Auflösung der Konflikte, markieren Sie die korrigierten Pfade\n"
 "mit 'git add <Pfade>' oder 'git rm <Pfade>'"
 
 #: sequencer.c:149
@@ -790,9 +790,9 @@ msgid ""
 "with 'git add <paths>' or 'git rm <paths>'\n"
 "and commit the result with 'git commit'"
 msgstr ""
-"nach Auflösung der Konflikte, markiere die korrigierten Pfade\n"
-"mit 'git add <Pfade>' oder 'git rm <Pfade>'und trage das Ergebnis ein mit "
-"'git commit'"
+"nach Auflösung der Konflikte, markieren Sie die korrigierten Pfade\n"
+"mit 'git add <Pfade>' oder 'git rm <Pfade>'und tragen Sie das Ergebnis mit\n"
+"'git commit' ein"
 
 #: sequencer.c:162 sequencer.c:770 sequencer.c:853
 #, c-format
@@ -807,15 +807,15 @@ msgstr "Fehler bei Nachbereitung von %s"
 #: sequencer.c:180
 msgid "Your local changes would be overwritten by cherry-pick."
 msgstr ""
-"Deine lokalen Ã„nderungen würden von \"cherry-pick\" Ã¼berschrieben werden."
+"Ihre lokalen Ã„nderungen würden von \"cherry-pick\" Ã¼berschrieben werden."
 
 #: sequencer.c:182
 msgid "Your local changes would be overwritten by revert."
-msgstr "Deine lokalen Ã„nderungen würden von \"revert\" Ã¼berschrieben werden."
+msgstr "Ihre lokalen Ã„nderungen würden von \"revert\" Ã¼berschrieben werden."
 
 #: sequencer.c:185
 msgid "Commit your changes or stash them to proceed."
-msgstr "Trage deine Ã„nderungen ein oder benutze \"stash\" um fortzufahren."
+msgstr "Tragen Sie Ihre Ã„nderungen ein oder benutzen Sie \"stash\" um fortzufahren."
 
 #. TRANSLATORS: %s will be "revert" or "cherry-pick"
 #: sequencer.c:235
@@ -843,11 +843,11 @@ msgstr "Konnte Elternversion %s nicht parsen\n"
 
 #: sequencer.c:403
 msgid "Your index file is unmerged."
-msgstr "Deine Bereitstellungsdatei ist nicht zusammengeführt."
+msgstr "Ihre Bereitstellungsdatei ist nicht zusammengeführt."
 
 #: sequencer.c:406
 msgid "You do not have a valid HEAD"
-msgstr "Du hast keine gültige Zweigspitze (HEAD)"
+msgstr "Sie haben keine gültige Zweigspitze (HEAD)"
 
 #: sequencer.c:421
 #, c-format
@@ -953,7 +953,7 @@ msgstr "\"cherry-pick\" oder \"revert\" ist bereits im Gang"
 
 #: sequencer.c:752
 msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
-msgstr "versuche \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr "versuchen Sie \"git cherry-pick (--continue | --quit | --abort)\""
 
 #: sequencer.c:756
 #, c-format
@@ -1053,28 +1053,28 @@ msgstr "Nicht zusammengeführte Pfade:"
 #, c-format
 msgid "  (use \"git reset %s <file>...\" to unstage)"
 msgstr ""
-"  (benutze \"git reset %s <Datei>...\" zum Herausnehmen aus der "
+"  (benutzen Sie \"git reset %s <Datei>...\" zum Herausnehmen aus der "
 "Bereitstellung)"
 
 #: wt-status.c:169 wt-status.c:196
 msgid "  (use \"git rm --cached <file>...\" to unstage)"
 msgstr ""
-"  (benutze \"git rm --cached <Datei>...\" zum Herausnehmen aus der "
+"  (benutzen Sie \"git rm --cached <Datei>...\" zum Herausnehmen aus der "
 "Bereitstellung)"
 
 #: wt-status.c:173
 msgid "  (use \"git add <file>...\" to mark resolution)"
-msgstr "  (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
+msgstr "  (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
 
 #: wt-status.c:175 wt-status.c:179
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
 msgstr ""
-"  (benutze \"git add/rm <Datei>...\" um die Auflösung entsprechend zu "
+"  (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung entsprechend zu "
 "markieren)"
 
 #: wt-status.c:177
 msgid "  (use \"git rm <file>...\" to mark resolution)"
-msgstr "  (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
+msgstr "  (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
 
 #: wt-status.c:188
 msgid "Changes to be committed:"
@@ -1086,29 +1086,29 @@ msgstr "Änderungen, die nicht zum Eintragen bereitgestellt sind:"
 
 #: wt-status.c:210
 msgid "  (use \"git add <file>...\" to update what will be committed)"
-msgstr "  (benutze \"git add <Datei>...\" zum Bereitstellen)"
+msgstr "  (benutzen Sie \"git add <Datei>...\" zum Bereitstellen)"
 
 #: wt-status.c:212
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
-msgstr "  (benutze \"git add/rm <Datei>...\" zum Bereitstellen)"
+msgstr "  (benutzen Sie \"git add/rm <Datei>...\" zum Bereitstellen)"
 
 #: wt-status.c:213
 msgid ""
 "  (use \"git checkout -- <file>...\" to discard changes in working directory)"
 msgstr ""
-"  (benutze \"git checkout -- <Datei>...\" um die Ã„nderungen im "
+"  (benutzen Sie \"git checkout -- <Datei>...\" um die Ã„nderungen im "
 "Arbeitsverzeichnis zu verwerfen)"
 
 #: wt-status.c:215
 msgid "  (commit or discard the untracked or modified content in submodules)"
 msgstr ""
-"  (trage ein oder verwerfe den unbeobachteten oder geänderten Inhalt in den "
+"  (tragen Sie ein oder verwerfen Sie den unbeobachteten oder geänderten Inhalt in den "
 "Unterprojekten)"
 
 #: wt-status.c:227
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
-msgstr "  (benutze \"git %s <Datei>...\" zum Einfügen in die Eintragung)"
+msgstr "  (benutzen Sie \"git %s <Datei>...\" zum Einfügen in die Eintragung)"
 
 #: wt-status.c:244
 msgid "bug"
@@ -1201,20 +1201,20 @@ msgstr "Fehler: unbehandelter Differenz-Status %c"
 
 #: wt-status.c:785
 msgid "You have unmerged paths."
-msgstr "Du hast nicht zusammengeführte Pfade."
+msgstr "Sie haben nicht zusammengeführte Pfade."
 
 #: wt-status.c:788 wt-status.c:912
 msgid "  (fix conflicts and run \"git commit\")"
-msgstr " (behebe die Konflikte und führe \"git commit\" aus)"
+msgstr " (beheben Sie die Konflikte und führen Sie \"git commit\" aus)"
 
 #: wt-status.c:791
 msgid "All conflicts fixed but you are still merging."
 msgstr ""
-"Alle Konflikte sind behoben, aber du bist immer noch beim Zusammenführen."
+"Alle Konflikte sind behoben, aber Sie sind immer noch beim Zusammenführen."
 
 #: wt-status.c:794
 msgid "  (use \"git commit\" to conclude merge)"
-msgstr "  (benutze \"git commit\" um die Zusammenführung abzuschließen)"
+msgstr "  (benutzen Sie \"git commit\" um die Zusammenführung abzuschließen)"
 
 #: wt-status.c:804
 msgid "You are in the middle of an am session."
@@ -1226,80 +1226,80 @@ msgstr "Der aktuelle Patch ist leer."
 
 #: wt-status.c:811
 msgid "  (fix conflicts and then run \"git am --resolved\")"
-msgstr "  (behebe die Konflikte und führe dann \"git am --resolved\" aus)"
+msgstr "  (beheben Sie die Konflikte und führen Sie dann \"git am --resolved\" aus)"
 
 #: wt-status.c:813
 msgid "  (use \"git am --skip\" to skip this patch)"
-msgstr " (benutze \"git am --skip\" um diesen Patch auszulassen)"
+msgstr " (benutzen Sie \"git am --skip\" um diesen Patch auszulassen)"
 
 #: wt-status.c:815
 msgid "  (use \"git am --abort\" to restore the original branch)"
 msgstr ""
-"  (benutze \"git am --abort\" um den ursprünglichen Zweig wiederherzustellen)"
+"  (benutzen Sie \"git am --abort\" um den ursprünglichen Zweig wiederherzustellen)"
 
 #: wt-status.c:873 wt-status.c:883
 msgid "You are currently rebasing."
-msgstr "Du bist gerade beim Neuaufbau."
+msgstr "Sie sind gerade beim Neuaufbau."
 
 #: wt-status.c:876
 msgid "  (fix conflicts and then run \"git rebase --continue\")"
-msgstr "  (behebe die Konflikte und führe dann \"git rebase --continue\" aus)"
+msgstr "  (beheben Sie die Konflikte und führen Sie dann \"git rebase --continue\" aus)"
 
 #: wt-status.c:878
 msgid "  (use \"git rebase --skip\" to skip this patch)"
-msgstr "  (benutze \"git rebase --skip\" um diesen Patch auszulassen)"
+msgstr "  (benutzen Sie \"git rebase --skip\" um diesen Patch auszulassen)"
 
 #: wt-status.c:880
 msgid "  (use \"git rebase --abort\" to check out the original branch)"
 msgstr ""
-"  (benutze \"git rebase --abort\" um den ursprünglichen Zweig auszuchecken)"
+"  (benutzen Sie \"git rebase --abort\" um den ursprünglichen Zweig auszuchecken)"
 
 #: wt-status.c:886
 msgid "  (all conflicts fixed: run \"git rebase --continue\")"
-msgstr "  (alle Konflikte behoben: führe \"git rebase --continue\" aus)"
+msgstr "  (alle Konflikte behoben: führen Sie \"git rebase --continue\" aus)"
 
 #: wt-status.c:888
 msgid "You are currently splitting a commit during a rebase."
-msgstr "Du teilst gerade eine Version während eines Neuaufbaus auf."
+msgstr "Sie teilen gerade eine Version während eines Neuaufbaus auf."
 
 #: wt-status.c:891
 msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
 msgstr ""
-"  (Sobald dein Arbeitsverzeichnis sauber ist, führe \"git rebase --continue"
+"  (Sobald Ihr Arbeitsverzeichnis sauber ist, führen Sie \"git rebase --continue"
 "\" aus)"
 
 #: wt-status.c:893
 msgid "You are currently editing a commit during a rebase."
-msgstr "Du editierst gerade eine Version während eines Neuaufbaus."
+msgstr "Sie editieren gerade eine Version während eines Neuaufbaus."
 
 #: wt-status.c:896
 msgid "  (use \"git commit --amend\" to amend the current commit)"
 msgstr ""
-"  (benutze \"git commit --amend\" um die aktuelle Version nachzubessern)"
+"  (benutzen Sie \"git commit --amend\" um die aktuelle Version nachzubessern)"
 
 #: wt-status.c:898
 msgid ""
 "  (use \"git rebase --continue\" once you are satisfied with your changes)"
 msgstr ""
-"  (benutze \"git rebase --continue\" sobald deine Ã„nderungen abgeschlossen "
+"  (benutzen Sie \"git rebase --continue\" sobald Ihre Ã„nderungen abgeschlossen "
 "sind)"
 
 #: wt-status.c:908
 msgid "You are currently cherry-picking."
-msgstr "Du führst gerade \"cherry-pick\" aus."
+msgstr "Sie führen gerade \"cherry-pick\" aus."
 
 #: wt-status.c:915
 msgid "  (all conflicts fixed: run \"git commit\")"
-msgstr "  (alle Konflikte behoben: führe \"git commit\" aus)"
+msgstr "  (alle Konflikte behoben: führen Sie \"git commit\" aus)"
 
 #: wt-status.c:924
 msgid "You are currently bisecting."
-msgstr "Du bist gerade beim Halbieren."
+msgstr "Sie sind gerade beim Halbieren."
 
 #: wt-status.c:927
 msgid "  (use \"git bisect reset\" to get back to the original branch)"
 msgstr ""
-"  (benutze \"git bisect reset\" um zum ursprünglichen Zweig zurückzukehren)"
+"  (benutzen Sie \"git bisect reset\" um zum ursprünglichen Zweig zurückzukehren)"
 
 #: wt-status.c:978
 msgid "On branch "
@@ -1328,7 +1328,7 @@ msgstr "Unbeobachtete Dateien nicht aufgelistet%s"
 
 #: wt-status.c:1017
 msgid " (use -u option to show untracked files)"
-msgstr " (benutze die Option -u um unbeobachteten Dateien anzuzeigen)"
+msgstr " (benutzen Sie die Option -u um unbeobachteten Dateien anzuzeigen)"
 
 #: wt-status.c:1023
 msgid "No changes"
@@ -1338,7 +1338,7 @@ msgstr "Keine Ã„nderungen"
 #, c-format
 msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
 msgstr ""
-"keine Ã„nderungen zum Eintragen hinzugefügt (benutze \"git add\" und/oder "
+"keine Ã„nderungen zum Eintragen hinzugefügt (benutzen Sie \"git add\" und/oder "
 "\"git commit -a\")\n"
 
 #: wt-status.c:1031
@@ -1353,7 +1353,7 @@ msgid ""
 "track)\n"
 msgstr ""
 "nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien "
-"(benutze \"git add\" zum Beobachten)\n"
+"(benutzen Sie \"git add\" zum Beobachten)\n"
 
 #: wt-status.c:1037
 #, c-format
@@ -1364,8 +1364,8 @@ msgstr "nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien\n"
 #, c-format
 msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
 msgstr ""
-"nichts einzutragen (Erstelle/Kopiere Dateien und benutze \"git add\" zum "
-"Beobachten)\n"
+"nichts einzutragen (Erstellen/Kopieren Sie Dateien und benutzen Sie \"git add\" "
+"zum Beobachten)\n"
 
 #: wt-status.c:1043 wt-status.c:1048
 #, c-format
@@ -1376,7 +1376,7 @@ msgstr "nichts einzutragen\n"
 #, c-format
 msgid "nothing to commit (use -u to show untracked files)\n"
 msgstr ""
-"nichts einzutragen (benutze die Option -u, um unbeobachtete Dateien "
+"nichts einzutragen (benutzen Sie die Option -u, um unbeobachtete Dateien "
 "anzuzeigen)\n"
 
 #: wt-status.c:1050
@@ -1477,7 +1477,7 @@ msgstr "Konnte '%s' nicht anwenden."
 #: builtin/add.c:313
 msgid "The following paths are ignored by one of your .gitignore files:\n"
 msgstr ""
-"Die folgenden Pfade werden durch eine deiner \".gitignore\" Dateien "
+"Die folgenden Pfade werden durch eine Ihrer \".gitignore\" Dateien "
 "ignoriert:\n"
 
 #: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63
@@ -1538,7 +1538,7 @@ msgstr "prüft ob - auch fehlende - Dateien im Probelauf ignoriert werden"
 #: builtin/add.c:353
 #, c-format
 msgid "Use -f if you really want to add them.\n"
-msgstr "Verwende -f wenn du diese wirklich hinzufügen möchtest.\n"
+msgstr "Verwenden Sie -f wenn Sie diese wirklich hinzufügen möchten.\n"
 
 #: builtin/add.c:354
 msgid "no files added"
@@ -1565,7 +1565,7 @@ msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
 #: builtin/add.c:415
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
-msgstr "Wolltest du vielleicht 'git add .' sagen?\n"
+msgstr "Wollten Sie vielleicht 'git add .' sagen?\n"
 
 #: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82
 #: builtin/rm.c:235
@@ -2269,7 +2269,7 @@ msgid ""
 "If you are sure you want to delete it, run 'git branch -D %s'."
 msgstr ""
 "Der Zweig '%s' ist nicht vollständig zusammengeführt.\n"
-"Wenn du sicher bist diesen Zweig zu entfernen, führe 'git branch -D %s' aus."
+"Wenn Sie sicher sind diesen Zweig zu entfernen, führen Sie 'git branch -D %s' aus."
 
 #: builtin/branch.c:180
 msgid "Update of config-file failed"
@@ -2287,7 +2287,7 @@ msgstr "Konnte Versionsobjekt für Zweigspitze (HEAD) nicht nachschlagen."
 #, c-format
 msgid "Cannot delete the branch '%s' which you are currently on."
 msgstr ""
-"Kann Zweig '%s' nicht entfernen, da du dich gerade auf diesem befindest."
+"Kann Zweig '%s' nicht entfernen, da Sie sich gerade auf diesem befinden."
 
 #: builtin/branch.c:235
 #, c-format
@@ -2365,7 +2365,7 @@ msgstr "Konnte einige Referenzen nicht lesen"
 #: builtin/branch.c:638
 msgid "cannot rename the current branch while not on any."
 msgstr ""
-"Kann aktuellen Zweig nicht umbenennen, solange du dich auf keinem befindest."
+"Kann aktuellen Zweig nicht umbenennen, solange Sie sich auf keinem befinden."
 
 #: builtin/branch.c:648
 #, c-format
@@ -2527,8 +2527,8 @@ msgid ""
 "The --set-upstream flag is deprecated and will be removed. Consider using --"
 "track or --set-upstream-to\n"
 msgstr ""
-"Die --set-upstream Option ist veraltet und wird entfernt. Benutze --track "
-"oder --set-upstream-to\n"
+"Die --set-upstream Option ist veraltet und wird entfernt. Benutzen Sie "
+"--track oder --set-upstream-to\n"
 
 #: builtin/branch.c:934
 #, c-format
@@ -2538,8 +2538,8 @@ msgid ""
 "\n"
 msgstr ""
 "\n"
-"Wenn du wolltest, dass '%s' den Zweig '%s' als externen Ãœbernahmezweig hat, "
-"führe aus:\n"
+"Wenn Sie wollten, dass '%s' den Zweig '%s' als externen Ãœbernahmezweig hat, "
+"führen Sie aus:\n"
 
 #: builtin/branch.c:935
 #, c-format
@@ -2743,7 +2743,7 @@ msgstr "Pfad '%s' ist nicht zusammengeführt."
 
 #: builtin/checkout.c:448
 msgid "you need to resolve your current index first"
-msgstr "Du musst zuerst deine aktuelle Bereitstellung auflösen."
+msgstr "Sie müssen zuerst Ihre aktuelle Bereitstellung auflösen."
 
 #: builtin/checkout.c:569
 #, c-format
@@ -2798,13 +2798,13 @@ msgid_plural ""
 "\n"
 "%s\n"
 msgstr[0] ""
-"Warnung: Du bist um %d Version hinterher, nicht verbunden zu\n"
-"einem deiner Zweige:\n"
+"Warnung: Sie sind um %d Version hinterher, nicht verbunden zu\n"
+"einem Ihrer Zweige:\n"
 "\n"
 "%s\n"
 msgstr[1] ""
-"Warnung: Du bist um %d Versionen hinterher, nicht verbunden zu\n"
-"einem deiner Zweige:\n"
+"Warnung: Sie sind um %d Versionen hinterher, nicht verbunden zu\n"
+"einem Ihrer Zweige:\n"
 "\n"
 "%s\n"
 
@@ -2817,7 +2817,7 @@ msgid ""
 " git branch new_branch_name %s\n"
 "\n"
 msgstr ""
-"Wenn du diese durch einen neuen Zweig behalten möchtest, dann könnte jetzt\n"
+"Wenn Sie diese durch einen neuen Zweig behalten möchten, dann könnte jetzt\n"
 "ein guter Zeitpunkt sein dies zu tun mit:\n"
 "\n"
 " git branch neuer_zweig_name %s\n"
@@ -2833,7 +2833,7 @@ msgstr "Vorherige Position der Zweigspitze (HEAD) war"
 
 #: builtin/checkout.c:761 builtin/checkout.c:950
 msgid "You are on a branch yet to be born"
-msgstr "du bist auf einem Zweig, der noch geboren wird"
+msgstr "Sie sind auf einem Zweig, der noch geboren wird"
 
 #. case (1)
 #: builtin/checkout.c:886
@@ -2946,7 +2946,7 @@ msgstr "--track benötigt einen Zweignamen"
 
 #: builtin/checkout.c:1081
 msgid "Missing branch name; try -b"
-msgstr "Vermisse Zweignamen; versuche -b"
+msgstr "Vermisse Zweignamen; versuchen Sie -b"
 
 #: builtin/checkout.c:1116
 msgid "invalid path specification"
@@ -2959,7 +2959,7 @@ msgid ""
 "Did you intend to checkout '%s' which can not be resolved as commit?"
 msgstr ""
 "Kann nicht gleichzeitig Pfade aktualisieren und zu Zweig '%s' wechseln.\n"
-"Hast du beabsichtigt '%s' auszuchecken, welcher nicht als Version aufgelöst "
+"Haben Sie beabsichtigt '%s' auszuchecken, welcher nicht als Version aufgelöst "
 "werden kann?"
 
 #: builtin/checkout.c:1128
@@ -2973,7 +2973,7 @@ msgid ""
 "checking out of the index."
 msgstr ""
 "git checkout: --ours/--theirs, --force und --merge sind inkompatibel wenn\n"
-"du aus der Bereitstellung auscheckst."
+"Sie aus der Bereitstellung auschecken."
 
 #: builtin/clean.c:19
 msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
@@ -3203,7 +3203,7 @@ msgstr "Zu viele Argumente."
 
 #: builtin/clone.c:694
 msgid "You must specify a repository to clone."
-msgstr "Du musst ein Projektarchiv zum Klonen angeben."
+msgstr "Sie müssen ein Projektarchiv zum Klonen angeben."
 
 #: builtin/clone.c:705
 #, c-format
@@ -3217,7 +3217,7 @@ msgstr "Projektarchiv '%s' existiert nicht."
 
 #: builtin/clone.c:724
 msgid "--depth is ignored in local clones; use file:// instead."
-msgstr "--depth wird in lokalen Klonen ignoriert; benutze stattdessen file://."
+msgstr "--depth wird in lokalen Klonen ignoriert; benutzen Sie stattdessen file://."
 
 #: builtin/clone.c:734
 #, c-format
@@ -3261,7 +3261,7 @@ msgstr "externer Zweig %s nicht im anderen Projektarchiv %s gefunden"
 
 #: builtin/clone.c:879
 msgid "You appear to have cloned an empty repository."
-msgstr "Du scheinst ein leeres Projektarchiv geklont zu haben."
+msgstr "Sie scheinen ein leeres Projektarchiv geklont zu haben."
 
 #: builtin/column.c:9
 msgid "git column [options]"
@@ -3316,15 +3316,15 @@ msgid ""
 "\n"
 "    git commit --amend --reset-author\n"
 msgstr ""
-"Dein Name und E-Mail Adresse wurden automatisch auf Basis\n"
-"deines Benutzer- und Rechnernamens konfiguriert. Bitte prüfe, dass diese\n"
-"zutreffend sind. Du kannst diese Meldung unterdrücken, indem du diese\n"
-"explizit setzt:\n"
+"Ihr Name und E-Mail Adresse wurden automatisch auf Basis\n"
+"Ihres Benutzer- und Rechnernamens konfiguriert. Bitte prüfen Sie, dass\n"
+"diese zutreffend sind. Sie können diese Meldung unterdrücken, indem Sie\n"
+"diese explizit setzen:\n"
 "\n"
-"    git config --global user.name \"Dein Name\"\n"
-"    git config --global user.email deine@emailadresse.de\n"
+"    git config --global user.name \"Ihr Name\"\n"
+"    git config --global user.email ihre@emailadresse.de\n"
 "\n"
-"Nachdem du das getan hast, kannst du deine Identität für diese Version "
+"Nachdem Sie das getan hast, können Sie Ihre Identität für diese Version "
 "ändern mit:\n"
 "\n"
 "    git commit --amend --reset-author\n"
@@ -3335,8 +3335,8 @@ msgid ""
 "it empty. You can repeat your command with --allow-empty, or you can\n"
 "remove the commit entirely with \"git reset HEAD^\".\n"
 msgstr ""
-"Du fragtest die jüngste Version nachzubessern, aber das würde diese leer\n"
-"machen. Du kannst Dein Kommando mit --allow-empty wiederholen, oder die\n"
+"Sie fragten die jüngste Version nachzubessern, aber das würde diese leer\n"
+"machen. Sie können Ihr Kommando mit --allow-empty wiederholen, oder die\n"
 "Version mit \"git reset HEAD^\" vollständig entfernen.\n"
 
 #: builtin/commit.c:61
@@ -3350,11 +3350,11 @@ msgid ""
 msgstr ""
 "Der letzte \"cherry-pick\" ist jetzt leer, möglicherweise durch eine "
 "Konfliktauflösung.\n"
-"Wenn du dies trotzdem eintragen willst, benutze:\n"
+"Wenn Sie dies trotzdem eintragen wollen, benutzen Sie:\n"
 "\n"
 "    git commit --allow-empty\n"
 "\n"
-"Andernfalls benutze bitte 'git reset'\n"
+"Andernfalls benutzen Sie bitte 'git reset'\n"
 
 #: builtin/commit.c:258
 msgid "failed to unpack HEAD tree object"
@@ -3456,10 +3456,10 @@ msgid ""
 "and try again.\n"
 msgstr ""
 "\n"
-"Es sieht so aus, als trägst du eine Zusammenführung ein.\n"
-"Falls das nicht korrekt ist, lösche bitte die Datei\n"
+"Es sieht so aus, als tragen Sie eine Zusammenführung ein.\n"
+"Falls das nicht korrekt ist, löschen Sie bitte die Datei\n"
 "\t%s\n"
-"und versuche es erneut.\n"
+"und versuchen Sie es erneut.\n"
 
 #: builtin/commit.c:723
 #, c-format
@@ -3471,17 +3471,17 @@ msgid ""
 "and try again.\n"
 msgstr ""
 "\n"
-"Es sieht so aus, als trägst du ein \"cherry-pick\" ein.\n"
-"Falls das nicht korrekt ist, lösche bitte die Datei\n"
+"Es sieht so aus, als tragen Sie ein \"cherry-pick\" ein.\n"
+"Falls das nicht korrekt ist, löschen Sie bitte die Datei\n"
 "\t%s\n"
-"und versuche es erneut.\n"
+"und versuchen Sie es erneut.\n"
 
 #: builtin/commit.c:735
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
 msgstr ""
-"Bitte gebe eine Versionsbeschreibung für deine Ã„nderungen ein. Zeilen,\n"
+"Bitte geben Sie eine Versionsbeschreibung für Ihre Ã„nderungen ein. Zeilen,\n"
 "die mit '#' beginnen, werden ignoriert, und eine leere Versionsbeschreibung\n"
 "bricht die Eintragung ab.\n"
 
@@ -3491,8 +3491,8 @@ msgid ""
 "with '#' will be kept; you may remove them yourself if you want to.\n"
 "An empty message aborts the commit.\n"
 msgstr ""
-"Bitte gebe eine Versionsbeschreibung für deine Ã„nderungen ein. Zeilen, die\n"
-"mit '#' beginnen, werden beibehalten; wenn du möchtest, kannst du diese "
+"Bitte geben Sie eine Versionsbeschreibung für Ihre Ã„nderungen ein. Zeilen, die\n"
+"mit '#' beginnen, werden beibehalten; wenn Sie möchten, können Sie diese "
 "entfernen.\n"
 "Eine leere Versionsbeschreibung bricht die Eintragung ab.\n"
 
@@ -3535,7 +3535,7 @@ msgstr "Verwendung von --reset-author und --author macht keinen Sinn."
 
 #: builtin/commit.c:995
 msgid "You have nothing to amend."
-msgstr "Du hast nichts zum nachbessern."
+msgstr "Sie haben nichts zum nachbessern."
 
 #: builtin/commit.c:998
 msgid "You are in the middle of a merge -- cannot amend."
@@ -3726,7 +3726,7 @@ msgstr ""
 
 #: builtin/commit.c:1380
 msgid "the commit is authored by me now (used with -C/-c/--amend)"
-msgstr "Setze mich als Autor der Version (benutzt mit -C/-c/--amend)"
+msgstr "Setzt Sie als Autor der Version (benutzt mit -C/-c/--amend)"
 
 #: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109
 msgid "add Signed-off-by:"
@@ -3836,7 +3836,7 @@ msgstr "Konnte Versionsbeschreibung nicht lesen: %s"
 #: builtin/commit.c:1534
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
-msgstr "Eintragung abgebrochen; du hast die Beschreibung nicht editiert.\n"
+msgstr "Eintragung abgebrochen; Sie haben die Beschreibung nicht editiert.\n"
 
 #: builtin/commit.c:1539
 #, c-format
@@ -3862,8 +3862,8 @@ msgid ""
 "not exceeded, and then \"git reset HEAD\" to recover."
 msgstr ""
 "Das Projektarchiv wurde aktualisiert, aber die \"new_index\"-Datei\n"
-"konnte nicht geschrieben werden. Prüfe, dass deine Festplatte nicht\n"
-"voll und Dein Kontingent nicht aufgebraucht ist und führe\n"
+"konnte nicht geschrieben werden. Prüfen Sie, dass Ihre Festplatte nicht\n"
+"voll und Ihr Kontingent nicht aufgebraucht ist und führen Sie\n"
 "anschließend \"git reset HEAD\" zu Wiederherstellung aus."
 
 #: builtin/config.c:7
@@ -4041,7 +4041,7 @@ msgid ""
 "However, there were unannotated tags: try --tags."
 msgstr ""
 "Keine annotierten Markierungen können '%s' beschreiben.\n"
-"Jedoch gab es nicht annotierte Markierungen: versuche --tags."
+"Jedoch gab es nicht annotierte Markierungen: versuchen Sie --tags."
 
 #: builtin/describe.c:357
 #, c-format
@@ -4050,7 +4050,7 @@ msgid ""
 "Try --always, or create some tags."
 msgstr ""
 "Keine Markierungen können '%s' beschreiben.\n"
-"Versuche --always oder erstelle einige Markierungen."
+"Versuchen Sie --always oder erstellen Sie einige Markierungen."
 
 #: builtin/describe.c:378
 #, c-format
@@ -4354,7 +4354,7 @@ msgid ""
 "some local refs could not be updated; try running\n"
 " 'git remote prune %s' to remove any old, conflicting branches"
 msgstr ""
-"Einige lokale Referenzen konnten nicht aktualisiert werden; versuche\n"
+"Einige lokale Referenzen konnten nicht aktualisiert werden; versuchen Sie\n"
 "'git remote prune %s' um jeden Ã¤lteren, widersprüchlichen Zweig zu löschen."
 
 #: builtin/fetch.c:549
@@ -4412,13 +4412,13 @@ msgid ""
 "No remote repository specified.  Please, specify either a URL or a\n"
 "remote name from which new revisions should be fetched."
 msgstr ""
-"Kein externes Projektarchiv angegeben. Bitte gebe entweder eine URL\n"
+"Kein externes Projektarchiv angegeben. Bitte geben Sie entweder eine URL\n"
 "oder den Namen des externen Archivs an, von welchem neue\n"
 "Versionen angefordert werden sollen."
 
 #: builtin/fetch.c:932
 msgid "You need to specify a tag name."
-msgstr "Du musst den Namen der Markierung angeben."
+msgstr "Sie müssen den Namen der Markierung angeben."
 
 #: builtin/fetch.c:984
 msgid "fetch --all does not take a repository argument"
@@ -4587,15 +4587,15 @@ msgid ""
 "run \"git gc\" manually. See \"git help gc\" for more information.\n"
 msgstr ""
 "Die Datenbank des Projektarchivs wird für eine optimale Performance\n"
-"komprimiert. Du kannst auch \"git gc\" manuell ausführen.\n"
+"komprimiert. Sie können auch \"git gc\" manuell ausführen.\n"
 "Siehe \"git help gc\" für weitere Informationen.\n"
 
 #: builtin/gc.c:249
 msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
-"Es gibt zu viele unerreichbare lose Objekte; führe 'git prune' aus, um diese "
-"zu löschen."
+"Es gibt zu viele unerreichbare lose Objekte; führen Sie 'git prune' aus, um "
+"diese zu löschen."
 
 #: builtin/grep.c:22
 msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
@@ -4918,7 +4918,7 @@ msgid ""
 "Please consider using 'man.<tool>.cmd' instead."
 msgstr ""
 "'%s': Pfad für nicht unterstützten Handbuchbetrachter.\n"
-"Du könntest stattdessen 'man.<Werkzeug>.cmd' benutzen."
+"Sie könnten stattdessen 'man.<Werkzeug>.cmd' benutzen."
 
 #: builtin/help.c:229
 #, c-format
@@ -4927,7 +4927,7 @@ msgid ""
 "Please consider using 'man.<tool>.path' instead."
 msgstr ""
 "'%s': Kommando für unterstützten Handbuchbetrachter.\n"
-"Du könntest stattdessen 'man.<Werkzeug>.path' benutzen."
+"Sie könnten stattdessen 'man.<Werkzeug>.path' benutzen."
 
 #: builtin/help.c:299
 msgid "The most commonly used git commands are:"
@@ -5636,8 +5636,8 @@ msgstr "git cherry [-v] [<Ãœbernahmezweig> [<Arbeitszweig> [<Limit>]]]"
 msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr ""
-"Konnte gefolgten, externen Zweig nicht finden, bitte gebe <upstream> manuell "
-"an.\n"
+"Konnte gefolgten, externen Zweig nicht finden, bitte geben Sie <upstream> "
+"manuell an.\n"
 
 #: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531
 #, c-format
@@ -5956,7 +5956,7 @@ msgstr "konnte nicht von '%s' lesen"
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
-"Zusammenführung wurde nicht eingetragen; benutze 'git commit' um die "
+"Zusammenführung wurde nicht eingetragen; benutzen Sie 'git commit' um die "
 "Zusammenführung abzuschließen.\n"
 
 #: builtin/merge.c:788
@@ -5967,7 +5967,7 @@ msgid ""
 "Lines starting with '#' will be ignored, and an empty message aborts\n"
 "the commit.\n"
 msgstr ""
-"Bitte gebe eine Versionsbeschreibung ein um zu erklären, warum diese "
+"Bitte geben Sie eine Versionsbeschreibung ein um zu erklären, warum diese "
 "Zusammenführung erforderlich ist,\n"
 "insbesondere wenn es einen aktualisierten, externen Zweig mit einem Thema-"
 "Zweig zusammenführt.\n"
@@ -5988,8 +5988,8 @@ msgstr "Wunderbar.\n"
 #, c-format
 msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
 msgstr ""
-"Automatische Zusammenführung fehlgeschlagen; behebe die Konflikte und trage "
-"dann das Ergebnis ein.\n"
+"Automatische Zusammenführung fehlgeschlagen; beheben Sie die Konflikte und tragen "
+"Sie dann das Ergebnis ein.\n"
 
 #: builtin/merge.c:905
 #, c-format
@@ -5998,7 +5998,7 @@ msgstr "'%s' ist keine Version"
 
 #: builtin/merge.c:946
 msgid "No current branch."
-msgstr "Du befindest dich auf keinem Zweig."
+msgstr "Sie befinden sich auf keinem Zweig."
 
 #: builtin/merge.c:948
 msgid "No remote for the current branch."
@@ -6029,34 +6029,34 @@ msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
 msgstr ""
-"Du hast deine Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert).\n"
-"Bitte trage deine Ã„nderungen ein, bevor du zusammenführen kannst."
+"Sie haben Ihre Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert).\n"
+"Bitte tragen Sie Ihre Ã„nderungen ein, bevor Sie zusammenführen können."
 
 #: builtin/merge.c:1129 git-pull.sh:34
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr ""
-"Du hast deine Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert)."
+"Sie haben Ihre Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert)."
 
 #: builtin/merge.c:1133
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
 msgstr ""
-"Du hast \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert).\n"
-"Bitte trage deine Ã„nderungen ein, bevor du zusammenführen kannst."
+"Sie haben \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert).\n"
+"Bitte tragen Sie Ihre Ã„nderungen ein, bevor Sie zusammenführen können."
 
 #: builtin/merge.c:1136
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
 msgstr ""
-"Du hast \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert)."
+"Sie haben \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert)."
 
 #: builtin/merge.c:1145
 msgid "You cannot combine --squash with --no-ff."
-msgstr "Du kannst --squash nicht mit --no-ff kombinieren."
+msgstr "Sie können --squash nicht mit --no-ff kombinieren."
 
 #: builtin/merge.c:1150
 msgid "You cannot combine --no-ff with --ff-only."
-msgstr "Du kannst --no-ff nicht mit --ff--only kombinieren."
+msgstr "Sie können --no-ff nicht mit --ff--only kombinieren."
 
 #: builtin/merge.c:1157
 msgid "No commit specified and merge.defaultToUpstream not set."
@@ -6116,7 +6116,7 @@ msgstr "Zusammenführung mit Strategie %s fehlgeschlagen.\n"
 #: builtin/merge.c:1491
 #, c-format
 msgid "Using the %s to prepare resolving by hand.\n"
-msgstr "Benutze \"%s\" um die Auflösung per Hand vorzubereiten.\n"
+msgstr "Benutzen Sie \"%s\" um die Auflösung per Hand vorzubereiten.\n"
 
 #: builtin/merge.c:1503
 #, c-format
@@ -6461,7 +6461,7 @@ msgstr "konnte Datei '%s' nicht erstellen"
 
 #: builtin/notes.c:192
 msgid "Please supply the note contents using either -m or -F option"
-msgstr "Bitte liefere den Notiz-Inhalt unter Verwendung der Option -m oder -F."
+msgstr "Bitte liefern Sie den Notiz-Inhalt unter Verwendung der Option -m oder -F."
 
 #: builtin/notes.c:213 builtin/notes.c:976
 #, c-format
@@ -6575,7 +6575,7 @@ msgid ""
 "existing notes"
 msgstr ""
 "Konnte Notizen nicht hinzufügen. Existierende Notizen für Objekt %s "
-"gefunden. Verwende '-f' um die existierenden Notizen zu Ã¼berschreiben."
+"gefunden. Verwenden Sie '-f' um die existierenden Notizen zu Ã¼berschreiben."
 
 #: builtin/notes.c:588 builtin/notes.c:665
 #, c-format
@@ -6603,7 +6603,7 @@ msgid ""
 "existing notes"
 msgstr ""
 "Kann Notizen nicht kopieren. Existierende Notizen für Objekt %s gefunden. "
-"Verwende '-f' um die existierenden Notizen zu Ã¼berschreiben."
+"Verwenden Sie '-f' um die existierenden Notizen zu Ã¼berschreiben."
 
 #: builtin/notes.c:671
 #, c-format
@@ -6617,7 +6617,7 @@ msgid ""
 "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
 msgstr ""
 "Die Optionen -m/-F/-c/-C sind für das Unterkommando 'edit' veraltet.\n"
-"Bitte benutze stattdessen 'git notes add -f -m/-F/-c/-C'.\n"
+"Bitte benutzen Sie stattdessen 'git notes add -f -m/-F/-c/-C'.\n"
 
 #: builtin/notes.c:867
 msgid "General options"
@@ -6908,14 +6908,14 @@ msgid ""
 "    git push %s %s\n"
 "%s"
 msgstr ""
-"Der Name des externen Ãœbernahmezweiges stimmt nicht mit dem Namen deines\n"
+"Der Name des externen Ãœbernahmezweiges stimmt nicht mit dem Namen Ihres\n"
 "aktuellen Zweiges Ã¼berein. Um auf den Ãœbernahmezweig in dem externen\n"
-"Projektarchiv zu versenden, benutze:\n"
+"Projektarchiv zu versenden, benutzen Sie:\n"
 "\n"
 "    git push %s HEAD:%s\n"
 "\n"
 "Um auf den Zweig mit dem selben Namen in dem externen Projekarchiv\n"
-"zu versenden, benutze:\n"
+"zu versenden, benutzen Sie:\n"
 "\n"
 "    git push %s %s\n"
 "%s"
@@ -6929,9 +6929,9 @@ msgid ""
 "\n"
 "    git push %s HEAD:<name-of-remote-branch>\n"
 msgstr ""
-"Du befindest dich sich im Moment auf keinem Zweig.\n"
+"Sie befinden sich im Moment auf keinem Zweig.\n"
 "Um die Historie, führend zum aktuellen (freistehende Zweigspitze (HEAD))\n"
-"Status zu versenden, benutze\n"
+"Status zu versenden, benutzen Sie\n"
 "\n"
 "    git push %s HEAD:<Name-des-externen-Zweiges>\n"
 
@@ -6945,7 +6945,7 @@ msgid ""
 msgstr ""
 "Der aktuelle Zweig %s hat keinen Zweig im externen Projektarchiv.\n"
 "Um den aktuellen Zweig zu versenden und das Fernarchiv als externes\n"
-"Projektarchiv zu verwenden, benutze\n"
+"Projektarchiv zu verwenden, benutzen Sie\n"
 "\n"
 "    git push --set-upstream %s %s\n"
 
@@ -6961,7 +6961,7 @@ msgid ""
 "your current branch '%s', without telling me what to push\n"
 "to update which remote branch."
 msgstr ""
-"Du versendest nach '%s', welches kein externes Projektarchiv deines\n"
+"Sie versenden nach '%s', welches kein externes Projektarchiv Ihres\n"
 "aktuellen Zweiges '%s' ist, ohne mir mitzuteilen, was ich versenden\n"
 "soll, um welchen externen Zweig zu aktualisieren."
 
@@ -6985,26 +6985,25 @@ msgstr ""
 "'push.default' ist nicht gesetzt; der implizit gesetzte Wert\n"
 "wird in Git 2.0 von 'matching' nach 'simple' geändert. Um diese Meldung zu\n"
 "unterdrücken und das aktuelle Verhalten nach Ã„nderung des Standardwertes\n"
-"beizubehalten, benutze:\n"
+"beizubehalten, benutzen Sie:\n"
 "  git config --global push.default matching\n"
 "\n"
 "Um diese Meldung zu unterdrücken und das neue Verhalten jetzt zu "
-"übernehmen,\n"
-"benutze:\n"
+"übernehmen, benutzen Sie:\n"
 "\n"
 "  git config --global push.default simple\n"
 "\n"
-"Führe 'git help config' aus und suche nach 'push.default' für weitere "
-"Informationen.\n"
+"Führen Sie 'git help config' aus und suchen Sie nach 'push.default' für "
+"weitere Informationen.\n"
 "(Der Modus 'simple' wurde in Git 1.7.11 eingeführt. Benutze den Ã¤hnlichen "
-"Modus 'current' anstatt 'simple', falls du gelegentlich Ã¤ltere Versionen von "
-"Git benutzt.)"
+"Modus 'current' anstatt 'simple', falls Sie gelegentlich Ã¤ltere Versionen von "
+"Git benutzen.)"
 
 #: builtin/push.c:199
 msgid ""
 "You didn't specify any refspecs to push, and push.default is \"nothing\"."
 msgstr ""
-"Du hast keine Referenzspezifikationen zum Versenden angegeben, und push."
+"Sie haben keine Referenzspezifikationen zum Versenden angegeben, und push."
 "default ist \"nothing\"."
 
 #: builtin/push.c:206
@@ -7014,9 +7013,10 @@ msgid ""
 "before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Aktualisierungen wurden zurückgewiesen, weil die Spitze deines aktuellen\n"
-"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Führe die\n"
-"externen Ã„nderungen zusammen (z.B. 'git pull') bevor du erneut versendest.\n"
+"Aktualisierungen wurden zurückgewiesen, weil die Spitze Ihres aktuellen\n"
+"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Führen Sie\n"
+"die externen Ã„nderungen zusammen (z.B. 'git pull') bevor Sie erneut\n"
+"versenden.\n"
 "Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
 "für weitere Details."
 
@@ -7028,8 +7028,8 @@ msgid ""
 "to 'simple', 'current' or 'upstream' to push only the current branch."
 msgstr ""
 "Aktualisierungen wurden zurückgewiesen, weil die Spitze eines versendeten\n"
-"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Wenn du nicht\n"
-"beabsichtigt hast, diesen Zweig zu versenden, kannst du auch den zu "
+"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Wenn Sie nicht\n"
+"beabsichtigt haben, diesen Zweig zu versenden, können Sie auch den zu "
 "versendenden\n"
 "Zweig spezifizieren oder die Konfigurationsvariable 'push.default' zu "
 "'simple', 'current'\n"
@@ -7043,9 +7043,9 @@ msgid ""
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Aktualisierungen wurden zurückgewiesen, weil die Spitze eines versendeten\n"
-"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Checke diesen\n"
-"Zweig aus und führe die externen Ã„nderungen zusammen (z.B. 'git pull')\n"
-"bevor du erneut versendest.\n"
+"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Checken Sie\n"
+"diesen Zweig aus und führen Sie die externen Ã„nderungen zusammen\n"
+"(z.B. 'git pull') bevor Sie erneut versenden.\n"
 "Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
 "für weitere Details."
 
@@ -7077,12 +7077,12 @@ msgid ""
 "    git push <name>\n"
 msgstr ""
 "Kein Ziel zum Versenden konfiguriert.\n"
-"Entweder spezifizierst du die URL von der Kommandozeile oder konfigurierst "
+"Entweder spezifizieren Sie die URL von der Kommandozeile oder konfigurieren "
 "ein externes Projektarchiv unter Benutzung von\n"
 "\n"
 "    git remote add <Name> <URL>\n"
 "\n"
-"und versendest dann unter Benutzung dieses Namens\n"
+"und versenden dann unter Benutzung dieses Namens\n"
 "\n"
 "    git push <Name>\n"
 
@@ -7331,7 +7331,7 @@ msgid ""
 "\t use --mirror=fetch or --mirror=push instead"
 msgstr ""
 "--mirror ist gefährlich und veraltet; bitte\n"
-"\t benutze stattdessen --mirror=fetch oder --mirror=push"
+"\t benutzen Sie stattdessen --mirror=fetch oder --mirror=push"
 
 #: builtin/remote.c:147
 #, c-format
@@ -7440,7 +7440,7 @@ msgstr ""
 "Keine Aktualisierung der nicht standardmäßigen Referenzspezifikation zum "
 "Abholen\n"
 "\t%s\n"
-"\tBitte aktualisiere, falls notwendig, die Konfiguration manuell."
+"\tBitte aktualisieren Sie, falls notwendig, die Konfiguration manuell."
 
 #: builtin/remote.c:683
 #, c-format
@@ -7477,11 +7477,11 @@ msgid_plural ""
 msgstr[0] ""
 "Hinweis: Ein Zweig außerhalb der /refs/remotes/ Hierachie wurde nicht "
 "gelöscht;\n"
-"um diesen zu löschen, benutze:"
+"um diesen zu löschen, benutzen Sie:"
 msgstr[1] ""
 "Hinweis: Einige Zweige außer der /refs/remotes/ Hierarchie wurden nicht "
 "entfernt;\n"
-"um diese zu entfernen, benutze:"
+"um diese zu entfernen, benutzen Sie:"
 
 #: builtin/remote.c:943
 #, c-format
@@ -7494,7 +7494,7 @@ msgstr " gefolgt"
 
 #: builtin/remote.c:948
 msgid " stale (use 'git remote prune' to remove)"
-msgstr " veraltet (benutze 'git remote prune' zum Löschen)"
+msgstr " veraltet (benutzen Sie 'git remote prune' zum Löschen)"
 
 #: builtin/remote.c:950
 msgid " ???"
@@ -7647,8 +7647,8 @@ msgstr "Kann Hauptzweig des externen Projektarchivs nicht bestimmen"
 #: builtin/remote.c:1218
 msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
 msgstr ""
-"Mehrere Hauptzweige im externen Projektarchiv. Bitte wähle explizit einen "
-"aus mit:"
+"Mehrere Hauptzweige im externen Projektarchiv. Bitte wählen Sie explizit "
+"einen aus mit:"
 
 #: builtin/remote.c:1228
 #, c-format
@@ -7814,7 +7814,7 @@ msgstr "keep"
 
 #: builtin/reset.c:77
 msgid "You do not have a valid HEAD."
-msgstr "Du hast keine gültige Zweigspitze (HEAD)."
+msgstr "Sie haben keine gültige Zweigspitze (HEAD)."
 
 #: builtin/reset.c:79
 msgid "Failed to find tree of HEAD."
@@ -7881,7 +7881,8 @@ msgstr "--patch ist inkompatibel mit --{hard,mixed,soft}"
 #: builtin/reset.c:317
 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
 msgstr ""
-"--mixed mit Pfaden ist veraltet; benutze stattdessen 'git reset -- <Pfade>'."
+"--mixed mit Pfaden ist veraltet; benutzen Sie stattdessen "
+"'git reset -- <Pfade>'."
 
 #: builtin/reset.c:319
 #, c-format
@@ -7922,7 +7923,7 @@ msgstr ""
 "   oder: git rev-parse --sq-quote [<Argumente>...]\n"
 "   oder: git rev-parse [Optionen] [<Argumente>...]\n"
 "\n"
-"Führe \"git rev-parse --parseopt -h\" für weitere Informationen bei erster "
+"Führen Sie \"git rev-parse --parseopt -h\" für weitere Informationen bei erster "
 "Verwendung aus."
 
 #: builtin/revert.c:22
@@ -8025,8 +8026,8 @@ msgid ""
 "(use 'rm -rf' if you really want to remove it including all of its history)"
 msgstr ""
 "Unterprojekt '%s' (oder ein geschachteltes Unterprojekt hiervon) verwendet\n"
-"ein .git-Verzeichnis (benutze 'rm -rf' wenn du dieses wirklich mitsamt\n"
-"seiner Historie löschen möchtest)"
+"ein .git-Verzeichnis (benutzen Sie 'rm -rf' wenn Sie dieses wirklich mitsamt\n"
+"seiner Historie löschen möchten)"
 
 #: builtin/rm.c:174
 #, c-format
@@ -8035,7 +8036,7 @@ msgid ""
 "(use -f to force removal)"
 msgstr ""
 "'%s' hat bereitgestellten Inhalt unterschiedlich zu der Datei und der\n"
-"Zweigspitze (HEAD) (benutze -f um die Entfernung zu erzwingen)"
+"Zweigspitze (HEAD) (benutzen Sie -f um die Entfernung zu erzwingen)"
 
 #: builtin/rm.c:180
 #, c-format
@@ -8044,7 +8045,7 @@ msgid ""
 "(use --cached to keep the file, or -f to force removal)"
 msgstr ""
 "'%s' hat Ã„nderungen in der Bereitstellung\n"
-"(benutze --cached um die Datei zu behalten, oder -f um die Entfernung zu "
+"(benutzen Sie --cached um die Datei zu behalten, oder -f um die Entfernung zu "
 "erzwingen)"
 
 #: builtin/rm.c:191
@@ -8054,7 +8055,7 @@ msgid ""
 "(use --cached to keep the file, or -f to force removal)"
 msgstr ""
 "'%s' hat lokale Modifikationen\n"
-"(benutze --cached um die Datei zu behalten, oder -f um die Entfernung zu "
+"(benutzen Sie --cached um die Datei zu behalten, oder -f um die Entfernung zu "
 "erzwingen)"
 
 #: builtin/rm.c:207
@@ -8334,7 +8335,7 @@ msgid ""
 msgstr ""
 "\n"
 "#\n"
-"# Gebe eine Markierungsbeschreibung ein\n"
+"# Geben Sie eine Markierungsbeschreibung ein.\n"
 "# Zeilen, die mit '#' beginnen, werden ignoriert.\n"
 "#\n"
 
@@ -8349,9 +8350,9 @@ msgid ""
 msgstr ""
 "\n"
 "#\n"
-"# Gebe eine Markierungsbeschreibung ein\n"
-"# Zeilen, die mit '#' beginnen, werden behalten; du darfst diese\n"
-"# selbst entfernen wenn du möchtest.\n"
+"# Geben Sie eine Markierungsbeschreibung ein.\n"
+"# Zeilen, die mit '#' beginnen, werden behalten; Sie dürfen diese\n"
+"# selbst entfernen wenn Sie möchten.\n"
 "#\n"
 
 #: builtin/tag.c:298
@@ -8790,14 +8791,14 @@ msgstr ""
 
 #: git-am.sh:50
 msgid "You need to set your committer info first"
-msgstr "Du musst zuerst die Informationen des Eintragenden setzen."
+msgstr "Sie müssen zuerst die Informationen des Eintragenden setzen."
 
 #: git-am.sh:95
 msgid ""
 "You seem to have moved HEAD since the last 'am' failure.\n"
 "Not rewinding to ORIG_HEAD"
 msgstr ""
-"Du scheinst seit dem letzten gescheiterten 'am' die Zweigspitze (HEAD)\n"
+"Sie scheinen seit dem letzten gescheiterten 'am' die Zweigspitze (HEAD)\n"
 "geändert zu haben.\n"
 "Keine Zurücksetzung zu ORIG_HEAD."
 
@@ -8808,12 +8809,11 @@ msgid ""
 "If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
 "To restore the original branch and stop patching, run \"$cmdline --abort\"."
 msgstr ""
-"Wenn du das Problem gelöst hast, führe \"$cmdline --resolved\" aus.\n"
-"Falls du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip"
-"\" aus.\n"
-"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der "
-"Patches\n"
-"abzubrechen, führe \"$cmdline --abort\" aus."
+"Wenn Sie das Problem gelöst haben, führen Sie \"$cmdline --resolved\" aus.\n"
+"Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen\n"
+"\"$cmdline --skip\" aus.\n"
+"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der\n"
+"Patches abzubrechen, führen Sie \"$cmdline --abort\" aus."
 
 #: git-am.sh:121
 msgid "Cannot fall back to three-way merge."
@@ -8836,7 +8836,7 @@ msgid ""
 "Did you hand edit your patch?\n"
 "It does not apply to blobs recorded in its index."
 msgstr ""
-"Hast du den Patch per Hand editiert?\n"
+"Haben Sie den Patch per Hand editiert?\n"
 "Er kann nicht auf die Blobs in seiner 'index' Zeile angewendet werden."
 
 #: git-am.sh:163
@@ -8877,7 +8877,7 @@ msgstr ""
 
 #: git-am.sh:482
 msgid "Please make up your mind. --skip or --abort?"
-msgstr "Bitte werde dir klar. --skip oder --abort?"
+msgstr "Bitte werden Sie sich klar. --skip oder --abort?"
 
 #: git-am.sh:509
 msgid "Resolve operation not in progress, we are not resuming."
@@ -8897,11 +8897,11 @@ msgid ""
 "To restore the original branch and stop patching run \"$cmdline --abort\"."
 msgstr ""
 "Patch ist leer. Wurde er falsch aufgeteilt?\n"
-"Wenn du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip"
-"\" aus.\n"
+"Wenn Sie diesen Patch auslassen möchten, führen Sie stattdessen\n"
+"\"$cmdline --skip\" aus.\n"
 "Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der "
 "Patches\n"
-"abzubrechen, führe \"$cmdline --abort\" aus."
+"abzubrechen, führen Sie \"$cmdline --abort\" aus."
 
 #: git-am.sh:706
 msgid "Patch does not have a valid e-mail address."
@@ -8935,9 +8935,9 @@ msgid ""
 "If there is nothing left to stage, chances are that something else\n"
 "already introduced the same changes; you might want to skip this patch."
 msgstr ""
-"Keine Ã„nderungen - hast du vergessen 'git add' zu benutzen?\n"
+"Keine Ã„nderungen - haben Sie vergessen 'git add' zu benutzen?\n"
 "Wenn keine Ã„nderungen mehr zum Bereitstellen vorhanden sind, könnten\n"
-"diese bereits anderweitig eingefügt worden sein; du könntest diesen Patch\n"
+"diese bereits anderweitig eingefügt worden sein; Sie könnten diesen Patch\n"
 "auslassen."
 
 #: git-am.sh:829
@@ -8945,8 +8945,8 @@ msgid ""
 "You still have unmerged paths in your index\n"
 "did you forget to use 'git add'?"
 msgstr ""
-"Du hast immer noch nicht zusammengeführte Pfade in der Bereitstellung.\n"
-"Hast du vergessen 'git add' zu benutzen?"
+"Sie haben immer noch nicht zusammengeführte Pfade in der Bereitstellung.\n"
+"Haben Sie vergessen 'git add' zu benutzen?"
 
 #: git-am.sh:845
 msgid "No changes -- Patch already applied."
@@ -8972,14 +8972,14 @@ msgstr "wende zu leerer Historie an"
 
 #: git-bisect.sh:48
 msgid "You need to start by \"git bisect start\""
-msgstr "Du musst mit \"git bisect start\" beginnen."
+msgstr "Sie müssen mit \"git bisect start\" beginnen."
 
 #. TRANSLATORS: Make sure to include [Y] and [n] in your
 #. translation. The program will only accept English input
 #. at this point.
 #: git-bisect.sh:54
 msgid "Do you want me to do it for you [Y/n]? "
-msgstr "Willst du, dass ich es für dich mache [Y/n]? "
+msgstr "Wollen Sie, dass ich es für Sie mache [Y/n]? "
 
 #: git-bisect.sh:95
 #, sh-format
@@ -9000,7 +9000,7 @@ msgstr "Ungültige Zweigspitze (HEAD) - Zweigspitze (HEAD) wird benötigt"
 msgid ""
 "Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
 msgstr ""
-"Auschecken von '$start_head' fehlgeschlagen. Versuche 'git bisect reset "
+"Auschecken von '$start_head' fehlgeschlagen. Versuchen Sie 'git bisect reset "
 "<gueltigerzweig>'."
 
 #: git-bisect.sh:140
@@ -9023,7 +9023,7 @@ msgstr "Ungültige Referenz-Eingabe: $arg"
 
 #: git-bisect.sh:232
 msgid "Please call 'bisect_state' with at least one argument."
-msgstr "Bitte rufe 'bisect_state' mit mindestens einem Argument auf."
+msgstr "Bitte rufen Sie 'bisect_state' mit mindestens einem Argument auf."
 
 #: git-bisect.sh:244
 #, sh-format
@@ -9045,15 +9045,15 @@ msgstr "Warnung: halbiere nur mit einer fehlerhaften Version"
 #. at this point.
 #: git-bisect.sh:279
 msgid "Are you sure [Y/n]? "
-msgstr "Bist du sicher [Y/n]? "
+msgstr "Sind Sie sicher [Y/n]? "
 
 #: git-bisect.sh:289
 msgid ""
 "You need to give me at least one good and one bad revisions.\n"
 "(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
 msgstr ""
-"Du musst mindestens eine korrekte und eine fehlerhafte Version angeben.\n"
-"(Du kannst dafür \"git bisect bad\" und \"git bisect good\" benutzen.)"
+"Sie müssen mindestens eine korrekte und eine fehlerhafte Version angeben.\n"
+"(Sie können dafür \"git bisect bad\" und \"git bisect good\" benutzen.)"
 
 #: git-bisect.sh:292
 msgid ""
@@ -9061,10 +9061,10 @@ msgid ""
 "You then need to give me at least one good and one bad revisions.\n"
 "(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
 msgstr ""
-"Du musst mit \"git bisect start\" beginnen.\n"
-"Danach musst du mindestens eine korrekte und eine fehlerhafte Version "
+"Sie müssen mit \"git bisect start\" beginnen.\n"
+"Danach müssen Sie mindestens eine korrekte und eine fehlerhafte Version "
 "angeben.\n"
-"(Du kannst dafür \"git bisect bad\" und \"git bisect good\" benutzen.)"
+"(Sie können dafür \"git bisect bad\" und \"git bisect good\" benutzen.)"
 
 #: git-bisect.sh:347 git-bisect.sh:474
 msgid "We are not bisecting."
@@ -9082,7 +9082,7 @@ msgid ""
 "Try 'git bisect reset <commit>'."
 msgstr ""
 "Konnte die ursprüngliche Zweigspitze (HEAD) '$branch' nicht auschecken.\n"
-"Versuche 'git bisect reset <Version>'."
+"Versuchen Sie 'git bisect reset <Version>'."
 
 #: git-bisect.sh:390
 msgid "No logfile given"
@@ -9095,7 +9095,7 @@ msgstr "kann $file nicht für das Abspielen lesen"
 
 #: git-bisect.sh:408
 msgid "?? what are you talking about?"
-msgstr "?? Was redest du da?"
+msgstr "?? Was reden Sie da?"
 
 #: git-bisect.sh:420
 #, sh-format
@@ -9134,14 +9134,14 @@ msgid ""
 "Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
 "as appropriate to mark resolution, or use 'git commit -a'."
 msgstr ""
-"\"pull\" ist nicht möglich, weil du nicht zusammengeführte Dateien hast.\n"
-"Bitte korrigiere dies im Arbeitsbaum und benutze dann 'git add/rm <Datei>'\n"
-"um die Auflösung entsprechend zu markieren, oder benutze 'git commit -a'."
+"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben.\n"
+"Bitte korrigieren Sie dies im Arbeitsbaum und benutzen Sie dann 'git add/rm <Datei>'\n"
+"um die Auflösung entsprechend zu markieren, oder benutzen Sie 'git commit -a'."
 
 #: git-pull.sh:25
 msgid "Pull is not possible because you have unmerged files."
 msgstr ""
-"\"pull\" ist nicht möglich, weil du nicht zusammengeführte Dateien hast."
+"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: git-pull.sh:197
 msgid "updating an unborn branch with changes added to the index"
@@ -9161,7 +9161,7 @@ msgid ""
 "Warning: commit $orig_head."
 msgstr ""
 "Warnung: Die Anforderung aktualisierte die Spitze des aktuellen Zweiges.\n"
-"Warnung: Spule deinen Arbeitszweig von Version $orig_head vor."
+"Warnung: Spule Ihren Arbeitszweig von Version $orig_head vor."
 
 #: git-pull.sh:254
 msgid "Cannot merge multiple branches into empty head"
@@ -9178,12 +9178,12 @@ msgid ""
 "To check out the original branch and stop rebasing, run \"git rebase --abort"
 "\"."
 msgstr ""
-"Wenn du das Problem aufgelöst hast, führe \"git rebase --continue\" aus.\n"
-"Falls du diesen Patch auslassen möchtest, führe stattdessen \"git rebase --"
+"Wenn Sie das Problem aufgelöst haben, führen Sie \"git rebase --continue\" aus.\n"
+"Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen \"git rebase --"
 "skip\" aus.\n"
 "Um den ursprünglichen Zweig wiederherzustellen und den Neuaufbau "
 "abzubrechen,\n"
-"führe \"git rebase --abort\" aus."
+"führen Sie \"git rebase --abort\" aus."
 
 #: git-rebase.sh:160
 msgid "The pre-rebase hook refused to rebase."
@@ -9215,7 +9215,7 @@ msgid ""
 "You must edit all merge conflicts and then\n"
 "mark them as resolved using git add"
 msgstr ""
-"Du musst alle Zusammenführungskonflikte editieren und diese dann\n"
+"Sie müssen alle Zusammenführungskonflikte editieren und diese dann\n"
 "mittels \"git add\" als aufgelöst markieren"
 
 #: git-rebase.sh:340
@@ -9237,11 +9237,11 @@ msgid ""
 msgstr ""
 "Es sieht so aus, als ob es das Verzeichnis $state_dir_base bereits gibt\n"
 "und es könnte ein anderer Neuaufbau im Gange sein. Wenn das der Fall ist,\n"
-"probiere bitte\n"
+"probieren Sie bitte\n"
 "\t$cmd_live_rebase\n"
-"Wenn das nicht der Fall ist, probiere bitte\n"
+"Wenn das nicht der Fall ist, probieren Sie bitte\n"
 "\t$cmd_clear_stale_rebase\n"
-"und führe dieses Kommando nochmal aus. Es wird angehalten, falls noch\n"
+"und führen Sie dieses Kommando nochmal aus. Es wird angehalten, falls noch\n"
 "etwas Schützenswertes vorhanden ist."
 
 #: git-rebase.sh:404
@@ -9271,7 +9271,7 @@ msgstr "fatal: Zweig $branch_name nicht gefunden"
 
 #: git-rebase.sh:483
 msgid "Please commit or stash them."
-msgstr "Bitte trage die Ã„nderungen ein oder benutze \"stash\"."
+msgstr "Bitte tragen Sie die Ã„nderungen ein oder benutzen Sie \"stash\"."
 
 #: git-rebase.sh:501
 #, sh-format
@@ -9293,7 +9293,7 @@ msgstr "Änderungen von $mb zu $onto:"
 #: git-rebase.sh:524
 msgid "First, rewinding head to replay your work on top of it..."
 msgstr ""
-"Zunächst wird die Zweigspitze zurückgespult, um deine Ã„nderungen\n"
+"Zunächst wird die Zweigspitze zurückgespult, um Ihre Ã„nderungen\n"
 "darauf neu anzuwenden..."
 
 #: git-rebase.sh:532
@@ -9307,7 +9307,7 @@ msgstr "git stash clear mit Parametern ist nicht implementiert"
 
 #: git-stash.sh:74
 msgid "You do not have the initial commit yet"
-msgstr "Du hast bisher noch keine initiale Version"
+msgstr "Sie haben bisher noch keine initiale Version"
 
 #: git-stash.sh:89
 msgid "Cannot save the current index state"
@@ -9346,7 +9346,7 @@ msgid ""
 "       To provide a message, use git stash save -- '$option'"
 msgstr ""
 "Fehler: unbekannte Option für 'stash save': $option\n"
-"        Um eine Beschreibung anzugeben, benutze \"git stash save -- "
+"        Um eine Beschreibung anzugeben, benutzen Sie \"git stash save -- "
 "'$option'\""
 
 #: git-stash.sh:223
@@ -9400,7 +9400,7 @@ msgstr ""
 
 #: git-stash.sh:424
 msgid "Conflicts in index. Try without --index."
-msgstr "Konflikte in der Bereitstellung. Versuche es ohne --index."
+msgstr "Konflikte in der Bereitstellung. Versuchen Sie es ohne --index."
 
 #: git-stash.sh:426
 msgid "Could not save index tree"
@@ -9430,7 +9430,7 @@ msgstr "Kein Zweigname spezifiziert"
 
 #: git-stash.sh:571
 msgid "(To restore them type \"git stash apply\")"
-msgstr "(Zur Wiederherstellung gebe \"git stash apply\" ein)"
+msgstr "(Zur Wiederherstellung geben Sie \"git stash apply\" ein)"
 
 #: git-submodule.sh:89
 #, sh-format
@@ -9471,9 +9471,9 @@ msgid ""
 "$sm_path\n"
 "Use -f if you really want to add it."
 msgstr ""
-"Der folgende Pfad wird durch eine deiner \".gitignore\" Dateien ignoriert:\n"
+"Der folgende Pfad wird durch eine Ihrer \".gitignore\" Dateien ignoriert:\n"
 "$sm_path\n"
-"Benutze -f wenn du diesen wirklich hinzufügen möchtest."
+"Benutzen Sie -f wenn Sie diesen wirklich hinzufügen möchten."
 
 #: git-submodule.sh:355
 #, sh-format
@@ -9497,7 +9497,7 @@ msgstr "Ein Git-Verzeichnis für '$sm_name' wurde lokal gefunden mit den "
 msgid ""
 "If you want to reuse this local git directory instead of cloning again from"
 msgstr ""
-"Wenn du dieses lokale Git-Verzeichnis wiederverwenden möchtest, anstatt "
+"Wenn Sie dieses lokale Git-Verzeichnis wiederverwenden möchtest, anstatt "
 "erneut zu klonen"
 
 #: git-submodule.sh:369
@@ -9505,7 +9505,7 @@ msgstr ""
 msgid ""
 "use the '--force' option. If the local git directory is not the correct repo"
 msgstr ""
-"benutze die Option '--force'. Wenn das lokale Git-Verzeichnis nicht das "
+"benutzen Sie die Option '--force'. Wenn das lokale Git-Verzeichnis nicht das "
 "korrekte Projektarchiv ist"
 
 #: git-submodule.sh:370
@@ -9514,8 +9514,8 @@ msgid ""
 "or you are unsure what this means choose another name with the '--name' "
 "option."
 msgstr ""
-"oder du dir unsicher bist, was das bedeutet, wähle einen anderen Namen mit "
-"der Option '--name'."
+"oder Sie sich unsicher sind, was das bedeutet, wählen Sie einen anderen Namen"
+"mit der Option '--name'."
 
 #: git-submodule.sh:372
 #, sh-format
@@ -9576,7 +9576,7 @@ msgid ""
 "Maybe you want to use 'update --init'?"
 msgstr ""
 "Unterprojekt-Pfad '$sm_path' ist nicht initialisiert\n"
-"Vielleicht möchtest du 'update --init' benutzen?"
+"Vielleicht möchten Sie 'update --init' benutzen?"
 
 #: git-submodule.sh:627
 #, sh-format
index 91bb2d3ef675b12ac5425ae71600e13c1adc34f9..92c839fe641da15d05c2afe2b498a9fe390624c8 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -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;
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:
index 22604902aa4c4dd146f562c4841c344a773a9bda..aef5e8a0170c5b337f1aa3ac7a35be3b54957729 100644 (file)
@@ -186,14 +186,15 @@ static int error_dirty_index(struct replay_opts *opts)
        return -1;
 }
 
-static int fast_forward_to(const unsigned char *to, const unsigned char *from)
+static int fast_forward_to(const unsigned char *to, const unsigned char *from,
+                          int unborn)
 {
        struct ref_lock *ref_lock;
 
        read_cache();
        if (checkout_fast_forward(from, to, 1))
                exit(1); /* the callee should have complained already */
-       ref_lock = lock_any_ref_for_update("HEAD", from, 0);
+       ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from, 0);
        return write_ref_sha1(ref_lock, to, "cherry-pick");
 }
 
@@ -390,7 +391,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
        struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
        char *defmsg = NULL;
        struct strbuf msgbuf = STRBUF_INIT;
-       int res;
+       int res, unborn = 0;
 
        if (opts->no_commit) {
                /*
@@ -402,9 +403,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
                if (write_cache_as_tree(head, 0, NULL))
                        die (_("Your index file is unmerged."));
        } else {
-               if (get_sha1("HEAD", head))
-                       return error(_("You do not have a valid HEAD"));
-               if (index_differs_from("HEAD", 0))
+               unborn = get_sha1("HEAD", head);
+               if (unborn)
+                       hashcpy(head, EMPTY_TREE_SHA1_BIN);
+               if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0))
                        return error_dirty_index(opts);
        }
        discard_cache();
@@ -435,8 +437,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
        else
                parent = commit->parents->item;
 
-       if (opts->allow_ff && parent && !hashcmp(parent->object.sha1, head))
-               return fast_forward_to(commit->object.sha1, head);
+       if (opts->allow_ff &&
+           ((parent && !hashcmp(parent->object.sha1, head)) ||
+            (!parent && unborn)))
+            return fast_forward_to(commit->object.sha1, head, unborn);
 
        if (parent && parse_commit(parent) < 0)
                /* TRANSLATORS: The first %s will be "revert" or
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 3025418ff57c8c16cd11dd0db4f9d442743118fa..1923cc104bc71e5a696676232d6f42b47a19de25 100644 (file)
@@ -13,9 +13,11 @@ TAR ?= $(TAR)
 RM ?= rm -f
 PROVE ?= prove
 DEFAULT_TEST_TARGET ?= test
+TEST_LINT ?= test-lint-duplicates test-lint-executable
 
 # Shell quote;
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
 
 T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
 TSVN = $(sort $(wildcard t91[0-9][0-9]-*.sh))
@@ -43,7 +45,7 @@ clean-except-prove-cache:
 clean: clean-except-prove-cache
        $(RM) .prove
 
-test-lint: test-lint-duplicates test-lint-executable
+test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax
 
 test-lint-duplicates:
        @dups=`echo $(T) | tr ' ' '\n' | sed 's/-.*//' | sort | uniq -d` && \
@@ -55,6 +57,9 @@ test-lint-executable:
                test -z "$$bad" || { \
                echo >&2 "non-executable tests:" $$bad; exit 1; }
 
+test-lint-shell-syntax:
+       @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T)
+
 aggregate-results-and-cleanup: $(T)
        $(MAKE) aggregate-results
        $(MAKE) clean
@@ -87,7 +92,7 @@ test-results:
        mkdir -p test-results
 
 test-results/git-smoke.tar.gz: test-results
-       $(PERL_PATH) ./harness \
+       '$(PERL_PATH_SQ)' ./harness \
                --archive="test-results/git-smoke.tar.gz" \
                $(T)
 
diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl
new file mode 100755 (executable)
index 0000000..8b5a71d
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+
+# Test t0000..t9999.sh for non portable shell scripts
+# This script can be called with one or more filenames as parameters
+
+use strict;
+use warnings;
+
+my $exit_code=0;
+
+sub err {
+       my $msg = shift;
+       print "$ARGV:$.: error: $msg: $_\n";
+       $exit_code = 1;
+}
+
+while (<>) {
+       chomp;
+       /^\s*sed\s+-i/ and err 'sed -i is not portable';
+       /^\s*echo\s+-n/ and err 'echo -n is not portable (please use printf)';
+       /^\s*declare\s+/ and err 'arrays/declare not portable';
+       /^\s*[^#]\s*which\s/ and err 'which is not portable (please use type)';
+       /test\s+[^=]*==/ and err '"test a == b" is not portable (please use =)';
+       # this resets our $. for each file
+       close ARGV if eof;
+}
+exit $exit_code;
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 807b8b88e215df5ce39504b1858be8694499727d..43b25137e9878e41557fd7d095cc991c27efdfc7 100755 (executable)
@@ -206,6 +206,43 @@ test_expect_success 'patterns starting with exclamation' '
        attr_check "!f" foo
 '
 
+test_expect_success '"**" test' '
+       echo "**/f foo=bar" >.gitattributes &&
+       cat <<\EOF >expect &&
+f: foo: bar
+a/f: foo: bar
+a/b/f: foo: bar
+a/b/c/f: foo: bar
+EOF
+       git check-attr foo -- "f" >actual 2>err &&
+       git check-attr foo -- "a/f" >>actual 2>>err &&
+       git check-attr foo -- "a/b/f" >>actual 2>>err &&
+       git check-attr foo -- "a/b/c/f" >>actual 2>>err &&
+       test_cmp expect actual &&
+       test_line_count = 0 err
+'
+
+test_expect_success '"**" with no slashes test' '
+       echo "a**f foo=bar" >.gitattributes &&
+       git check-attr foo -- "f" >actual &&
+       cat <<\EOF >expect &&
+f: foo: unspecified
+af: foo: bar
+axf: foo: bar
+a/f: foo: unspecified
+a/b/f: foo: unspecified
+a/b/c/f: foo: unspecified
+EOF
+       git check-attr foo -- "f" >actual 2>err &&
+       git check-attr foo -- "af" >>actual 2>err &&
+       git check-attr foo -- "axf" >>actual 2>err &&
+       git check-attr foo -- "a/f" >>actual 2>>err &&
+       git check-attr foo -- "a/b/f" >>actual 2>>err &&
+       git check-attr foo -- "a/b/c/f" >>actual 2>>err &&
+       test_cmp expect actual &&
+       test_line_count = 0 err
+'
+
 test_expect_success 'setup bare' '
        git clone --bare . bare.git &&
        cd bare.git
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 d709ecf8df136539a746ef1873821baee6fab428..4969edb31441c81cf2e63385d07d780a52faa53b 100755 (executable)
@@ -32,32 +32,24 @@ test_expect_success 'setup' '
 #
 # and 'side' should be the last branch
 
-test_rev_equivalent () {
-
-       git rev-parse "$1" > expect &&
-       git rev-parse "$2" > output &&
-       test_cmp expect output
-
-}
-
 test_expect_success '@{-1} works' '
-       test_rev_equivalent side @{-1}
+       test_cmp_rev side @{-1}
 '
 
 test_expect_success '@{-1}~2 works' '
-       test_rev_equivalent side~2 @{-1}~2
+       test_cmp_rev side~2 @{-1}~2
 '
 
 test_expect_success '@{-1}^2 works' '
-       test_rev_equivalent side^2 @{-1}^2
+       test_cmp_rev side^2 @{-1}^2
 '
 
 test_expect_success '@{-1}@{1} works' '
-       test_rev_equivalent side@{1} @{-1}@{1}
+       test_cmp_rev side@{1} @{-1}@{1}
 '
 
 test_expect_success '@{-2} works' '
-       test_rev_equivalent master @{-2}
+       test_cmp_rev master @{-2}
 '
 
 test_expect_success '@{-3} fails' '
index dc2f0458fd0e74a3dcb4769517f5cde2606eb6f2..efb7ebc91f2f46b38e0c02f4dd11e2224678baea 100755 (executable)
@@ -220,4 +220,22 @@ test_expect_success 'pattern matches prefix completely' '
        test_cmp expect actual
 '
 
+test_expect_success 'ls-files with "**" patterns' '
+       cat <<\EOF >expect &&
+a.1
+one/a.1
+one/two/a.1
+three/a.1
+EOF
+       git ls-files -o -i --exclude "**/a.1" >actual
+       test_cmp expect actual
+'
+
+
+test_expect_success 'ls-files with "**" patterns and no slashes' '
+       : >expect &&
+       git ls-files -o -i --exclude "one**a.1" >actual &&
+       test_cmp expect actual
+'
+
 test_done
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
new file mode 100755 (executable)
index 0000000..af54c83
--- /dev/null
@@ -0,0 +1,195 @@
+#!/bin/sh
+
+test_description='wildmatch tests'
+
+. ./test-lib.sh
+
+match() {
+    if [ $1 = 1 ]; then
+       test_expect_success "wildmatch:    match '$3' '$4'" "
+           test-wildmatch wildmatch '$3' '$4'
+       "
+    else
+       test_expect_success "wildmatch: no match '$3' '$4'" "
+           ! test-wildmatch wildmatch '$3' '$4'
+       "
+    fi
+    if [ $2 = 1 ]; then
+       test_expect_success "fnmatch:      match '$3' '$4'" "
+           test-wildmatch fnmatch '$3' '$4'
+       "
+    elif [ $2 = 0 ]; then
+       test_expect_success "fnmatch:   no match '$3' '$4'" "
+           ! test-wildmatch fnmatch '$3' '$4'
+       "
+#    else
+#      test_expect_success BROKEN_FNMATCH "fnmatch:       '$3' '$4'" "
+#          ! test-wildmatch fnmatch '$3' '$4'
+#      "
+    fi
+}
+
+# Basic wildmat features
+match 1 1 foo foo
+match 0 0 foo bar
+match 1 1 '' ""
+match 1 1 foo '???'
+match 0 0 foo '??'
+match 1 1 foo '*'
+match 1 1 foo 'f*'
+match 0 0 foo '*f'
+match 1 1 foo '*foo*'
+match 1 1 foobar '*ob*a*r*'
+match 1 1 aaaaaaabababab '*ab'
+match 1 1 'foo*' 'foo\*'
+match 0 0 foobar 'foo\*bar'
+match 1 1 'f\oo' 'f\\oo'
+match 1 1 ball '*[al]?'
+match 0 0 ten '[ten]'
+match 0 1 ten '**[!te]'
+match 0 0 ten '**[!ten]'
+match 1 1 ten 't[a-g]n'
+match 0 0 ten 't[!a-g]n'
+match 1 1 ton 't[!a-g]n'
+match 1 1 ton 't[^a-g]n'
+match 1 x 'a]b' 'a[]]b'
+match 1 x a-b 'a[]-]b'
+match 1 x 'a]b' 'a[]-]b'
+match 0 x aab 'a[]-]b'
+match 1 x aab 'a[]a-]b'
+match 1 1 ']' ']'
+
+# Extended slash-matching features
+match 0 0 'foo/baz/bar' 'foo*bar'
+match 0 0 'foo/baz/bar' 'foo**bar'
+match 0 1 'foobazbar' 'foo**bar'
+match 1 1 'foo/baz/bar' 'foo/**/bar'
+match 1 0 'foo/baz/bar' 'foo/**/**/bar'
+match 1 0 'foo/b/a/z/bar' 'foo/**/bar'
+match 1 0 'foo/b/a/z/bar' 'foo/**/**/bar'
+match 1 0 'foo/bar' 'foo/**/bar'
+match 1 0 'foo/bar' 'foo/**/**/bar'
+match 0 0 'foo/bar' 'foo?bar'
+match 0 0 'foo/bar' 'foo[/]bar'
+match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
+match 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
+match 1 0 'foo' '**/foo'
+match 1 x 'XXX/foo' '**/foo'
+match 1 0 'bar/baz/foo' '**/foo'
+match 0 0 'bar/baz/foo' '*/foo'
+match 0 0 'foo/bar/baz' '**/bar*'
+match 1 0 'deep/foo/bar/baz' '**/bar/*'
+match 0 0 'deep/foo/bar/baz/' '**/bar/*'
+match 1 0 'deep/foo/bar/baz/' '**/bar/**'
+match 0 0 'deep/foo/bar' '**/bar/*'
+match 1 0 'deep/foo/bar/' '**/bar/**'
+match 0 0 'foo/bar/baz' '**/bar**'
+match 1 0 'foo/bar/baz/x' '*/bar/**'
+match 0 0 'deep/foo/bar/baz/x' '*/bar/**'
+match 1 0 'deep/foo/bar/baz/x' '**/bar/*/*'
+
+# Various additional tests
+match 0 0 'acrt' 'a[c-c]st'
+match 1 1 'acrt' 'a[c-c]rt'
+match 0 0 ']' '[!]-]'
+match 1 x 'a' '[!]-]'
+match 0 0 '' '\'
+match 0 x '\' '\'
+match 0 x 'XXX/\' '*/\'
+match 1 x 'XXX/\' '*/\\'
+match 1 1 'foo' 'foo'
+match 1 1 '@foo' '@foo'
+match 0 0 'foo' '@foo'
+match 1 1 '[ab]' '\[ab]'
+match 1 1 '[ab]' '[[]ab]'
+match 1 x '[ab]' '[[:]ab]'
+match 0 x '[ab]' '[[::]ab]'
+match 1 x '[ab]' '[[:digit]ab]'
+match 1 x '[ab]' '[\[:]ab]'
+match 1 1 '?a?b' '\??\?b'
+match 1 1 'abc' '\a\b\c'
+match 0 0 'foo' ''
+match 1 0 'foo/bar/baz/to' '**/t[o]'
+
+# Character class tests
+match 1 x 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]'
+match 0 x 'a' '[[:digit:][:upper:][:space:]]'
+match 1 x 'A' '[[:digit:][:upper:][:space:]]'
+match 1 x '1' '[[:digit:][:upper:][:space:]]'
+match 0 x '1' '[[:digit:][:upper:][:spaci:]]'
+match 1 x ' ' '[[:digit:][:upper:][:space:]]'
+match 0 x '.' '[[:digit:][:upper:][:space:]]'
+match 1 x '.' '[[:digit:][:punct:][:space:]]'
+match 1 x '5' '[[:xdigit:]]'
+match 1 x 'f' '[[:xdigit:]]'
+match 1 x 'D' '[[:xdigit:]]'
+match 1 x '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'
+match 1 x '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'
+match 1 x '.' '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]'
+match 1 x '5' '[a-c[:digit:]x-z]'
+match 1 x 'b' '[a-c[:digit:]x-z]'
+match 1 x 'y' '[a-c[:digit:]x-z]'
+match 0 x 'q' '[a-c[:digit:]x-z]'
+
+# Additional tests, including some malformed wildmats
+match 1 x ']' '[\\-^]'
+match 0 0 '[' '[\\-^]'
+match 1 x '-' '[\-_]'
+match 1 x ']' '[\]]'
+match 0 0 '\]' '[\]]'
+match 0 0 '\' '[\]]'
+match 0 0 'ab' 'a[]b'
+match 0 x 'a[]b' 'a[]b'
+match 0 x 'ab[' 'ab['
+match 0 0 'ab' '[!'
+match 0 0 'ab' '[-'
+match 1 1 '-' '[-]'
+match 0 0 '-' '[a-'
+match 0 0 '-' '[!a-'
+match 1 x '-' '[--A]'
+match 1 x '5' '[--A]'
+match 1 1 ' ' '[ --]'
+match 1 1 '$' '[ --]'
+match 1 1 '-' '[ --]'
+match 0 0 '0' '[ --]'
+match 1 x '-' '[---]'
+match 1 x '-' '[------]'
+match 0 0 'j' '[a-e-n]'
+match 1 x '-' '[a-e-n]'
+match 1 x 'a' '[!------]'
+match 0 0 '[' '[]-a]'
+match 1 x '^' '[]-a]'
+match 0 0 '^' '[!]-a]'
+match 1 x '[' '[!]-a]'
+match 1 1 '^' '[a^bc]'
+match 1 x '-b]' '[a-]b]'
+match 0 0 '\' '[\]'
+match 1 1 '\' '[\\]'
+match 0 0 '\' '[!\\]'
+match 1 1 'G' '[A-\\]'
+match 0 0 'aaabbb' 'b*a'
+match 0 0 'aabcaa' '*ba*'
+match 1 1 ',' '[,]'
+match 1 1 ',' '[\\,]'
+match 1 1 '\' '[\\,]'
+match 1 1 '-' '[,-.]'
+match 0 0 '+' '[,-.]'
+match 0 0 '-.]' '[,-.]'
+match 1 1 '2' '[\1-\3]'
+match 1 1 '3' '[\1-\3]'
+match 0 0 '4' '[\1-\3]'
+match 1 1 '\' '[[-\]]'
+match 1 1 '[' '[[-\]]'
+match 1 1 ']' '[[-\]]'
+match 0 0 '-' '[[-\]]'
+
+# Test recursion and the abort code (use "wildtest -i" to see iteration counts)
+match 1 1 '-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
+match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
+match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
+match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
+
+test_done
index 32fdc9938e1dc29d9a1c6c1dd54379ee33644561..8462be1db6a0fe4f9e28cd1662be604196141055 100755 (executable)
@@ -29,12 +29,6 @@ Initial setup:
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
-test_cmp_rev () {
-       git rev-parse --verify "$1" >expect.rev &&
-       git rev-parse --verify "$2" >actual.rev &&
-       test_cmp expect.rev actual.rev
-}
-
 set_fake_editor
 
 # WARNING: Modifications to the initial repository can change the SHA ID used
index 34c86e5de69468fe7618383e556d1711cc49b0bb..6f489e20eecb48c6e1a2dc2b1fe90e47e7b3e7ad 100755 (executable)
@@ -100,4 +100,13 @@ test_expect_success 'revert forbidden on dirty working tree' '
 
 '
 
+test_expect_success 'chery-pick on unborn branch' '
+       git checkout --orphan unborn &&
+       git rm --cached -r . &&
+       rm -rf * &&
+       git cherry-pick initial &&
+       git diff --quiet initial &&
+       ! test_cmp_rev initial HEAD
+'
+
 test_done
index 51ca391e472441d2d503e721795d609bfaad1100..373aad623c8f02f6f9753eb38c6393a69c027001 100755 (executable)
@@ -105,4 +105,12 @@ test_expect_success 'cherry pick a root commit with --ff' '
        test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1"
 '
 
+test_expect_success 'chery-pick --ff on unborn branch' '
+       git checkout --orphan unborn &&
+       git rm --cached -r . &&
+       rm -rf * &&
+       git cherry-pick --ff first &&
+       test_cmp_rev first HEAD
+'
+
 test_done
index c82f7210c4ca10e35d9d2000aa8da2d10194a6c6..223b98433c502b03c4ba70550cb32d42a5f6295b 100755 (executable)
@@ -11,12 +11,6 @@ test_description='test cherry-pick and revert with conflicts
 
 . ./test-lib.sh
 
-test_cmp_rev () {
-       git rev-parse --verify "$1" >expect.rev &&
-       git rev-parse --verify "$2" >actual.rev &&
-       test_cmp expect.rev actual.rev
-}
-
 pristine_detach () {
        git checkout -f "$1^0" &&
        git read-tree -u --reset HEAD &&
index 340afc760de030879fff496dca3db8432a6b992b..4e7136b83775946a07678119c7c9897bb0f2b709 100755 (executable)
@@ -5,15 +5,11 @@ test_description='test cherry-picking many commits'
 . ./test-lib.sh
 
 check_head_differs_from() {
-       head=$(git rev-parse --verify HEAD) &&
-       arg=$(git rev-parse --verify "$1") &&
-       test "$head" != "$arg"
+       ! test_cmp_rev HEAD "$1"
 }
 
 check_head_equals() {
-       head=$(git rev-parse --verify HEAD) &&
-       arg=$(git rev-parse --verify "$1") &&
-       test "$head" = "$arg"
+       test_cmp_rev HEAD "$1"
 }
 
 test_expect_success setup '
index b5fb527b2e686d158a6e7d53d6246b9e66f80a7b..7b7a89dbd5ce578e0a722345a00f247e383689ef 100755 (executable)
@@ -24,12 +24,6 @@ pristine_detach () {
        git clean -d -f -f -q -x
 }
 
-test_cmp_rev () {
-       git rev-parse --verify "$1" >expect.rev &&
-       git rev-parse --verify "$2" >actual.rev &&
-       test_cmp expect.rev actual.rev
-}
-
 test_expect_success setup '
        git config advice.detachedhead false &&
        echo unrelated >unrelated &&
index 90fd598c747482354c7fa1a9fa281c26c06e9de8..dc0d8ae928229e3e0abbc1c486905f2a713075b5 100755 (executable)
@@ -963,4 +963,46 @@ test_expect_success 'format patch ignores color.ui' '
        test_cmp expect actual
 '
 
+test_expect_success 'cover letter using branch description (1)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter master >actual &&
+       grep hello actual >/dev/null
+'
+
+test_expect_success 'cover letter using branch description (2)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual &&
+       grep hello actual >/dev/null
+'
+
+test_expect_success 'cover letter using branch description (3)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter ^master rebuild-1 >actual &&
+       grep hello actual >/dev/null
+'
+
+test_expect_success 'cover letter using branch description (4)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter master.. >actual &&
+       grep hello actual >/dev/null
+'
+
+test_expect_success 'cover letter using branch description (5)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter -2 HEAD >actual &&
+       grep hello actual >/dev/null
+'
+
+test_expect_success 'cover letter using branch description (6)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter -2 >actual &&
+       grep hello actual >/dev/null
+'
+
 test_done
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
index ee06d2864949de71b000402fda4378c9b483fe72..4435693bb2ca48d053003c87fccd8f8612d8b4a9 100755 (executable)
@@ -37,6 +37,16 @@ test_expect_success \
 
 test_expect_success \
     'successful clone must leave the directory' \
-    'cd bar'
+    'test -d bar'
+
+test_expect_success 'failed clone --separate-git-dir should not leave any directories' '
+       mkdir foo/.git/objects.bak/ &&
+       mv foo/.git/objects/* foo/.git/objects.bak/ &&
+       test_must_fail git clone --separate-git-dir gitdir foo worktree &&
+       test_must_fail test -e gitdir &&
+       test_must_fail test -e worktree &&
+       mv foo/.git/objects.bak/* foo/.git/objects/ &&
+       rmdir foo/.git/objects.bak
+'
 
 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
 
index 72e28ee5350926f3c4f27e2c99f8323a3eb8e57c..3e0e15fb3e0b92ab7e95789d27db34d9a1fa423c 100755 (executable)
@@ -676,9 +676,7 @@ test_expect_success 'bisect fails if tree is broken on trial commit' '
 check_same()
 {
        echo "Checking $1 is the same as $2" &&
-       git rev-parse "$1" > expected.same &&
-       git rev-parse "$2" > expected.actual &&
-       test_cmp expected.same expected.actual
+       test_cmp_rev "$1" "$2"
 }
 
 test_expect_success 'bisect: --no-checkout - start commit bad' '
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 5b4b694f1801f5c2284346f882cb496df9e7d74e..357375151d79d03d11275875dd10ceea42a3ba47 100755 (executable)
@@ -167,5 +167,19 @@ test_expect_success 'with failing hook (--no-verify)' '
 
 '
 
+test_expect_success 'with failing hook (merge)' '
+
+       git checkout -B other HEAD@{1} &&
+       echo "more" >> file &&
+       git add file &&
+       rm -f "$HOOK" &&
+       git commit -m other &&
+       write_script "$HOOK" <<-EOF
+       exit 1
+       EOF
+       git checkout - &&
+       test_must_fail git merge other
+
+'
 
 test_done
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 22a4f8fb64a4e8084139fc148e8e7dd4aa73d684..fa62d010f68e3ee97e6754687ad4d08564d3c96b 100644 (file)
@@ -602,6 +602,13 @@ test_cmp() {
        $GIT_TEST_CMP "$@"
 }
 
+# Tests that its two parameters refer to the same revision
+test_cmp_rev () {
+       git rev-parse --verify "$1" >expect.rev &&
+       git rev-parse --verify "$2" >actual.rev &&
+       test_cmp expect.rev actual.rev
+}
+
 # Print a sequence of numbers or letters in increasing order.  This is
 # similar to GNU seq(1), but the latter might not be available
 # everywhere (and does not do letters).  It may be used like:
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;
diff --git a/test-wildmatch.c b/test-wildmatch.c
new file mode 100644 (file)
index 0000000..e384c8e
--- /dev/null
@@ -0,0 +1,22 @@
+#include "cache.h"
+#include "wildmatch.h"
+
+int main(int argc, char **argv)
+{
+       int i;
+       for (i = 2; i < argc; i++) {
+               if (argv[i][0] == '/')
+                       die("Forward slash is not allowed at the beginning of the\n"
+                           "pattern because Windows does not like it. Use `XXX/' instead.");
+               else if (!strncmp(argv[i], "XXX/", 4))
+                       argv[i] += 3;
+       }
+       if (!strcmp(argv[1], "wildmatch"))
+               return !!wildmatch(argv[3], argv[2], 0);
+       else if (!strcmp(argv[1], "iwildmatch"))
+               return !!wildmatch(argv[3], argv[2], FNM_CASEFOLD);
+       else if (!strcmp(argv[1], "fnmatch"))
+               return !!fnmatch(argv[3], argv[2], FNM_PATHNAME);
+       else
+               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..0e1a196ace33110e2bb74cde90d6f62358413ead 100644 (file)
@@ -837,7 +837,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
 {
        struct cache_entry **cache_end;
        int dtype = DT_DIR;
-       int ret = excluded_from_list(prefix, prefix_len, basename, &dtype, el);
+       int ret = is_excluded_from_list(prefix, prefix_len,
+                                       basename, &dtype, el);
 
        prefix[prefix_len++] = '/';
 
@@ -856,7 +857,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
         * with ret (iow, we know in advance the incl/excl
         * decision for the entire directory), clear flag here without
         * calling clear_ce_flags_1(). That function will call
-        * the expensive excluded_from_list() on every entry.
+        * the expensive is_excluded_from_list() on every entry.
         */
        return clear_ce_flags_1(cache, cache_end - cache,
                                prefix, prefix_len,
@@ -939,7 +940,8 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
 
                /* Non-directory */
                dtype = ce_to_dtype(ce);
-               ret = excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el);
+               ret = is_excluded_from_list(ce->name, ce_namelen(ce),
+                                           name, &dtype, el);
                if (ret < 0)
                        ret = defval;
                if (ret > 0)
@@ -1152,7 +1154,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                *o->dst_index = o->result;
 
 done:
-       free_excludes(&el);
+       clear_exclude_list(&el);
        if (o->path_exclude_check) {
                path_exclude_check_clear(o->path_exclude_check);
                free(o->path_exclude_check);
@@ -1373,7 +1375,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
                return 0;
 
        if (o->dir &&
-           path_excluded(o->path_exclude_check, name, -1, &dtype))
+           is_path_excluded(o->path_exclude_check, name, -1, &dtype))
                /*
                 * ce->name is explicitly excluded, so it is Ok to
                 * overwrite it.
@@ -1834,7 +1836,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/wildmatch.c b/wildmatch.c
new file mode 100644 (file)
index 0000000..2d3ed84
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+**  Do shell-style pattern matching for ?, \, [], and * characters.
+**  It is 8bit clean.
+**
+**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
+**  Rich $alz is now <rsalz@bbn.com>.
+**
+**  Modified by Wayne Davison to special-case '/' matching, to make '**'
+**  work differently than '*', and to fix the character-class code.
+*/
+
+#include "cache.h"
+#include "wildmatch.h"
+
+typedef unsigned char uchar;
+
+/* What character marks an inverted character class? */
+#define NEGATE_CLASS   '!'
+#define NEGATE_CLASS2  '^'
+
+#define FALSE 0
+#define TRUE 1
+
+#define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
+                                   && *(class) == *(litmatch) \
+                                   && strncmp((char*)class, litmatch, len) == 0)
+
+#if defined STDC_HEADERS || !defined isascii
+# define ISASCII(c) 1
+#else
+# define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+# define ISBLANK(c) (ISASCII(c) && isblank(c))
+#else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+
+#ifdef isgraph
+# define ISGRAPH(c) (ISASCII(c) && isgraph(c))
+#else
+# define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c))
+#endif
+
+#define ISPRINT(c) (ISASCII(c) && isprint(c))
+#define ISDIGIT(c) (ISASCII(c) && isdigit(c))
+#define ISALNUM(c) (ISASCII(c) && isalnum(c))
+#define ISALPHA(c) (ISASCII(c) && isalpha(c))
+#define ISCNTRL(c) (ISASCII(c) && iscntrl(c))
+#define ISLOWER(c) (ISASCII(c) && islower(c))
+#define ISPUNCT(c) (ISASCII(c) && ispunct(c))
+#define ISSPACE(c) (ISASCII(c) && isspace(c))
+#define ISUPPER(c) (ISASCII(c) && isupper(c))
+#define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
+
+/* Match pattern "p" against "text" */
+static int dowild(const uchar *p, const uchar *text, int force_lower_case)
+{
+       uchar p_ch;
+       const uchar *pattern = p;
+
+       for ( ; (p_ch = *p) != '\0'; text++, p++) {
+               int matched, match_slash, negated;
+               uchar t_ch, prev_ch;
+               if ((t_ch = *text) == '\0' && p_ch != '*')
+                       return ABORT_ALL;
+               if (force_lower_case && ISUPPER(t_ch))
+                       t_ch = tolower(t_ch);
+               if (force_lower_case && ISUPPER(p_ch))
+                       p_ch = tolower(p_ch);
+               switch (p_ch) {
+               case '\\':
+                       /* Literal match with following character.  Note that the test
+                        * in "default" handles the p[1] == '\0' failure case. */
+                       p_ch = *++p;
+                       /* FALLTHROUGH */
+               default:
+                       if (t_ch != p_ch)
+                               return NOMATCH;
+                       continue;
+               case '?':
+                       /* Match anything but '/'. */
+                       if (t_ch == '/')
+                               return NOMATCH;
+                       continue;
+               case '*':
+                       if (*++p == '*') {
+                               const uchar *prev_p = p - 2;
+                               while (*++p == '*') {}
+                               if ((prev_p < pattern || *prev_p == '/') &&
+                                   (*p == '\0' || *p == '/' ||
+                                    (p[0] == '\\' && p[1] == '/'))) {
+                                       /*
+                                        * Assuming we already match 'foo/' and are at
+                                        * <star star slash>, just assume it matches
+                                        * nothing and go ahead match the rest of the
+                                        * pattern with the remaining string. This
+                                        * helps make foo/<*><*>/bar (<> because
+                                        * otherwise it breaks C comment syntax) match
+                                        * both foo/bar and foo/a/bar.
+                                        */
+                                       if (p[0] == '/' &&
+                                           dowild(p + 1, text, force_lower_case) == MATCH)
+                                               return MATCH;
+                                       match_slash = TRUE;
+                               } else
+                                       return ABORT_MALFORMED;
+                       } else
+                               match_slash = FALSE;
+                       if (*p == '\0') {
+                               /* Trailing "**" matches everything.  Trailing "*" matches
+                                * only if there are no more slash characters. */
+                               if (!match_slash) {
+                                       if (strchr((char*)text, '/') != NULL)
+                                               return NOMATCH;
+                               }
+                               return MATCH;
+                       }
+                       while (1) {
+                               if (t_ch == '\0')
+                                       break;
+                               if ((matched = dowild(p, text,  force_lower_case)) != NOMATCH) {
+                                       if (!match_slash || matched != ABORT_TO_STARSTAR)
+                                               return matched;
+                               } else if (!match_slash && t_ch == '/')
+                                       return ABORT_TO_STARSTAR;
+                               t_ch = *++text;
+                       }
+                       return ABORT_ALL;
+               case '[':
+                       p_ch = *++p;
+#ifdef NEGATE_CLASS2
+                       if (p_ch == NEGATE_CLASS2)
+                               p_ch = NEGATE_CLASS;
+#endif
+                       /* Assign literal TRUE/FALSE because of "matched" comparison. */
+                       negated = p_ch == NEGATE_CLASS? TRUE : FALSE;
+                       if (negated) {
+                               /* Inverted character class. */
+                               p_ch = *++p;
+                       }
+                       prev_ch = 0;
+                       matched = FALSE;
+                       do {
+                               if (!p_ch)
+                                       return ABORT_ALL;
+                               if (p_ch == '\\') {
+                                       p_ch = *++p;
+                                       if (!p_ch)
+                                               return ABORT_ALL;
+                                       if (t_ch == p_ch)
+                                               matched = TRUE;
+                               } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
+                                       p_ch = *++p;
+                                       if (p_ch == '\\') {
+                                               p_ch = *++p;
+                                               if (!p_ch)
+                                                       return ABORT_ALL;
+                                       }
+                                       if (t_ch <= p_ch && t_ch >= prev_ch)
+                                               matched = TRUE;
+                                       p_ch = 0; /* This makes "prev_ch" get set to 0. */
+                               } else if (p_ch == '[' && p[1] == ':') {
+                                       const uchar *s;
+                                       int i;
+                                       for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/
+                                       if (!p_ch)
+                                               return ABORT_ALL;
+                                       i = p - s - 1;
+                                       if (i < 0 || p[-1] != ':') {
+                                               /* Didn't find ":]", so treat like a normal set. */
+                                               p = s - 2;
+                                               p_ch = '[';
+                                               if (t_ch == p_ch)
+                                                       matched = TRUE;
+                                               continue;
+                                       }
+                                       if (CC_EQ(s,i, "alnum")) {
+                                               if (ISALNUM(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "alpha")) {
+                                               if (ISALPHA(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "blank")) {
+                                               if (ISBLANK(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "cntrl")) {
+                                               if (ISCNTRL(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "digit")) {
+                                               if (ISDIGIT(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "graph")) {
+                                               if (ISGRAPH(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "lower")) {
+                                               if (ISLOWER(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "print")) {
+                                               if (ISPRINT(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "punct")) {
+                                               if (ISPUNCT(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "space")) {
+                                               if (ISSPACE(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "upper")) {
+                                               if (ISUPPER(t_ch))
+                                                       matched = TRUE;
+                                       } else if (CC_EQ(s,i, "xdigit")) {
+                                               if (ISXDIGIT(t_ch))
+                                                       matched = TRUE;
+                                       } else /* malformed [:class:] string */
+                                               return ABORT_ALL;
+                                       p_ch = 0; /* This makes "prev_ch" get set to 0. */
+                               } else if (t_ch == p_ch)
+                                       matched = TRUE;
+                       } while (prev_ch = p_ch, (p_ch = *++p) != ']');
+                       if (matched == negated || t_ch == '/')
+                               return NOMATCH;
+                       continue;
+               }
+       }
+
+       return *text ? NOMATCH : MATCH;
+}
+
+/* Match the "pattern" against the "text" string. */
+int wildmatch(const char *pattern, const char *text, int flags)
+{
+       return dowild((const uchar*)pattern, (const uchar*)text,
+                     flags & FNM_CASEFOLD ? 1 :0);
+}
diff --git a/wildmatch.h b/wildmatch.h
new file mode 100644 (file)
index 0000000..984a38c
--- /dev/null
@@ -0,0 +1,9 @@
+/* wildmatch.h */
+
+#define ABORT_MALFORMED 2
+#define NOMATCH 1
+#define MATCH 0
+#define ABORT_ALL -1
+#define ABORT_TO_STARSTAR -2
+
+int wildmatch(const char *pattern, const char *text, int flags);
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;