summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/1.8.5.6.txt34
-rw-r--r--Documentation/RelNotes/1.9.5.txt34
-rw-r--r--Documentation/RelNotes/2.0.5.txt34
-rw-r--r--Documentation/RelNotes/2.1.4.txt34
-rw-r--r--Documentation/RelNotes/2.2.1.txt34
-rw-r--r--Documentation/RelNotes/2.2.2.txt63
-rw-r--r--Documentation/RelNotes/2.3.0.txt194
-rw-r--r--Documentation/SubmittingPatches22
-rw-r--r--Documentation/config.txt26
-rw-r--r--Documentation/git-add.txt2
-rw-r--r--Documentation/git-am.txt12
-rw-r--r--Documentation/git-check-ignore.txt3
-rw-r--r--Documentation/git-clone.txt11
-rw-r--r--Documentation/git-imap-send.txt27
-rw-r--r--Documentation/git-mailinfo.txt5
-rw-r--r--Documentation/git-pack-objects.txt7
-rw-r--r--Documentation/git-rev-list.txt3
-rw-r--r--Documentation/git-send-email.txt28
-rw-r--r--Documentation/git-stripspace.txt1
-rw-r--r--Documentation/git-update-index.txt18
-rw-r--r--Documentation/git.txt20
-rw-r--r--Documentation/gitignore.txt4
-rw-r--r--Documentation/rev-list-options.txt7
-rw-r--r--Documentation/technical/api-credentials.txt5
-rw-r--r--Documentation/technical/api-string-list.txt4
-rw-r--r--Documentation/technical/index-format.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL15
-rw-r--r--Makefile38
-rw-r--r--archive.c34
-rw-r--r--bisect.c2
-rw-r--r--builtin/add.c2
-rw-r--r--builtin/apply.c2
-rw-r--r--builtin/branch.c13
-rw-r--r--builtin/cat-file.c4
-rw-r--r--builtin/checkout-index.c16
-rw-r--r--builtin/checkout.c8
-rw-r--r--builtin/clean.c2
-rw-r--r--builtin/clone.c20
-rw-r--r--builtin/commit-tree.c4
-rw-r--r--builtin/commit.c76
-rw-r--r--builtin/fmt-merge-msg.c3
-rw-r--r--builtin/for-each-ref.c13
-rw-r--r--builtin/help.c9
-rw-r--r--builtin/index-pack.c4
-rw-r--r--builtin/init-db.c17
-rw-r--r--builtin/log.c6
-rw-r--r--builtin/ls-tree.c20
-rw-r--r--builtin/mailinfo.c22
-rw-r--r--builtin/merge-base.c4
-rw-r--r--builtin/merge.c27
-rw-r--r--builtin/pack-objects.c7
-rw-r--r--builtin/receive-pack.c95
-rw-r--r--builtin/remote.c73
-rw-r--r--builtin/repack.c2
-rw-r--r--builtin/rev-parse.c2
-rw-r--r--builtin/show-branch.c5
-rw-r--r--builtin/unpack-objects.c2
-rw-r--r--builtin/update-ref.c14
-rw-r--r--cache.h10
-rw-r--r--color.c172
-rw-r--r--color.h8
-rw-r--r--commit.c75
-rw-r--r--commit.h10
-rw-r--r--compat/stat.c48
-rw-r--r--config.c10
-rw-r--r--config.mak.uname4
-rw-r--r--configure.ac62
-rw-r--r--connect.c2
-rw-r--r--contrib/completion/git-completion.bash19
-rw-r--r--contrib/completion/git-completion.zsh2
-rw-r--r--contrib/completion/git-prompt.sh36
-rw-r--r--contrib/diff-highlight/README41
-rwxr-xr-xcontrib/diff-highlight/diff-highlight62
-rw-r--r--contrib/subtree/git-subtree.txt194
-rwxr-xr-xcontrib/workdir/git-new-workdir53
-rw-r--r--credential.c5
-rw-r--r--credential.h1
-rw-r--r--date.c21
-rw-r--r--diffcore-break.c7
-rw-r--r--environment.c10
-rw-r--r--exec_cmd.c7
-rw-r--r--exec_cmd.h2
-rw-r--r--fsck.c8
-rwxr-xr-xgit-add--interactive.perl1
-rwxr-xr-xgit-am.sh21
-rwxr-xr-xgit-bisect.sh11
-rw-r--r--git-compat-util.h44
-rw-r--r--git-rebase--interactive.sh4
-rwxr-xr-xgit-send-email.perl108
-rw-r--r--git-sh-setup.sh2
-rwxr-xr-xgit-svn.perl49
-rw-r--r--git.c3
-rw-r--r--imap-send.c206
-rw-r--r--list-objects.c4
-rw-r--r--lockfile.c14
-rw-r--r--mailmap.c20
-rw-r--r--merge-recursive.c17
-rw-r--r--notes-merge.c2
-rw-r--r--notes-utils.c3
-rw-r--r--notes.c2
-rw-r--r--path.c33
-rw-r--r--perl/Git/SVN/Editor.pm38
-rw-r--r--pkt-line.c37
-rw-r--r--prompt.c16
-rw-r--r--quote.c21
-rw-r--r--quote.h2
-rw-r--r--read-cache.c10
-rw-r--r--refs.c143
-rw-r--r--refs.h10
-rw-r--r--remote.c40
-rw-r--r--revision.c10
-rw-r--r--revision.h1
-rw-r--r--run-command.c17
-rw-r--r--run-command.h4
-rw-r--r--send-pack.c3
-rw-r--r--sequencer.c34
-rw-r--r--sequencer.h1
-rw-r--r--server-info.c2
-rw-r--r--sha1_file.c2
-rw-r--r--sha1_name.c4
-rw-r--r--strbuf.c3
-rw-r--r--string-list.c12
-rw-r--r--string-list.h14
-rw-r--r--submodule.c2
-rw-r--r--t/README3
-rwxr-xr-xt/lib-gpg.sh35
-rw-r--r--t/lib-gpg/keyring.gpg88
-rw-r--r--t/lib-gpg/ownertrust4
-rw-r--r--t/lib-gpg/pubring.gpgbin2359 -> 0 bytes
-rw-r--r--t/lib-gpg/random_seedbin600 -> 0 bytes
-rw-r--r--t/lib-gpg/secring.gpgbin3734 -> 0 bytes
-rw-r--r--t/lib-gpg/trustdb.gpgbin1360 -> 0 bytes
-rw-r--r--t/lib-httpd/apache.conf1
-rwxr-xr-xt/t0006-date.sh3
-rwxr-xr-xt/t0027-auto-crlf.sh82
-rwxr-xr-xt/t0030-stripspace.sh6
-rwxr-xr-xt/t0050-filesystem.sh2
-rwxr-xr-xt/t0090-cache-tree.sh2
-rwxr-xr-xt/t0300-credentials.sh9
-rwxr-xr-xt/t1014-read-tree-confusing.sh62
-rwxr-xr-xt/t1301-shared-repo.sh11
-rwxr-xr-xt/t1400-update-ref.sh92
-rwxr-xr-xt/t1410-reflog.sh30
-rwxr-xr-xt/t1450-fsck.sh82
-rwxr-xr-xt/t2004-checkout-cache-temp.sh400
-rwxr-xr-xt/t2024-checkout-dwim.sh18
-rwxr-xr-xt/t2107-update-index-basic.sh15
-rwxr-xr-xt/t3102-ls-tree-wildcards.sh22
-rwxr-xr-xt/t3200-branch.sh14
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh42
-rwxr-xr-xt/t3700-add.sh8
-rwxr-xr-xt/t4008-diff-break-rewrite.sh4
-rwxr-xr-xt/t4023-diff-rename-typechange.sh3
-rwxr-xr-xt/t4026-color.sh15
-rwxr-xr-xt/t4150-am.sh23
-rwxr-xr-xt/t5000-tar-tree.sh2
-rwxr-xr-xt/t5100-mailinfo.sh4
-rw-r--r--t/t5100/info0012--message-id5
-rw-r--r--t/t5100/msg0012--message-id8
-rw-r--r--t/t5100/patch0012--message-id30
-rwxr-xr-xt/t5400-send-pack.sh16
-rwxr-xr-xt/t5505-remote.sh5
-rwxr-xr-xt/t5516-fetch-push.sh104
-rwxr-xr-xt/t5527-fetch-odd-refs.sh33
-rwxr-xr-xt/t5700-clone-reference.sh17
-rwxr-xr-xt/t6030-bisect-porcelain.sh9
-rwxr-xr-xt/t6300-for-each-ref.sh13
-rwxr-xr-xt/t7004-tag.sh14
-rwxr-xr-xt/t7513-interpret-trailers.sh34
-rwxr-xr-xt/t9001-send-email.sh644
-rwxr-xr-xt/t9148-git-svn-propset.sh95
-rwxr-xr-xt/t9903-bash-prompt.sh106
-rw-r--r--t/test-lib.sh101
-rwxr-xr-xtemplates/hooks--pre-push.sample1
-rw-r--r--test-hashmap.c2
-rw-r--r--trace.c6
-rw-r--r--trailer.c32
-rw-r--r--transport.c4
-rw-r--r--tree.c16
-rw-r--r--tree.h3
-rw-r--r--unpack-trees.c10
-rwxr-xr-xupdate_unicode.sh17
-rw-r--r--upload-pack.c4
-rw-r--r--utf8.c72
-rw-r--r--utf8.h8
186 files changed, 4183 insertions, 1344 deletions
diff --git a/Documentation/RelNotes/1.8.5.6.txt b/Documentation/RelNotes/1.8.5.6.txt
new file mode 100644
index 0000000000..92ff92b1e6
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.6.txt
@@ -0,0 +1,34 @@
+Git v1.8.5.6 Release Notes
+==========================
+
+Fixes since v1.8.5.5
+--------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.9.5.txt b/Documentation/RelNotes/1.9.5.txt
new file mode 100644
index 0000000000..8d6ac0cf53
--- /dev/null
+++ b/Documentation/RelNotes/1.9.5.txt
@@ -0,0 +1,34 @@
+Git v1.9.5 Release Notes
+========================
+
+Fixes since v1.9.4
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.0.5.txt b/Documentation/RelNotes/2.0.5.txt
new file mode 100644
index 0000000000..3a16f697e8
--- /dev/null
+++ b/Documentation/RelNotes/2.0.5.txt
@@ -0,0 +1,34 @@
+Git v2.0.5 Release Notes
+========================
+
+Fixes since v2.0.4
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.1.4.txt b/Documentation/RelNotes/2.1.4.txt
new file mode 100644
index 0000000000..d16e5f041f
--- /dev/null
+++ b/Documentation/RelNotes/2.1.4.txt
@@ -0,0 +1,34 @@
+Git v2.1.4 Release Notes
+========================
+
+Fixes since v2.1.3
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.2.1.txt b/Documentation/RelNotes/2.2.1.txt
new file mode 100644
index 0000000000..d5a3cd9e73
--- /dev/null
+++ b/Documentation/RelNotes/2.2.1.txt
@@ -0,0 +1,34 @@
+Git v2.2.1 Release Notes
+========================
+
+Fixes since v2.2
+----------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.2.2.txt b/Documentation/RelNotes/2.2.2.txt
new file mode 100644
index 0000000000..b19a35d94f
--- /dev/null
+++ b/Documentation/RelNotes/2.2.2.txt
@@ -0,0 +1,63 @@
+Git v2.2.2 Release Notes
+========================
+
+Fixes since v2.2.1
+------------------
+
+ * "git checkout $treeish $path", when $path in the index and the
+ working tree already matched what is in $treeish at the $path,
+ still overwrote the $path unnecessarily.
+
+ * "git config --get-color" did not parse its command line arguments
+ carefully.
+
+ * open() emulated on Windows platforms did not give EISDIR upon
+ an attempt to open a directory for writing.
+
+ * A few code paths used abs() when they should have used labs() on
+ long integers.
+
+ * "gitweb" used to depend on a behaviour recent CGI.pm deprecated.
+
+ * "git init" (hence "git clone") initialized the per-repository
+ configuration file .git/config with x-bit by mistake.
+
+ * Git 2.0 was supposed to make the "simple" mode for the default of
+ "git push", but it didn't.
+
+ * "Everyday" document had a broken link.
+
+ * The build procedure did not bother fixing perl and python scripts
+ when NO_PERL and NO_PYTHON build-time configuration changed.
+
+ * The code that reads the reflog from the newer to the older entries
+ did not handle an entry that crosses a boundary of block it uses to
+ read them correctly.
+
+ * "git apply" was described in the documentation to take --ignore-date
+ option, which it does not.
+
+ * Traditionally we tried to avoid interpreting date strings given by
+ the user as future dates, e.g. GIT_COMMITTER_DATE=2014-12-10 when
+ used early November 2014 was taken as "October 12, 2014" because it
+ is likely that a date in the future, December 10, is a mistake.
+ This heuristics has been loosened to allow people to express future
+ dates (most notably, --until=<date> may want to be far in the
+ future) and we no longer tiebreak by future-ness of the date when
+
+ (1) ISO-like format is used, and
+ (2) the string can make sense interpreted as both y-m-d and y-d-m.
+
+ Git may still have to use the heuristics to tiebreak between dd/mm/yy
+ and mm/dd/yy, though.
+
+ * The code to abbreviate an object name to its short unique prefix
+ has been optimized when no abbreviation was requested.
+
+ * "git add --ignore-errors ..." did not ignore an error to
+ give a file that did not exist.
+
+ * Git did not correctly read an overlong refname from a packed refs
+ file.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.0.txt b/Documentation/RelNotes/2.3.0.txt
index 880c062117..72db8d211f 100644
--- a/Documentation/RelNotes/2.3.0.txt
+++ b/Documentation/RelNotes/2.3.0.txt
@@ -6,7 +6,9 @@ Updates since v2.2
Ports
- *
+ * Recent gcc toolchain on Cygwin started throwing compilation warning,
+ which has been squelched.
+
UI, Workflows & Features
@@ -18,10 +20,96 @@ UI, Workflows & Features
note from the object but with --allow-empty we will store a
(surprise!) note that is empty.
+ * "git interpret-trailers" learned to properly handle the
+ "Conflicts:" block at the end.
+
+ * "git am" learned "--message-id" option to copy the message ID of
+ the incoming e-mail to the log message of resulting commit.
+
+ * "git clone --reference=<over there>" learned the "--dissociate"
+ option to go with it; it borrows objects from the reference object
+ store while cloning only to reduce network traffic and then
+ dissociates the resulting clone from the reference by performing
+ local copies of borrowed objects.
+
+ * "git send-email" learned "--transfer-encoding" option to force a
+ non-fault Content-Transfer-Encoding header (e.g. base64).
+
+ * "git send-email" normally identifies itself via X-Mailer: header in
+ the message it sends out. A new command line flag --no-xmailer
+ allows the user to squelch the header.
+
+ * "git push" into a repository with a working tree normally refuses
+ to modify the branch that is checked out. The command learned to
+ optionally do an equivalent of "git reset --hard" only when there
+ is no change to the working tree and the index instead, which would
+ be useful to "deploy" by pushing into a repository.
+
+ * "git new-workdir" (in contrib/) can be used to populate an empty
+ and existing directory now.
+
+ * Credential helpers are asked in turn until one of them give
+ positive response, which is cumbersome to turn off when you need to
+ run Git in an automated setting. The credential helper interface
+ learned to allow a helper to say "stop, don't ask other helpers."
+ Also GIT_TERMINAL_PROMPT environment can be set to false to disable
+ our built-in prompt mechanism for passwords.
+
+ * "git branch -d" (delete) and "git branch -m" (move) learned to
+ honor "-f" (force) flag; unlike many other subcommands, the way to
+ force these have been with separate "-D/-M" options, which was
+ inconsistent.
+
+ * "diff-highlight" filter (in contrib/) allows its color output to be
+ customized via configuration variables.
+
+ * "git imap-send" learned to take "-v" (verbose) and "-q" (quiet)
+ command line options.
+
+ * "git imap-send" now can be built to use cURL library to talk to
+ IMAP servers (if the library is recent enough, of course).
+ This allows you to use authenticate method other than CRAM-MD5,
+ among other things.
+
Performance, Internal Implementation, Development Support etc.
- *
+ * Earlier we made "rev-list --object-edge" more aggressively list the
+ objects at the edge commits, in order to reduce number of objects 
+ fetched into a shallow repository, but the change affected cases
+ other than "fetching into a shallow repository" and made it
+ unusably slow (e.g. fetching into a normal repository should not
+ have to suffer the overhead from extra processing). Limit it to a
+ more specific case by introducing --objects-edge-aggressive, a new
+ option to rev-list.
+
+ * Squelched useless compiler warnings on Mac OS X regarding the
+ crypto API.
+
+ * The procedure to generate unicode table has been simplified.
+
+ * Some filesystems assign filemodes in a strange way, fooling then
+ automatic "filemode trustability" check done during a new
+ repository creation. The initialization codepath has been hardened
+ against this issue.
+
+ * The codepath in "git remote update --prune" to drop many refs has
+ been optimized.
+
+ * The API into get_merge_bases*() family of functions was easy to
+ misuse, which has been corrected to make it harder to do so.
+
+ * Long overdue departure from the assumption that S_IFMT is shared by
+ everybody made in 2005, which was necessary to port to z/OS.
+
+ * "git push" and "git fetch" did not communicate an overlong refname
+ correctly. Now it uses 64kB sideband to accommodate longer ones.
+
+ * Recent GPG changes the keyring format and drops support for RFC1991
+ formatted signatures, breaking our existing tests.
+
+ * "git-prompt" (in contrib/) used a variable from the global scope,
+ possibly contaminating end-user's namespace.
Also contains various documentation updates and code clean-ups.
@@ -34,6 +122,108 @@ Unless otherwise noted, all the fixes since v2.2 in the maintenance
track are contained in this release (see the maintenance releases'
notes for details).
+ * The logic in "git bisect bad HEAD" etc. to avoid forcing the test
+ of the common ancestor of bad and good commits was broken.
+ (merge 07913d5 cc/bisect-rev-parsing later to maint).
+
+ * "git checkout-index --temp=$target $path" did not work correctly
+ for paths outside the current subdirectory in the project.
+ (merge 74c4de5 es/checkout-index-temp later to maint).
+
+ * The report from "git checkout" on a branch that builds on another
+ local branch by setting its branch.*.merge to branch name (not a
+ full refname) incorrectly said that the upstream is gone.
+ (merge 05e7368 jc/checkout-local-track-report later to maint).
+
+ * With The git-prompt support (in contrib/), using the exit status of
+ the last command in the prompt, e.g. PS1='$(__git_ps1) $? ', did
+ not work well, because the helper function stomped on the exit
+ status.
+ (merge eb443e3 tf/prompt-preserve-exit-status later to maint).
+
+
+ * Recent update to "git commit" broke amending an existing commit
+ with bogus author/committer lines without a valid e-mail address.
+ (merge c83a509 jk/commit-date-approxidate later to maint).
+
+ * The lockfile API used to get confused which file to clean up when
+ the process moved the $cwd after creating a lockfile.
+ (merge fa137f6 nd/lockfile-absolute later to maint).
+
+ * Traditionally we tried to avoid interpreting date strings given by
+ the user as future dates, e.g. GIT_COMMITTER_DATE=2014-12-10 when
+ used early November 2014 was taken as "October 12, 2014" because it
+ is likely that a date in the future, December 10, is a mistake.
+ This heuristics has been loosened to allow people to express future
+ dates (most notably, --until=<date> may want to be far in the
+ future) and we no longer tiebreak by future-ness of the date when
+
+ (1) ISO-like format is used, and
+ (2) the string can make sense interpreted as both y-m-d and y-d-m.
+
+ Git may still have to use the heuristics to tiebreak between dd/mm/yy
+ and mm/dd/yy, though.
+ (merge d372395 jk/approxidate-avoid-y-d-m-over-future-dates later to maint).
+
+ * Git did not correctly read an overlong refname from a packed refs
+ file.
+ (merge ea41783 jk/read-packed-refs-without-path-max later to maint).
+
+ * "git apply" was described in the documentation to take --ignore-date
+ option, which it does not.
+ (merge 0cef4e7 rw/apply-does-not-take-ignore-date later to maint).
+
+ * "git add -i" did not notice when the interactive command input
+ stream went away and kept asking the same question.
+ (merge a8bec7a jk/add-i-read-error later to maint).
+
+ * "git send-email" did not handle RFC 2047 encoded headers quite
+ right.
+ (merge ab47e2a rd/send-email-2047-fix later to maint).
+
+ * New tag object format validation added in 2.2 showed garbage after
+ a tagname it reported in its error message.
+ (merge a1e920a js/fsck-tag-validation later to maint).
+
+ * The code that reads the reflog from the newer to the older entries
+ did not handle an entry that crosses a boundary of block it uses to
+ read them correctly.
+ (merge 69216bf jk/for-each-reflog-ent-reverse later to maint).
+
+ * "git diff -B -M" after making a new copy B out of an existing file
+ A and then editing A extensively ought to report that B was created
+ by copying A and A was modified, which is what "git diff -C"
+ reports, but it instead said A was renamed to B and A was edited
+ heavily in place. This was not just incoherent but also failed to
+ apply with "git apply". The report has been corrected to match what
+ "git diff -C" produces for this case.
+ (merge 6936b58 jc/diff-b-m later to maint).
+
+ * In files we pre-populate for the user to edit with commented hints,
+ a line of hint that is indented with a tab used to show as '#' (or
+ any comment char), ' ' (space), and then the hint text that began
+ with the tab, which some editors flag as an indentation error (tab
+ following space). We now omit the space after the comment char in
+ such a case.
+ (merge d55aeb7 jc/strbuf-add-lines-avoid-sp-ht-sequence later to maint).
+
+ * "git ls-tree" does not support path selection based on negative
+ pathspecs, but did not error out when negative pathspecs are given.
+ (merge f1f6224 nd/ls-tree-pathspec later to maint).
+
+ * The function sometimes returned a non-freeable memory and some
+ other times returned a piece of memory that must be freed, leading
+ to inevitable leaks.
+ (merge 59362e5 jc/exec-cmd-system-path-leak-fix later to maint).
+
+ * The code to abbreviate an object name to its short unique prefix
+ has been optimized when no abbreviation was requested.
+ (merge 61e704e mh/find-uniq-abbrev later to maint).
+
+ * "git add --ignore-errors ..." did not ignore an error to
+ give a file that did not exist.
+ (merge 1d31e5a mg/add-ignore-errors later to maint).
+
* "git checkout $treeish $path", when $path in the index and the
working tree already matched what is in $treeish at the $path,
still overwrote the $path unnecessarily.
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index fa71b5f0b6..ef0eeb40cd 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -57,7 +57,8 @@ 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.
+Make sure that you have tests for the bug you are fixing. See
+t/README for guidance.
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
@@ -175,8 +176,11 @@ message starts, you can put a "From: " line to name that person.
You often want to add additional explanation about the patch,
other than the commit message itself. Place such "cover letter"
-material between the three dash lines and the diffstat. Git-notes
-can also be inserted using the `--notes` option.
+material between the three-dash line and the diffstat. For
+patches requiring multiple iterations of review and discussion,
+an explanation of changes between each iteration can be kept in
+Git-notes and inserted automatically following the three-dash
+line via `git format-patch --notes`.
Do not attach the patch as a MIME attachment, compressed or not.
Do not let your e-mail client send quoted-printable. Do not let
@@ -254,15 +258,15 @@ pretty simple: if you can certify the below:
person who certified (a), (b) or (c) and I have not modified
it.
- (d) I understand and agree that this project and the contribution
- are public and that a record of the contribution (including all
- personal information I submit with it, including my sign-off) is
- maintained indefinitely and may be redistributed consistent with
- this project or the open source license(s) involved.
+ (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
then you just add a line saying
- Signed-off-by: Random J Developer <random@developer.example.org>
+ Signed-off-by: Random J Developer <random@developer.example.org>
This line can be automatically added by Git if you run the git-commit
command with the -s option.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 493ab196fa..04e2a71687 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -246,6 +246,17 @@ core.precomposeunicode::
When false, file names are handled fully transparent by Git,
which is backward compatible with older versions of Git.
+core.protectHFS::
+ If set to true, do not allow checkout of paths that would
+ be considered equivalent to `.git` on an HFS+ filesystem.
+ Defaults to `true` on Mac OS, and `false` elsewhere.
+
+core.protectNTFS::
+ If set to true, do not allow checkout of paths that would
+ cause problems with the NTFS filesystem, e.g. conflict with
+ 8.3 "short" names.
+ Defaults to `true` on Windows, and `false` elsewhere.
+
core.trustctime::
If false, the ctime differences between the index and the
working tree are ignored; useful when the inode change time
@@ -843,11 +854,13 @@ accepted are `normal`, `black`, `red`, `green`, `yellow`, `blue`,
`magenta`, `cyan` and `white`; the attributes are `bold`, `dim`, `ul`,
`blink` and `reverse`. The first color given is the foreground; the
second is the background. The position of the attribute, if any,
-doesn't matter.
+doesn't matter. Attributes may be turned off specifically by prefixing
+them with `no` (e.g., `noreverse`, `noul`, etc).
+
Colors (foreground and background) may also be given as numbers between
0 and 255; these use ANSI 256-color mode (but note that not all
-terminals may support this).
+terminals may support this). If your terminal supports it, you may also
+specify 24-bit RGB values as hex, like `#ff0ab3`.
color.diff::
Whether to use ANSI escape sequences to add color to patches.
@@ -2138,6 +2151,13 @@ receive.denyCurrentBranch::
print a warning of such a push to stderr, but allow the push to
proceed. If set to false or "ignore", allow such pushes with no
message. Defaults to "refuse".
++
+Another option is "updateInstead" which will update the working
+directory (must be clean) if pushing into the current branch. This option is
+intended for synchronizing working directories when one side is not easily
+accessible via interactive ssh (e.g. a live web site, hence the requirement
+that the working directory be clean). This mode also comes in handy when
+developing inside a VM to test and fix code on different Operating Systems.
receive.denyNonFastForwards::
If set to true, git-receive-pack will deny a ref update which is
@@ -2312,7 +2332,9 @@ sendemail.smtpserverport::
sendemail.smtpserveroption::
sendemail.smtpuser::
sendemail.thread::
+sendemail.transferencoding::
sendemail.validate::
+sendemail.xmailer::
See linkgit:git-send-email[1] for description.
sendemail.signedoffcc::
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 9631526110..1c74907dd4 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -8,7 +8,7 @@ git-add - Add file contents to the index
SYNOPSIS
--------
[verse]
-'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
+'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
[--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing]
[--] [<pathspec>...]
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 9adce372ec..f4eea28dc4 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -57,6 +57,17 @@ OPTIONS
--no-scissors::
Ignore scissors lines (see linkgit:git-mailinfo[1]).
+-m::
+--message-id::
+ Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
+ so that the Message-ID header is added to the commit message.
+ The `am.messageid` configuration variable can be used to specify
+ the default behaviour.
+
+--no-message-id::
+ Do not add the Message-ID header to the commit message.
+ `no-message-id` is useful to override `am.messageid`.
+
-q::
--quiet::
Be quiet. Only print error messages.
@@ -83,7 +94,6 @@ default. You can use `--no-utf8` to override this.
it is supposed to apply to and we have those blobs
available locally.
---ignore-date::
--ignore-space-change::
--ignore-whitespace::
--whitespace=<option>::
diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt
index ee2e091704..788a011580 100644
--- a/Documentation/git-check-ignore.txt
+++ b/Documentation/git-check-ignore.txt
@@ -21,6 +21,9 @@ the exclude mechanism) that decides if the pathname is excluded or
included. Later patterns within a file take precedence over earlier
ones.
+By default, tracked files are not shown at all since they are not
+subject to exclude rules; but see `--no-index'.
+
OPTIONS
-------
-q, --quiet::
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 0363d0039b..f1f2a3f7ea 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -12,7 +12,7 @@ SYNOPSIS
'git clone' [--template=<template_directory>]
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
- [--separate-git-dir <git dir>]
+ [--dissociate] [--separate-git-dir <git dir>]
[--depth <depth>] [--[no-]single-branch]
[--recursive | --recurse-submodules] [--] <repository>
[<directory>]
@@ -98,7 +98,14 @@ objects from the source repository into a pack in the cloned repository.
require fewer objects to be copied from the repository
being cloned, reducing network and local storage costs.
+
-*NOTE*: see the NOTE for the `--shared` option.
+*NOTE*: see the NOTE for the `--shared` option, and also the
+`--dissociate` option.
+
+--dissociate::
+ Borrow the objects from reference repositories specified
+ with the `--reference` options only to reduce network
+ transfer and stop borrowing from them after a clone is made
+ by making necessary local copies of borrowed objects.
--quiet::
-q::
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index c7c0d21429..77aacf1309 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -9,7 +9,7 @@ git-imap-send - Send a collection of patches from stdin to an IMAP folder
SYNOPSIS
--------
[verse]
-'git imap-send'
+'git imap-send' [-v] [-q] [--[no-]curl]
DESCRIPTION
@@ -26,6 +26,27 @@ Typical usage is something like:
git format-patch --signoff --stdout --attach origin | git imap-send
+OPTIONS
+-------
+
+-v::
+--verbose::
+ Be verbose.
+
+-q::
+--quiet::
+ Be quiet.
+
+--curl::
+ Use libcurl to communicate with the IMAP server, unless tunneling
+ into it. Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
+ option set.
+
+--no-curl::
+ Talk to the IMAP server using git's own IMAP routines instead of
+ using libcurl.
+
+
CONFIGURATION
-------------
@@ -75,7 +96,9 @@ imap.preformattedHTML::
imap.authMethod::
Specify authenticate method for authentication with IMAP server.
- Current supported method is 'CRAM-MD5' only. If this is not set
+ If Git was built with the NO_CURL option, or if your curl version is older
+ than 7.34.0, or if you're running git-imap-send with the `--no-curl`
+ option, the only supported method is 'CRAM-MD5'. If this is not set
then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
Examples
diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt
index 164a3c6ede..0947084140 100644
--- a/Documentation/git-mailinfo.txt
+++ b/Documentation/git-mailinfo.txt
@@ -66,6 +66,11 @@ conversion, even with this flag.
-n::
Disable all charset re-coding of the metadata.
+-m::
+--message-id::
+ Copy the Message-ID header at the end of the commit message. This
+ is useful in order to associate commits with mailing list discussions.
+
--scissors::
Remove everything in body before a scissors line. A line that
mainly consists of scissors (either ">8" or "8<") and perforation
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index d2d8f4792a..c2f76fb1ea 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -13,7 +13,7 @@ SYNOPSIS
[--no-reuse-delta] [--delta-base-offset] [--non-empty]
[--local] [--incremental] [--window=<n>] [--depth=<n>]
[--revs [--unpacked | --all]] [--stdout | base-name]
- [--keep-true-parents] < object-list
+ [--shallow] [--keep-true-parents] < object-list
DESCRIPTION
@@ -190,6 +190,11 @@ required objects and is thus unusable by Git without making it
self-contained. Use `git index-pack --fix-thin`
(see linkgit:git-index-pack[1]) to restore the self-contained property.
+--shallow::
+ Optimize a pack that will be provided to a client with a shallow
+ repository. This option, combined with \--thin, can result in a
+ smaller pack at the cost of speed.
+
--delta-base-offset::
A packed archive can express the base object of a delta as
either a 20-byte object name or as an offset in the
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index fd7f8b5bc1..5b119220bf 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -46,7 +46,8 @@ SYNOPSIS
[ \--extended-regexp | -E ]
[ \--fixed-strings | -F ]
[ \--date=(local|relative|default|iso|iso-strict|rfc|short) ]
- [ [\--objects | \--objects-edge] [ \--unpacked ] ]
+ [ [ \--objects | \--objects-edge | \--objects-edge-aggressive ]
+ [ \--unpacked ] ]
[ \--pretty | \--header ]
[ \--bisect ]
[ \--bisect-vars ]
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index a60776eb57..f248a8665e 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -131,6 +131,21 @@ Note that no attempts whatsoever are made to validate the encoding.
Specify encoding of compose message. Default is the value of the
'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
+--transfer-encoding=(7bit|8bit|quoted-printable|base64)::
+ Specify the transfer encoding to be used to send the message over SMTP.
+ 7bit will fail upon encountering a non-ASCII message. quoted-printable
+ can be useful when the repository contains files that contain carriage
+ returns, but makes the raw patch email file (as saved from a MUA) much
+ harder to inspect manually. base64 is even more fool proof, but also
+ even more opaque. Default is the value of the 'sendemail.transferEncoding'
+ configuration value; if that is unspecified, git will use 8bit and not
+ add a Content-Transfer-Encoding header.
+
+--xmailer::
+--no-xmailer::
+ Add (or prevent adding) the "X-Mailer:" header. By default,
+ the header is added, but it can be turned off by setting the
+ `sendemail.xmailer` configuration variable to `false`.
Sending
~~~~~~~
@@ -199,10 +214,15 @@ must be used for each option.
Legacy alias for '--smtp-encryption ssl'.
--smtp-ssl-cert-path::
- Path to ca-certificates (either a directory or a single file).
- Set it to an empty string to disable certificate verification.
- Defaults to the value set to the 'sendemail.smtpsslcertpath'
- configuration variable, if set, or `/etc/ssl/certs` otherwise.
+ Path to a store of trusted CA certificates for SMTP SSL/TLS
+ certificate validation (either a directory that has been processed
+ by 'c_rehash', or a single file containing one or more PEM format
+ certificates concatenated together: see verify(1) -CAfile and
+ -CApath for more information on these). Set it to an empty string
+ to disable certificate verification. Defaults to the value of the
+ 'sendemail.smtpsslcertpath' configuration variable, if set, or the
+ backing SSL library's compiled-in default otherwise (which should
+ be the best choice on most platforms).
--smtp-user=<user>::
Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
diff --git a/Documentation/git-stripspace.txt b/Documentation/git-stripspace.txt
index c87bfcb674..6c6e989074 100644
--- a/Documentation/git-stripspace.txt
+++ b/Documentation/git-stripspace.txt
@@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git stripspace' [-s | --strip-comments] < input
+'git stripspace' [-c | --comment-lines] < input
DESCRIPTION
-----------
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 929869b0a0..aff01798cd 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -82,20 +82,18 @@ OPTIONS
Set the execute permissions on the updated files.
--[no-]assume-unchanged::
- When these flags are specified, the object names recorded
- for the paths are not updated. Instead, these options
- set and unset the "assume unchanged" bit for the
- paths. When the "assume unchanged" bit is on, Git stops
- checking the working tree files for possible
- modifications, so you need to manually unset the bit to
- tell Git when you change the working tree file. This is
+ When this flag is specified, the object names recorded
+ for the paths are not updated. Instead, this option
+ sets/unsets the "assume unchanged" bit for the
+ paths. When the "assume unchanged" bit is on, the user
+ promises not to change the file and allows Git to assume
+ that the working tree file matches what is recorded in
+ the index. If you want to change the working tree file,
+ you need to unset the bit to tell Git. This is
sometimes helpful when working with a big project on a
filesystem that has very slow lstat(2) system call
(e.g. cifs).
+
-This option can be also used as a coarse file-level mechanism
-to ignore uncommitted changes in tracked files (akin to what
-`.gitignore` does for untracked files).
Git will fail (gracefully) in case it needs to modify this file
in the index e.g. when merging in a commit;
thus, in case the assumed-untracked file is changed upstream,
diff --git a/Documentation/git.txt b/Documentation/git.txt
index dd172548f3..9d33431427 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,40 +43,46 @@ unreleased) version of Git, that is available from the 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v2.2.0/git.html[documentation for release 2.2]
+* link:v2.2.2/git.html[documentation for release 2.2.2]
* release notes for
+ link:RelNotes/2.2.2.txt[2.2.2],
+ link:RelNotes/2.2.1.txt[2.2.1],
link:RelNotes/2.2.0.txt[2.2].
-* link:v2.1.3/git.html[documentation for release 2.1.3]
+* link:v2.1.4/git.html[documentation for release 2.1.4]
* release notes for
+ link:RelNotes/2.1.4.txt[2.1.4],
link:RelNotes/2.1.3.txt[2.1.3],
link:RelNotes/2.1.2.txt[2.1.2],
link:RelNotes/2.1.1.txt[2.1.1],
link:RelNotes/2.1.0.txt[2.1].
-* link:v2.0.4/git.html[documentation for release 2.0.4]
+* link:v2.0.5/git.html[documentation for release 2.0.5]
* release notes for
+ link:RelNotes/2.0.5.txt[2.0.5],
link:RelNotes/2.0.4.txt[2.0.4],
link:RelNotes/2.0.3.txt[2.0.3],
link:RelNotes/2.0.2.txt[2.0.2],
link:RelNotes/2.0.1.txt[2.0.1],
link:RelNotes/2.0.0.txt[2.0.0].
-* link:v1.9.4/git.html[documentation for release 1.9.4]
+* link:v1.9.5/git.html[documentation for release 1.9.5]
* release notes for
+ link:RelNotes/1.9.5.txt[1.9.5],
link:RelNotes/1.9.4.txt[1.9.4],
link:RelNotes/1.9.3.txt[1.9.3],
link:RelNotes/1.9.2.txt[1.9.2],
link:RelNotes/1.9.1.txt[1.9.1],
link:RelNotes/1.9.0.txt[1.9.0].
-* link:v1.8.5.5/git.html[documentation for release 1.8.5.5]
+* link:v1.8.5.6/git.html[documentation for release 1.8.5.6]
* release notes for
+ link:RelNotes/1.8.5.6.txt[1.8.5.6],
link:RelNotes/1.8.5.5.txt[1.8.5.5],
link:RelNotes/1.8.5.4.txt[1.8.5.4],
link:RelNotes/1.8.5.3.txt[1.8.5.3],
@@ -908,6 +914,10 @@ for further details.
and read the password from its STDOUT. See also the 'core.askpass'
option in linkgit:git-config[1].
+'GIT_TERMINAL_PROMPT'::
+ If this environment variable is set to `0`, git will not prompt
+ on the terminal (e.g., when asking for HTTP authentication).
+
'GIT_CONFIG_NOSYSTEM'::
Whether to skip reading settings from the system-wide
`$(prefix)/etc/gitconfig` file. This environment variable can
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 09e82c31bd..4fd04423e9 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -138,9 +138,6 @@ NOTES
The purpose of gitignore files is to ensure that certain files
not tracked by Git remain untracked.
-To ignore uncommitted changes in a file that is already tracked,
-use 'git update-index {litdd}assume-unchanged'.
-
To stop tracking a file that is currently tracked, use
'git rm --cached'.
@@ -203,7 +200,6 @@ everything within `foo/bar`):
SEE ALSO
--------
linkgit:git-rm[1],
-linkgit:git-update-index[1],
linkgit:gitrepository-layout[5],
linkgit:git-check-ignore[1]
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index afccfdc23a..2984f407a9 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -653,10 +653,15 @@ These options are mostly targeted for packing of Git repositories.
--objects-edge::
Similar to `--objects`, but also print the IDs of excluded
commits prefixed with a ``-'' character. This is used by
- linkgit:git-pack-objects[1] to build ``thin'' pack, which records
+ linkgit:git-pack-objects[1] to build a ``thin'' pack, which records
objects in deltified form based on objects contained in these
excluded commits to reduce network traffic.
+--objects-edge-aggressive::
+ Similar to `--objects-edge`, but it tries harder to find excluded
+ commits at the cost of increased time. This is used instead of
+ `--objects-edge` to build ``thin'' packs for shallow repositories.
+
--unpacked::
Only useful with `--objects`; print the object IDs that are not
in packs.
diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt
index c1b42a40d3..e44426dd04 100644
--- a/Documentation/technical/api-credentials.txt
+++ b/Documentation/technical/api-credentials.txt
@@ -248,7 +248,10 @@ FORMAT` in linkgit:git-credential[7] for a detailed specification).
For a `get` operation, the helper should produce a list of attributes
on stdout in the same format. A helper is free to produce a subset, or
even no values at all if it has nothing useful to provide. Any provided
-attributes will overwrite those already known about by Git.
+attributes will overwrite those already known about by Git. If a helper
+outputs a `quit` attribute with a value of `true` or `1`, no further
+helpers will be consulted, nor will the user be prompted (if no
+credential has been provided, the operation will then fail).
For a `store` or `erase` operation, the helper's output is ignored.
If it fails to perform the requested operation, it may complain to
diff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt
index d51a6579c8..c08402b12e 100644
--- a/Documentation/technical/api-string-list.txt
+++ b/Documentation/technical/api-string-list.txt
@@ -29,7 +29,7 @@ member (you need this if you add things later) and you should set the
`unsorted_string_list_has_string` and get it from the list using
`string_list_lookup` for sorted lists.
-. Can sort an unsorted list using `sort_string_list`.
+. Can sort an unsorted list using `string_list_sort`.
. Can remove duplicate items from a sorted list using
`string_list_remove_duplicates`.
@@ -146,7 +146,7 @@ write `string_list_insert(...)->util = ...;`.
ownership of a malloc()ed string to a `string_list` that has
`strdup_string` set.
-`sort_string_list`::
+`string_list_sort`::
Sort the list's entries by string value in `strcmp()` order.
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index 1250b5ca8b..35112e4966 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -207,7 +207,7 @@ Git index format
in a separate file. This extension records the changes to be made on
top of that to produce the final index.
- The signature for this extension is { 'l', 'i, 'n', 'k' }.
+ The signature for this extension is { 'l', 'i', 'n', 'k' }.
The extension consists of:
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 53dd6b3285..57dc9635aa 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.2.0.GIT
+DEF_VER=v2.3.0-rc0
LF='
'
diff --git a/INSTALL b/INSTALL
index 6ec7a24e1a..ffb071e9f0 100644
--- a/INSTALL
+++ b/INSTALL
@@ -108,18 +108,21 @@ Issues of note:
so you might need to install additional packages other than Perl
itself, e.g. Time::HiRes.
- - "openssl" library is used by git-imap-send to use IMAP over SSL.
- If you don't need it, use NO_OPENSSL.
+ - git-imap-send needs the OpenSSL library to talk IMAP over SSL if
+ you are using libcurl older than 7.34.0. Otherwise you can use
+ NO_OPENSSL without losing git-imap-send.
By default, git uses OpenSSL for SHA1 but it will use its own
library (inspired by Mozilla's) with either NO_OPENSSL or
BLK_SHA1. Also included is a version optimized for PowerPC
(PPC_SHA1).
- - "libcurl" library is used by git-http-fetch and git-fetch. You
- might also want the "curl" executable for debugging purposes.
- If you do not use http:// or https:// repositories, you do not
- have to have them (use NO_CURL).
+ - "libcurl" library is used by git-http-fetch, git-fetch, and, if
+ the curl version >= 7.34.0, for git-imap-send. You might also
+ want the "curl" executable for debugging purposes. If you do not
+ use http:// or https:// repositories, and do not want to put
+ patches into an IMAP mailbox, you do not have to have them
+ (use NO_CURL).
- "expat" library; git-http-push uses it for remote lock
management over DAV. Similar to "curl" above, this is optional
diff --git a/Makefile b/Makefile
index 7482a4dbab..c44eb3a851 100644
--- a/Makefile
+++ b/Makefile
@@ -191,6 +191,10 @@ all::
# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
# the executable mode bit, but doesn't really do so.
#
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values (e.g. z/OS defines I_SFMT to 0xFF000000 as opposed to the
+# usual 0xF000).
+#
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
#
# Define NO_UNIX_SOCKETS if your system does not offer unix sockets.
@@ -339,6 +343,11 @@ all::
# return NULL when it receives a bogus time_t.
#
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt.
+#
+# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC in librt.
+#
+# Define NO_HMAC_CTX_CLEANUP if your OpenSSL is version 0.9.6b or earlier to
+# cleanup the HMAC context with the older HMAC_cleanup function.
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -995,6 +1004,9 @@ ifdef HAVE_ALLOCA_H
BASIC_CFLAGS += -DHAVE_ALLOCA_H
endif
+IMAP_SEND_BUILDDEPS =
+IMAP_SEND_LDFLAGS = $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
+
ifdef NO_CURL
BASIC_CFLAGS += -DNO_CURL
REMOTE_CURL_PRIMARY =
@@ -1029,6 +1041,15 @@ else
PROGRAM_OBJS += http-push.o
endif
endif
+ curl_check := $(shell (echo 072200; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
+ ifeq "$(curl_check)" "072200"
+ USE_CURL_FOR_IMAP_SEND = YesPlease
+ endif
+ ifdef USE_CURL_FOR_IMAP_SEND
+ BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
+ IMAP_SEND_BUILDDEPS = http.o
+ IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
+ endif
ifndef NO_EXPAT
ifdef EXPATDIR
BASIC_CFLAGS += -I$(EXPATDIR)/include
@@ -1059,6 +1080,9 @@ ifndef NO_OPENSSL
ifdef NEEDS_CRYPTO_WITH_SSL
OPENSSL_LIBSSL += -lcrypto
endif
+ ifdef NO_HMAC_CTX_CLEANUP
+ BASIC_CFLAGS += -DNO_HMAC_CTX_CLEANUP
+ endif
else
BASIC_CFLAGS += -DNO_OPENSSL
BLK_SHA1 = 1
@@ -1230,6 +1254,10 @@ endif
ifdef NO_TRUSTABLE_FILEMODE
BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
endif
+ifdef NEEDS_MODE_TRANSLATION
+ COMPAT_CFLAGS += -DNEEDS_MODE_TRANSLATION
+ COMPAT_OBJS += compat/stat.o
+endif
ifdef NO_IPV6
BASIC_CFLAGS += -DNO_IPV6
endif
@@ -1382,6 +1410,10 @@ ifdef HAVE_CLOCK_GETTIME
EXTLIBS += -lrt
endif
+ifdef HAVE_CLOCK_MONOTONIC
+ BASIC_CFLAGS += -DHAVE_CLOCK_MONOTONIC
+endif
+
ifeq ($(TCLTK_PATH),)
NO_TCLTK = NoThanks
endif
@@ -1880,7 +1912,7 @@ gettext.sp gettext.s gettext.o: GIT-PREFIX
gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
-DGIT_LOCALE_PATH='"$(localedir_SQ)"'
-http-push.sp http.sp http-walker.sp remote-curl.sp: SPARSE_FLAGS += \
+http-push.sp http.sp http-walker.sp remote-curl.sp imap-send.sp: SPARSE_FLAGS += \
-DCURL_DISABLE_TYPECHECK
ifdef NO_EXPAT
@@ -1901,9 +1933,9 @@ endif
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
-git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)
+git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
+ $(LIBS) $(IMAP_SEND_LDFLAGS)
git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
diff --git a/archive.c b/archive.c
index 94a9981adf..9e30246b64 100644
--- a/archive.c
+++ b/archive.c
@@ -157,18 +157,26 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
return write_entry(args, sha1, path.buf, path.len, mode);
}
+static int write_archive_entry_buf(const unsigned char *sha1, struct strbuf *base,
+ const char *filename, unsigned mode, int stage,
+ void *context)
+{
+ return write_archive_entry(sha1, base->buf, base->len,
+ filename, mode, stage, context);
+}
+
static void queue_directory(const unsigned char *sha1,
- const char *base, int baselen, const char *filename,
+ struct strbuf *base, const char *filename,
unsigned mode, int stage, struct archiver_context *c)
{
struct directory *d;
- d = xmallocz(sizeof(*d) + baselen + 1 + strlen(filename));
+ d = xmallocz(sizeof(*d) + base->len + 1 + strlen(filename));
d->up = c->bottom;
- d->baselen = baselen;
+ d->baselen = base->len;
d->mode = mode;
d->stage = stage;
c->bottom = d;
- d->len = sprintf(d->path, "%.*s%s/", baselen, base, filename);
+ d->len = sprintf(d->path, "%.*s%s/", (int)base->len, base->buf, filename);
hashcpy(d->sha1, sha1);
}
@@ -191,28 +199,28 @@ static int write_directory(struct archiver_context *c)
}
static int queue_or_write_archive_entry(const unsigned char *sha1,
- const char *base, int baselen, const char *filename,
+ struct strbuf *base, const char *filename,
unsigned mode, int stage, void *context)
{
struct archiver_context *c = context;
while (c->bottom &&
- !(baselen >= c->bottom->len &&
- !strncmp(base, c->bottom->path, c->bottom->len))) {
+ !(base->len >= c->bottom->len &&
+ !strncmp(base->buf, c->bottom->path, c->bottom->len))) {
struct directory *next = c->bottom->up;
free(c->bottom);
c->bottom = next;
}
if (S_ISDIR(mode)) {
- queue_directory(sha1, base, baselen, filename,
+ queue_directory(sha1, base, filename,
mode, stage, c);
return READ_TREE_RECURSIVE;
}
if (write_directory(c))
return -1;
- return write_archive_entry(sha1, base, baselen, filename, mode,
+ return write_archive_entry(sha1, base->buf, base->len, filename, mode,
stage, context);
}
@@ -260,7 +268,7 @@ int write_archive_entries(struct archiver_args *args,
err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
args->pathspec.has_wildcard ?
queue_or_write_archive_entry :
- write_archive_entry,
+ write_archive_entry_buf,
&context);
if (err == READ_TREE_RECURSIVE)
err = 0;
@@ -286,14 +294,14 @@ static const struct archiver *lookup_archiver(const char *name)
return NULL;
}
-static int reject_entry(const unsigned char *sha1, const char *base,
- int baselen, const char *filename, unsigned mode,
+static int reject_entry(const unsigned char *sha1, struct strbuf *base,
+ const char *filename, unsigned mode,
int stage, void *context)
{
int ret = -1;
if (S_ISDIR(mode)) {
struct strbuf sb = STRBUF_INIT;
- strbuf_addstr(&sb, base);
+ strbuf_addbuf(&sb, base);
strbuf_addstr(&sb, filename);
if (!match_pathspec(context, sb.buf, sb.len, 0, NULL, 1))
ret = READ_TREE_RECURSIVE;
diff --git a/bisect.c b/bisect.c
index df09cbc8ca..8c6d843699 100644
--- a/bisect.c
+++ b/bisect.c
@@ -777,7 +777,7 @@ static void check_merge_bases(int no_checkout)
int rev_nr;
struct commit **rev = get_bad_and_good_commits(&rev_nr);
- result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
+ result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1);
for (; result; result = result->next) {
const unsigned char *mb = result->item->object.sha1;
diff --git a/builtin/add.c b/builtin/add.c
index ae6d3e262b..1074e32349 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -284,7 +284,7 @@ static int add_files(struct dir_struct *dir, int flags)
for (i = 0; i < dir->ignored_nr; i++)
fprintf(stderr, "%s\n", dir->ignored[i]->name);
fprintf(stderr, _("Use -f if you really want to add them.\n"));
- die(_("no files added"));
+ exit_status = 1;
}
for (i = 0; i < dir->nr; i++)
diff --git a/builtin/apply.c b/builtin/apply.c
index 28d24f8e34..0aad912839 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -4180,7 +4180,7 @@ static int write_out_results(struct patch *list)
if (cpath.nr) {
struct string_list_item *item;
- sort_string_list(&cpath);
+ string_list_sort(&cpath);
for_each_string_list_item(item, &cpath)
fprintf(stderr, "U %s\n", item->string);
string_list_clear(&cpath, 0);
diff --git a/builtin/branch.c b/builtin/branch.c
index 3b79c5087f..dc6f0b266c 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -800,7 +800,7 @@ static int edit_branch_description(const char *branch_name)
int cmd_branch(int argc, const char **argv, const char *prefix)
{
- int delete = 0, rename = 0, force_create = 0, list = 0;
+ int delete = 0, rename = 0, force = 0, list = 0;
int verbose = 0, abbrev = -1, detached = 0;
int reflog = 0, edit_description = 0;
int quiet = 0, unset_upstream = 0;
@@ -848,7 +848,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
OPT_BOOL(0, "edit-description", &edit_description,
N_("edit the description for the branch")),
- OPT__FORCE(&force_create, N_("force creation (when already exists)")),
+ OPT__FORCE(&force, N_("force creation, move/rename, deletion")),
{
OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
N_("commit"), N_("print only not merged branches"),
@@ -891,7 +891,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (with_commit || merge_filter != NO_FILTER)
list = 1;
- if (!!delete + !!rename + !!force_create + !!new_upstream +
+ if (!!delete + !!rename + !!new_upstream +
list + unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
@@ -904,6 +904,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
colopts = 0;
}
+ if (force) {
+ delete *= 2;
+ rename *= 2;
+ }
+
if (delete) {
if (!argc)
die(_("branch name required"));
@@ -1020,7 +1025,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
branch_existed = ref_exists(branch->refname);
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
- force_create, reflog, 0, quiet, track);
+ force, reflog, 0, quiet, track);
/*
* We only show the instructions if the user gave us
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index f8d81291b9..750b5a24b4 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -4,12 +4,8 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
-#include "exec_cmd.h"
-#include "tag.h"
-#include "tree.h"
#include "builtin.h"
#include "parse-options.h"
-#include "diff.h"
#include "userdiff.h"
#include "streaming.h"
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 383dccf93e..031780f49e 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -18,7 +18,7 @@ static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
static struct checkout state;
-static void write_tempfile_record(const char *name, int prefix_length)
+static void write_tempfile_record(const char *name, const char *prefix)
{
int i;
@@ -35,14 +35,14 @@ static void write_tempfile_record(const char *name, int prefix_length)
fputs(topath[checkout_stage], stdout);
putchar('\t');
- write_name_quoted(name + prefix_length, stdout, line_termination);
+ write_name_quoted_relative(name, prefix, stdout, line_termination);
for (i = 0; i < 4; i++) {
topath[i][0] = 0;
}
}
-static int checkout_file(const char *name, int prefix_length)
+static int checkout_file(const char *name, const char *prefix)
{
int namelen = strlen(name);
int pos = cache_name_pos(name, namelen);
@@ -71,7 +71,7 @@ static int checkout_file(const char *name, int prefix_length)
if (did_checkout) {
if (to_tempfile)
- write_tempfile_record(name, prefix_length);
+ write_tempfile_record(name, prefix);
return errs > 0 ? -1 : 0;
}
@@ -106,7 +106,7 @@ static void checkout_all(const char *prefix, int prefix_length)
if (last_ce && to_tempfile) {
if (ce_namelen(last_ce) != ce_namelen(ce)
|| memcmp(last_ce->name, ce->name, ce_namelen(ce)))
- write_tempfile_record(last_ce->name, prefix_length);
+ write_tempfile_record(last_ce->name, prefix);
}
if (checkout_entry(ce, &state,
to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
@@ -114,7 +114,7 @@ static void checkout_all(const char *prefix, int prefix_length)
last_ce = ce;
}
if (last_ce && to_tempfile)
- write_tempfile_record(last_ce->name, prefix_length);
+ write_tempfile_record(last_ce->name, prefix);
if (errs)
/* we have already done our error reporting.
* exit with the same code as die().
@@ -248,7 +248,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
if (read_from_stdin)
die("git checkout-index: don't mix '--stdin' and explicit filenames");
p = prefix_path(prefix, prefix_length, arg);
- checkout_file(p, prefix_length);
+ checkout_file(p, prefix);
if (p < arg || p > arg + strlen(arg))
free((char *)p);
}
@@ -268,7 +268,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
strbuf_swap(&buf, &nbuf);
}
p = prefix_path(prefix, prefix_length, buf.buf);
- checkout_file(p, prefix_length);
+ checkout_file(p, prefix);
if (p < buf.buf || p > buf.buf + buf.len)
free((char *)p);
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 5a78758036..52d6cbb0a8 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -62,7 +62,7 @@ static int post_checkout_hook(struct commit *old, struct commit *new,
}
-static int update_some(const unsigned char *sha1, const char *base, int baselen,
+static int update_some(const unsigned char *sha1, struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
int len;
@@ -72,11 +72,11 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
if (S_ISDIR(mode))
return READ_TREE_RECURSIVE;
- len = baselen + strlen(pathname);
+ len = base->len + strlen(pathname);
ce = xcalloc(1, cache_entry_size(len));
hashcpy(ce->sha1, sha1);
- memcpy(ce->name, base, baselen);
- memcpy(ce->name + baselen, pathname, len - baselen);
+ memcpy(ce->name, base->buf, base->len);
+ memcpy(ce->name + base->len, pathname, len - base->len);
ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
diff --git a/builtin/clean.c b/builtin/clean.c
index 77846762b5..7e7fdcfe54 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -321,7 +321,7 @@ static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen)
switch (stuff->type) {
default:
- die("Bad type of menu_staff when print menu");
+ die("Bad type of menu_stuff when print menu");
case MENU_STUFF_TYPE_MENU_ITEM:
menu_item = (struct menu_item *)stuff->stuff;
for (i = 0; i < stuff->nr; i++, menu_item++) {
diff --git a/builtin/clone.c b/builtin/clone.c
index d5e7532105..316c75d0b3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -49,6 +49,7 @@ static int option_verbosity;
static int option_progress = -1;
static struct string_list option_config;
static struct string_list option_reference;
+static int option_dissociate;
static int opt_parse_reference(const struct option *opt, const char *arg, int unset)
{
@@ -94,6 +95,8 @@ static struct option builtin_clone_options[] = {
N_("create a shallow clone of that depth")),
OPT_BOOL(0, "single-branch", &option_single_branch,
N_("clone only one branch, HEAD or --branch")),
+ OPT_BOOL(0, "dissociate", &option_dissociate,
+ N_("use --reference only while cloning")),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")),
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
@@ -735,6 +738,16 @@ static void write_refspec_config(const char *src_ref_prefix,
strbuf_release(&value);
}
+static void dissociate_from_references(void)
+{
+ static const char* argv[] = { "repack", "-a", "-d", NULL };
+
+ if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN))
+ die(_("cannot repack to clean up"));
+ if (unlink(git_path("objects/info/alternates")) && errno != ENOENT)
+ die_errno(_("cannot unlink temporary alternates file"));
+}
+
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
@@ -880,6 +893,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_reference.nr)
setup_reference();
+ else if (option_dissociate) {
+ warning(_("--dissociate given, but there is no --reference"));
+ option_dissociate = 0;
+ }
fetch_pattern = value.buf;
refspec = parse_fetch_refspec(1, &fetch_pattern);
@@ -993,6 +1010,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
transport_unlock_pack(transport);
transport_disconnect(transport);
+ if (option_dissociate)
+ dissociate_from_references();
+
junk_mode = JUNK_LEAVE_REPO;
err = checkout();
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 8a66c74e0f..25aa2cdef3 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -66,10 +66,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
continue;
}
- if (!memcmp(arg, "-S", 2)) {
- sign_commit = arg + 2;
+ if (skip_prefix(arg, "-S", &sign_commit))
continue;
- }
if (!strcmp(arg, "--no-gpg-sign")) {
sign_commit = NULL;
diff --git a/builtin/commit.c b/builtin/commit.c
index e108c53015..7d90c35915 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -522,6 +522,12 @@ static int is_a_merge(const struct commit *current_head)
return !!(current_head->parents && current_head->parents->next);
}
+static void assert_split_ident(struct ident_split *id, const struct strbuf *buf)
+{
+ if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin)
+ die("BUG: unable to parse our own ident: %s", buf->buf);
+}
+
static void export_one(const char *var, const char *s, const char *e, int hack)
{
struct strbuf buf = STRBUF_INIT;
@@ -532,20 +538,6 @@ static void export_one(const char *var, const char *s, const char *e, int hack)
strbuf_release(&buf);
}
-static int sane_ident_split(struct ident_split *person)
-{
- if (!person->name_begin || !person->name_end ||
- person->name_begin == person->name_end)
- return 0; /* no human readable name */
- if (!person->mail_begin || !person->mail_end ||
- person->mail_begin == person->mail_end)
- return 0; /* no usable mail */
- if (!person->date_begin || !person->date_end ||
- !person->tz_begin || !person->tz_end)
- return 0;
- return 1;
-}
-
static int parse_force_date(const char *in, struct strbuf *out)
{
strbuf_addch(out, '@');
@@ -623,25 +615,15 @@ static void determine_author_info(struct strbuf *author_ident)
}
strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
- if (!split_ident_line(&author, author_ident->buf, author_ident->len) &&
- sane_ident_split(&author)) {
- export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
- export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
- export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
- }
-
+ assert_split_ident(&author, author_ident);
+ export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
+ export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
+ export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
free(name);
free(email);
free(date);
}
-static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf)
-{
- if (split_ident_line(id, buf->buf, buf->len) ||
- !sane_ident_split(id))
- die(_("Malformed ident string: '%s'"), buf->buf);
-}
-
static int author_date_is_interesting(void)
{
return author_message || force_date;
@@ -800,32 +782,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (clean_message_contents)
stripspace(&sb, 0);
- if (signoff) {
- /*
- * See if we have a Conflicts: block at the end. If yes, count
- * its size, so we can ignore it.
- */
- int ignore_footer = 0;
- int i, eol, previous = 0;
- const char *nl;
-
- for (i = 0; i < sb.len; i++) {
- nl = memchr(sb.buf + i, '\n', sb.len - i);
- if (nl)
- eol = nl - sb.buf;
- else
- eol = sb.len;
- if (starts_with(sb.buf + previous, "\nConflicts:\n")) {
- ignore_footer = sb.len - previous;
- break;
- }
- while (i < eol)
- i++;
- previous = eol;
- }
-
- append_signoff(&sb, ignore_footer, 0);
- }
+ if (signoff)
+ append_signoff(&sb, ignore_non_trailer(&sb), 0);
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
die_errno(_("could not write commit template"));
@@ -880,8 +838,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
status_printf_ln(s, GIT_COLOR_NORMAL,
"%s", only_include_assumed);
- split_ident_or_die(&ai, author_ident);
- split_ident_or_die(&ci, &committer_ident);
+ /*
+ * These should never fail because they come from our own
+ * fmt_ident. They may fail the sane_ident test, but we know
+ * that the name and mail pointers will at least be valid,
+ * which is enough for our tests and printing here.
+ */
+ assert_split_ident(&ai, author_ident);
+ assert_split_ident(&ci, &committer_ident);
if (ident_cmp(&ai, &ci))
status_printf_ln(s, GIT_COLOR_NORMAL,
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 37177c6c29..af7919e51e 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -216,8 +216,7 @@ static void add_branch_desc(struct strbuf *out, const char *name)
strbuf_addf(out, " : %.*s", (int)(ep - bp), bp);
bp = ep;
}
- if (out->buf[out->len - 1] != '\n')
- strbuf_addch(out, '\n');
+ strbuf_complete_line(out);
}
strbuf_release(&desc);
}
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 603a90e29b..a0123f6146 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -717,7 +717,10 @@ static void populate_value(struct refinfo *ref)
starts_with(name, "upstream")) {
char buf[40];
- stat_tracking_info(branch, &num_ours, &num_theirs);
+ if (stat_tracking_info(branch, &num_ours,
+ &num_theirs) != 1)
+ continue;
+
if (!num_ours && !num_theirs)
v->s = "";
else if (!num_ours) {
@@ -735,7 +738,11 @@ static void populate_value(struct refinfo *ref)
} else if (!strcmp(formatp, "trackshort") &&
starts_with(name, "upstream")) {
assert(branch);
- stat_tracking_info(branch, &num_ours, &num_theirs);
+
+ if (stat_tracking_info(branch, &num_ours,
+ &num_theirs) != 1)
+ continue;
+
if (!num_ours && !num_theirs)
v->s = "=";
else if (!num_ours)
@@ -1075,7 +1082,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
OPT_BIT(0 , "python", &quote_style,
N_("quote placeholders suitably for python"), QUOTE_PYTHON),
OPT_BIT(0 , "tcl", &quote_style,
- N_("quote placeholders suitably for tcl"), QUOTE_TCL),
+ N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
OPT_GROUP(""),
OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
diff --git a/builtin/help.c b/builtin/help.c
index b3c818ee01..e78c135e01 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -321,16 +321,18 @@ static void setup_man_path(void)
{
struct strbuf new_path = STRBUF_INIT;
const char *old_path = getenv("MANPATH");
+ char *git_man_path = system_path(GIT_MAN_PATH);
/* We should always put ':' after our path. If there is no
* old_path, the ':' at the end will let 'man' to try
* system-wide paths after ours to find the manual page. If
* there is old_path, we need ':' as delimiter. */
- strbuf_addstr(&new_path, system_path(GIT_MAN_PATH));
+ strbuf_addstr(&new_path, git_man_path);
strbuf_addch(&new_path, ':');
if (old_path)
strbuf_addstr(&new_path, old_path);
+ free(git_man_path);
setenv("MANPATH", new_path.buf, 1);
strbuf_release(&new_path);
@@ -380,8 +382,10 @@ static void show_info_page(const char *git_cmd)
static void get_html_page_path(struct strbuf *page_path, const char *page)
{
struct stat st;
+ char *to_free = NULL;
+
if (!html_path)
- html_path = system_path(GIT_HTML_PATH);
+ html_path = to_free = system_path(GIT_HTML_PATH);
/* Check that we have a git documentation directory. */
if (!strstr(html_path, "://")) {
@@ -392,6 +396,7 @@ static void get_html_page_path(struct strbuf *page_path, const char *page)
strbuf_init(page_path, 0);
strbuf_addf(page_path, "%s/%s.html", html_path, page);
+ free(to_free);
}
/*
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index a369f55353..4632117671 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -447,7 +447,7 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size,
if (type == OBJ_BLOB && size > big_file_threshold)
buf = fixed_buf;
else
- buf = xmalloc(size);
+ buf = xmallocz(size);
memset(&stream, 0, sizeof(stream));
git_inflate_init(&stream);
@@ -552,7 +552,7 @@ static void *unpack_data(struct object_entry *obj,
git_zstream stream;
int status;
- data = xmalloc(consume ? 64*1024 : obj->size);
+ data = xmallocz(consume ? 64*1024 : obj->size);
inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
memset(&stream, 0, sizeof(stream));
diff --git a/builtin/init-db.c b/builtin/init-db.c
index aab44d2e45..9966522b4a 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -119,15 +119,18 @@ static void copy_templates(const char *template_dir)
DIR *dir;
const char *git_dir = get_git_dir();
int len = strlen(git_dir);
+ char *to_free = NULL;
if (!template_dir)
template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
if (!template_dir)
template_dir = init_db_template_dir;
if (!template_dir)
- template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
- if (!template_dir[0])
+ template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
+ if (!template_dir[0]) {
+ free(to_free);
return;
+ }
template_len = strlen(template_dir);
if (PATH_MAX <= (template_len+strlen("/config")))
die(_("insanely long template path %s"), template_dir);
@@ -139,7 +142,7 @@ static void copy_templates(const char *template_dir)
dir = opendir(template_path);
if (!dir) {
warning(_("templates not found %s"), template_dir);
- return;
+ goto free_return;
}
/* Make sure that template is from the correct vintage */
@@ -155,8 +158,7 @@ static void copy_templates(const char *template_dir)
"a wrong format version %d from '%s'"),
repository_format_version,
template_dir);
- closedir(dir);
- return;
+ goto close_free_return;
}
memcpy(path, git_dir, len);
@@ -166,7 +168,10 @@ static void copy_templates(const char *template_dir)
copy_templates_1(path, len,
template_path, template_len,
dir);
+close_free_return:
closedir(dir);
+free_return:
+ free(to_free);
}
static int git_init_db_config(const char *k, const char *v, void *cb)
@@ -256,6 +261,8 @@ static int create_default_files(const char *template_path)
!lstat(path, &st2) &&
st1.st_mode != st2.st_mode &&
!chmod(path, st1.st_mode));
+ if (filemode && !reinit && (st1.st_mode & S_IXUSR))
+ filemode = 0;
}
git_config_set("core.filemode", filemode ? "true" : "false");
diff --git a/builtin/log.c b/builtin/log.c
index 734aab3a73..923ffe72ce 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -38,8 +38,8 @@ static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
static const char * const builtin_log_usage[] = {
- N_("git log [<options>] [<revision range>] [[--] <path>...]\n")
- N_(" or: git show [options] <object>..."),
+ N_("git log [<options>] [<revision range>] [[--] <path>...]"),
+ N_("git show [options] <object>..."),
NULL
};
@@ -489,7 +489,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
}
static int show_tree_object(const unsigned char *sha1,
- const char *base, int baselen,
+ struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 51184dfa2e..3b04a0f082 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -61,10 +61,11 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
}
}
-static int show_tree(const unsigned char *sha1, const char *base, int baselen,
+static int show_tree(const unsigned char *sha1, struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
int retval = 0;
+ int baselen;
const char *type = blob_type;
if (S_ISGITLINK(mode)) {
@@ -79,7 +80,7 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
*/
type = commit_type;
} else if (S_ISDIR(mode)) {
- if (show_recursive(base, baselen, pathname)) {
+ if (show_recursive(base->buf, base->len, pathname)) {
retval = READ_TREE_RECURSIVE;
if (!(ls_options & LS_SHOW_TREES))
return retval;
@@ -89,10 +90,6 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
else if (ls_options & LS_TREE_ONLY)
return 0;
- if (chomp_prefix &&
- (baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix)))
- return 0;
-
if (!(ls_options & LS_NAME_ONLY)) {
if (ls_options & LS_SHOW_SIZE) {
char size_text[24];
@@ -112,8 +109,12 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
printf("%06o %s %s\t", mode, type,
find_unique_abbrev(sha1, abbrev));
}
- write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,
- pathname, stdout, line_termination);
+ baselen = base->len;
+ strbuf_addstr(base, pathname);
+ write_name_quoted_relative(base->buf,
+ chomp_prefix ? ls_tree_prefix : NULL,
+ stdout, line_termination);
+ strbuf_setlen(base, baselen);
return retval;
}
@@ -173,7 +174,8 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
* cannot be lifted until it is converted to use
* match_pathspec() or tree_entry_interesting()
*/
- parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE,
+ parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE,
PATHSPEC_PREFER_CWD,
prefix, argv + 1);
for (i = 0; i < pathspec.nr; i++)
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 6a14d2985d..c8a47c173d 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -15,6 +15,7 @@ static const char *metainfo_charset;
static struct strbuf line = STRBUF_INIT;
static struct strbuf name = STRBUF_INIT;
static struct strbuf email = STRBUF_INIT;
+static char *message_id;
static enum {
TE_DONTCARE, TE_QP, TE_BASE64
@@ -24,6 +25,7 @@ static struct strbuf charset = STRBUF_INIT;
static int patch_lines;
static struct strbuf **p_hdr_data, **s_hdr_data;
static int use_scissors;
+static int add_message_id;
static int use_inbody_headers = 1;
#define MAX_HDR_PARSED 10
@@ -198,6 +200,12 @@ static void handle_content_type(struct strbuf *line)
}
}
+static void handle_message_id(const struct strbuf *line)
+{
+ if (add_message_id)
+ message_id = strdup(line->buf);
+}
+
static void handle_content_transfer_encoding(const struct strbuf *line)
{
if (strcasestr(line->buf, "base64"))
@@ -342,6 +350,14 @@ static int check_header(const struct strbuf *line,
ret = 1;
goto check_header_out;
}
+ if (cmp_header(line, "Message-Id")) {
+ len = strlen("Message-Id: ");
+ strbuf_add(&sb, line->buf + len, line->len - len);
+ decode_header(&sb);
+ handle_message_id(&sb);
+ ret = 1;
+ goto check_header_out;
+ }
/* for inbody stuff */
if (starts_with(line->buf, ">From") && isspace(line->buf[5])) {
@@ -816,6 +832,8 @@ static int handle_commit_msg(struct strbuf *line)
}
if (patchbreak(line)) {
+ if (message_id)
+ fprintf(cmitmsg, "Message-Id: %s\n", message_id);
fclose(cmitmsg);
cmitmsg = NULL;
return 1;
@@ -1013,7 +1031,7 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused)
}
static const char mailinfo_usage[] =
- "git mailinfo [-k|-b] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
+ "git mailinfo [-k|-b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
int cmd_mailinfo(int argc, const char **argv, const char *prefix)
{
@@ -1032,6 +1050,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
keep_subject = 1;
else if (!strcmp(argv[1], "-b"))
keep_non_patch_brackets_in_subject = 1;
+ else if (!strcmp(argv[1], "-m") || !strcmp(argv[1], "--message-id"))
+ add_message_id = 1;
else if (!strcmp(argv[1], "-u"))
metainfo_charset = def_charset;
else if (!strcmp(argv[1], "-n"))
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 0ecde8da30..fdebef6fa1 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -10,7 +10,7 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
struct commit_list *result;
- result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
+ result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
if (!result)
return 1;
@@ -176,7 +176,7 @@ static int handle_fork_point(int argc, const char **argv)
for (i = 0; i < revs.nr; i++)
revs.commit[i]->object.flags &= ~TMP_MARK;
- bases = get_merge_bases_many(derived, revs.nr, revs.commit, 0);
+ bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);
/*
* There should be one and only one merge base, when we found
diff --git a/builtin/merge.c b/builtin/merge.c
index bebbe5b308..c638fd5a9a 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -29,6 +29,7 @@
#include "remote.h"
#include "fmt-merge-msg.h"
#include "gpg-interface.h"
+#include "sequencer.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
@@ -880,28 +881,20 @@ static int finish_automerge(struct commit *head,
return 0;
}
-static int suggest_conflicts(int renormalizing)
+static int suggest_conflicts(void)
{
const char *filename;
FILE *fp;
- int pos;
+ struct strbuf msgbuf = STRBUF_INIT;
filename = git_path("MERGE_MSG");
fp = fopen(filename, "a");
if (!fp)
die_errno(_("Could not open '%s' for writing"), filename);
- fprintf(fp, "\nConflicts:\n");
- for (pos = 0; pos < active_nr; pos++) {
- const struct cache_entry *ce = active_cache[pos];
-
- if (ce_stage(ce)) {
- fprintf(fp, "\t%s\n", ce->name);
- while (pos + 1 < active_nr &&
- !strcmp(ce->name,
- active_cache[pos + 1]->name))
- pos++;
- }
- }
+
+ append_conflicts_hint(&msgbuf);
+ fputs(msgbuf.buf, fp);
+ strbuf_release(&msgbuf);
fclose(fp);
rerere(allow_rerere_auto);
printf(_("Automatic merge failed; "
@@ -1320,7 +1313,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!remoteheads)
; /* already up-to-date */
else if (!remoteheads->next)
- common = get_merge_bases(head_commit, remoteheads->item, 1);
+ common = get_merge_bases(head_commit, remoteheads->item);
else {
struct commit_list *list = remoteheads;
commit_list_insert(head_commit, &list);
@@ -1417,7 +1410,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* merge_bases again, otherwise "git merge HEAD^
* HEAD^^" would be missed.
*/
- common_one = get_merge_bases(head_commit, j->item, 1);
+ common_one = get_merge_bases(head_commit, j->item);
if (hashcmp(common_one->item->object.sha1,
j->item->object.sha1)) {
up_to_date = 0;
@@ -1550,7 +1543,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
fprintf(stderr, _("Automatic merge went well; "
"stopped before committing as requested\n"));
else
- ret = suggest_conflicts(option_renormalize);
+ ret = suggest_conflicts();
done:
free(branch_to_free);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 3f9f5c7760..d8165878e1 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2613,6 +2613,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
int thin = 0;
+ int shallow = 0;
int all_progress_implied = 0;
struct argv_array rp = ARGV_ARRAY_INIT;
int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
@@ -2677,6 +2678,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
OPT_BOOL(0, "thin", &thin,
N_("create thin packs")),
+ OPT_BOOL(0, "shallow", &shallow,
+ N_("create packs suitable for shallow fetches")),
OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
N_("ignore packs that have companion .keep file")),
OPT_INTEGER(0, "compression", &pack_compression_level,
@@ -2711,7 +2714,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
argv_array_push(&rp, "pack-objects");
if (thin) {
use_internal_rev_list = 1;
- argv_array_push(&rp, "--objects-edge");
+ argv_array_push(&rp, shallow
+ ? "--objects-edge-aggressive"
+ : "--objects-edge");
} else
argv_array_push(&rp, "--objects");
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index e908d079ba..8266c1fccf 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -26,7 +26,8 @@ enum deny_action {
DENY_UNCONFIGURED,
DENY_IGNORE,
DENY_WARN,
- DENY_REFUSE
+ DENY_REFUSE,
+ DENY_UPDATE_INSTEAD
};
static int deny_deletes;
@@ -76,6 +77,8 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
return DENY_WARN;
if (!strcasecmp(value, "refuse"))
return DENY_REFUSE;
+ if (!strcasecmp(value, "updateinstead"))
+ return DENY_UPDATE_INSTEAD;
}
if (git_config_bool(var, value))
return DENY_REFUSE;
@@ -730,11 +733,89 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
return 0;
}
+static const char *update_worktree(unsigned char *sha1)
+{
+ const char *update_refresh[] = {
+ "update-index", "-q", "--ignore-submodules", "--refresh", NULL
+ };
+ const char *diff_files[] = {
+ "diff-files", "--quiet", "--ignore-submodules", "--", NULL
+ };
+ const char *diff_index[] = {
+ "diff-index", "--quiet", "--cached", "--ignore-submodules",
+ "HEAD", "--", NULL
+ };
+ const char *read_tree[] = {
+ "read-tree", "-u", "-m", NULL, NULL
+ };
+ const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
+ struct argv_array env = ARGV_ARRAY_INIT;
+ struct child_process child = CHILD_PROCESS_INIT;
+
+ if (is_bare_repository())
+ return "denyCurrentBranch = updateInstead needs a worktree";
+
+ argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+
+ child.argv = update_refresh;
+ child.env = env.argv;
+ child.dir = work_tree;
+ child.no_stdin = 1;
+ child.stdout_to_stderr = 1;
+ child.git_cmd = 1;
+ if (run_command(&child)) {
+ argv_array_clear(&env);
+ return "Up-to-date check failed";
+ }
+
+ /* run_command() does not clean up completely; reinitialize */
+ child_process_init(&child);
+ child.argv = diff_files;
+ child.env = env.argv;
+ child.dir = work_tree;
+ child.no_stdin = 1;
+ child.stdout_to_stderr = 1;
+ child.git_cmd = 1;
+ if (run_command(&child)) {
+ argv_array_clear(&env);
+ return "Working directory has unstaged changes";
+ }
+
+ child_process_init(&child);
+ child.argv = diff_index;
+ child.env = env.argv;
+ child.no_stdin = 1;
+ child.no_stdout = 1;
+ child.stdout_to_stderr = 0;
+ child.git_cmd = 1;
+ if (run_command(&child)) {
+ argv_array_clear(&env);
+ return "Working directory has staged changes";
+ }
+
+ read_tree[3] = sha1_to_hex(sha1);
+ child_process_init(&child);
+ child.argv = read_tree;
+ child.env = env.argv;
+ child.dir = work_tree;
+ child.no_stdin = 1;
+ child.no_stdout = 1;
+ child.stdout_to_stderr = 0;
+ child.git_cmd = 1;
+ if (run_command(&child)) {
+ argv_array_clear(&env);
+ return "Could not update working tree to new HEAD";
+ }
+
+ argv_array_clear(&env);
+ return NULL;
+}
+
static const char *update(struct command *cmd, struct shallow_info *si)
{
const char *name = cmd->ref_name;
struct strbuf namespaced_name_buf = STRBUF_INIT;
- const char *namespaced_name;
+ const char *namespaced_name, *ret;
unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1;
@@ -760,6 +841,11 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (deny_current_branch == DENY_UNCONFIGURED)
refuse_unconfigured_deny();
return "branch is currently checked out";
+ case DENY_UPDATE_INSTEAD:
+ ret = update_worktree(new_sha1);
+ if (ret)
+ return ret;
+ break;
}
}
@@ -784,10 +870,13 @@ static const char *update(struct command *cmd, struct shallow_info *si)
break;
case DENY_REFUSE:
case DENY_UNCONFIGURED:
+ case DENY_UPDATE_INSTEAD:
if (deny_delete_current == DENY_UNCONFIGURED)
refuse_unconfigured_deny_delete_current();
rp_error("refusing to delete the current branch: %s", name);
return "deletion of the current branch prohibited";
+ default:
+ return "Invalid denyDeleteCurrent setting";
}
}
}
@@ -964,7 +1053,7 @@ static void check_aliased_updates(struct command *commands)
string_list_append(&ref_list, cmd->ref_name);
item->util = (void *)cmd;
}
- sort_string_list(&ref_list);
+ string_list_sort(&ref_list);
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string)
diff --git a/builtin/remote.c b/builtin/remote.c
index 7f28f92a37..b4ff468977 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -180,7 +180,9 @@ static int add(int argc, const char **argv)
url = argv[1];
remote = remote_get(name);
- if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) ||
+ if (remote && (remote->url_nr > 1 ||
+ (strcmp(name, remote->url[0]) &&
+ strcmp(url, remote->url[0])) ||
remote->fetch_refspec_nr))
die(_("remote %s already exists."), name);
@@ -352,9 +354,9 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
free_refs(stale_refs);
free_refs(fetch_map);
- sort_string_list(&states->new);
- sort_string_list(&states->tracked);
- sort_string_list(&states->stale);
+ string_list_sort(&states->new);
+ string_list_sort(&states->tracked);
+ string_list_sort(&states->stale);
return 0;
}
@@ -750,16 +752,11 @@ static int mv(int argc, const char **argv)
static int remove_branches(struct string_list *branches)
{
struct strbuf err = STRBUF_INIT;
- const char **branch_names;
int i, result = 0;
- branch_names = xmalloc(branches->nr * sizeof(*branch_names));
- for (i = 0; i < branches->nr; i++)
- branch_names[i] = branches->items[i].string;
- if (repack_without_refs(branch_names, branches->nr, &err))
+ if (repack_without_refs(branches, &err))
result |= error("%s", err.buf);
strbuf_release(&err);
- free(branch_names);
for (i = 0; i < branches->nr; i++) {
struct string_list_item *item = branches->items + i;
@@ -914,7 +911,7 @@ static int get_remote_ref_states(const char *name,
get_push_ref_states(remote_refs, states);
} else {
for_each_ref(append_ref_to_tracked_list, states);
- sort_string_list(&states->tracked);
+ string_list_sort(&states->tracked);
get_push_ref_states_noquery(states);
}
@@ -1133,7 +1130,7 @@ static int show_all(void)
if (!result) {
int i;
- sort_string_list(&list);
+ string_list_sort(&list);
for (i = 0; i < list.nr; i++) {
struct string_list_item *item = list.items + i;
if (verbose)
@@ -1314,10 +1311,10 @@ static int set_head(int argc, const char **argv)
static int prune_remote(const char *remote, int dry_run)
{
- int result = 0, i;
+ int result = 0;
struct ref_states states;
- struct string_list delete_refs_list = STRING_LIST_INIT_NODUP;
- const char **delete_refs;
+ struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
+ struct string_list_item *item;
const char *dangling_msg = dry_run
? _(" %s will become dangling!")
: _(" %s has become dangling!");
@@ -1325,30 +1322,30 @@ static int prune_remote(const char *remote, int dry_run)
memset(&states, 0, sizeof(states));
get_remote_ref_states(remote, &states, GET_REF_STATES);
- if (states.stale.nr) {
- printf_ln(_("Pruning %s"), remote);
- printf_ln(_("URL: %s"),
- states.remote->url_nr
- ? states.remote->url[0]
- : _("(no URL)"));
-
- delete_refs = xmalloc(states.stale.nr * sizeof(*delete_refs));
- for (i = 0; i < states.stale.nr; i++)
- delete_refs[i] = states.stale.items[i].util;
- if (!dry_run) {
- struct strbuf err = STRBUF_INIT;
- if (repack_without_refs(delete_refs, states.stale.nr,
- &err))
- result |= error("%s", err.buf);
- strbuf_release(&err);
- }
- free(delete_refs);
+ if (!states.stale.nr) {
+ free_remote_ref_states(&states);
+ return 0;
}
- for (i = 0; i < states.stale.nr; i++) {
- const char *refname = states.stale.items[i].util;
+ printf_ln(_("Pruning %s"), remote);
+ printf_ln(_("URL: %s"),
+ states.remote->url_nr
+ ? states.remote->url[0]
+ : _("(no URL)"));
+
+ for_each_string_list_item(item, &states.stale)
+ string_list_append(&refs_to_prune, item->util);
+ string_list_sort(&refs_to_prune);
+
+ if (!dry_run) {
+ struct strbuf err = STRBUF_INIT;
+ if (repack_without_refs(&refs_to_prune, &err))
+ result |= error("%s", err.buf);
+ strbuf_release(&err);
+ }
- string_list_insert(&delete_refs_list, refname);
+ for_each_string_list_item(item, &states.stale) {
+ const char *refname = item->util;
if (!dry_run)
result |= delete_ref(refname, NULL, 0);
@@ -1361,9 +1358,9 @@ static int prune_remote(const char *remote, int dry_run)
abbrev_ref(refname, "refs/remotes/"));
}
- warn_dangling_symrefs(stdout, dangling_msg, &delete_refs_list);
- string_list_clear(&delete_refs_list, 0);
+ warn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune);
+ string_list_clear(&refs_to_prune, 0);
free_remote_ref_states(&states);
return result;
}
diff --git a/builtin/repack.c b/builtin/repack.c
index 83e91c7382..3f852f35d1 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -376,7 +376,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (delete_redundant) {
int opts = 0;
- sort_string_list(&names);
+ string_list_sort(&names);
for_each_string_list_item(item, &existing_packs) {
char *sha1;
size_t len = strlen(item->string);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 35d3c43ed6..95328b80d9 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -279,7 +279,7 @@ static int try_difference(const char *arg)
struct commit *a, *b;
a = lookup_commit_reference(sha1);
b = lookup_commit_reference(end);
- exclude = get_merge_bases(a, b, 1);
+ exclude = get_merge_bases(a, b);
while (exclude) {
struct commit_list *n = exclude->next;
show_rev(REVERSED,
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 270e39c6c1..691eeda345 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -6,7 +6,10 @@
#include "parse-options.h"
static const char* show_branch_usage[] = {
- N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
+ N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order]\n"
+ " [--current] [--color[=<when>] | --no-color] [--sparse]\n"
+ " [--more=<n> | --list | --independent | --merge-base]\n"
+ " [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
NULL
};
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 855d94b90b..ac6667242c 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -91,7 +91,7 @@ static void use(int bytes)
static void *get_data(unsigned long size)
{
git_zstream stream;
- void *buf = xmalloc(size);
+ void *buf = xmallocz(size);
memset(&stream, 0, sizeof(stream));
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 6c9be05128..1993529521 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -282,26 +282,22 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
char *refname;
unsigned char new_sha1[20];
unsigned char old_sha1[20];
- int have_old;
refname = parse_refname(input, &next);
if (!refname)
die("verify: missing <ref>");
if (parse_next_sha1(input, &next, old_sha1, "verify", refname,
- PARSE_SHA1_OLD)) {
- hashclr(new_sha1);
- have_old = 0;
- } else {
- hashcpy(new_sha1, old_sha1);
- have_old = 1;
- }
+ PARSE_SHA1_OLD))
+ hashclr(old_sha1);
+
+ hashcpy(new_sha1, old_sha1);
if (*next != line_termination)
die("verify %s: extra input: %s", refname, next);
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
- update_flags, have_old, msg, &err))
+ update_flags, 1, msg, &err))
die("%s", err.buf);
update_flags = 0;
diff --git a/cache.h b/cache.h
index 99ed096aed..f704af5df0 100644
--- a/cache.h
+++ b/cache.h
@@ -65,13 +65,6 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long);
*
* The value 0160000 is not normally a valid mode, and
* also just happens to be S_IFDIR + S_IFLNK
- *
- * NOTE! We *really* shouldn't depend on the S_IFxxx macros
- * always having the same values everywhere. We should use
- * our internal git values for these things, and then we can
- * translate that to the OS-specific value. It just so
- * happens that everybody shares the same bit representation
- * in the UNIX world (and apparently wider too..)
*/
#define S_IFGITLINK 0160000
#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
@@ -617,6 +610,8 @@ extern int fsync_object_files;
extern int core_preload_index;
extern int core_apply_sparse_checkout;
extern int precomposed_unicode;
+extern int protect_hfs;
+extern int protect_ntfs;
/*
* The character that begins a commented line in user-editable file
@@ -831,6 +826,7 @@ int normalize_path_copy(char *dst, const char *src);
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);
+extern int is_ntfs_dotgit(const char *name);
/* object replacement */
#define LOOKUP_REPLACE_OBJECT 1
diff --git a/color.c b/color.c
index 7941e932d2..809b359a42 100644
--- a/color.c
+++ b/color.c
@@ -26,30 +26,109 @@ const char *column_colors_ansi[] = {
/* Ignore the RESET at the end when giving the size */
const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
-static int parse_color(const char *name, int len)
+/* An individual foreground or background color. */
+struct color {
+ enum {
+ COLOR_UNSPECIFIED = 0,
+ COLOR_NORMAL,
+ COLOR_ANSI, /* basic 0-7 ANSI colors */
+ COLOR_256,
+ COLOR_RGB
+ } type;
+ /* The numeric value for ANSI and 256-color modes */
+ unsigned char value;
+ /* 24-bit RGB color values */
+ unsigned char red, green, blue;
+};
+
+/*
+ * "word" is a buffer of length "len"; does it match the NUL-terminated
+ * "match" exactly?
+ */
+static int match_word(const char *word, int len, const char *match)
{
+ return !strncasecmp(word, match, len) && !match[len];
+}
+
+static int get_hex_color(const char *in, unsigned char *out)
+{
+ unsigned int val;
+ val = (hexval(in[0]) << 4) | hexval(in[1]);
+ if (val & ~0xff)
+ return -1;
+ *out = val;
+ return 0;
+}
+
+static int parse_color(struct color *out, const char *name, int len)
+{
+ /* Positions in array must match ANSI color codes */
static const char * const color_names[] = {
- "normal", "black", "red", "green", "yellow",
+ "black", "red", "green", "yellow",
"blue", "magenta", "cyan", "white"
};
char *end;
int i;
+ long val;
+
+ /* First try the special word "normal"... */
+ if (match_word(name, len, "normal")) {
+ out->type = COLOR_NORMAL;
+ return 0;
+ }
+
+ /* Try a 24-bit RGB value */
+ if (len == 7 && name[0] == '#') {
+ if (!get_hex_color(name + 1, &out->red) &&
+ !get_hex_color(name + 3, &out->green) &&
+ !get_hex_color(name + 5, &out->blue)) {
+ out->type = COLOR_RGB;
+ return 0;
+ }
+ }
+
+ /* Then pick from our human-readable color names... */
for (i = 0; i < ARRAY_SIZE(color_names); i++) {
- const char *str = color_names[i];
- if (!strncasecmp(name, str, len) && !str[len])
- return i - 1;
+ if (match_word(name, len, color_names[i])) {
+ out->type = COLOR_ANSI;
+ out->value = i;
+ return 0;
+ }
+ }
+
+ /* And finally try a literal 256-color-mode number */
+ val = strtol(name, &end, 10);
+ if (end - name == len) {
+ /*
+ * Allow "-1" as an alias for "normal", but other negative
+ * numbers are bogus.
+ */
+ if (val < -1)
+ ; /* fall through to error */
+ else if (val < 0) {
+ out->type = COLOR_NORMAL;
+ return 0;
+ /* Rewrite low numbers as more-portable standard colors. */
+ } else if (val < 8) {
+ out->type = COLOR_ANSI;
+ out->value = val;
+ } else if (val < 256) {
+ out->type = COLOR_256;
+ out->value = val;
+ return 0;
+ }
}
- i = strtol(name, &end, 10);
- if (end - name == len && i >= -1 && i <= 255)
- return i;
- return -2;
+
+ return -1;
}
static int parse_attr(const char *name, int len)
{
- static const int attr_values[] = { 1, 2, 4, 5, 7 };
+ static const int attr_values[] = { 1, 2, 4, 5, 7,
+ 22, 22, 24, 25, 27 };
static const char * const attr_names[] = {
- "bold", "dim", "ul", "blink", "reverse"
+ "bold", "dim", "ul", "blink", "reverse",
+ "nobold", "nodim", "noul", "noblink", "noreverse"
};
int i;
for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
@@ -65,13 +144,44 @@ int color_parse(const char *value, char *dst)
return color_parse_mem(value, strlen(value), dst);
}
+/*
+ * Write the ANSI color codes for "c" to "out"; the string should
+ * already have the ANSI escape code in it. "out" should have enough
+ * space in it to fit any color.
+ */
+static char *color_output(char *out, const struct color *c, char type)
+{
+ switch (c->type) {
+ case COLOR_UNSPECIFIED:
+ case COLOR_NORMAL:
+ break;
+ case COLOR_ANSI:
+ *out++ = type;
+ *out++ = '0' + c->value;
+ break;
+ case COLOR_256:
+ out += sprintf(out, "%c8;5;%d", type, c->value);
+ break;
+ case COLOR_RGB:
+ out += sprintf(out, "%c8;2;%d;%d;%d", type,
+ c->red, c->green, c->blue);
+ break;
+ }
+ return out;
+}
+
+static int color_empty(const struct color *c)
+{
+ return c->type <= COLOR_NORMAL;
+}
+
int color_parse_mem(const char *value, int value_len, char *dst)
{
const char *ptr = value;
int len = value_len;
unsigned int attr = 0;
- int fg = -2;
- int bg = -2;
+ struct color fg = { COLOR_UNSPECIFIED };
+ struct color bg = { COLOR_UNSPECIFIED };
if (!strncasecmp(value, "reset", len)) {
strcpy(dst, GIT_COLOR_RESET);
@@ -81,6 +191,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
/* [fg [bg]] [attr]... */
while (len > 0) {
const char *word = ptr;
+ struct color c;
int val, wordlen = 0;
while (len > 0 && !isspace(word[wordlen])) {
@@ -94,14 +205,13 @@ int color_parse_mem(const char *value, int value_len, char *dst)
len--;
}
- val = parse_color(word, wordlen);
- if (val >= -1) {
- if (fg == -2) {
- fg = val;
+ if (!parse_color(&c, word, wordlen)) {
+ if (fg.type == COLOR_UNSPECIFIED) {
+ fg = c;
continue;
}
- if (bg == -2) {
- bg = val;
+ if (bg.type == COLOR_UNSPECIFIED) {
+ bg = c;
continue;
}
goto bad;
@@ -113,7 +223,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
goto bad;
}
- if (attr || fg >= 0 || bg >= 0) {
+ if (attr || !color_empty(&fg) || !color_empty(&bg)) {
int sep = 0;
int i;
@@ -127,27 +237,19 @@ int color_parse_mem(const char *value, int value_len, char *dst)
attr &= ~bit;
if (sep++)
*dst++ = ';';
- *dst++ = '0' + i;
+ dst += sprintf(dst, "%d", i);
}
- if (fg >= 0) {
+ if (!color_empty(&fg)) {
if (sep++)
*dst++ = ';';
- if (fg < 8) {
- *dst++ = '3';
- *dst++ = '0' + fg;
- } else {
- dst += sprintf(dst, "38;5;%d", fg);
- }
+ /* foreground colors are all in the 3x range */
+ dst = color_output(dst, &fg, '3');
}
- if (bg >= 0) {
+ if (!color_empty(&bg)) {
if (sep++)
*dst++ = ';';
- if (bg < 8) {
- *dst++ = '4';
- *dst++ = '0' + bg;
- } else {
- dst += sprintf(dst, "48;5;%d", bg);
- }
+ /* background colors are all in the 4x range */
+ dst = color_output(dst, &bg, '4');
}
*dst++ = 'm';
}
diff --git a/color.h b/color.h
index f5beab1ed7..7fe77fb55e 100644
--- a/color.h
+++ b/color.h
@@ -8,15 +8,15 @@ struct strbuf;
/*
* The maximum length of ANSI color sequence we would generate:
* - leading ESC '[' 2
- * - attr + ';' 2 * 8 (e.g. "1;")
- * - fg color + ';' 9 (e.g. "38;5;2xx;")
- * - fg color + ';' 9 (e.g. "48;5;2xx;")
+ * - attr + ';' 3 * 10 (e.g. "1;")
+ * - fg color + ';' 17 (e.g. "38;2;255;255;255;")
+ * - bg color + ';' 17 (e.g. "48;2;255;255;255;")
* - terminating 'm' NUL 2
*
* The above overcounts attr (we only use 5 not 8) and one semicolon
* but it is close enough.
*/
-#define COLOR_MAXLEN 40
+#define COLOR_MAXLEN 70
/*
* IMPORTANT: Due to the way these color codes are emulated on Windows,
diff --git a/commit.c b/commit.c
index 19cf8f9c67..a8c7577d28 100644
--- a/commit.c
+++ b/commit.c
@@ -867,7 +867,7 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
for (j = ret; j; j = j->next) {
struct commit_list *bases;
- bases = get_merge_bases(i->item, j->item, 1);
+ bases = get_merge_bases(i->item, j->item);
if (!new)
new = bases;
else
@@ -936,10 +936,10 @@ static int remove_redundant(struct commit **array, int cnt)
return filled;
}
-struct commit_list *get_merge_bases_many(struct commit *one,
- int n,
- struct commit **twos,
- int cleanup)
+static struct commit_list *get_merge_bases_many_0(struct commit *one,
+ int n,
+ struct commit **twos,
+ int cleanup)
{
struct commit_list *list;
struct commit **rslt;
@@ -977,10 +977,23 @@ struct commit_list *get_merge_bases_many(struct commit *one,
return result;
}
-struct commit_list *get_merge_bases(struct commit *one, struct commit *two,
- int cleanup)
+struct commit_list *get_merge_bases_many(struct commit *one,
+ int n,
+ struct commit **twos)
{
- return get_merge_bases_many(one, 1, &two, cleanup);
+ return get_merge_bases_many_0(one, n, twos, 1);
+}
+
+struct commit_list *get_merge_bases_many_dirty(struct commit *one,
+ int n,
+ struct commit **twos)
+{
+ return get_merge_bases_many_0(one, n, twos, 0);
+}
+
+struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
+{
+ return get_merge_bases_many_0(one, 1, &two, 1);
}
/*
@@ -1640,3 +1653,49 @@ const char *find_commit_header(const char *msg, const char *key, size_t *out_len
}
return NULL;
}
+
+/*
+ * Inspect sb and determine the true "end" of the log message, in
+ * order to find where to put a new Signed-off-by: line. Ignored are
+ * trailing comment lines and blank lines, and also the traditional
+ * "Conflicts:" block that is not commented out, so that we can use
+ * "git commit -s --amend" on an existing commit that forgot to remove
+ * it.
+ *
+ * Returns the number of bytes from the tail to ignore, to be fed as
+ * the second parameter to append_signoff().
+ */
+int ignore_non_trailer(struct strbuf *sb)
+{
+ int boc = 0;
+ int bol = 0;
+ int in_old_conflicts_block = 0;
+
+ while (bol < sb->len) {
+ char *next_line;
+
+ if (!(next_line = memchr(sb->buf + bol, '\n', sb->len - bol)))
+ next_line = sb->buf + sb->len;
+ else
+ next_line++;
+
+ if (sb->buf[bol] == comment_line_char || sb->buf[bol] == '\n') {
+ /* is this the first of the run of comments? */
+ if (!boc)
+ boc = bol;
+ /* otherwise, it is just continuing */
+ } else if (starts_with(sb->buf + bol, "Conflicts:\n")) {
+ in_old_conflicts_block = 1;
+ if (!boc)
+ boc = bol;
+ } else if (in_old_conflicts_block && sb->buf[bol] == '\t') {
+ ; /* a pathname in the conflicts block */
+ } else if (boc) {
+ /* the previous was not trailing comment */
+ boc = 0;
+ in_old_conflicts_block = 0;
+ }
+ bol = next_line - sb->buf;
+ }
+ return boc ? sb->len - boc : 0;
+}
diff --git a/commit.h b/commit.h
index bc68ccbe69..5cc1e7ec9e 100644
--- a/commit.h
+++ b/commit.h
@@ -236,10 +236,13 @@ struct commit_graft *read_graft_line(char *buf, int len);
int register_commit_graft(struct commit_graft *, int);
struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
-extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
-extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);
+extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2);
+extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos);
extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
+/* To be used only when object flags after this call no longer matter */
+extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
+
/* largest positive number a signed 32-bit integer can contain */
#define INFINITE_DEPTH 0x7fffffff
@@ -337,6 +340,9 @@ extern void free_commit_extra_headers(struct commit_extra_header *extra);
extern const char *find_commit_header(const char *msg, const char *key,
size_t *out_len);
+/* Find the end of the log message, the right place for a new trailer. */
+extern int ignore_non_trailer(struct strbuf *sb);
+
typedef void (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra,
void *cb_data);
diff --git a/compat/stat.c b/compat/stat.c
new file mode 100644
index 0000000000..a2d3931cb7
--- /dev/null
+++ b/compat/stat.c
@@ -0,0 +1,48 @@
+#define _POSIX_C_SOURCE 200112L
+#include <sys/stat.h> /* *stat, S_IS* */
+#include <sys/types.h> /* mode_t */
+
+static inline mode_t mode_native_to_git(mode_t native_mode)
+{
+ mode_t perm_bits = native_mode & 07777;
+ if (S_ISREG(native_mode))
+ return 0100000 | perm_bits;
+ if (S_ISDIR(native_mode))
+ return 0040000 | perm_bits;
+ if (S_ISLNK(native_mode))
+ return 0120000 | perm_bits;
+ if (S_ISBLK(native_mode))
+ return 0060000 | perm_bits;
+ if (S_ISCHR(native_mode))
+ return 0020000 | perm_bits;
+ if (S_ISFIFO(native_mode))
+ return 0010000 | perm_bits;
+ if (S_ISSOCK(native_mode))
+ return 0140000 | perm_bits;
+ /* Non-standard type bits were given. */
+ return perm_bits;
+}
+
+int git_stat(const char *path, struct stat *buf)
+{
+ int rc = stat(path, buf);
+ if (rc == 0)
+ buf->st_mode = mode_native_to_git(buf->st_mode);
+ return rc;
+}
+
+int git_fstat(int fd, struct stat *buf)
+{
+ int rc = fstat(fd, buf);
+ if (rc == 0)
+ buf->st_mode = mode_native_to_git(buf->st_mode);
+ return rc;
+}
+
+int git_lstat(const char *path, struct stat *buf)
+{
+ int rc = lstat(path, buf);
+ if (rc == 0)
+ buf->st_mode = mode_native_to_git(buf->st_mode);
+ return rc;
+}
diff --git a/config.c b/config.c
index ae1398f4f4..752e2e227f 100644
--- a/config.c
+++ b/config.c
@@ -896,6 +896,16 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.protecthfs")) {
+ protect_hfs = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.protectntfs")) {
+ protect_ntfs = git_config_bool(var, value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
diff --git a/config.mak.uname b/config.mak.uname
index a2f380fd8d..b64b63c34c 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -35,6 +35,7 @@ ifeq ($(uname_S),Linux)
LIBC_CONTAINS_LIBINTL = YesPlease
HAVE_DEV_TTY = YesPlease
HAVE_CLOCK_GETTIME = YesPlease
+ HAVE_CLOCK_MONOTONIC = YesPlease
endif
ifeq ($(uname_S),GNU/kFreeBSD)
HAVE_ALLOCA_H = YesPlease
@@ -105,6 +106,7 @@ ifeq ($(uname_S),Darwin)
HAVE_DEV_TTY = YesPlease
COMPAT_OBJS += compat/precompose_utf8.o
BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
+ BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
@@ -373,6 +375,7 @@ ifeq ($(uname_S),Windows)
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib invalidcontinue.obj
PTHREAD_LIBS =
lib =
+ BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
ifndef DEBUG
BASIC_CFLAGS += -GL -Os -MD
BASIC_LDFLAGS += -LTCG
@@ -514,6 +517,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
compat/win32/dirent.o
+ BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
BASIC_LDFLAGS += -Wl,--large-address-aware
EXTLIBS += -lws2_32
GITLIBS += git.res
diff --git a/configure.ac b/configure.ac
index 6af964797f..55e5a9b3e6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -754,6 +754,19 @@ AC_CHECK_TYPES([struct itimerval],
[#include <sys/time.h>])
GIT_CONF_SUBST([NO_STRUCT_ITIMERVAL])
#
+# Define USE_ST_TIMESPEC=YesPlease when stat.st_mtimespec.tv_nsec exists.
+# Define NO_NSEC=YesPlease when neither stat.st_mtim.tv_nsec nor
+# stat.st_mtimespec.tv_nsec exists.
+AC_CHECK_MEMBER([struct stat.st_mtimespec.tv_nsec])
+AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec])
+if test x$ac_cv_member_struct_stat_st_mtimespec_tv_nsec = xyes; then
+ USE_ST_TIMESPEC=YesPlease
+ GIT_CONF_SUBST([USE_ST_TIMESPEC])
+elif test x$ac_cv_member_struct_stat_st_mtim_tv_nsec != xyes; then
+ NO_NSEC=YesPlease
+ GIT_CONF_SUBST([NO_NSEC])
+fi
+#
# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
AC_CHECK_MEMBER(struct dirent.d_ino,
[NO_D_INO_IN_DIRENT=],
@@ -873,6 +886,29 @@ else
SNPRINTF_RETURNS_BOGUS=
fi
GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS])
+#
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values.
+AC_CACHE_CHECK([whether the platform uses typical file type bits],
+ [ac_cv_sane_mode_bits], [
+AC_EGREP_CPP(yippeeyeswehaveit,
+ AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+[#if S_IFMT == 0170000 && \
+ S_IFREG == 0100000 && S_IFDIR == 0040000 && S_IFLNK == 0120000 && \
+ S_IFBLK == 0060000 && S_IFCHR == 0020000 && \
+ S_IFIFO == 0010000 && S_IFSOCK == 0140000
+yippeeyeswehaveit
+#endif
+]),
+ [ac_cv_sane_mode_bits=yes],
+ [ac_cv_sane_mode_bits=no])
+])
+if test $ac_cv_sane_mode_bits = yes; then
+ NEEDS_MODE_TRANSLATION=
+else
+ NEEDS_MODE_TRANSLATION=UnfortunatelyYes
+fi
+GIT_CONF_SUBST([NEEDS_MODE_TRANSLATION])
## Checks for library functions.
@@ -911,6 +947,32 @@ AC_CHECK_LIB([iconv], [locale_charset],
[CHARSET_LIB=-lcharset])])
GIT_CONF_SUBST([CHARSET_LIB])
#
+# Define NO_HMAC_CTX_CLEANUP=YesPlease if HMAC_CTX_cleanup is missing.
+AC_CHECK_LIB([crypto], [HMAC_CTX_cleanup],
+ [], [GIT_CONF_SUBST([NO_HMAC_CTX_CLEANUP], [YesPlease])])
+#
+# Define HAVE_CLOCK_GETTIME=YesPlease if clock_gettime is available.
+GIT_CHECK_FUNC(clock_gettime,
+ [HAVE_CLOCK_GETTIME=YesPlease],
+ [HAVE_CLOCK_GETTIME=])
+GIT_CONF_SUBST([HAVE_CLOCK_GETTIME])
+
+AC_DEFUN([CLOCK_MONOTONIC_SRC], [
+AC_LANG_PROGRAM([[
+#include <time.h>
+clockid_t id = CLOCK_MONOTONIC;
+]])])
+
+#
+# Define HAVE_CLOCK_MONOTONIC=YesPlease if CLOCK_MONOTONIC is available.
+AC_MSG_CHECKING([for CLOCK_MONOTONIC])
+AC_COMPILE_IFELSE([CLOCK_MONOTONIC_SRC],
+ [AC_MSG_RESULT([yes])
+ HAVE_CLOCK_MONOTONIC=YesPlease],
+ [AC_MSG_RESULT([no])
+ HAVE_CLOCK_MONOTONIC=])
+GIT_CONF_SUBST([HAVE_CLOCK_MONOTONIC])
+#
# Define NO_SETITIMER if you don't have setitimer.
GIT_CHECK_FUNC(setitimer,
[NO_SETITIMER=],
diff --git a/connect.c b/connect.c
index cb23bbcf22..062e133aa3 100644
--- a/connect.c
+++ b/connect.c
@@ -93,7 +93,7 @@ static void annotate_refs_with_symref_info(struct ref *ref)
parse_one_symref_info(&symref, val, len);
feature_list = val + 1;
}
- sort_string_list(&symref);
+ string_list_sort(&symref);
for (; ref; ref = ref->next) {
struct string_list_item *item;
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 2fece98c60..8cfee95f88 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -16,9 +16,9 @@
#
# To use these routines:
#
-# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
+# 1) Copy this file to somewhere (e.g. ~/.git-completion.bash).
# 2) Add the following line to your .bashrc/.zshrc:
-# source ~/.git-completion.sh
+# source ~/.git-completion.bash
# 3) Consider changing your PS1 to also show the current branch,
# see git-prompt.sh for details.
#
@@ -1693,6 +1693,7 @@ _git_rebase ()
--committer-date-is-author-date --ignore-date
--ignore-whitespace --whitespace=
--autosquash --fork-point --no-fork-point
+ --autostash
"
return
@@ -1875,6 +1876,10 @@ _git_config ()
__gitcomp "$__git_send_email_suppresscc_options"
return
;;
+ sendemail.transferencoding)
+ __gitcomp "7bit 8bit quoted-printable base64"
+ return
+ ;;
--get|--get-all|--unset|--unset-all)
__gitcomp_nl "$(__git_config_get_set_variables)"
return
@@ -2548,6 +2553,16 @@ _git_tag ()
__gitcomp_nl "$(__git_refs)"
;;
esac
+
+ case "$cur" in
+ --*)
+ __gitcomp "
+ --list --delete --verify --annotate --message --file
+ --sign --cleanup --local-user --force --column --sort
+ --contains --points-at
+ "
+ ;;
+ esac
}
_git_whatchanged ()
diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index 9f6f0fa558..e25541308a 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -9,7 +9,7 @@
#
# If your script is somewhere else, you can configure it on your ~/.zshrc:
#
-# zstyle ':completion:*:*:git:*' script ~/.git-completion.sh
+# zstyle ':completion:*:*:git:*' script ~/.git-completion.zsh
#
# The recommended way to install this script is to copy to '~/.zsh/_git', and
# then add the following to your ~/.zshrc file:
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index c5473dc8db..214e859f99 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -84,6 +84,11 @@
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
# the colored output of "git status -sb" and are available only when
# using __git_ps1 for PROMPT_COMMAND or precmd.
+#
+# If you would like __git_ps1 to do nothing in the case when the current
+# directory is set up to be ignored by git, then set
+# GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the
+# repository level by setting bash.hideIfPwdIgnored to "false".
# check whether printf supports -v
__git_printf_supports_v=
@@ -270,7 +275,7 @@ __git_ps1_colorize_gitstring ()
__git_eread ()
{
- f="$1"
+ local f="$1"
shift
test -r "$f" && read "$@" <"$f"
}
@@ -288,6 +293,8 @@ __git_eread ()
# In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
__git_ps1 ()
{
+ # preserve exit status
+ local exit=$?
local pcmode=no
local detached=no
local ps1pc_start='\u@\h:\w '
@@ -299,10 +306,14 @@ __git_ps1 ()
ps1pc_start="$1"
ps1pc_end="$2"
printf_format="${3:-$printf_format}"
+ # set PS1 to a plain prompt so that we can
+ # simply return early if the prompt should not
+ # be decorated
+ PS1="$ps1pc_start$ps1pc_end"
;;
0|1) printf_format="${1:-$printf_format}"
;;
- *) return
+ *) return $exit
;;
esac
@@ -350,11 +361,7 @@ __git_ps1 ()
rev_parse_exit_code="$?"
if [ -z "$repo_info" ]; then
- if [ $pcmode = yes ]; then
- #In PC mode PS1 always needs to be set
- PS1="$ps1pc_start$ps1pc_end"
- fi
- return
+ return $exit
fi
local short_sha
@@ -369,6 +376,14 @@ __git_ps1 ()
local inside_gitdir="${repo_info##*$'\n'}"
local g="${repo_info%$'\n'*}"
+ if [ "true" = "$inside_worktree" ] &&
+ [ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] &&
+ [ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] &&
+ git check-ignore -q .
+ then
+ return $exit
+ fi
+
local r=""
local b=""
local step=""
@@ -412,10 +427,7 @@ __git_ps1 ()
else
local head=""
if ! __git_eread "$g/HEAD" head; then
- if [ $pcmode = yes ]; then
- PS1="$ps1pc_start$ps1pc_end"
- fi
- return
+ return $exit
fi
# is it a symbolic ref?
b="${head#ref: }"
@@ -511,4 +523,6 @@ __git_ps1 ()
else
printf -- "$printf_format" "$gitstring"
fi
+
+ return $exit
}
diff --git a/contrib/diff-highlight/README b/contrib/diff-highlight/README
index 502e03b305..836b97a730 100644
--- a/contrib/diff-highlight/README
+++ b/contrib/diff-highlight/README
@@ -58,6 +58,47 @@ following in your git configuration:
diff = diff-highlight | less
---------------------------------------------
+
+Color Config
+------------
+
+You can configure the highlight colors and attributes using git's
+config. The colors for "old" and "new" lines can be specified
+independently. There are two "modes" of configuration:
+
+ 1. You can specify a "highlight" color and a matching "reset" color.
+ This will retain any existing colors in the diff, and apply the
+ "highlight" and "reset" colors before and after the highlighted
+ portion.
+
+ 2. You can specify a "normal" color and a "highlight" color. In this
+ case, existing colors are dropped from that line. The non-highlighted
+ bits of the line get the "normal" color, and the highlights get the
+ "highlight" color.
+
+If no "new" colors are specified, they default to the "old" colors. If
+no "old" colors are specified, the default is to reverse the foreground
+and background for highlighted portions.
+
+Examples:
+
+---------------------------------------------
+# Underline highlighted portions
+[color "diff-highlight"]
+oldHighlight = ul
+oldReset = noul
+---------------------------------------------
+
+---------------------------------------------
+# Varying background intensities
+[color "diff-highlight"]
+oldNormal = "black #f8cbcb"
+oldHighlight = "black #ffaaaa"
+newNormal = "black #cbeecb"
+newHighlight = "black #aaffaa"
+---------------------------------------------
+
+
Bugs
----
diff --git a/contrib/diff-highlight/diff-highlight b/contrib/diff-highlight/diff-highlight
index 69a652e7b2..08c88bbc87 100755
--- a/contrib/diff-highlight/diff-highlight
+++ b/contrib/diff-highlight/diff-highlight
@@ -5,8 +5,18 @@ use strict;
# Highlight by reversing foreground and background. You could do
# other things like bold or underline if you prefer.
-my $HIGHLIGHT = "\x1b[7m";
-my $UNHIGHLIGHT = "\x1b[27m";
+my @OLD_HIGHLIGHT = (
+ color_config('color.diff-highlight.oldnormal'),
+ color_config('color.diff-highlight.oldhighlight', "\x1b[7m"),
+ color_config('color.diff-highlight.oldreset', "\x1b[27m")
+);
+my @NEW_HIGHLIGHT = (
+ color_config('color.diff-highlight.newnormal', $OLD_HIGHLIGHT[0]),
+ color_config('color.diff-highlight.newhighlight', $OLD_HIGHLIGHT[1]),
+ color_config('color.diff-highlight.newreset', $OLD_HIGHLIGHT[2])
+);
+
+my $RESET = "\x1b[m";
my $COLOR = qr/\x1b\[[0-9;]*m/;
my $BORING = qr/$COLOR|\s/;
@@ -57,6 +67,17 @@ show_hunk(\@removed, \@added);
exit 0;
+# Ideally we would feed the default as a human-readable color to
+# git-config as the fallback value. But diff-highlight does
+# not otherwise depend on git at all, and there are reports
+# of it being used in other settings. Let's handle our own
+# fallback, which means we will work even if git can't be run.
+sub color_config {
+ my ($key, $default) = @_;
+ my $s = `git config --get-color $key 2>/dev/null`;
+ return length($s) ? $s : $default;
+}
+
sub show_hunk {
my ($a, $b) = @_;
@@ -132,8 +153,8 @@ sub highlight_pair {
}
if (is_pair_interesting(\@a, $pa, $sa, \@b, $pb, $sb)) {
- return highlight_line(\@a, $pa, $sa),
- highlight_line(\@b, $pb, $sb);
+ return highlight_line(\@a, $pa, $sa, \@OLD_HIGHLIGHT),
+ highlight_line(\@b, $pb, $sb, \@NEW_HIGHLIGHT);
}
else {
return join('', @a),
@@ -148,15 +169,30 @@ sub split_line {
}
sub highlight_line {
- my ($line, $prefix, $suffix) = @_;
-
- return join('',
- @{$line}[0..($prefix-1)],
- $HIGHLIGHT,
- @{$line}[$prefix..$suffix],
- $UNHIGHLIGHT,
- @{$line}[($suffix+1)..$#$line]
- );
+ my ($line, $prefix, $suffix, $theme) = @_;
+
+ my $start = join('', @{$line}[0..($prefix-1)]);
+ my $mid = join('', @{$line}[$prefix..$suffix]);
+ my $end = join('', @{$line}[($suffix+1)..$#$line]);
+
+ # If we have a "normal" color specified, then take over the whole line.
+ # Otherwise, we try to just manipulate the highlighted bits.
+ if (defined $theme->[0]) {
+ s/$COLOR//g for ($start, $mid, $end);
+ chomp $end;
+ return join('',
+ $theme->[0], $start, $RESET,
+ $theme->[1], $mid, $RESET,
+ $theme->[0], $end, $RESET,
+ "\n"
+ );
+ } else {
+ return join('',
+ $start,
+ $theme->[1], $mid, $theme->[2],
+ $end
+ );
+ }
}
# Pairs are interesting to highlight only if we are going to end up
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 8272100ff5..54e4b4a243 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -81,12 +81,11 @@ merge::
changes into the latest <commit>. With '--squash',
creates only one commit that contains all the changes,
rather than merging in the entire history.
-
- If you use '--squash', the merge direction doesn't
- always have to be forward; you can use this command to
- go back in time from v2.5 to v2.4, for example. If your
- merge introduces a conflict, you can resolve it in the
- usual ways.
++
+If you use '--squash', the merge direction doesn't always have to be
+forward; you can use this command to go back in time from v2.5 to v2.4,
+for example. If your merge introduces a conflict, you can resolve it in
+the usual ways.
pull::
Exactly like 'merge', but parallels 'git pull' in that
@@ -107,21 +106,19 @@ split::
contents of <prefix> at the root of the project instead
of in a subdirectory. Thus, the newly created history
is suitable for export as a separate git repository.
-
- After splitting successfully, a single commit id is
- printed to stdout. This corresponds to the HEAD of the
- newly created tree, which you can manipulate however you
- want.
-
- Repeated splits of exactly the same history are
- guaranteed to be identical (i.e. to produce the same
- commit ids). Because of this, if you add new commits
- and then re-split, the new commits will be attached as
- commits on top of the history you generated last time,
- so 'git merge' and friends will work as expected.
-
- Note that if you use '--squash' when you merge, you
- should usually not just '--rejoin' when you split.
++
+After splitting successfully, a single commit id is printed to stdout.
+This corresponds to the HEAD of the newly created tree, which you can
+manipulate however you want.
++
+Repeated splits of exactly the same history are guaranteed to be
+identical (i.e. to produce the same commit ids). Because of this, if
+you add new commits and then re-split, the new commits will be attached
+as commits on top of the history you generated last time, so 'git merge'
+and friends will work as expected.
++
+Note that if you use '--squash' when you merge, you should usually not
+just '--rejoin' when you split.
OPTIONS
@@ -151,109 +148,96 @@ OPTIONS FOR add, merge, push, pull
--squash::
This option is only valid for add, merge, push and pull
commands.
-
- Instead of merging the entire history from the subtree
- project, produce only a single commit that contains all
- the differences you want to merge, and then merge that
- new commit into your project.
-
- Using this option helps to reduce log clutter. People
- rarely want to see every change that happened between
- v1.0 and v1.1 of the library they're using, since none of the
- interim versions were ever included in their application.
-
- Using '--squash' also helps avoid problems when the same
- subproject is included multiple times in the same
- project, or is removed and then re-added. In such a
- case, it doesn't make sense to combine the histories
- anyway, since it's unclear which part of the history
- belongs to which subtree.
-
- Furthermore, with '--squash', you can switch back and
- forth between different versions of a subtree, rather
- than strictly forward. 'git subtree merge --squash'
- always adjusts the subtree to match the exactly
- specified commit, even if getting to that commit would
- require undoing some changes that were added earlier.
-
- Whether or not you use '--squash', changes made in your
- local repository remain intact and can be later split
- and send upstream to the subproject.
++
+Instead of merging the entire history from the subtree project, produce
+only a single commit that contains all the differences you want to
+merge, and then merge that new commit into your project.
++
+Using this option helps to reduce log clutter. People rarely want to see
+every change that happened between v1.0 and v1.1 of the library they're
+using, since none of the interim versions were ever included in their
+application.
++
+Using '--squash' also helps avoid problems when the same subproject is
+included multiple times in the same project, or is removed and then
+re-added. In such a case, it doesn't make sense to combine the
+histories anyway, since it's unclear which part of the history belongs
+to which subtree.
++
+Furthermore, with '--squash', you can switch back and forth between
+different versions of a subtree, rather than strictly forward. 'git
+subtree merge --squash' always adjusts the subtree to match the exactly
+specified commit, even if getting to that commit would require undoing
+some changes that were added earlier.
++
+Whether or not you use '--squash', changes made in your local repository
+remain intact and can be later split and send upstream to the
+subproject.
OPTIONS FOR split
-----------------
--annotate=<annotation>::
This option is only valid for the split command.
-
- When generating synthetic history, add <annotation> as a
- prefix to each commit message. Since we're creating new
- commits with the same commit message, but possibly
- different content, from the original commits, this can help
- to differentiate them and avoid confusion.
-
- Whenever you split, you need to use the same
- <annotation>, or else you don't have a guarantee that
- the new re-created history will be identical to the old
- one. That will prevent merging from working correctly.
- git subtree tries to make it work anyway, particularly
- if you use --rejoin, but it may not always be effective.
++
+When generating synthetic history, add <annotation> as a prefix to each
+commit message. Since we're creating new commits with the same commit
+message, but possibly different content, from the original commits, this
+can help to differentiate them and avoid confusion.
++
+Whenever you split, you need to use the same <annotation>, or else you
+don't have a guarantee that the new re-created history will be identical
+to the old one. That will prevent merging from working correctly. git
+subtree tries to make it work anyway, particularly if you use --rejoin,
+but it may not always be effective.
-b <branch>::
--branch=<branch>::
This option is only valid for the split command.
-
- After generating the synthetic history, create a new
- branch called <branch> that contains the new history.
- This is suitable for immediate pushing upstream.
- <branch> must not already exist.
++
+After generating the synthetic history, create a new branch called
+<branch> that contains the new history. This is suitable for immediate
+pushing upstream. <branch> must not already exist.
--ignore-joins::
This option is only valid for the split command.
-
- If you use '--rejoin', git subtree attempts to optimize
- its history reconstruction to generate only the new
- commits since the last '--rejoin'. '--ignore-join'
- disables this behaviour, forcing it to regenerate the
- entire history. In a large project, this can take a
- long time.
++
+If you use '--rejoin', git subtree attempts to optimize its history
+reconstruction to generate only the new commits since the last
+'--rejoin'. '--ignore-join' disables this behaviour, forcing it to
+regenerate the entire history. In a large project, this can take a long
+time.
--onto=<onto>::
This option is only valid for the split command.
-
- If your subtree was originally imported using something
- other than git subtree, its history may not match what
- git subtree is expecting. In that case, you can specify
- the commit id <onto> that corresponds to the first
- revision of the subproject's history that was imported
- into your project, and git subtree will attempt to build
- its history from there.
-
- If you used 'git subtree add', you should never need
- this option.
++
+If your subtree was originally imported using something other than git
+subtree, its history may not match what git subtree is expecting. In
+that case, you can specify the commit id <onto> that corresponds to the
+first revision of the subproject's history that was imported into your
+project, and git subtree will attempt to build its history from there.
++
+If you used 'git subtree add', you should never need this option.
--rejoin::
This option is only valid for the split command.
-
- After splitting, merge the newly created synthetic
- history back into your main project. That way, future
- splits can search only the part of history that has
- been added since the most recent --rejoin.
-
- If your split commits end up merged into the upstream
- subproject, and then you want to get the latest upstream
- version, this will allow git's merge algorithm to more
- intelligently avoid conflicts (since it knows these
- synthetic commits are already part of the upstream
- repository).
-
- Unfortunately, using this option results in 'git log'
- showing an extra copy of every new commit that was
- created (the original, and the synthetic one).
-
- If you do all your merges with '--squash', don't use
- '--rejoin' when you split, because you don't want the
- subproject's history to be part of your project anyway.
++
+After splitting, merge the newly created synthetic history back into
+your main project. That way, future splits can search only the part of
+history that has been added since the most recent --rejoin.
++
+If your split commits end up merged into the upstream subproject, and
+then you want to get the latest upstream version, this will allow git's
+merge algorithm to more intelligently avoid conflicts (since it knows
+these synthetic commits are already part of the upstream repository).
++
+Unfortunately, using this option results in 'git log' showing an extra
+copy of every new commit that was created (the original, and the
+synthetic one).
++
+If you do all your merges with '--squash', don't use '--rejoin' when you
+split, because you don't want the subproject's history to be part of
+your project anyway.
EXAMPLE 1. Add command
diff --git a/contrib/workdir/git-new-workdir b/contrib/workdir/git-new-workdir
index 75e8b25817..888c34a521 100755
--- a/contrib/workdir/git-new-workdir
+++ b/contrib/workdir/git-new-workdir
@@ -10,6 +10,10 @@ die () {
exit 128
}
+failed () {
+ die "unable to create new workdir '$new_workdir'!"
+}
+
if test $# -lt 2 || test $# -gt 3
then
usage "$0 <repository> <new_workdir> [<branch>]"
@@ -35,7 +39,7 @@ esac
# don't link to a configured bare repository
isbare=$(git --git-dir="$git_dir" config --bool --get core.bare)
-if test ztrue = z$isbare
+if test ztrue = "z$isbare"
then
die "\"$git_dir\" has core.bare set to true," \
" remove from \"$git_dir/config\" to use $0"
@@ -48,35 +52,54 @@ then
"a complete repository."
fi
-# don't recreate a workdir over an existing repository
-if test -e "$new_workdir"
+# make sure the links in the workdir have full paths to the original repo
+git_dir=$(cd "$git_dir" && pwd) || exit 1
+
+# don't recreate a workdir over an existing directory, unless it's empty
+if test -d "$new_workdir"
then
- die "destination directory '$new_workdir' already exists."
+ if test $(ls -a1 "$new_workdir/." | wc -l) -ne 2
+ then
+ die "destination directory '$new_workdir' is not empty."
+ fi
+ cleandir="$new_workdir/.git"
+else
+ cleandir="$new_workdir"
fi
-# make sure the links use full paths
-git_dir=$(cd "$git_dir"; pwd)
+mkdir -p "$new_workdir/.git" || failed
+cleandir=$(cd "$cleandir" && pwd) || failed
-# create the workdir
-mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"
+cleanup () {
+ rm -rf "$cleandir"
+}
+siglist="0 1 2 15"
+trap cleanup $siglist
# create the links to the original repo. explicitly exclude index, HEAD and
# logs/HEAD from the list since they are purely related to the current working
# directory, and should not be shared.
for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn
do
+ # create a containing directory if needed
case $x in
*/*)
- mkdir -p "$(dirname "$new_workdir/.git/$x")"
+ mkdir -p "$new_workdir/.git/${x%/*}"
;;
esac
- ln -s "$git_dir/$x" "$new_workdir/.git/$x"
+
+ ln -s "$git_dir/$x" "$new_workdir/.git/$x" || failed
done
-# now setup the workdir
-cd "$new_workdir"
+# commands below this are run in the context of the new workdir
+cd "$new_workdir" || failed
+
# copy the HEAD from the original repository as a default branch
-cp "$git_dir/HEAD" .git/HEAD
-# checkout the branch (either the same as HEAD from the original repository, or
-# the one that was asked for)
+cp "$git_dir/HEAD" .git/HEAD || failed
+
+# the workdir is set up. if the checkout fails, the user can fix it.
+trap - $siglist
+
+# checkout the branch (either the same as HEAD from the original repository,
+# or the one that was asked for)
git checkout -f $branch
diff --git a/credential.c b/credential.c
index 1886ea50b3..b146ad8481 100644
--- a/credential.c
+++ b/credential.c
@@ -173,6 +173,8 @@ int credential_read(struct credential *c, FILE *fp)
c->path = xstrdup(value);
} else if (!strcmp(key, "url")) {
credential_from_url(c, value);
+ } else if (!strcmp(key, "quit")) {
+ c->quit = !!git_config_bool("quit", value);
}
/*
* Ignore other lines; we don't know what they mean, but
@@ -274,6 +276,9 @@ void credential_fill(struct credential *c)
credential_do(c, c->helpers.items[i].string, "get");
if (c->username && c->password)
return;
+ if (c->quit)
+ die("credential helper '%s' told us to quit",
+ c->helpers.items[i].string);
}
credential_getpass(c);
diff --git a/credential.h b/credential.h
index 0c3e85e8e4..6b0cd16be2 100644
--- a/credential.h
+++ b/credential.h
@@ -7,6 +7,7 @@ struct credential {
struct string_list helpers;
unsigned approved:1,
configured:1,
+ quit:1,
use_http_path:1;
char *username;
diff --git a/date.c b/date.c
index 59dfe579c6..3eba2dfe88 100644
--- a/date.c
+++ b/date.c
@@ -405,9 +405,9 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
return 0;
}
-static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
+static int match_multi_number(unsigned long num, char c, const char *date,
+ char *end, struct tm *tm, time_t now)
{
- time_t now;
struct tm now_tm;
struct tm *refuse_future;
long num2, num3;
@@ -433,17 +433,18 @@ static int match_multi_number(unsigned long num, char c, const char *date, char
case '-':
case '/':
case '.':
- now = time(NULL);
+ if (!now)
+ now = time(NULL);
refuse_future = NULL;
if (gmtime_r(&now, &now_tm))
refuse_future = &now_tm;
if (num > 70) {
/* yyyy-mm-dd? */
- if (is_date(num, num2, num3, refuse_future, now, tm))
+ if (is_date(num, num2, num3, NULL, now, tm))
break;
/* yyyy-dd-mm? */
- if (is_date(num, num3, num2, refuse_future, now, tm))
+ if (is_date(num, num3, num2, NULL, now, tm))
break;
}
/* Our eastern European friends say dd.mm.yy[yy]
@@ -513,7 +514,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
case '/':
case '-':
if (isdigit(end[1])) {
- int match = match_multi_number(num, *end, date, end, tm);
+ int match = match_multi_number(num, *end, date, end, tm, 0);
if (match)
return match;
}
@@ -1013,7 +1014,8 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
return end;
}
-static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
+static const char *approxidate_digit(const char *date, struct tm *tm, int *num,
+ time_t now)
{
char *end;
unsigned long number = strtoul(date, &end, 10);
@@ -1024,7 +1026,8 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
case '/':
case '-':
if (isdigit(end[1])) {
- int match = match_multi_number(number, *end, date, end, tm);
+ int match = match_multi_number(number, *end, date, end,
+ tm, now);
if (match)
return date + match;
}
@@ -1087,7 +1090,7 @@ static unsigned long approxidate_str(const char *date,
date++;
if (isdigit(c)) {
pending_number(&tm, &number);
- date = approxidate_digit(date-1, &tm, &number);
+ date = approxidate_digit(date-1, &tm, &number, time_sec);
touched = 1;
continue;
}
diff --git a/diffcore-break.c b/diffcore-break.c
index 1d9e530a84..5473493e10 100644
--- a/diffcore-break.c
+++ b/diffcore-break.c
@@ -246,6 +246,13 @@ static void merge_broken(struct diff_filepair *p,
dp = diff_queue(outq, d->one, c->two);
dp->score = p->score;
+ /*
+ * We will be one extra user of the same src side of the
+ * broken pair, if it was used as the rename source for other
+ * paths elsewhere. Increment to mark that the path stays
+ * in the resulting tree.
+ */
+ d->one->rename_used++;
diff_free_filespec_data(d->two);
diff_free_filespec_data(c->one);
free(d);
diff --git a/environment.c b/environment.c
index 565f65293b..1ade5c9684 100644
--- a/environment.c
+++ b/environment.c
@@ -64,6 +64,16 @@ int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
struct startup_info *startup_info;
unsigned long pack_size_limit_cfg;
+#ifndef PROTECT_HFS_DEFAULT
+#define PROTECT_HFS_DEFAULT 0
+#endif
+int protect_hfs = PROTECT_HFS_DEFAULT;
+
+#ifndef PROTECT_NTFS_DEFAULT
+#define PROTECT_NTFS_DEFAULT 0
+#endif
+int protect_ntfs = PROTECT_NTFS_DEFAULT;
+
/*
* The character that begins a commented line in user-editable file
* that is subject to stripspace.
diff --git a/exec_cmd.c b/exec_cmd.c
index 698e7526c4..8ab37b5f74 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -6,7 +6,7 @@
static const char *argv_exec_path;
static const char *argv0_path;
-const char *system_path(const char *path)
+char *system_path(const char *path)
{
#ifdef RUNTIME_PREFIX
static const char *prefix;
@@ -16,7 +16,7 @@ const char *system_path(const char *path)
struct strbuf d = STRBUF_INIT;
if (is_absolute_path(path))
- return path;
+ return xstrdup(path);
#ifdef RUNTIME_PREFIX
assert(argv0_path);
@@ -34,8 +34,7 @@ const char *system_path(const char *path)
#endif
strbuf_addf(&d, "%s/%s", prefix, path);
- path = strbuf_detach(&d, NULL);
- return path;
+ return strbuf_detach(&d, NULL);
}
const char *git_extract_argv0_path(const char *argv0)
diff --git a/exec_cmd.h b/exec_cmd.h
index e4c9702f02..93b0c02529 100644
--- a/exec_cmd.h
+++ b/exec_cmd.h
@@ -9,6 +9,6 @@ extern const char **prepare_git_cmd(const char **argv);
extern int execv_git_cmd(const char **argv); /* NULL terminated */
LAST_ARG_MUST_BE_NULL
extern int execl_git_cmd(const char *cmd, ...);
-extern const char *system_path(const char *path);
+extern char *system_path(const char *path);
#endif /* GIT_EXEC_CMD_H */
diff --git a/fsck.c b/fsck.c
index 2fffa434a5..10bcb65151 100644
--- a/fsck.c
+++ b/fsck.c
@@ -7,6 +7,7 @@
#include "tag.h"
#include "fsck.h"
#include "refs.h"
+#include "utf8.h"
static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data)
{
@@ -171,7 +172,9 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
has_empty_name |= !*name;
has_dot |= !strcmp(name, ".");
has_dotdot |= !strcmp(name, "..");
- has_dotgit |= !strcmp(name, ".git");
+ has_dotgit |= (!strcmp(name, ".git") ||
+ is_hfs_dotgit(name) ||
+ is_ntfs_dotgit(name));
has_zero_pad |= *(char *)desc.buffer == '0';
update_tree_entry(&desc);
@@ -423,7 +426,8 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
}
strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
if (check_refname_format(sb.buf, 0))
- error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %s", buffer);
+ error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %.*s",
+ (int)(eol - buffer), buffer);
buffer = eol + 1;
if (!skip_prefix(buffer, "tagger ", &buffer))
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 1fadd69f88..c7256741cc 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -1356,6 +1356,7 @@ sub patch_update_file {
$patch_mode_flavour{TARGET},
" [y,n,q,a,d,/$other,?]? ";
my $line = prompt_single_character;
+ last unless defined $line;
if ($line) {
if ($line =~ /^y/i) {
$hunk[$ix]{USE} = 1;
diff --git a/git-am.sh b/git-am.sh
index ee61a77d71..a67d0f9898 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -17,6 +17,7 @@ s,signoff add a Signed-off-by line to the commit message
u,utf8 recode into utf8 (default)
k,keep pass -k flag to git-mailinfo
keep-non-patch pass -b flag to git-mailinfo
+m,message-id pass -m flag to git-mailinfo
keep-cr pass --keep-cr flag to git-mailsplit for mbox format
no-keep-cr do not pass --keep-cr flag to git-mailsplit independent of am.keepcr
c,scissors strip everything before a scissors line
@@ -371,13 +372,18 @@ split_patches () {
prec=4
dotest="$GIT_DIR/rebase-apply"
sign= utf8=t keep= keepcr= skip= interactive= resolved= rebasing= abort=
-resolvemsg= resume= scissors= no_inbody_headers=
+messageid= resolvemsg= resume= scissors= no_inbody_headers=
git_apply_opt=
committer_date_is_author_date=
ignore_date=
allow_rerere_autoupdate=
gpg_sign_opt=
+if test "$(git config --bool --get am.messageid)" = true
+then
+ messageid=t
+fi
+
if test "$(git config --bool --get am.keepcr)" = true
then
keepcr=t
@@ -400,6 +406,10 @@ it will be removed. Please do not use it anymore."
utf8=t ;; # this is now default
--no-utf8)
utf8= ;;
+ -m|--message-id)
+ messageid=t ;;
+ --no-message-id)
+ messageid=f ;;
-k|--keep)
keep=t ;;
--keep-non-patch)
@@ -567,6 +577,7 @@ Use \"git am --abort\" to remove it.")"
echo "$sign" >"$dotest/sign"
echo "$utf8" >"$dotest/utf8"
echo "$keep" >"$dotest/keep"
+ echo "$messageid" >"$dotest/messageid"
echo "$scissors" >"$dotest/scissors"
echo "$no_inbody_headers" >"$dotest/no_inbody_headers"
echo "$GIT_QUIET" >"$dotest/quiet"
@@ -621,6 +632,12 @@ b)
*)
keep= ;;
esac
+case "$(cat "$dotest/messageid")" in
+t)
+ messageid=-m ;;
+f)
+ messageid= ;;
+esac
case "$(cat "$dotest/scissors")" in
t)
scissors=--scissors ;;
@@ -692,7 +709,7 @@ do
get_author_ident_from_commit "$commit" >"$dotest/author-script"
git diff-tree --root --binary --full-index "$commit" >"$dotest/patch"
else
- git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
+ git mailinfo $keep $no_inbody_headers $messageid $scissors $utf8 "$dotest/msg" "$dotest/patch" \
<"$dotest/$msgnum" >"$dotest/info" ||
stop_here $this
diff --git a/git-bisect.sh b/git-bisect.sh
index 6cda2b5a60..2fc07acb0f 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -237,15 +237,18 @@ bisect_state() {
check_expected_revs "$rev" ;;
2,bad|*,good|*,skip)
shift
- eval=''
+ hash_list=''
for rev in "$@"
do
sha=$(git rev-parse --verify "$rev^{commit}") ||
die "$(eval_gettext "Bad rev input: \$rev")"
- eval="$eval bisect_write '$state' '$sha'; "
+ hash_list="$hash_list $sha"
done
- eval "$eval"
- check_expected_revs "$@" ;;
+ for rev in $hash_list
+ do
+ bisect_write "$state" "$rev"
+ done
+ check_expected_revs $hash_list ;;
*,bad)
die "$(gettext "'git bisect bad' can take only one argument.")" ;;
*)
diff --git a/git-compat-util.h b/git-compat-util.h
index 400e921086..eb9b0ff328 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -75,7 +75,8 @@
# endif
#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
!defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
- !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__)
+ !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__) && \
+ !defined(__CYGWIN__)
#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
@@ -211,8 +212,15 @@ extern char *gitbasename(char *);
#endif
#ifndef NO_OPENSSL
+#define __AVAILABILITY_MACROS_USES_AVAILABILITY 0
+#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
#include <openssl/ssl.h>
#include <openssl/err.h>
+#undef MAC_OS_X_VERSION_MIN_REQUIRED
+#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
+#ifdef NO_HMAC_CTX_CLEANUP
+#define HMAC_CTX_cleanup HMAC_cleanup
+#endif
#endif
/* On most systems <netdb.h> would have given us this, but
@@ -474,6 +482,40 @@ extern int git_munmap(void *start, size_t length);
#define on_disk_bytes(st) ((st).st_blocks * 512)
#endif
+#ifdef NEEDS_MODE_TRANSLATION
+#undef S_IFMT
+#undef S_IFREG
+#undef S_IFDIR
+#undef S_IFLNK
+#undef S_IFBLK
+#undef S_IFCHR
+#undef S_IFIFO
+#undef S_IFSOCK
+#define S_IFMT 0170000
+#define S_IFREG 0100000
+#define S_IFDIR 0040000
+#define S_IFLNK 0120000
+#define S_IFBLK 0060000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_IFSOCK 0140000
+#ifdef stat
+#undef stat
+#endif
+#define stat(path, buf) git_stat(path, buf)
+extern int git_stat(const char *, struct stat *);
+#ifdef fstat
+#undef fstat
+#endif
+#define fstat(fd, buf) git_fstat(fd, buf)
+extern int git_fstat(int, struct stat *);
+#ifdef lstat
+#undef lstat
+#endif
+#define lstat(path, buf) git_lstat(path, buf)
+extern int git_lstat(const char *, struct stat *);
+#endif
+
#define DEFAULT_PACKED_GIT_LIMIT \
((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index b64dd28acf..c6a4629cbc 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -1031,9 +1031,11 @@ test -s "$todo" || echo noop >> "$todo"
test -n "$autosquash" && rearrange_squash "$todo"
test -n "$cmd" && add_exec_commands "$todo"
+todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
+
cat >>"$todo" <<EOF
-$comment_char Rebase $shortrevisions onto $shortonto
+$comment_char Rebase $shortrevisions onto $shortonto ($todocount TODO item(s))
EOF
append_todo_help
git stripspace --comment-lines >>"$todo" <<\EOF
diff --git a/git-send-email.perl b/git-send-email.perl
index 9949db01e1..3092ab356c 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -54,10 +54,12 @@ git send-email [options] <file | directory | rev-list options >
--[no-]bcc <str> * Email Bcc:
--subject <str> * Email "Subject:"
--in-reply-to <str> * Email "In-Reply-To:"
+ --[no-]xmailer * Add "X-Mailer:" header (default).
--[no-]annotate * Review each patch that will be sent in an editor.
--compose * Open an editor for introduction.
--compose-encoding <str> * Encoding to assume for introduction.
--8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
+ --transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
Sending:
--envelope-sender <str> * Email envelope sender.
@@ -145,10 +147,15 @@ my $have_mail_address = eval { require Mail::Address; 1 };
my $smtp;
my $auth;
+# Regexes for RFC 2047 productions.
+my $re_token = qr/[^][()<>@,;:\\"\/?.= \000-\037\177-\377]+/;
+my $re_encoded_text = qr/[^? \000-\037\177-\377]+/;
+my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
+
# Variables we fill in automatically, or via prompting:
my (@to,$no_to,@initial_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
$initial_reply_to,$initial_subject,@files,
- $author,$sender,$smtp_authpass,$annotate,$compose,$time);
+ $author,$sender,$smtp_authpass,$annotate,$use_xmailer,$compose,$time);
my $envelope_sender;
@@ -206,6 +213,7 @@ my ($validate, $confirm);
my (@suppress_cc);
my ($auto_8bit_encoding);
my ($compose_encoding);
+my ($target_xfer_encoding);
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
@@ -219,7 +227,8 @@ my %config_bool_settings = (
"signedoffcc" => [\$signed_off_by_cc, undef], # Deprecated
"validate" => [\$validate, 1],
"multiedit" => [\$multiedit, undef],
- "annotate" => [\$annotate, undef]
+ "annotate" => [\$annotate, undef],
+ "xmailer" => [\$use_xmailer, 1]
);
my %config_settings = (
@@ -242,6 +251,7 @@ my %config_settings = (
"from" => \$sender,
"assume8bitencoding" => \$auto_8bit_encoding,
"composeencoding" => \$compose_encoding,
+ "transferencoding" => \$target_xfer_encoding,
);
my %config_path_settings = (
@@ -314,10 +324,12 @@ my $rc = GetOptions("h" => \$help,
"envelope-sender=s" => \$envelope_sender,
"thread!" => \$thread,
"validate!" => \$validate,
+ "transfer-encoding=s" => \$target_xfer_encoding,
"format-patch!" => \$format_patch,
"8bit-encoding=s" => \$auto_8bit_encoding,
"compose-encoding=s" => \$compose_encoding,
"force" => \$force,
+ "xmailer!" => \$use_xmailer,
);
usage() if $help;
@@ -913,15 +925,26 @@ $time = time - scalar $#files;
sub unquote_rfc2047 {
local ($_) = @_;
- my $encoding;
- s{=\?([^?]+)\?q\?(.*?)\?=}{
- $encoding = $1;
- my $e = $2;
- $e =~ s/_/ /g;
- $e =~ s/=([0-9A-F]{2})/chr(hex($1))/eg;
- $e;
+ my $charset;
+ my $sep = qr/[ \t]+/;
+ s{$re_encoded_word(?:$sep$re_encoded_word)*}{
+ my @words = split $sep, $&;
+ foreach (@words) {
+ m/$re_encoded_word/;
+ $charset = $1;
+ my $encoding = $2;
+ my $text = $3;
+ if ($encoding eq 'q' || $encoding eq 'Q') {
+ $_ = $text;
+ s/_/ /g;
+ s/=([0-9A-F]{2})/chr(hex($1))/egi;
+ } else {
+ # other encodings not supported yet
+ }
+ }
+ join '', @words;
}eg;
- return wantarray ? ($_, $encoding) : $_;
+ return wantarray ? ($_, $charset) : $_;
}
sub quote_rfc2047 {
@@ -934,10 +957,8 @@ sub quote_rfc2047 {
sub is_rfc2047_quoted {
my $s = shift;
- my $token = qr/[^][()<>@,;:"\/?.= \000-\037\177-\377]+/;
- my $encoded_text = qr/[!->@-~]+/;
length($s) <= 75 &&
- $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o;
+ $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
}
sub subject_needs_rfc2047_quoting {
@@ -1163,8 +1184,10 @@ To: $to${ccline}
Subject: $subject
Date: $date
Message-Id: $message_id
-X-Mailer: git-send-email $gitversion
";
+ if ($use_xmailer) {
+ $header .= "X-Mailer: git-send-email $gitversion\n";
+ }
if ($reply_to) {
$header .= "In-Reply-To: $reply_to\n";
@@ -1324,6 +1347,8 @@ foreach my $t (@files) {
my $author_encoding;
my $has_content_type;
my $body_encoding;
+ my $xfer_encoding;
+ my $has_mime_version;
@to = ();
@cc = ();
@xh = ();
@@ -1394,9 +1419,16 @@ foreach my $t (@files) {
}
push @xh, $_;
}
+ elsif (/^MIME-Version/i) {
+ $has_mime_version = 1;
+ push @xh, $_;
+ }
elsif (/^Message-Id: (.*)/i) {
$message_id = $1;
}
+ elsif (/^Content-Transfer-Encoding: (.*)/i) {
+ $xfer_encoding = $1 if not defined $xfer_encoding;
+ }
elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
push @xh, $_;
}
@@ -1444,10 +1476,9 @@ foreach my $t (@files) {
if defined $cc_cmd && !$suppress_cc{'cccmd'};
if ($broken_encoding{$t} && !$has_content_type) {
+ $xfer_encoding = '8bit' if not defined $xfer_encoding;
$has_content_type = 1;
- push @xh, "MIME-Version: 1.0",
- "Content-Type: text/plain; charset=$auto_8bit_encoding",
- "Content-Transfer-Encoding: 8bit";
+ push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
$body_encoding = $auto_8bit_encoding;
}
@@ -1467,14 +1498,25 @@ foreach my $t (@files) {
}
}
else {
+ $xfer_encoding = '8bit' if not defined $xfer_encoding;
$has_content_type = 1;
push @xh,
- 'MIME-Version: 1.0',
- "Content-Type: text/plain; charset=$author_encoding",
- 'Content-Transfer-Encoding: 8bit';
+ "Content-Type: text/plain; charset=$author_encoding";
}
}
}
+ if (defined $target_xfer_encoding) {
+ $xfer_encoding = '8bit' if not defined $xfer_encoding;
+ $message = apply_transfer_encoding(
+ $message, $xfer_encoding, $target_xfer_encoding);
+ $xfer_encoding = $target_xfer_encoding;
+ }
+ if (defined $xfer_encoding) {
+ push @xh, "Content-Transfer-Encoding: $xfer_encoding";
+ }
+ if (defined $xfer_encoding or $has_content_type) {
+ unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
+ }
$needs_confirm = (
$confirm eq "always" or
@@ -1543,6 +1585,32 @@ sub cleanup_compose_files {
$smtp->quit if $smtp;
+sub apply_transfer_encoding {
+ my $message = shift;
+ my $from = shift;
+ my $to = shift;
+
+ return $message if ($from eq $to and $from ne '7bit');
+
+ require MIME::QuotedPrint;
+ require MIME::Base64;
+
+ $message = MIME::QuotedPrint::decode($message)
+ if ($from eq 'quoted-printable');
+ $message = MIME::Base64::decode($message)
+ if ($from eq 'base64');
+
+ die "cannot send message as 7bit"
+ if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
+ return $message
+ if ($to eq '7bit' or $to eq '8bit');
+ return MIME::QuotedPrint::encode($message, "\n", 0)
+ if ($to eq 'quoted-printable');
+ return MIME::Base64::encode($message, "\n")
+ if ($to eq 'base64');
+ die "invalid transfer encoding";
+}
+
sub unique_email_list {
my %seen;
my @emails;
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index d968760139..c42c6e6365 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -81,7 +81,7 @@ if test -n "$OPTIONS_SPEC"; then
echo exit $?
)"
else
- dashless=$(basename "$0" | sed -e 's/-/ /')
+ dashless=$(basename -- "$0" | sed -e 's/-/ /')
usage() {
die "usage: $dashless $USAGE"
}
diff --git a/git-svn.perl b/git-svn.perl
index b6e2186cef..60f8814cc5 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -115,7 +115,7 @@ my ($_stdin, $_help, $_edit,
$_before, $_after,
$_merge, $_strategy, $_preserve_merges, $_dry_run, $_parents, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
- $_commit_url, $_tag, $_merge_info, $_interactive);
+ $_commit_url, $_tag, $_merge_info, $_interactive, $_set_svn_props);
# This is a refactoring artifact so Git::SVN can get at this git-svn switch.
sub opt_prefix { return $_prefix || '' }
@@ -193,6 +193,7 @@ my %cmd = (
'dry-run|n' => \$_dry_run,
'fetch-all|all' => \$_fetch_all,
'commit-url=s' => \$_commit_url,
+ 'set-svn-props=s' => \$_set_svn_props,
'revision|r=i' => \$_revision,
'no-rebase' => \$_no_rebase,
'mergeinfo=s' => \$_merge_info,
@@ -228,6 +229,9 @@ my %cmd = (
'propget' => [ \&cmd_propget,
'Print the value of a property on a file or directory',
{ 'revision|r=i' => \$_revision } ],
+ 'propset' => [ \&cmd_propset,
+ 'Set the value of a property on a file or directory - will be set on commit',
+ {} ],
'proplist' => [ \&cmd_proplist,
'List all properties of a file or directory',
{ 'revision|r=i' => \$_revision } ],
@@ -1376,6 +1380,49 @@ sub cmd_propget {
print $props->{$prop} . "\n";
}
+# cmd_propset (PROPNAME, PROPVAL, PATH)
+# ------------------------
+# Adjust the SVN property PROPNAME to PROPVAL for PATH.
+sub cmd_propset {
+ my ($propname, $propval, $path) = @_;
+ $path = '.' if not defined $path;
+ $path = $cmd_dir_prefix . $path;
+ usage(1) if not defined $propname;
+ usage(1) if not defined $propval;
+ my $file = basename($path);
+ my $dn = dirname($path);
+ my $cur_props = Git::SVN::Editor::check_attr( "svn-properties", $path );
+ my @new_props;
+ if (!$cur_props || $cur_props eq "unset" || $cur_props eq "" || $cur_props eq "set") {
+ push @new_props, "$propname=$propval";
+ } else {
+ # TODO: handle combining properties better
+ my @props = split(/;/, $cur_props);
+ my $replaced_prop;
+ foreach my $prop (@props) {
+ # Parse 'name=value' syntax and set the property.
+ if ($prop =~ /([^=]+)=(.*)/) {
+ my ($n,$v) = ($1,$2);
+ if ($n eq $propname) {
+ $v = $propval;
+ $replaced_prop = 1;
+ }
+ push @new_props, "$n=$v";
+ }
+ }
+ if (!$replaced_prop) {
+ push @new_props, "$propname=$propval";
+ }
+ }
+ my $attrfile = "$dn/.gitattributes";
+ open my $attrfh, '>>', $attrfile or die "Can't open $attrfile: $!\n";
+ # TODO: don't simply append here if $file already has svn-properties
+ my $new_props = join(';', @new_props);
+ print $attrfh "$file svn-properties=$new_props\n" or
+ die "write to $attrfile: $!\n";
+ close $attrfh or die "close $attrfile: $!\n";
+}
+
# cmd_proplist (PATH)
# -------------------
# Print the list of SVN properties for PATH.
diff --git a/git.c b/git.c
index 82d7a1cfee..6b5ae6a2ac 100644
--- a/git.c
+++ b/git.c
@@ -1,10 +1,7 @@
#include "builtin.h"
-#include "cache.h"
#include "exec_cmd.h"
#include "help.h"
-#include "quote.h"
#include "run-command.h"
-#include "commit.h"
const char git_usage_string[] =
"git [--version] [--help] [-C <path>] [-c name=value]\n"
diff --git a/imap-send.c b/imap-send.c
index 70bcc7a4e5..d69887da5a 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -26,11 +26,24 @@
#include "credential.h"
#include "exec_cmd.h"
#include "run-command.h"
+#include "parse-options.h"
#ifdef NO_OPENSSL
typedef void *SSL;
#endif
+#ifdef USE_CURL_FOR_IMAP_SEND
+#include "http.h"
+#endif
+
+static int verbosity;
+static int use_curl; /* strictly opt in */
-static const char imap_send_usage[] = "git imap-send < <mbox>";
+static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
+
+static struct option imap_send_options[] = {
+ OPT__VERBOSITY(&verbosity),
+ OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
+ OPT_END()
+};
#undef DRV_OK
#define DRV_OK 0
@@ -38,8 +51,6 @@ static const char imap_send_usage[] = "git imap-send < <mbox>";
#define DRV_BOX_BAD -2
#define DRV_STORE_BAD -3
-static int Verbose, Quiet;
-
__attribute__((format (printf, 1, 2)))
static void imap_info(const char *, ...);
__attribute__((format (printf, 1, 2)))
@@ -418,7 +429,7 @@ static int buffer_gets(struct imap_buffer *b, char **s)
if (b->buf[b->offset + 1] == '\n') {
b->buf[b->offset] = 0; /* terminate the string */
b->offset += 2; /* next line */
- if (Verbose)
+ if (0 < verbosity)
puts(*s);
return 0;
}
@@ -433,7 +444,7 @@ static void imap_info(const char *msg, ...)
{
va_list va;
- if (!Quiet) {
+ if (0 <= verbosity) {
va_start(va, msg);
vprintf(msg, va);
va_end(va);
@@ -445,7 +456,7 @@ static void imap_warn(const char *msg, ...)
{
va_list va;
- if (Quiet < 2) {
+ if (-2 < verbosity) {
va_start(va, msg);
vfprintf(stderr, msg, va);
va_end(va);
@@ -522,7 +533,7 @@ static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
cmd->tag, cmd->cmd, cmd->cb.dlen,
CAP(LITERALPLUS) ? "+" : "");
- if (Verbose) {
+ if (0 < verbosity) {
if (imap->num_in_progress)
printf("(%d in progress) ", imap->num_in_progress);
if (!starts_with(cmd->cmd, "LOGIN"))
@@ -1338,26 +1349,166 @@ static void git_imap_config(void)
git_config_get_string("imap.authmethod", &server.auth_method);
}
-int main(int argc, char **argv)
+static int append_msgs_to_imap(struct imap_server_conf *server,
+ struct strbuf* all_msgs, int total)
{
- struct strbuf all_msgs = STRBUF_INIT;
struct strbuf msg = STRBUF_INIT;
struct imap_store *ctx = NULL;
int ofs = 0;
int r;
- int total, n = 0;
+ int n = 0;
+
+ ctx = imap_open_store(server, server->folder);
+ if (!ctx) {
+ fprintf(stderr, "failed to open store\n");
+ return 1;
+ }
+ ctx->name = server->folder;
+
+ fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
+ while (1) {
+ unsigned percent = n * 100 / total;
+
+ fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
+
+ if (!split_msg(all_msgs, &msg, &ofs))
+ break;
+ if (server->use_html)
+ wrap_in_html(&msg);
+ r = imap_store_msg(ctx, &msg);
+ if (r != DRV_OK)
+ break;
+ n++;
+ }
+ fprintf(stderr, "\n");
+
+ imap_close_store(ctx);
+
+ return 0;
+}
+
+#ifdef USE_CURL_FOR_IMAP_SEND
+static CURL *setup_curl(struct imap_server_conf *srvc)
+{
+ CURL *curl;
+ struct strbuf path = STRBUF_INIT;
+
+ if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
+ die("curl_global_init failed");
+
+ curl = curl_easy_init();
+
+ if (!curl)
+ die("curl_easy_init failed");
+
+ curl_easy_setopt(curl, CURLOPT_USERNAME, server.user);
+ curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);
+
+ strbuf_addstr(&path, server.host);
+ if (!path.len || path.buf[path.len - 1] != '/')
+ strbuf_addch(&path, '/');
+ strbuf_addstr(&path, server.folder);
+
+ curl_easy_setopt(curl, CURLOPT_URL, path.buf);
+ strbuf_release(&path);
+ curl_easy_setopt(curl, CURLOPT_PORT, server.port);
+
+ if (server.auth_method) {
+ struct strbuf auth = STRBUF_INIT;
+ strbuf_addstr(&auth, "AUTH=");
+ strbuf_addstr(&auth, server.auth_method);
+ curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
+ strbuf_release(&auth);
+ }
+
+ if (!server.use_ssl)
+ curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
+
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, server.ssl_verify);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, server.ssl_verify);
+
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
+
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
+
+ if (0 < verbosity || getenv("GIT_CURL_VERBOSE"))
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+ return curl;
+}
+
+static int curl_append_msgs_to_imap(struct imap_server_conf *server,
+ struct strbuf* all_msgs, int total) {
+ int ofs = 0;
+ int n = 0;
+ struct buffer msgbuf = { STRBUF_INIT, 0 };
+ CURL *curl;
+ CURLcode res = CURLE_OK;
+
+ curl = setup_curl(server);
+ curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
+
+ fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
+ while (1) {
+ unsigned percent = n * 100 / total;
+ int prev_len;
+
+ fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
+
+ prev_len = msgbuf.buf.len;
+ if (!split_msg(all_msgs, &msgbuf.buf, &ofs))
+ break;
+ if (server->use_html)
+ wrap_in_html(&msgbuf.buf);
+ lf_to_crlf(&msgbuf.buf);
+
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
+ (curl_off_t)(msgbuf.buf.len-prev_len));
+
+ res = curl_easy_perform(curl);
+
+ if(res != CURLE_OK) {
+ fprintf(stderr, "curl_easy_perform() failed: %s\n",
+ curl_easy_strerror(res));
+ break;
+ }
+
+ n++;
+ }
+ fprintf(stderr, "\n");
+
+ curl_easy_cleanup(curl);
+ curl_global_cleanup();
+
+ return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+ struct strbuf all_msgs = STRBUF_INIT;
+ int total;
int nongit_ok;
git_extract_argv0_path(argv[0]);
git_setup_gettext();
- if (argc != 1)
- usage(imap_send_usage);
-
setup_git_directory_gently(&nongit_ok);
git_imap_config();
+ argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0);
+
+ if (argc)
+ usage_with_options(imap_send_usage, imap_send_options);
+
+#ifndef USE_CURL_FOR_IMAP_SEND
+ if (use_curl) {
+ warning("--use-curl not supported in this build");
+ use_curl = 0;
+ }
+#endif
+
if (!server.port)
server.port = server.use_ssl ? 993 : 143;
@@ -1391,29 +1542,14 @@ int main(int argc, char **argv)
}
/* write it to the imap server */
- ctx = imap_open_store(&server, server.folder);
- if (!ctx) {
- fprintf(stderr, "failed to open store\n");
- return 1;
- }
-
- fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
- while (1) {
- unsigned percent = n * 100 / total;
- fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
- if (!split_msg(&all_msgs, &msg, &ofs))
- break;
- if (server.use_html)
- wrap_in_html(&msg);
- r = imap_store_msg(ctx, &msg);
- if (r != DRV_OK)
- break;
- n++;
- }
- fprintf(stderr, "\n");
+ if (server.tunnel)
+ return append_msgs_to_imap(&server, &all_msgs, total);
- imap_close_store(ctx);
+#ifdef USE_CURL_FOR_IMAP_SEND
+ if (use_curl)
+ return curl_append_msgs_to_imap(&server, &all_msgs, total);
+#endif
- return 0;
+ return append_msgs_to_imap(&server, &all_msgs, total);
}
diff --git a/list-objects.c b/list-objects.c
index 2910becd6c..2a139b6ced 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -157,7 +157,7 @@ void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(commit->tree);
- if (revs->edge_hint && !(commit->object.flags & SHOWN)) {
+ if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
commit->object.flags |= SHOWN;
show_edge(commit);
}
@@ -165,7 +165,7 @@ void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
}
mark_edge_parents_uninteresting(commit, revs, show_edge);
}
- if (revs->edge_hint) {
+ if (revs->edge_hint_aggressive) {
for (i = 0; i < revs->cmdline.nr; i++) {
struct object *obj = revs->cmdline.rev[i].item;
struct commit *commit = (struct commit *)obj;
diff --git a/lockfile.c b/lockfile.c
index 4f16ee78ce..9889277751 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -128,9 +128,17 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
path);
}
- strbuf_add(&lk->filename, path, pathlen);
- if (!(flags & LOCK_NO_DEREF))
- resolve_symlink(&lk->filename);
+ if (flags & LOCK_NO_DEREF) {
+ strbuf_add_absolute_path(&lk->filename, path);
+ } else {
+ struct strbuf resolved_path = STRBUF_INIT;
+
+ strbuf_add(&resolved_path, path, pathlen);
+ resolve_symlink(&resolved_path);
+ strbuf_add_absolute_path(&lk->filename, resolved_path.buf);
+ strbuf_release(&resolved_path);
+ }
+
strbuf_addstr(&lk->filename, LOCK_SUFFIX);
lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
if (lk->fd < 0) {
diff --git a/mailmap.c b/mailmap.c
index 81890a6680..9e9589730f 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -71,22 +71,17 @@ static void add_mapping(struct string_list *map,
char *old_name, char *old_email)
{
struct mailmap_entry *me;
- int index;
+ struct string_list_item *item;
if (old_email == NULL) {
old_email = new_email;
new_email = NULL;
}
- if ((index = string_list_find_insert_index(map, old_email, 1)) < 0) {
- /* mailmap entry exists, invert index value */
- index = -1 - index;
- me = (struct mailmap_entry *)map->items[index].util;
+ item = string_list_insert(map, old_email);
+ if (item->util) {
+ me = (struct mailmap_entry *)item->util;
} else {
- /* create mailmap entry */
- struct string_list_item *item;
-
- item = string_list_insert_at_index(map, index, old_email);
me = xcalloc(1, sizeof(struct mailmap_entry));
me->namemap.strdup_strings = 1;
me->namemap.cmp = namemap_cmp;
@@ -94,8 +89,8 @@ static void add_mapping(struct string_list *map,
}
if (old_name == NULL) {
- debug_mm("mailmap: adding (simple) entry for %s at index %d\n",
- old_email, index);
+ debug_mm("mailmap: adding (simple) entry for '%s'\n", old_email);
+
/* Replace current name and new email for simple entry */
if (new_name) {
free(me->name);
@@ -107,8 +102,7 @@ static void add_mapping(struct string_list *map,
}
} else {
struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
- debug_mm("mailmap: adding (complex) entry for %s at index %d\n",
- old_email, index);
+ debug_mm("mailmap: adding (complex) entry for '%s'\n", old_email);
if (new_name)
mi->name = xstrdup(new_name);
if (new_email)
diff --git a/merge-recursive.c b/merge-recursive.c
index fdb7d0f10b..771f5e21b0 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -275,23 +275,20 @@ struct tree *write_tree_from_memory(struct merge_options *o)
}
static int save_files_dirs(const unsigned char *sha1,
- const char *base, int baselen, const char *path,
+ struct strbuf *base, const char *path,
unsigned int mode, int stage, void *context)
{
- int len = strlen(path);
- char *newpath = xmalloc(baselen + len + 1);
+ int baselen = base->len;
struct merge_options *o = context;
- memcpy(newpath, base, baselen);
- memcpy(newpath + baselen, path, len);
- newpath[baselen + len] = '\0';
+ strbuf_addstr(base, path);
if (S_ISDIR(mode))
- string_list_insert(&o->current_directory_set, newpath);
+ string_list_insert(&o->current_directory_set, base->buf);
else
- string_list_insert(&o->current_file_set, newpath);
- free(newpath);
+ string_list_insert(&o->current_file_set, base->buf);
+ strbuf_setlen(base, baselen);
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
}
@@ -1904,7 +1901,7 @@ int merge_recursive(struct merge_options *o,
}
if (!ca) {
- ca = get_merge_bases(h1, h2, 1);
+ ca = get_merge_bases(h1, h2);
ca = reverse_commit_list(ca);
}
diff --git a/notes-merge.c b/notes-merge.c
index 7eb9d7a010..109ff4ef41 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -594,7 +594,7 @@ int notes_merge(struct notes_merge_options *o,
assert(local && remote);
/* Find merge bases */
- bases = get_merge_bases(local, remote, 1);
+ bases = get_merge_bases(local, remote);
if (!bases) {
base_sha1 = null_sha1;
base_tree_sha1 = EMPTY_TREE_SHA1_BIN;
diff --git a/notes-utils.c b/notes-utils.c
index b64dc1b021..ccbf0737a3 100644
--- a/notes-utils.c
+++ b/notes-utils.c
@@ -44,8 +44,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
/* Prepare commit message and reflog message */
strbuf_addstr(&buf, msg);
- if (buf.buf[buf.len - 1] != '\n')
- strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
+ strbuf_complete_line(&buf);
create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1);
strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
diff --git a/notes.c b/notes.c
index 62bc6e1818..c763a21eef 100644
--- a/notes.c
+++ b/notes.c
@@ -902,7 +902,7 @@ int combine_notes_cat_sort_uniq(unsigned char *cur_sha1,
if (string_list_add_note_lines(&sort_uniq_list, new_sha1))
goto out;
string_list_remove_empty_items(&sort_uniq_list, 0);
- sort_string_list(&sort_uniq_list);
+ string_list_sort(&sort_uniq_list);
string_list_remove_duplicates(&sort_uniq_list, 0);
/* create a new blob object from sort_uniq_list */
diff --git a/path.c b/path.c
index f68df0cf88..e608993801 100644
--- a/path.c
+++ b/path.c
@@ -823,3 +823,36 @@ int daemon_avoid_alias(const char *p)
}
}
}
+
+static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
+{
+ if (len < skip)
+ return 0;
+ len -= skip;
+ path += skip;
+ while (len-- > 0) {
+ char c = *(path++);
+ if (c != ' ' && c != '.')
+ return 0;
+ }
+ return 1;
+}
+
+int is_ntfs_dotgit(const char *name)
+{
+ int len;
+
+ for (len = 0; ; len++)
+ if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
+ if (only_spaces_and_periods(name, len, 4) &&
+ !strncasecmp(name, ".git", 4))
+ return 1;
+ if (only_spaces_and_periods(name, len, 5) &&
+ !strncasecmp(name, "git~1", 5))
+ return 1;
+ if (name[len] != '\\')
+ return 0;
+ name += len + 1;
+ len = -1;
+ }
+}
diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm
index 34e8af966c..4088f13e72 100644
--- a/perl/Git/SVN/Editor.pm
+++ b/perl/Git/SVN/Editor.pm
@@ -288,6 +288,40 @@ sub apply_autoprops {
}
}
+sub check_attr {
+ my ($attr,$path) = @_;
+ my $val = command_oneline("check-attr", $attr, "--", $path);
+ if ($val) { $val =~ s/^[^:]*:\s*[^:]*:\s*(.*)\s*$/$1/; }
+ return $val;
+}
+
+sub apply_manualprops {
+ my ($self, $file, $fbat) = @_;
+ my $pending_properties = check_attr( "svn-properties", $file );
+ if ($pending_properties eq "") { return; }
+ # Parse the list of properties to set.
+ my @props = split(/;/, $pending_properties);
+ # TODO: get existing properties to compare to
+ # - this fails for add so currently not done
+ # my $existing_props = ::get_svnprops($file);
+ my $existing_props = {};
+ # TODO: caching svn properties or storing them in .gitattributes
+ # would make that faster
+ foreach my $prop (@props) {
+ # Parse 'name=value' syntax and set the property.
+ if ($prop =~ /([^=]+)=(.*)/) {
+ my ($n,$v) = ($1,$2);
+ for ($n, $v) {
+ s/^\s+//; s/\s+$//;
+ }
+ my $existing = $existing_props->{$n};
+ if (!defined($existing) || $existing ne $v) {
+ $self->change_file_prop($fbat, $n, $v);
+ }
+ }
+ }
+}
+
sub A {
my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
@@ -296,6 +330,7 @@ sub A {
undef, -1);
print "\tA\t$m->{file_b}\n" unless $::_q;
$self->apply_autoprops($file, $fbat);
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
@@ -311,6 +346,7 @@ sub C {
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
$upa, $self->{r});
print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
@@ -333,6 +369,7 @@ sub R {
$upa, $self->{r});
print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
$self->apply_autoprops($file, $fbat);
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
@@ -348,6 +385,7 @@ sub M {
my $fbat = $self->open_file($self->repo_path($m->{file_b}),
$pbat,$self->{r},$self->{pool});
print "\t$m->{chg}\t$m->{file_b}\n" unless $::_q;
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
diff --git a/pkt-line.c b/pkt-line.c
index 8bc89b1e0c..187a2293e7 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -64,44 +64,45 @@ void packet_buf_flush(struct strbuf *buf)
}
#define hex(a) (hexchar[(a) & 15])
-static char buffer[1000];
-static unsigned format_packet(const char *fmt, va_list args)
+static void format_packet(struct strbuf *out, const char *fmt, va_list args)
{
static char hexchar[] = "0123456789abcdef";
- unsigned n;
+ size_t orig_len, n;
- n = vsnprintf(buffer + 4, sizeof(buffer) - 4, fmt, args);
- if (n >= sizeof(buffer)-4)
+ orig_len = out->len;
+ strbuf_addstr(out, "0000");
+ strbuf_vaddf(out, fmt, args);
+ n = out->len - orig_len;
+
+ if (n > LARGE_PACKET_MAX)
die("protocol error: impossibly long line");
- n += 4;
- buffer[0] = hex(n >> 12);
- buffer[1] = hex(n >> 8);
- buffer[2] = hex(n >> 4);
- buffer[3] = hex(n);
- packet_trace(buffer+4, n-4, 1);
- return n;
+
+ out->buf[orig_len + 0] = hex(n >> 12);
+ out->buf[orig_len + 1] = hex(n >> 8);
+ out->buf[orig_len + 2] = hex(n >> 4);
+ out->buf[orig_len + 3] = hex(n);
+ packet_trace(out->buf + orig_len + 4, n - 4, 1);
}
void packet_write(int fd, const char *fmt, ...)
{
+ static struct strbuf buf = STRBUF_INIT;
va_list args;
- unsigned n;
+ strbuf_reset(&buf);
va_start(args, fmt);
- n = format_packet(fmt, args);
+ format_packet(&buf, fmt, args);
va_end(args);
- write_or_die(fd, buffer, n);
+ write_or_die(fd, buf.buf, buf.len);
}
void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
{
va_list args;
- unsigned n;
va_start(args, fmt);
- n = format_packet(fmt, args);
+ format_packet(buf, fmt, args);
va_end(args);
- strbuf_add(buf, buffer, n);
}
static int get_packet_data(int fd, char **src_buf, size_t *src_size,
diff --git a/prompt.c b/prompt.c
index e5b4938efc..8181eebbfc 100644
--- a/prompt.c
+++ b/prompt.c
@@ -57,11 +57,19 @@ char *git_prompt(const char *prompt, int flags)
r = do_askpass(askpass, prompt);
}
- if (!r)
- r = git_terminal_prompt(prompt, flags & PROMPT_ECHO);
if (!r) {
- /* prompts already contain ": " at the end */
- die("could not read %s%s", prompt, strerror(errno));
+ const char *err;
+
+ if (git_env_bool("GIT_TERMINAL_PROMPT", 1)) {
+ r = git_terminal_prompt(prompt, flags & PROMPT_ECHO);
+ err = strerror(errno);
+ } else {
+ err = "terminal prompts disabled";
+ }
+ if (!r) {
+ /* prompts already contain ": " at the end */
+ die("could not read %s%s", prompt, err);
+ }
}
return r;
}
diff --git a/quote.c b/quote.c
index 45e3db12d5..7920e18e44 100644
--- a/quote.c
+++ b/quote.c
@@ -274,27 +274,6 @@ void write_name_quoted(const char *name, FILE *fp, int terminator)
fputc(terminator, fp);
}
-void write_name_quotedpfx(const char *pfx, size_t pfxlen,
- const char *name, FILE *fp, int terminator)
-{
- int needquote = 0;
-
- if (terminator) {
- needquote = next_quote_pos(pfx, pfxlen) < pfxlen
- || name[next_quote_pos(name, -1)];
- }
- if (needquote) {
- fputc('"', fp);
- quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
- quote_c_style(name, NULL, fp, 1);
- fputc('"', fp);
- } else {
- fwrite(pfx, pfxlen, 1, fp);
- fputs(name, fp);
- }
- fputc(terminator, fp);
-}
-
void write_name_quoted_relative(const char *name, const char *prefix,
FILE *fp, int terminator)
{
diff --git a/quote.h b/quote.h
index 71dcc3aa02..99e04d34bf 100644
--- a/quote.h
+++ b/quote.h
@@ -56,8 +56,6 @@ extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq
extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
extern void write_name_quoted(const char *name, FILE *, int terminator);
-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
- const char *name, FILE *, int terminator);
extern void write_name_quoted_relative(const char *name, const char *prefix,
FILE *fp, int terminator);
diff --git a/read-cache.c b/read-cache.c
index 8f3e9eb314..9cff715d6b 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -17,6 +17,7 @@
#include "varint.h"
#include "split-index.h"
#include "sigchain.h"
+#include "utf8.h"
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
unsigned int options);
@@ -776,9 +777,10 @@ static int verify_dotfile(const char *rest)
* shares the path end test with the ".." case.
*/
case 'g':
- if (rest[1] != 'i')
+ case 'G':
+ if (rest[1] != 'i' && rest[1] != 'I')
break;
- if (rest[2] != 't')
+ if (rest[2] != 't' && rest[2] != 'T')
break;
rest += 2;
/* fallthrough */
@@ -802,6 +804,10 @@ int verify_path(const char *path)
return 1;
if (is_dir_sep(c)) {
inside:
+ if (protect_hfs && is_hfs_dotgit(path))
+ return 0;
+ if (protect_ntfs && is_ntfs_dotgit(path))
+ return 0;
c = *path++;
if ((c == '.' && !verify_dotfile(path)) ||
is_dir_sep(c) || c == '\0')
diff --git a/refs.c b/refs.c
index 5ff457ebfc..ed3b2cb405 100644
--- a/refs.c
+++ b/refs.c
@@ -1068,8 +1068,10 @@ static const char PACKED_REFS_HEADER[] =
* Return a pointer to the refname within the line (null-terminated),
* or NULL if there was a problem.
*/
-static const char *parse_ref_line(char *line, unsigned char *sha1)
+static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1)
{
+ const char *ref;
+
/*
* 42: the answer to everything.
*
@@ -1078,22 +1080,23 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
* +1 (space in between hex and name)
* +1 (newline at the end of the line)
*/
- int len = strlen(line) - 42;
-
- if (len <= 0)
+ if (line->len <= 42)
return NULL;
- if (get_sha1_hex(line, sha1) < 0)
+
+ if (get_sha1_hex(line->buf, sha1) < 0)
return NULL;
- if (!isspace(line[40]))
+ if (!isspace(line->buf[40]))
return NULL;
- line += 41;
- if (isspace(*line))
+
+ ref = line->buf + 41;
+ if (isspace(*ref))
return NULL;
- if (line[len] != '\n')
+
+ if (line->buf[line->len - 1] != '\n')
return NULL;
- line[len] = 0;
+ line->buf[--line->len] = 0;
- return line;
+ return ref;
}
/*
@@ -1126,16 +1129,15 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
static void read_packed_refs(FILE *f, struct ref_dir *dir)
{
struct ref_entry *last = NULL;
- char refline[PATH_MAX];
+ struct strbuf line = STRBUF_INIT;
enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
- while (fgets(refline, sizeof(refline), f)) {
+ while (strbuf_getwholeline(&line, f, '\n') != EOF) {
unsigned char sha1[20];
const char *refname;
- static const char header[] = "# pack-refs with:";
+ const char *traits;
- if (!strncmp(refline, header, sizeof(header)-1)) {
- const char *traits = refline + sizeof(header) - 1;
+ if (skip_prefix(line.buf, "# pack-refs with:", &traits)) {
if (strstr(traits, " fully-peeled "))
peeled = PEELED_FULLY;
else if (strstr(traits, " peeled "))
@@ -1144,7 +1146,7 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
continue;
}
- refname = parse_ref_line(refline, sha1);
+ refname = parse_ref_line(&line, sha1);
if (refname) {
int flag = REF_ISPACKED;
@@ -1160,10 +1162,10 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
continue;
}
if (last &&
- refline[0] == '^' &&
- strlen(refline) == PEELED_LINE_LENGTH &&
- refline[PEELED_LINE_LENGTH - 1] == '\n' &&
- !get_sha1_hex(refline + 1, sha1)) {
+ line.buf[0] == '^' &&
+ line.len == PEELED_LINE_LENGTH &&
+ line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
+ !get_sha1_hex(line.buf + 1, sha1)) {
hashcpy(last->u.value.peeled, sha1);
/*
* Regardless of what the file header said,
@@ -1173,6 +1175,8 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
last->flag |= REF_KNOWS_PEELED;
}
}
+
+ strbuf_release(&line);
}
/*
@@ -2318,6 +2322,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, lflags);
if (lock->lock_fd < 0) {
+ last_errno = errno;
if (errno == ENOENT && --attempts_remaining > 0)
/*
* Maybe somebody just deleted one of the
@@ -2325,8 +2330,13 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
* again:
*/
goto retry;
- else
- unable_to_lock_die(ref_file, errno);
+ else {
+ struct strbuf err = STRBUF_INIT;
+ unable_to_lock_message(ref_file, errno, &err);
+ error("%s", err.buf);
+ strbuf_release(&err);
+ goto error_return;
+ }
}
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
@@ -2639,22 +2649,25 @@ static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
return 0;
}
-int repack_without_refs(const char **refnames, int n, struct strbuf *err)
+int repack_without_refs(struct string_list *refnames, struct strbuf *err)
{
struct ref_dir *packed;
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
- struct string_list_item *ref_to_delete;
- int i, ret, removed = 0;
+ struct string_list_item *refname, *ref_to_delete;
+ int ret, needs_repacking = 0, removed = 0;
assert(err);
/* Look for a packed ref */
- for (i = 0; i < n; i++)
- if (get_packed_ref(refnames[i]))
+ for_each_string_list_item(refname, refnames) {
+ if (get_packed_ref(refname->string)) {
+ needs_repacking = 1;
break;
+ }
+ }
/* Avoid locking if we have nothing to do */
- if (i == n)
+ if (!needs_repacking)
return 0; /* no refname exists in packed refs */
if (lock_packed_refs(0)) {
@@ -2664,8 +2677,8 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
packed = get_packed_refs(&ref_cache);
/* Remove refnames from the cache */
- for (i = 0; i < n; i++)
- if (remove_entry(packed, refnames[i]) != -1)
+ for_each_string_list_item(refname, refnames)
+ if (remove_entry(packed, refname->string) != -1)
removed = 1;
if (!removed) {
/*
@@ -3404,29 +3417,54 @@ int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void
bp = find_beginning_of_line(buf, scanp);
- if (*bp != '\n') {
- strbuf_splice(&sb, 0, 0, buf, endp - buf);
- if (pos)
- break; /* need to fill another block */
- scanp = buf - 1; /* leave loop */
- } else {
+ if (*bp == '\n') {
/*
- * (bp + 1) thru endp is the beginning of the
- * current line we have in sb
+ * The newline is the end of the previous line,
+ * so we know we have complete line starting
+ * at (bp + 1). Prefix it onto any prior data
+ * we collected for the line and process it.
*/
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp;
endp = bp + 1;
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+ strbuf_reset(&sb);
+ if (ret)
+ break;
+ } else if (!pos) {
+ /*
+ * We are at the start of the buffer, and the
+ * start of the file; there is no previous
+ * line, and we have everything for this one.
+ * Process it, and we can end the loop.
+ */
+ strbuf_splice(&sb, 0, 0, buf, endp - buf);
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+ strbuf_reset(&sb);
+ break;
}
- ret = show_one_reflog_ent(&sb, fn, cb_data);
- strbuf_reset(&sb);
- if (ret)
+
+ if (bp == buf) {
+ /*
+ * We are at the start of the buffer, and there
+ * is more file to read backwards. Which means
+ * we are in the middle of a line. Note that we
+ * may get here even if *bp was a newline; that
+ * just means we are at the exact end of the
+ * previous line, rather than some spot in the
+ * middle.
+ *
+ * Save away what we have to be combined with
+ * the data from the next read.
+ */
+ strbuf_splice(&sb, 0, 0, buf, endp - buf);
break;
+ }
}
}
if (!ret && sb.len)
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ die("BUG: reverse reflog parser had leftover data");
fclose(logfp);
strbuf_release(&sb);
@@ -3738,10 +3776,11 @@ static int ref_update_reject_duplicates(struct ref_update **updates, int n,
int ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err)
{
- int ret = 0, delnum = 0, i;
- const char **delnames;
+ int ret = 0, i;
int n = transaction->nr;
struct ref_update **updates = transaction->updates;
+ struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
+ struct string_list_item *ref_to_delete;
assert(err);
@@ -3753,9 +3792,6 @@ int ref_transaction_commit(struct ref_transaction *transaction,
return 0;
}
- /* Allocate work space */
- delnames = xmalloc(sizeof(*delnames) * n);
-
/* Copy, sort, and reject duplicate refs */
qsort(updates, n, sizeof(*updates), ref_update_compare);
if (ref_update_reject_duplicates(updates, n, err)) {
@@ -3815,16 +3851,17 @@ int ref_transaction_commit(struct ref_transaction *transaction,
}
if (!(update->flags & REF_ISPRUNING))
- delnames[delnum++] = update->lock->ref_name;
+ string_list_append(&refs_to_delete,
+ update->lock->ref_name);
}
}
- if (repack_without_refs(delnames, delnum, err)) {
+ if (repack_without_refs(&refs_to_delete, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
- for (i = 0; i < delnum; i++)
- unlink_or_warn(git_path("logs/%s", delnames[i]));
+ for_each_string_list_item(ref_to_delete, &refs_to_delete)
+ unlink_or_warn(git_path("logs/%s", ref_to_delete->string));
clear_loose_ref_cache(&ref_cache);
cleanup:
@@ -3833,7 +3870,7 @@ cleanup:
for (i = 0; i < n; i++)
if (updates[i]->lock)
unlock_ref(updates[i]->lock);
- free(delnames);
+ string_list_clear(&refs_to_delete, 0);
return ret;
}
diff --git a/refs.h b/refs.h
index 2bc3556874..405c6572f1 100644
--- a/refs.h
+++ b/refs.h
@@ -163,7 +163,15 @@ extern void rollback_packed_refs(void);
*/
int pack_refs(unsigned int flags);
-extern int repack_without_refs(const char **refnames, int n,
+/*
+ * Rewrite the packed-refs file, omitting any refs listed in
+ * 'refnames'. On error, packed-refs will be unchanged, the return
+ * value is nonzero, and a message about the error is written to the
+ * 'err' strbuf.
+ *
+ * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
+ */
+extern int repack_without_refs(struct string_list *refnames,
struct strbuf *err);
extern int ref_exists(const char *);
diff --git a/remote.c b/remote.c
index f62421702f..5b9c6931c1 100644
--- a/remote.c
+++ b/remote.c
@@ -1356,7 +1356,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
}
clear_commit_marks_many(sent_tips.nr, sent_tips.tip, TMP_MARK);
- sort_string_list(&dst_tag);
+ string_list_sort(&dst_tag);
/* Collect tags they do not have. */
for (ref = src; ref; ref = ref->next) {
@@ -1421,7 +1421,7 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
for ( ; ref; ref = ref->next)
string_list_append_nodup(ref_index, ref->name)->util = ref;
- sort_string_list(ref_index);
+ string_list_sort(ref_index);
}
/*
@@ -1631,6 +1631,27 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
}
}
+static void set_merge(struct branch *ret)
+{
+ char *ref;
+ unsigned char sha1[20];
+ int i;
+
+ ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge));
+ for (i = 0; i < ret->merge_nr; i++) {
+ ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
+ ret->merge[i]->src = xstrdup(ret->merge_name[i]);
+ if (!remote_find_tracking(ret->remote, ret->merge[i]) ||
+ strcmp(ret->remote_name, "."))
+ continue;
+ if (dwim_ref(ret->merge_name[i], strlen(ret->merge_name[i]),
+ sha1, &ref) == 1)
+ ret->merge[i]->dst = ref;
+ else
+ ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
+ }
+}
+
struct branch *branch_get(const char *name)
{
struct branch *ret;
@@ -1642,17 +1663,8 @@ struct branch *branch_get(const char *name)
ret = make_branch(name, 0);
if (ret && ret->remote_name) {
ret->remote = remote_get(ret->remote_name);
- if (ret->merge_nr) {
- int i;
- ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge));
- for (i = 0; i < ret->merge_nr; i++) {
- ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
- ret->merge[i]->src = xstrdup(ret->merge_name[i]);
- if (remote_find_tracking(ret->remote, ret->merge[i])
- && !strcmp(ret->remote_name, "."))
- ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
- }
- }
+ if (ret->merge_nr)
+ set_merge(ret);
}
return ret;
}
@@ -2135,7 +2147,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet
info.ref_count = ref_count;
for (ref = fetch_map; ref; ref = ref->next)
string_list_append(&ref_names, ref->name);
- sort_string_list(&ref_names);
+ string_list_sort(&ref_names);
for_each_ref(get_stale_heads_cb, &info);
string_list_clear(&ref_names, 0);
return stale_refs;
diff --git a/revision.c b/revision.c
index 75dda928ea..86406a26a2 100644
--- a/revision.c
+++ b/revision.c
@@ -1441,7 +1441,7 @@ static void prepare_show_merge(struct rev_info *revs)
other = lookup_commit_or_die(sha1, "MERGE_HEAD");
add_pending_object(revs, &head->object, "HEAD");
add_pending_object(revs, &other->object, "MERGE_HEAD");
- bases = get_merge_bases(head, other, 1);
+ bases = get_merge_bases(head, other);
add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
free_commit_list(bases);
@@ -1546,7 +1546,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
: lookup_commit_reference(b_obj->sha1));
if (!a || !b)
goto missing;
- exclude = get_merge_bases(a, b, 1);
+ exclude = get_merge_bases(a, b);
add_rev_cmdline_list(revs, exclude,
REV_CMD_MERGE_BASE,
flags_exclude);
@@ -1853,6 +1853,12 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->tree_objects = 1;
revs->blob_objects = 1;
revs->edge_hint = 1;
+ } else if (!strcmp(arg, "--objects-edge-aggressive")) {
+ revs->tag_objects = 1;
+ revs->tree_objects = 1;
+ revs->blob_objects = 1;
+ revs->edge_hint = 1;
+ revs->edge_hint_aggressive = 1;
} else if (!strcmp(arg, "--verify-objects")) {
revs->tag_objects = 1;
revs->tree_objects = 1;
diff --git a/revision.h b/revision.h
index 9cb5adc4ea..033a24460e 100644
--- a/revision.h
+++ b/revision.h
@@ -93,6 +93,7 @@ struct rev_info {
blob_objects:1,
verify_objects:1,
edge_hint:1,
+ edge_hint_aggressive:1,
limited:1,
unpacked:1,
boundary:2,
diff --git a/run-command.c b/run-command.c
index a47699966c..0b432cc971 100644
--- a/run-command.c
+++ b/run-command.c
@@ -833,20 +833,3 @@ int run_hook_le(const char *const *env, const char *name, ...)
return ret;
}
-
-int run_hook_with_custom_index(const char *index_file, const char *name, ...)
-{
- const char *hook_env[3] = { NULL };
- char index[PATH_MAX];
- va_list args;
- int ret;
-
- snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
- hook_env[0] = index;
-
- va_start(args, name);
- ret = run_hook_ve(hook_env, name, args);
- va_end(args);
-
- return ret;
-}
diff --git a/run-command.h b/run-command.h
index 2137315ee4..d6868dc8c8 100644
--- a/run-command.h
+++ b/run-command.h
@@ -57,10 +57,6 @@ LAST_ARG_MUST_BE_NULL
extern int run_hook_le(const char *const *env, const char *name, ...);
extern int run_hook_ve(const char *const *env, const char *name, va_list args);
-LAST_ARG_MUST_BE_NULL
-__attribute__((deprecated))
-extern int run_hook_with_custom_index(const char *index_file, const char *name, ...);
-
#define RUN_COMMAND_NO_STDIN 1
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
#define RUN_COMMAND_STDOUT_TO_STDERR 4
diff --git a/send-pack.c b/send-pack.c
index 949cb61aa0..25947d7df9 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -47,6 +47,7 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
NULL,
NULL,
NULL,
+ NULL,
};
struct child_process po = CHILD_PROCESS_INIT;
int i;
@@ -60,6 +61,8 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
argv[i++] = "-q";
if (args->progress)
argv[i++] = "--progress";
+ if (is_repository_shallow())
+ argv[i++] = "--shallow";
po.argv = argv;
po.in = -1;
po.out = args->stateless_rpc ? -1 : fd;
diff --git a/sequencer.c b/sequencer.c
index a03d4fa252..77a1266760 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -267,6 +267,23 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
return 0;
}
+void append_conflicts_hint(struct strbuf *msgbuf)
+{
+ int i;
+
+ strbuf_addch(msgbuf, '\n');
+ strbuf_commented_addf(msgbuf, "Conflicts:\n");
+ for (i = 0; i < active_nr;) {
+ const struct cache_entry *ce = active_cache[i++];
+ if (ce_stage(ce)) {
+ strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
+ while (i < active_nr && !strcmp(ce->name,
+ active_cache[i]->name))
+ i++;
+ }
+ }
+}
+
static int do_recursive_merge(struct commit *base, struct commit *next,
const char *base_label, const char *next_label,
unsigned char *head, struct strbuf *msgbuf,
@@ -307,21 +324,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
if (opts->signoff)
append_signoff(msgbuf, 0, 0);
- if (!clean) {
- int i;
- strbuf_addstr(msgbuf, "\nConflicts:\n");
- for (i = 0; i < active_nr;) {
- const struct cache_entry *ce = active_cache[i++];
- if (ce_stage(ce)) {
- strbuf_addch(msgbuf, '\t');
- strbuf_addstr(msgbuf, ce->name);
- strbuf_addch(msgbuf, '\n');
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
- i++;
- }
- }
- }
+ if (!clean)
+ append_conflicts_hint(msgbuf);
return !clean;
}
diff --git a/sequencer.h b/sequencer.h
index db43e9cf86..5ed5cb1d97 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -53,5 +53,6 @@ int sequencer_pick_revisions(struct replay_opts *opts);
extern const char sign_off_header[];
void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);
+void append_conflicts_hint(struct strbuf *msgbuf);
#endif
diff --git a/server-info.c b/server-info.c
index 31f4a749fb..34b0253177 100644
--- a/server-info.c
+++ b/server-info.c
@@ -17,7 +17,7 @@ static int update_info_file(char *path, int (*generate)(FILE *))
FILE *fp = NULL;
safe_create_leading_directories(path);
- fd = mkstemp(tmp);
+ fd = git_mkstemp_mode(tmp, 0666);
if (fd < 0)
goto out;
fp = fdopen(fd, "w");
diff --git a/sha1_file.c b/sha1_file.c
index d7f1838c13..30995e61b3 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1198,7 +1198,7 @@ static void report_pack_garbage(struct string_list *list)
if (!report_garbage)
return;
- sort_string_list(list);
+ string_list_sort(list);
for (i = 0; i < list->nr; i++) {
const char *path = list->items[i].string;
diff --git a/sha1_name.c b/sha1_name.c
index 5b004f513b..cf2a83b143 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -372,10 +372,10 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
int status, exists;
static char hex[41];
- exists = has_sha1_file(sha1);
memcpy(hex, sha1_to_hex(sha1), 40);
if (len == 40 || !len)
return hex;
+ exists = has_sha1_file(sha1);
while (len < 40) {
unsigned char sha1_ret[20];
status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);
@@ -993,7 +993,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
two = lookup_commit_reference_gently(sha1_tmp, 0);
if (!two)
return -1;
- mbs = get_merge_bases(one, two, 1);
+ mbs = get_merge_bases(one, two);
if (!mbs || mbs->next)
st = -1;
else {
diff --git a/strbuf.c b/strbuf.c
index 0346e74a47..88cafd4a70 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -229,7 +229,8 @@ static void add_lines(struct strbuf *out,
const char *next = memchr(buf, '\n', size);
next = next ? (next + 1) : (buf + size);
- prefix = (prefix2 && buf[0] == '\n') ? prefix2 : prefix1;
+ prefix = ((prefix2 && (buf[0] == '\n' || buf[0] == '\t'))
+ ? prefix2 : prefix1);
strbuf_addstr(out, prefix);
strbuf_add(out, buf, next - buf);
size -= next - buf;
diff --git a/string-list.c b/string-list.c
index c5aa0765e8..2a32a3f1f5 100644
--- a/string-list.c
+++ b/string-list.c
@@ -59,13 +59,7 @@ static int add_entry(int insert_at, struct string_list *list, const char *string
struct string_list_item *string_list_insert(struct string_list *list, const char *string)
{
- return string_list_insert_at_index(list, -1, string);
-}
-
-struct string_list_item *string_list_insert_at_index(struct string_list *list,
- int insert_at, const char *string)
-{
- int index = add_entry(insert_at, list, string);
+ int index = add_entry(-1, list, string);
if (index < 0)
index = -1 - index;
@@ -220,7 +214,7 @@ struct string_list_item *string_list_append(struct string_list *list,
/* Yuck */
static compare_strings_fn compare_for_qsort;
-/* Only call this from inside sort_string_list! */
+/* Only call this from inside string_list_sort! */
static int cmp_items(const void *a, const void *b)
{
const struct string_list_item *one = a;
@@ -228,7 +222,7 @@ static int cmp_items(const void *a, const void *b)
return compare_for_qsort(one->string, two->string);
}
-void sort_string_list(struct string_list *list)
+void string_list_sort(struct string_list *list)
{
compare_for_qsort = list->cmp ? list->cmp : strcmp;
qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
diff --git a/string-list.h b/string-list.h
index 494eb5d95d..d3809a1417 100644
--- a/string-list.h
+++ b/string-list.h
@@ -55,9 +55,17 @@ void string_list_remove_empty_items(struct string_list *list, int free_util);
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,
int negative_existing_index);
+/*
+ * Inserts the given string into the sorted list.
+ * If the string already exists, the list is not altered.
+ * Returns the string_list_item, the string is part of.
+ */
struct string_list_item *string_list_insert(struct string_list *list, const char *string);
-struct string_list_item *string_list_insert_at_index(struct string_list *list,
- int insert_at, const char *string);
+
+/*
+ * Checks if the given string is part of a sorted list. If it is part of the list,
+ * return the coresponding string_list_item, NULL otherwise.
+ */
struct string_list_item *string_list_lookup(struct string_list *list, const char *string);
/*
@@ -85,7 +93,7 @@ struct string_list_item *string_list_append(struct string_list *list, const char
*/
struct string_list_item *string_list_append_nodup(struct string_list *list, char *string);
-void sort_string_list(struct string_list *list);
+void string_list_sort(struct string_list *list);
int unsorted_string_list_has_string(struct string_list *list, const char *string);
struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
const char *string);
diff --git a/submodule.c b/submodule.c
index 0690dc50d0..d37d400b22 100644
--- a/submodule.c
+++ b/submodule.c
@@ -301,7 +301,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
left->object.flags |= SYMMETRIC_LEFT;
add_pending_object(rev, &left->object, path);
add_pending_object(rev, &right->object, path);
- merge_bases = get_merge_bases(left, right, 1);
+ merge_bases = get_merge_bases(left, right);
if (merge_bases) {
if (merge_bases->item == left)
*fast_forward = 1;
diff --git a/t/README b/t/README
index 9952261299..d5bb0c9aa1 100644
--- a/t/README
+++ b/t/README
@@ -418,7 +418,8 @@ Don't:
dies in an unexpected way (e.g. segfault).
On the other hand, don't use test_must_fail for running regular
- platform commands; just use '! cmd'.
+ platform commands; just use '! cmd'. We are not in the business
+ of verifying that the world given to us sanely works.
- use perl without spelling it as "$PERL_PATH". This is to help our
friends on Windows where the platform Perl often adds CR before
diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
index cd2baef383..d88da29f77 100755
--- a/t/lib-gpg.sh
+++ b/t/lib-gpg.sh
@@ -12,20 +12,39 @@ else
say "Your version of gpg (1.0.6) is too buggy for testing"
;;
*)
- # key generation info: gpg --homedir t/lib-gpg --gen-key
- # Type DSA and Elgamal, size 2048 bits, no expiration date.
- # Name and email: C O Mitter <committer@example.com>
+ # Available key info:
+ # * Type DSA and Elgamal, size 2048 bits, no expiration date,
+ # name and email: C O Mitter <committer@example.com>
+ # * Type RSA, size 2048 bits, no expiration date,
+ # name and email: Eris Discordia <discord@example.net>
# No password given, to enable non-interactive operation.
- cp -R "$TEST_DIRECTORY"/lib-gpg ./gpghome
- chmod 0700 gpghome
- chmod 0600 gpghome/*
- GNUPGHOME="$(pwd)/gpghome"
- export GNUPGHOME
+ # To generate new key:
+ # gpg --homedir /tmp/gpghome --gen-key
+ # To write armored exported key to keyring:
+ # gpg --homedir /tmp/gpghome --export-secret-keys \
+ # --armor 0xDEADBEEF >> lib-gpg/keyring.gpg
+ # To export ownertrust:
+ # gpg --homedir /tmp/gpghome --export-ownertrust \
+ # > lib-gpg/ownertrust
+ mkdir ./gpghome &&
+ chmod 0700 ./gpghome &&
+ GNUPGHOME="$(pwd)/gpghome" &&
+ export GNUPGHOME &&
+ gpg --homedir "${GNUPGHOME}" 2>/dev/null --import \
+ "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
+ gpg --homedir "${GNUPGHOME}" 2>/dev/null --import-ownertrust \
+ "$TEST_DIRECTORY"/lib-gpg/ownertrust &&
test_set_prereq GPG
;;
esac
fi
+if test_have_prereq GPG &&
+ echo | gpg --homedir "${GNUPGHOME}" -b --rfc1991 >/dev/null 2>&1
+then
+ test_set_prereq RFC1991
+fi
+
sanitize_pgp() {
perl -ne '
/^-----END PGP/ and $in_pgp = 0;
diff --git a/t/lib-gpg/keyring.gpg b/t/lib-gpg/keyring.gpg
new file mode 100644
index 0000000000..fb1f048c22
--- /dev/null
+++ b/t/lib-gpg/keyring.gpg
@@ -0,0 +1,88 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQG7BEZnyykRBACzCPjIpTYNL7Y2tQqlEGTTDlvZcWNLjF5f7ZzuyOqNOidLUgFD
+36qch1LZLSZkShdR3Gae+bsolyjxrlFuFP0eXRPMtqK20aLw7WZvPFpEV1ThMne+
+PRJjYrvghWw3L0VVIAIZ8GXwrVBuU99uEjHEI0ojYloOvFc2jVPgSaoBvwCg48Tj
+fol2foSoJa7XUu9yAL8szg8D/RUsTzNF+I9hSRHl7MYKFMYoKEY9BDgrgAujp7YY
+8qdGsiUb0Ggyzp2kRjZFt4lpcvKhGfHn5GEjmtk+fRbD5qPfMqKFW+T0NPfYlYmL
+JJ4fs4qZ8Lx7x6iG6X51u+YNwsQuIGjMCC3CeNi3F7or651kkNYASbaQ1NROkCIN
+NudyA/0aasvoZUoNJAc2cP5Ifs6WhXMWLfMR2p2XbfKwKNYneec60usnSComcKqh
+sJVk0Gytvr3FOYVhRkXnKAbx+0W2urFP8OFVBTEKO6Ts2VygWGgneQYoHnqzwlUE
+yjOjlr+lyf7u2s/KAxpKA6jnttEdRZAmzWkhuox1wwAUkr27/QAAn3TEzKR1pxxR
++R3dHuFpnnfatMIDC5O0IkMgTyBNaXR0ZXIgPGNvbW1pdHRlckBleGFtcGxlLmNv
+bT6IXgQTEQIAHgUCRmfLKQIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRATtvUe
+zd5DDXQdAKC92f+wOrTkbmPEf+u+qA/Gv6BxQwCfQ128JXCi3MpMB8tI2Kmo15tY
+gnmdAj0ERmfLThAIAM65eT9T6+gg0fJn+Qxhs3FFDPjxK6AOBS3SieWWmXO6stZZ
+plvb7r2+sXYp8HMHntnOX3TRPolIx1dsdkv3W3w8yUzf9Lmo2XMPsZ3/isWdEbOI
+A0rO3B1xwbQO7vEoWHeB7uyYIF6YsIH0pMqxkImciwB1tnJPB9OxqPHlD/HyyHr2
+voj6nmEGaPQWj8/dkfyenXm6XmNZUZL/slk6tRhNwv4cW3QQLh39nbiz9rqvZMKF
+XX8wkY4FdQkJjCGwqzG+7yJcyHvem29/iq//jRLZgdiN8BwV3MCTJyDp8/Wb/d9y
+jZcUm1RdtwRiwfhfQ+zmpyspm7OxINfH65rf7f8ABA0IALRiMRs/eOD59jrYXmPS
+ZQUbiALlbJJtuP2c9N3WZ5OgrhDiAW+SDIN+hgDynJ9b7C2dE3xNaud4zaXAAF44
+J4J0bAo2ZtZoJajw+GXwaZfh4Z7nPNHwEcbFD4/uXPCj9jPkcLOJqGmUY1aXdygo
+t3Hn5U/zo8JxPQ83YbJQhkzAOZ/HGowLNqKgGkLLHn1X9qay0CxlfTQeEN5RZyl3
+b4qRzGgGALFvoheyZIUw1TbjRpbn3kqlJooEQY02VwXFXfLI/LwzglilH6sSckvs
+0WHKLZ+0L6b3CgJHN2RsZ7QxwCBi1aemsvr65FeEXp/AYxaG5duUbsugG8PgoJ06
+bsEAAVQNQO3cXWpuiJ/nNLLnWuPunBKJUlurkBdf2GD+m+muF0VpwDchhqqbTO4e
+FqOISQQYEQIACQUCRmfLTgIbDAAKCRATtvUezd5DDcHsAKDQcoAtDWJFupVRqleB
+Cezx4Q2khACcCs+/LtE8Lb9hC+2cvr3uH5p82AI=
+=aEiU
+-----END PGP PRIVATE KEY BLOCK-----
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQOYBFFMlkcBCADJi/xnAF8yI34PHilSCbM7VtOFO17oFMkpu4cgN2QpPuM5MVjy
+cvrzKSguZFvPCDLzeAFJW1uPxL4SHaHSkisCrFhijH7OJWcOPNPSFCwu+inAoAsv
+Hm4ns6pfDZyRjVTHSY4rdMISqKFRozaXu8vHeBRzIhFnubBCepKZW07oKPnrnELV
+TVUSUVI+6el8JFmJIWxxLNLhfRRSPF0v4MDXPF//iCWiZDI+J1pLvQ5V/f7YtfsD
+GV0oPY66J72BFJG555eKBttnNY901LmI3ocn5P5iVnXDaqMElw7FKpnANXucgY3H
+4kLyNkI3s3J0CGbXI7b3MBWtjctuhWv1q2G5ABEBAAEAB/wLiuza/qEfv1Cfj7FQ
+ytAXpz1YoAcrcM/53TeRQhrbvIee5ZNGhLdCkyot81QeuJrSaXO0E9CxRynrjQQ7
+ibYqN7Hy0uu1kAbQQJjmVdQXTKnKJ7Wm7oM4hYhNsVCKNXc+1+5AfDYGg4nZob36
+qqgHtc+Ardl5VfUg7uF+eZrnSMynjZANgikKbPtE09DKVtVOtUE4xTD9ijkpgn65
+glsZDqb7J4QVgTeEiCDKJsQvin3SwrPBqBxBRULF2TIaMbOwe6dHiiaI85rsvAWS
+VGzonUB3IU1470P2SDIVczbXYUK/nDSGx6ZZ0wLu9ZcCyUPvxVEykuh2P4UWHla+
+nHLRBADMLavcfjsCI5CRUsdurYpgE8Y3bEbcDpvzAu5jT5D25p3YPDODOXD3AKTt
+PzVMARVtv8twkbgAyWaoDevJz8OtmoSwsWjdFo4YvsYw9jV7Yf3GwzD3Ya1ZnW32
+JWQr6cX8qcK0AukAD7UZkVyhU2KBvB02t8lKHLbScHXTYVqrywQA/LNUXwmHji+6
+osnSQAC8X9ggMOEs9dGo7Qlk4JgfGAH17CFI3S3ubsaVEdxz3YwzOkD8SNmEbLyW
+a7CZ/RnpdAZU0nB7kSfbfZl7ajhPbgKBMsaV2yvaDdJeor4m5eKdXffRk0SksxjL
+Z/4P1tTIuL8WzetGB/aDcWDFgseSAAsEALzmf579ptlSmDyGRAKQqub+mj4V3EUZ
+1GVGcfBY86w3BZVDsaRiCtcNjk/lcP4AZ1Vbb42RM6jk8nLsENRc7rf2xa7ZPf0T
+6n5F6W+vk7EG76RoFhKVtGZngGKiDGVavxk3FT/yf8lKrT3wYiT03SZDuZ0pWvku
+FiJGEyesAC8WRz60JEVyaXMgRGlzY29yZGlhIDxkaXNjb3JkQGV4YW1wbGUubmV0
+PokBOAQTAQIAIgUCUUyWRwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ
+YQkuhbcicYlYowf7B+f+FDcLVfw8XzGlKku1F6PI1yGCt7AMO2/JkmO4LlgHuIgF
+pqe5b/XjKl0IsRcbVLitqiIokc8u+7H8yYU67DDliq7t1gqBy+qThSHcgn6WMKTa
+qCqOE2jzHyqulIAzQsJQ+c5SRofEZAKT4Qa2Dy+nsqWDpIE78aJd0Vnkk9U6H2Vu
+ABvUeN/IMgvxPr525o+rBD7LU4J3CtOzfV+sO6+33da+Bm9UhkR4tC4H/n1dDN1J
+YuxBQbgxTq/h8mKe4/7/Yvy+5WsYd96ZRLE2ZFWeWXtKkwmYbQ42G3SZUXaZ8R8O
+tbTyUrjbFKipO4wvXwhyju1l9cxAsrca6xbSCJ0DmARRTJZHAQgAqTtPFcTXqM+U
+o7bOoo+dcHi8XDf/8XSEmZfMKc/U5pSTBk7h1gSKuGzjF2n3wQm6A8+101vTLaQ6
+PoFDFW8uQB00mjymGrRDYFgz8bjhnaekZnA4XThr1ROjffgMhs3uTpCebdV+lL8K
+0oJTHc39TPLTg23DFcRSDN+3ARJJS7+CRBIbt9L5gObpgA4HUap/o6N7O04rQOPU
+83MAqnwo2JTO/Ded0zoad0Vo31Nmk4F+KvEE52ftGHbd7yqIUGKBt2SeTAh850ac
+LeNZP+V1Y7atBCr7/zm+JpHWq9OH7/NomlEIkxL8WDt8GfAKoqZgqefL+ACEnLbA
+t1du3f0FswARAQABAAf8DclaIQDfPM5kYo3y+YVPoykC11RskmQWpVibdlCLHJm/
+/ISSm1fVYT7lpTOpzl0XfVX/jw9s/cviPtNS/r0G/Iwki+gi9Av5bTDiUm/oWWqd
+1waPYPDGwB4QdKOviY/fOSFI9tOsszt5Czs4wDXWy90AZDWd7fkHYisbgofV1sjK
+Q8bYQPabcepcZ2JyET+EpZBEmUHHqQ76bTiqjN+Vz6k1OFlsEBzGkE+WIakAhkQ2
+57oUrRgFe+h6Ch7meB/v6vVfIRSsLpZe183uc4SigqtfsgjbG9PqOcAJOqovDncB
+Scg3qvpWFOAkTA3Re+yBPUd2HHl9WF/TPa2kBDCT2QQAxcJZeUCuUgDgCizqEgfs
+Kzm6dy4G/OJdW0q9m9psHqD1XWLd7ZLE4+eTS1cxktJiGcGNdGoZD0EtgxkV09uM
+12QYCOBErFJzv4/4oledHeEhTaRR/mFFGRp+kWTz2Ai/zNqUd3D++DYUe8g4mVQJ
+6JP014XhvoRnaCfT8cH9Zd0EANsSL70WGdifcVoWKA9jFJhahc0sSG6IZvMOc7bs
+cSbhBqLEnheObkarBP+A+zgllqIf+sbCassMXjcV52mnl9th3J5RWr7scrQLJ9ZX
+Ivz3uoP85vwlUI98dI9roYK0OpKmG4hNFppAcgiCVNVjnQlhuQ/HoexRHxRmnmcb
+38jPA/sEHPCFbLCGOSB+HQNKx/5Wf6VpFX/4oBNbIUiYoxcRl0jpYT7Lc0zbc8So
+HthjPfWhXhKzYvEDC5YgASEy1cNbGMUJcGyuAInwIQjq44FSwRMkI3ISSHnbv1iH
+0wBVJUzpluMebEAesdZUz1DcZWVf6eVJD0dhZxD6DoG7Xj1m9ThUiQEfBBgBAgAJ
+BQJRTJZHAhsMAAoJEGEJLoW3InGJ7HEIAMXkMf4cOWmnAuvvcSm3KpLghuWik9dy
+fn1sY/IG5atoKK+ypmV/TlBlMZqFQzuPIJQT8VLbmxtLlDhJG04LbI6c8axIZxOO
+ZKLy5nTTSy16ztqEeS7eifHLPZg1UFFyEEIQ1XW0CNDAeuWKh90ERjyl4Cg7PnWS
+Z9Ei+zj6JD5Pcdi3BJhQo9WOLOVEJ0NHmewTYqk9QVXH/0v1Hdl4LMJtgcbdbDWk
+4UTkXbg9pn3umCgkNJ3Vs8fWnIWO9Izdr2/wrFY2JvUT7Yvl+wsNIWatvOEzGy7n
+BOW78WUxzhu0YJTLKy+iKCjg5HS5dx6OC+e4aEEgfhNPCMkbvDsJjtQ=
+=hieJ
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/t/lib-gpg/ownertrust b/t/lib-gpg/ownertrust
new file mode 100644
index 0000000000..b3e3c4f1cd
--- /dev/null
+++ b/t/lib-gpg/ownertrust
@@ -0,0 +1,4 @@
+# List of assigned trustvalues, created Thu 11 Dec 2014 01:26:28 PM CET
+# (Use "gpg --import-ownertrust" to restore them)
+73D758744BE721698EC54E8713B6F51ECDDE430D:6:
+D4BE22311AD3131E5EDA29A461092E85B7227189:3:
diff --git a/t/lib-gpg/pubring.gpg b/t/lib-gpg/pubring.gpg
deleted file mode 100644
index 1a3c2d487c..0000000000
--- a/t/lib-gpg/pubring.gpg
+++ /dev/null
Binary files differ
diff --git a/t/lib-gpg/random_seed b/t/lib-gpg/random_seed
deleted file mode 100644
index 95d249f15f..0000000000
--- a/t/lib-gpg/random_seed
+++ /dev/null
Binary files differ
diff --git a/t/lib-gpg/secring.gpg b/t/lib-gpg/secring.gpg
deleted file mode 100644
index 82dca8f80b..0000000000
--- a/t/lib-gpg/secring.gpg
+++ /dev/null
Binary files differ
diff --git a/t/lib-gpg/trustdb.gpg b/t/lib-gpg/trustdb.gpg
deleted file mode 100644
index 4879ae9a84..0000000000
--- a/t/lib-gpg/trustdb.gpg
+++ /dev/null
Binary files differ
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 7713dd2609..03a4c2ee84 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -69,6 +69,7 @@ LockFile accept.lock
PassEnv GIT_VALGRIND
PassEnv GIT_VALGRIND_OPTIONS
PassEnv GNUPGHOME
+PassEnv ASAN_OPTIONS
Alias /dumb/ www/
Alias /auth/dumb/ www/auth/dumb/
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index e53cf6d36d..fac0986134 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -82,4 +82,7 @@ check_approxidate 'Jun 6, 5AM' '2009-06-06 05:00:00'
check_approxidate '5AM Jun 6' '2009-06-06 05:00:00'
check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'
+check_approxidate '2008-12-01' '2008-12-01 19:20:00'
+check_approxidate '2009-12-01' '2009-12-01 19:20:00'
+
test_done
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 2a4a6c1226..452320df83 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -55,16 +55,41 @@ create_gitattributes () {
esac
}
+check_warning () {
+ case "$1" in
+ LF_CRLF) grep "LF will be replaced by CRLF" $2;;
+ CRLF_LF) grep "CRLF will be replaced by LF" $2;;
+ '')
+ >expect
+ grep "will be replaced by" $2 >actual
+ test_cmp expect actual
+ ;;
+ *) false ;;
+ esac
+}
+
create_file_in_repo () {
crlf=$1
attr=$2
+ lfname=$3
+ crlfname=$4
+ lfmixcrlf=$5
+ lfmixcr=$6
+ crlfnul=$7
create_gitattributes "$attr" &&
+ pfx=crlf_${crlf}_attr_${attr}
for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul
do
- pfx=crlf_${crlf}_attr_${attr}_$f.txt &&
- cp $f $pfx && git -c core.autocrlf=$crlf add $pfx
+ fname=${pfx}_$f.txt &&
+ cp $f $fname &&
+ git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
done &&
- git commit -m "core.autocrlf $crlf"
+ git commit -m "core.autocrlf $crlf" &&
+ check_warning "$lfname" ${pfx}_LF.err &&
+ check_warning "$crlfname" ${pfx}_CRLF.err &&
+ check_warning "$lfmixcrlf" ${pfx}_CRLF_mix_LF.err &&
+ check_warning "$lfmixcr" ${pfx}_LF_mix_CR.err &&
+ check_warning "$crlfnul" ${pfx}_CRLF_nul.err
}
check_files_in_repo () {
@@ -140,22 +165,47 @@ test_expect_success 'setup master' '
'
-test_expect_success 'create files' '
- create_file_in_repo false "" &&
- create_file_in_repo true "" &&
- create_file_in_repo input "" &&
- create_file_in_repo false "auto" &&
- create_file_in_repo true "auto" &&
- create_file_in_repo input "auto" &&
+warn_LF_CRLF="LF will be replaced by CRLF"
+warn_CRLF_LF="CRLF will be replaced by LF"
+
+test_expect_success 'add files empty attr' '
+ create_file_in_repo false "" "" "" "" "" "" &&
+ create_file_in_repo true "" "LF_CRLF" "" "LF_CRLF" "" "" &&
+ create_file_in_repo input "" "" "CRLF_LF" "CRLF_LF" "" ""
+'
+
+test_expect_success 'add files attr=auto' '
+ create_file_in_repo false "auto" "" "CRLF_LF" "CRLF_LF" "" "" &&
+ create_file_in_repo true "auto" "LF_CRLF" "" "LF_CRLF" "" "" &&
+ create_file_in_repo input "auto" "" "CRLF_LF" "CRLF_LF" "" ""
+'
+
+test_expect_success 'add files attr=text' '
+ create_file_in_repo false "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" &&
+ create_file_in_repo true "text" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" &&
+ create_file_in_repo input "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF"
+'
+
+test_expect_success 'add files attr=-text' '
+ create_file_in_repo false "-text" "" "" "" "" "" &&
+ create_file_in_repo true "-text" "" "" "" "" "" &&
+ create_file_in_repo input "-text" "" "" "" "" ""
+'
+
+test_expect_success 'add files attr=lf' '
+ create_file_in_repo false "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" &&
+ create_file_in_repo true "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" &&
+ create_file_in_repo input "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF"
+'
- create_file_in_repo false "text" &&
- create_file_in_repo true "text" &&
- create_file_in_repo input "text" &&
+test_expect_success 'add files attr=crlf' '
+ create_file_in_repo false "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" &&
+ create_file_in_repo true "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" &&
+ create_file_in_repo input "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" ""
+'
- create_file_in_repo false "-text" &&
- create_file_in_repo true "-text" &&
- create_file_in_repo input "-text" &&
+test_expect_success 'create files cleanup' '
rm -f *.txt &&
git reset --hard
'
diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh
index 0333dd9875..29e91d861c 100755
--- a/t/t0030-stripspace.sh
+++ b/t/t0030-stripspace.sh
@@ -432,4 +432,10 @@ test_expect_success '-c with changed comment char' '
test_cmp expect actual
'
+test_expect_success 'avoid SP-HT sequence in commented line' '
+ printf "#\tone\n#\n# two\n" >expect &&
+ printf "\tone\n\ntwo\n" | git stripspace -c >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index 6b3cedcf24..988c3925d5 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -64,7 +64,7 @@ test_expect_success "setup case tests" '
git checkout -f master
'
-$test_case 'rename (case change)' '
+test_expect_success 'rename (case change)' '
git mv camelcase CamelCase &&
git commit -m "rename"
'
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index 067f4c6e52..601d02d71f 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -22,7 +22,7 @@ generate_expected_cache_tree_rec () {
# ls-files might have foo/bar, foo/bar/baz, and foo/bar/quux
# We want to count only foo because it's the only direct child
subtrees=$(git ls-files|grep /|cut -d / -f 1|uniq) &&
- subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 {++c} END {print c}') &&
+ subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 != "" {++c} END {print c}') &&
entries=$(git ls-files|wc -l) &&
printf "SHA $dir (%d entries, %d subtrees)\n" "$entries" "$subtree_count" &&
for subtree in $subtrees
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index 57ea5a10c5..d7ef44b4a2 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -289,4 +289,13 @@ test_expect_success 'http paths can be part of context' '
EOF
'
+test_expect_success 'helpers can abort the process' '
+ test_must_fail git \
+ -c credential.helper="!f() { echo quit=1; }; f" \
+ -c credential.helper="verbatim foo bar" \
+ credential fill >stdout &&
+ >expect &&
+ test_cmp expect stdout
+'
+
test_done
diff --git a/t/t1014-read-tree-confusing.sh b/t/t1014-read-tree-confusing.sh
new file mode 100755
index 0000000000..2f5a25d503
--- /dev/null
+++ b/t/t1014-read-tree-confusing.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+test_description='check that read-tree rejects confusing paths'
+. ./test-lib.sh
+
+test_expect_success 'create base tree' '
+ echo content >file &&
+ git add file &&
+ git commit -m base &&
+ blob=$(git rev-parse HEAD:file) &&
+ tree=$(git rev-parse HEAD^{tree})
+'
+
+test_expect_success 'enable core.protectHFS for rejection tests' '
+ git config core.protectHFS true
+'
+
+test_expect_success 'enable core.protectNTFS for rejection tests' '
+ git config core.protectNTFS true
+'
+
+while read path pretty; do
+ : ${pretty:=$path}
+ case "$path" in
+ *SPACE)
+ path="${path%SPACE} "
+ ;;
+ esac
+ test_expect_success "reject $pretty at end of path" '
+ printf "100644 blob %s\t%s" "$blob" "$path" >tree &&
+ bogus=$(git mktree <tree) &&
+ test_must_fail git read-tree $bogus
+ '
+
+ test_expect_success "reject $pretty as subtree" '
+ printf "040000 tree %s\t%s" "$tree" "$path" >tree &&
+ bogus=$(git mktree <tree) &&
+ test_must_fail git read-tree $bogus
+ '
+done <<-EOF
+.
+..
+.git
+.GIT
+${u200c}.Git {u200c}.Git
+.gI${u200c}T .gI{u200c}T
+.GiT${u200c} .GiT{u200c}
+git~1
+.git.SPACE .git.{space}
+.\\\\.GIT\\\\foobar backslashes
+.git\\\\foobar backslashes2
+EOF
+
+test_expect_success 'utf-8 paths allowed with core.protectHFS off' '
+ test_when_finished "git read-tree HEAD" &&
+ test_config core.protectHFS false &&
+ printf "100644 blob %s\t%s" "$blob" ".gi${u200c}t" >tree &&
+ ok=$(git mktree <tree) &&
+ git read-tree $ok
+'
+
+test_done
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index de42d21c92..7eecfb836a 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -111,7 +111,18 @@ do
done
+test_expect_success POSIXPERM 'info/refs respects umask in unshared repo' '
+ rm -f .git/info/refs &&
+ test_unconfig core.sharedrepository &&
+ umask 002 &&
+ git update-server-info &&
+ echo "-rw-rw-r--" >expect &&
+ modebits .git/info/refs >actual &&
+ test_cmp expect actual
+'
+
test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
+ umask 077 &&
git config core.sharedRepository group &&
git reflog expire --all &&
actual="$(ls -l .git/logs/refs/heads/master)" &&
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 7b4707b776..6805b9e6bb 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -619,6 +619,52 @@ test_expect_success 'stdin update/create/verify combination works' '
test_must_fail git rev-parse --verify -q $c
'
+test_expect_success 'stdin verify succeeds for correct value' '
+ git rev-parse $m >expect &&
+ echo "verify $m $m" >stdin &&
+ git update-ref --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin verify succeeds for missing reference' '
+ echo "verify refs/heads/missing $Z" >stdin &&
+ git update-ref --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin verify treats no value as missing' '
+ echo "verify refs/heads/missing" >stdin &&
+ git update-ref --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin verify fails for wrong value' '
+ git rev-parse $m >expect &&
+ echo "verify $m $m~1" >stdin &&
+ test_must_fail git update-ref --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin verify fails for mistaken null value' '
+ git rev-parse $m >expect &&
+ echo "verify $m $Z" >stdin &&
+ test_must_fail git update-ref --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin verify fails for mistaken empty value' '
+ M=$(git rev-parse $m) &&
+ test_when_finished "git update-ref $m $M" &&
+ git rev-parse $m >expect &&
+ echo "verify $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'stdin update refs works with identity updates' '
cat >stdin <<-EOF &&
update $a $m $m
@@ -938,6 +984,52 @@ test_expect_success 'stdin -z update/create/verify combination works' '
test_must_fail git rev-parse --verify -q $c
'
+test_expect_success 'stdin -z verify succeeds for correct value' '
+ git rev-parse $m >expect &&
+ printf $F "verify $m" "$m" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify succeeds for missing reference' '
+ printf $F "verify refs/heads/missing" "$Z" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin -z verify treats no value as missing' '
+ printf $F "verify refs/heads/missing" "" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin -z verify fails for wrong value' '
+ git rev-parse $m >expect &&
+ printf $F "verify $m" "$m~1" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify fails for mistaken null value' '
+ git rev-parse $m >expect &&
+ printf $F "verify $m" "$Z" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify fails for mistaken empty value' '
+ M=$(git rev-parse $m) &&
+ test_when_finished "git update-ref $m $M" &&
+ git rev-parse $m >expect &&
+ printf $F "verify $m" "" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'stdin -z update refs works with identity updates' '
printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "$Z" "" >stdin &&
git update-ref -z --stdin <stdin &&
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index 8cf446165e..779d4e3829 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -287,4 +287,34 @@ test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' '
test_cmp expect actual
'
+# Triggering the bug detected by this test requires a newline to fall
+# exactly BUFSIZ-1 bytes from the end of the file. We don't know
+# what that value is, since it's platform dependent. However, if
+# we choose some value N, we also catch any D which divides N evenly
+# (since we will read backwards in chunks of D). So we choose 8K,
+# which catches glibc (with an 8K BUFSIZ) and *BSD (1K).
+#
+# Each line is 114 characters, so we need 75 to still have a few before the
+# last 8K. The 89-character padding on the final entry lines up our
+# newline exactly.
+test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' '
+ git checkout -b reflogskip &&
+ z38=00000000000000000000000000000000000000 &&
+ ident="abc <xyz> 0000000001 +0000" &&
+ for i in $(test_seq 1 75); do
+ printf "$z38%02d $z38%02d %s\t" $i $(($i+1)) "$ident" &&
+ if test $i = 75; then
+ for j in $(test_seq 1 89); do
+ printf X
+ done
+ else
+ printf X
+ fi &&
+ printf "\n"
+ done >.git/logs/refs/heads/reflogskip &&
+ git rev-parse reflogskip@{73} >actual &&
+ echo ${z38}03 >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 019fddd4e8..cfb32b6242 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -229,8 +229,12 @@ test_expect_success 'tag with incorrect tag name & missing tagger' '
echo $tag >.git/refs/tags/wrong &&
test_when_finished "git update-ref -d refs/tags/wrong" &&
git fsck --tags 2>out &&
- grep "invalid .tag. name" out &&
- grep "expected .tagger. line" out
+
+ cat >expect <<-EOF &&
+ warning in tag $tag: invalid '\''tag'\'' name: wrong name format
+ warning in tag $tag: invalid format - expected '\''tagger'\'' line
+ EOF
+ test_cmp expect out
'
test_expect_success 'tag with bad tagger' '
@@ -309,34 +313,54 @@ 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' '
+while read name path pretty; do
+ while read mode type; do
+ : ${pretty:=$path}
+ test_expect_success "fsck notices $pretty as $type" '
+ (
+ git init $name-$type &&
+ cd $name-$type &&
+ echo content >file &&
+ git add file &&
+ git commit -m base &&
+ blob=$(git rev-parse :file) &&
+ tree=$(git rev-parse HEAD^{tree}) &&
+ value=$(eval "echo \$$type") &&
+ printf "$mode $type %s\t%s" "$value" "$path" >bad &&
+ bad_tree=$(git mktree <bad) &&
+ git fsck 2>out &&
+ cat out &&
+ grep "warning.*tree $bad_tree" out
+ )'
+ done <<-\EOF
+ 100644 blob
+ 040000 tree
+ EOF
+done <<-EOF
+dot .
+dotdot ..
+dotgit .git
+dotgit-case .GIT
+dotgit-unicode .gI${u200c}T .gI{u200c}T
+dotgit-case2 .Git
+git-tilde1 git~1
+dotgitdot .git.
+dot-backslash-case .\\\\.GIT\\\\foobar
+dotgit-case-backslash .git\\\\foobar
+EOF
+
+test_expect_success 'fsck allows .Ňit' '
(
- 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
+ git init not-dotgit &&
+ cd not-dotgit &&
+ echo content >file &&
+ git add file &&
+ git commit -m base &&
+ blob=$(git rev-parse :file) &&
+ printf "100644 blob $blob\t.\\305\\207it" >tree &&
+ tree=$(git mktree <tree) &&
+ git fsck 2>err &&
+ test_line_count = 0 err
)
'
diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh
index f171a5578b..a12afe93f3 100755
--- a/t/t2004-checkout-cache-temp.sh
+++ b/t/t2004-checkout-cache-temp.sh
@@ -10,202 +10,212 @@ rather than the tracked path.'
. ./test-lib.sh
-test_expect_success \
-'preparation' '
-mkdir asubdir &&
-echo tree1path0 >path0 &&
-echo tree1path1 >path1 &&
-echo tree1path3 >path3 &&
-echo tree1path4 >path4 &&
-echo tree1asubdir/path5 >asubdir/path5 &&
-git update-index --add path0 path1 path3 path4 asubdir/path5 &&
-t1=$(git write-tree) &&
-rm -f path* .merge_* out .git/index &&
-echo tree2path0 >path0 &&
-echo tree2path1 >path1 &&
-echo tree2path2 >path2 &&
-echo tree2path4 >path4 &&
-git update-index --add path0 path1 path2 path4 &&
-t2=$(git write-tree) &&
-rm -f path* .merge_* out .git/index &&
-echo tree2path0 >path0 &&
-echo tree3path1 >path1 &&
-echo tree3path2 >path2 &&
-echo tree3path3 >path3 &&
-git update-index --add path0 path1 path2 path3 &&
-t3=$(git write-tree)'
-
-test_expect_success \
-'checkout one stage 0 to temporary file' '
-rm -f path* .merge_* out .git/index &&
-git read-tree $t1 &&
-git checkout-index --temp -- path1 >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = path1 &&
-p=$(cut "-d " -f1 out) &&
-test -f $p &&
-test $(cat $p) = tree1path1'
-
-test_expect_success \
-'checkout all stage 0 to temporary files' '
-rm -f path* .merge_* out .git/index &&
-git read-tree $t1 &&
-git checkout-index -a --temp >out &&
-test_line_count = 5 out &&
-for f in path0 path1 path3 path4 asubdir/path5
-do
- test $(grep $f out | cut "-d " -f2) = $f &&
- p=$(grep $f out | cut "-d " -f1) &&
+test_expect_success 'setup' '
+ mkdir asubdir &&
+ echo tree1path0 >path0 &&
+ echo tree1path1 >path1 &&
+ echo tree1path3 >path3 &&
+ echo tree1path4 >path4 &&
+ echo tree1asubdir/path5 >asubdir/path5 &&
+ git update-index --add path0 path1 path3 path4 asubdir/path5 &&
+ t1=$(git write-tree) &&
+ rm -f path* .merge_* actual .git/index &&
+ echo tree2path0 >path0 &&
+ echo tree2path1 >path1 &&
+ echo tree2path2 >path2 &&
+ echo tree2path4 >path4 &&
+ git update-index --add path0 path1 path2 path4 &&
+ t2=$(git write-tree) &&
+ rm -f path* .merge_* actual .git/index &&
+ echo tree2path0 >path0 &&
+ echo tree3path1 >path1 &&
+ echo tree3path2 >path2 &&
+ echo tree3path3 >path3 &&
+ git update-index --add path0 path1 path2 path3 &&
+ t3=$(git write-tree)
+'
+
+test_expect_success 'checkout one stage 0 to temporary file' '
+ rm -f path* .merge_* actual .git/index &&
+ git read-tree $t1 &&
+ git checkout-index --temp -- path1 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path1 &&
+ p=$(cut "-d " -f1 actual) &&
test -f $p &&
- test $(cat $p) = tree1$f
-done'
-
-test_expect_success \
-'prepare 3-way merge' '
-rm -f path* .merge_* out .git/index &&
-git read-tree -m $t1 $t2 $t3'
-
-test_expect_success \
-'checkout one stage 2 to temporary file' '
-rm -f path* .merge_* out &&
-git checkout-index --stage=2 --temp -- path1 >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = path1 &&
-p=$(cut "-d " -f1 out) &&
-test -f $p &&
-test $(cat $p) = tree2path1'
-
-test_expect_success \
-'checkout all stage 2 to temporary files' '
-rm -f path* .merge_* out &&
-git checkout-index --all --stage=2 --temp >out &&
-test_line_count = 3 out &&
-for f in path1 path2 path4
-do
- test $(grep $f out | cut "-d " -f2) = $f &&
- p=$(grep $f out | cut "-d " -f1) &&
+ test $(cat $p) = tree1path1
+'
+
+test_expect_success 'checkout all stage 0 to temporary files' '
+ rm -f path* .merge_* actual .git/index &&
+ git read-tree $t1 &&
+ git checkout-index -a --temp >actual &&
+ test_line_count = 5 actual &&
+ for f in path0 path1 path3 path4 asubdir/path5
+ do
+ test $(grep $f actual | cut "-d " -f2) = $f &&
+ p=$(grep $f actual | cut "-d " -f1) &&
+ test -f $p &&
+ test $(cat $p) = tree1$f
+ done
+'
+
+test_expect_success 'setup 3-way merge' '
+ rm -f path* .merge_* actual .git/index &&
+ git read-tree -m $t1 $t2 $t3
+'
+
+test_expect_success 'checkout one stage 2 to temporary file' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=2 --temp -- path1 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path1 &&
+ p=$(cut "-d " -f1 actual) &&
test -f $p &&
- test $(cat $p) = tree2$f
-done'
-
-test_expect_success \
-'checkout all stages/one file to nothing' '
-rm -f path* .merge_* out &&
-git checkout-index --stage=all --temp -- path0 >out &&
-test_line_count = 0 out'
-
-test_expect_success \
-'checkout all stages/one file to temporary files' '
-rm -f path* .merge_* out &&
-git checkout-index --stage=all --temp -- path1 >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = path1 &&
-cut "-d " -f1 out | (read s1 s2 s3 &&
-test -f $s1 &&
-test -f $s2 &&
-test -f $s3 &&
-test $(cat $s1) = tree1path1 &&
-test $(cat $s2) = tree2path1 &&
-test $(cat $s3) = tree3path1)'
-
-test_expect_success \
-'checkout some stages/one file to temporary files' '
-rm -f path* .merge_* out &&
-git checkout-index --stage=all --temp -- path2 >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = path2 &&
-cut "-d " -f1 out | (read s1 s2 s3 &&
-test $s1 = . &&
-test -f $s2 &&
-test -f $s3 &&
-test $(cat $s2) = tree2path2 &&
-test $(cat $s3) = tree3path2)'
-
-test_expect_success \
-'checkout all stages/all files to temporary files' '
-rm -f path* .merge_* out &&
-git checkout-index -a --stage=all --temp >out &&
-test_line_count = 5 out'
-
-test_expect_success \
-'-- path0: no entry' '
-test x$(grep path0 out | cut "-d " -f2) = x'
-
-test_expect_success \
-'-- path1: all 3 stages' '
-test $(grep path1 out | cut "-d " -f2) = path1 &&
-grep path1 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test -f $s1 &&
-test -f $s2 &&
-test -f $s3 &&
-test $(cat $s1) = tree1path1 &&
-test $(cat $s2) = tree2path1 &&
-test $(cat $s3) = tree3path1)'
-
-test_expect_success \
-'-- path2: no stage 1, have stage 2 and 3' '
-test $(grep path2 out | cut "-d " -f2) = path2 &&
-grep path2 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test $s1 = . &&
-test -f $s2 &&
-test -f $s3 &&
-test $(cat $s2) = tree2path2 &&
-test $(cat $s3) = tree3path2)'
-
-test_expect_success \
-'-- path3: no stage 2, have stage 1 and 3' '
-test $(grep path3 out | cut "-d " -f2) = path3 &&
-grep path3 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test -f $s1 &&
-test $s2 = . &&
-test -f $s3 &&
-test $(cat $s1) = tree1path3 &&
-test $(cat $s3) = tree3path3)'
-
-test_expect_success \
-'-- path4: no stage 3, have stage 1 and 3' '
-test $(grep path4 out | cut "-d " -f2) = path4 &&
-grep path4 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test -f $s1 &&
-test -f $s2 &&
-test $s3 = . &&
-test $(cat $s1) = tree1path4 &&
-test $(cat $s2) = tree2path4)'
-
-test_expect_success \
-'-- asubdir/path5: no stage 2 and 3 have stage 1' '
-test $(grep asubdir/path5 out | cut "-d " -f2) = asubdir/path5 &&
-grep asubdir/path5 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test -f $s1 &&
-test $s2 = . &&
-test $s3 = . &&
-test $(cat $s1) = tree1asubdir/path5)'
-
-test_expect_success \
-'checkout --temp within subdir' '
-(cd asubdir &&
- git checkout-index -a --stage=all >out &&
- test_line_count = 1 out &&
- test $(grep path5 out | cut "-d " -f2) = path5 &&
- grep path5 out | cut "-d " -f1 | (read s1 s2 s3 &&
- test -f ../$s1 &&
- test $s2 = . &&
- test $s3 = . &&
- test $(cat ../$s1) = tree1asubdir/path5)
-)'
-
-test_expect_success \
-'checkout --temp symlink' '
-rm -f path* .merge_* out .git/index &&
-test_ln_s_add b a &&
-t4=$(git write-tree) &&
-rm -f .git/index &&
-git read-tree $t4 &&
-git checkout-index --temp -a >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = a &&
-p=$(cut "-d " -f1 out) &&
-test -f $p &&
-test $(cat $p) = b'
+ test $(cat $p) = tree2path1
+'
+
+test_expect_success 'checkout all stage 2 to temporary files' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --all --stage=2 --temp >actual &&
+ test_line_count = 3 actual &&
+ for f in path1 path2 path4
+ do
+ test $(grep $f actual | cut "-d " -f2) = $f &&
+ p=$(grep $f actual | cut "-d " -f1) &&
+ test -f $p &&
+ test $(cat $p) = tree2$f
+ done
+'
+
+test_expect_success 'checkout all stages/one file to nothing' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=all --temp -- path0 >actual &&
+ test_line_count = 0 actual
+'
+
+test_expect_success 'checkout all stages/one file to temporary files' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=all --temp -- path1 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path1 &&
+ cut "-d " -f1 actual | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test -f $s2 &&
+ test -f $s3 &&
+ test $(cat $s1) = tree1path1 &&
+ test $(cat $s2) = tree2path1 &&
+ test $(cat $s3) = tree3path1)
+'
+
+test_expect_success 'checkout some stages/one file to temporary files' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=all --temp -- path2 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path2 &&
+ cut "-d " -f1 actual | (read s1 s2 s3 &&
+ test $s1 = . &&
+ test -f $s2 &&
+ test -f $s3 &&
+ test $(cat $s2) = tree2path2 &&
+ test $(cat $s3) = tree3path2)
+'
+
+test_expect_success 'checkout all stages/all files to temporary files' '
+ rm -f path* .merge_* actual &&
+ git checkout-index -a --stage=all --temp >actual &&
+ test_line_count = 5 actual
+'
+
+test_expect_success '-- path0: no entry' '
+ test x$(grep path0 actual | cut "-d " -f2) = x
+'
+
+test_expect_success '-- path1: all 3 stages' '
+ test $(grep path1 actual | cut "-d " -f2) = path1 &&
+ grep path1 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test -f $s2 &&
+ test -f $s3 &&
+ test $(cat $s1) = tree1path1 &&
+ test $(cat $s2) = tree2path1 &&
+ test $(cat $s3) = tree3path1)
+'
+
+test_expect_success '-- path2: no stage 1, have stage 2 and 3' '
+ test $(grep path2 actual | cut "-d " -f2) = path2 &&
+ grep path2 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test $s1 = . &&
+ test -f $s2 &&
+ test -f $s3 &&
+ test $(cat $s2) = tree2path2 &&
+ test $(cat $s3) = tree3path2)
+'
+
+test_expect_success '-- path3: no stage 2, have stage 1 and 3' '
+ test $(grep path3 actual | cut "-d " -f2) = path3 &&
+ grep path3 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test $s2 = . &&
+ test -f $s3 &&
+ test $(cat $s1) = tree1path3 &&
+ test $(cat $s3) = tree3path3)
+'
+
+test_expect_success '-- path4: no stage 3, have stage 1 and 3' '
+ test $(grep path4 actual | cut "-d " -f2) = path4 &&
+ grep path4 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test -f $s2 &&
+ test $s3 = . &&
+ test $(cat $s1) = tree1path4 &&
+ test $(cat $s2) = tree2path4)
+'
+
+test_expect_success '-- asubdir/path5: no stage 2 and 3 have stage 1' '
+ test $(grep asubdir/path5 actual | cut "-d " -f2) = asubdir/path5 &&
+ grep asubdir/path5 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test $s2 = . &&
+ test $s3 = . &&
+ test $(cat $s1) = tree1asubdir/path5)
+'
+
+test_expect_success 'checkout --temp within subdir' '
+ (
+ cd asubdir &&
+ git checkout-index -a --stage=all >actual &&
+ test_line_count = 1 actual &&
+ test $(grep path5 actual | cut "-d " -f2) = path5 &&
+ grep path5 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f ../$s1 &&
+ test $s2 = . &&
+ test $s3 = . &&
+ test $(cat ../$s1) = tree1asubdir/path5)
+ )
+'
+
+test_expect_success 'checkout --temp symlink' '
+ rm -f path* .merge_* actual .git/index &&
+ test_ln_s_add path7 path6 &&
+ git checkout-index --temp -a >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path6 &&
+ p=$(cut "-d " -f1 actual) &&
+ test -f $p &&
+ test $(cat $p) = path7
+'
+
+test_expect_success 'emit well-formed relative path' '
+ rm -f path* .merge_* actual .git/index &&
+ >path0123456789 &&
+ git update-index --add path0123456789 &&
+ (
+ cd asubdir &&
+ git checkout-index --temp -- ../path0123456789 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = ../path0123456789
+ )
+'
test_done
diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh
index 6ecb559465..468a000e4b 100755
--- a/t/t2024-checkout-dwim.sh
+++ b/t/t2024-checkout-dwim.sh
@@ -185,4 +185,22 @@ test_expect_success 'checkout <branch> -- succeeds, even if a file with the same
test_branch_upstream spam repo_c spam
'
+test_expect_success 'loosely defined local base branch is reported correctly' '
+
+ git checkout master &&
+ git branch strict &&
+ git branch loose &&
+ git commit --allow-empty -m "a bit more" &&
+
+ test_config branch.strict.remote . &&
+ test_config branch.loose.remote . &&
+ test_config branch.strict.merge refs/heads/master &&
+ test_config branch.loose.merge master &&
+
+ git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect &&
+ git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual &&
+
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh
index 1bafb9098c..dfe02f4818 100755
--- a/t/t2107-update-index-basic.sh
+++ b/t/t2107-update-index-basic.sh
@@ -65,4 +65,19 @@ test_expect_success '--cacheinfo mode,sha1,path (new syntax)' '
test_cmp expect actual
'
+test_expect_success '.lock files cleaned up' '
+ mkdir cleanup &&
+ (
+ cd cleanup &&
+ mkdir worktree &&
+ git init repo &&
+ cd repo &&
+ git config core.worktree ../../worktree &&
+ # --refresh triggers late setup_work_tree,
+ # active_cache_changed is zero, rollback_lock_file fails
+ git update-index --refresh &&
+ ! test -f .git/index.lock
+ )
+'
+
test_done
diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..4d4b02e760 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -12,11 +12,25 @@ test_expect_success 'setup' '
'
test_expect_success 'ls-tree a[a] matches literally' '
- cat >expected <<EOF &&
-100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a[a]/three
-EOF
+ cat >expect <<-\EOF &&
+ 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a[a]/three
+ EOF
git ls-tree -r HEAD "a[a]" >actual &&
- test_cmp expected actual
+ test_cmp expect actual
+'
+
+test_expect_success 'ls-tree outside prefix' '
+ cat >expect <<-\EOF &&
+ 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 ../a[a]/three
+ EOF
+ ( cd aa && git ls-tree -r HEAD "../a[a]"; ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'ls-tree does not yet support negated pathspec' '
+ git ls-files ":(exclude)a" "a*" >expect &&
+ git ls-tree --name-only -r HEAD ":(exclude)a" "a*" >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 432921b6b8..ddea49808d 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -97,6 +97,20 @@ test_expect_success 'git branch -m o/o o should fail when o/p exists' '
test_must_fail git branch -m o/o o
'
+test_expect_success 'git branch -m o/q o/p should fail when o/p exists' '
+ git branch o/q &&
+ test_must_fail git branch -m o/q o/p
+'
+
+test_expect_success 'git branch -M o/q o/p should work when o/p exists' '
+ git branch -M o/q o/p
+'
+
+test_expect_success 'git branch -m -f o/q o/p should work when o/p exists' '
+ git branch o/q &&
+ git branch -m -f o/q o/p
+'
+
test_expect_success 'git branch -m q r/q should fail when r exists' '
git branch q &&
git branch r &&
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 223b98433c..7c5ad08626 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -351,19 +351,45 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s'
test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
pristine_detach initial &&
test_must_fail git cherry-pick picked &&
+
git commit -a -s &&
- pwd &&
- cat <<EOF > expected &&
-picked
-Signed-off-by: C O Mitter <committer@example.com>
+ # Do S-o-b and Conflicts appear in the right order?
+ cat <<-\EOF >expect &&
+ Signed-off-by: C O Mitter <committer@example.com>
+ # Conflicts:
+ EOF
+ grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+ test_cmp expect actual &&
+
+ cat <<-\EOF >expected &&
+ picked
-Conflicts:
- foo
-EOF
+ Signed-off-by: C O Mitter <committer@example.com>
+ EOF
- git show -s --pretty=format:%B > actual &&
+ git show -s --pretty=format:%B >actual &&
test_cmp expected actual
'
+test_expect_success 'commit --amend -s places the sign-off at the right place' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick picked &&
+
+ # emulate old-style conflicts block
+ mv .git/MERGE_MSG .git/MERGE_MSG+ &&
+ sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
+
+ git commit -a &&
+ git commit --amend -s &&
+
+ # Do S-o-b and Conflicts appear in the right order?
+ cat <<-\EOF >expect &&
+ Signed-off-by: C O Mitter <committer@example.com>
+ Conflicts:
+ EOF
+ grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index fe274e2fb1..f7ff1f555d 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -91,6 +91,13 @@ test_expect_success 'error out when attempting to add ignored ones without -f' '
! (git ls-files | grep "\\.ig")
'
+test_expect_success 'error out when attempting to add ignored ones but add others' '
+ touch a.if &&
+ test_must_fail git add a.?? &&
+ ! (git ls-files | grep "\\.ig") &&
+ (git ls-files | grep a.if)
+'
+
test_expect_success 'add ignored ones with -f' '
git add -f a.?? &&
git ls-files --error-unmatch a.ig
@@ -311,7 +318,6 @@ cat >expect.err <<\EOF
The following paths are ignored by one of your .gitignore files:
ignored-file
Use -f if you really want to add them.
-fatal: no files added
EOF
cat >expect.out <<\EOF
add 'track-this'
diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh
index 27e98a8f9d..8920464896 100755
--- a/t/t4008-diff-break-rewrite.sh
+++ b/t/t4008-diff-break-rewrite.sh
@@ -123,10 +123,10 @@ test_expect_success \
'git diff-index -B -M "$tree" >current'
# file0 changed from regular to symlink. file1 is very close to the preimage of file0.
-# because we break file0, file1 can become a rename of it.
+# the change does not make file0 disappear, so file1 is denoted as a copy of file0
cat >expected <<\EOF
:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R file0 file1
+:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 C file0 file1
EOF
test_expect_success \
diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
index 55d549fcf4..8c9823765e 100755
--- a/t/t4023-diff-rename-typechange.sh
+++ b/t/t4023-diff-rename-typechange.sh
@@ -76,7 +76,8 @@ test_expect_success 'moves and renames' '
git diff-tree three four -r --name-status -B -M | sort >actual &&
{
- echo "R100 foo bar"
+ # see -B -M (#6) in t4008
+ echo "C100 foo bar"
echo "T100 foo"
} | sort >expect &&
test_cmp expect actual
diff --git a/t/t4026-color.sh b/t/t4026-color.sh
index 63e423838f..267c43bd95 100755
--- a/t/t4026-color.sh
+++ b/t/t4026-color.sh
@@ -45,14 +45,29 @@ test_expect_success 'fg bg attr...' '
color "blue bold dim ul blink reverse" "[1;2;4;5;7;34m"
'
+# note that nobold and nodim are the same code (22)
+test_expect_success 'attr negation' '
+ color "nobold nodim noul noblink noreverse" "[22;24;25;27m"
+'
+
test_expect_success 'long color specification' '
color "254 255 bold dim ul blink reverse" "[1;2;4;5;7;38;5;254;48;5;255m"
'
+test_expect_success 'absurdly long color specification' '
+ color \
+ "#ffffff #ffffff bold nobold dim nodim ul noul blink noblink reverse noreverse" \
+ "[1;2;4;5;7;22;24;25;27;38;2;255;255;255;48;2;255;255;255m"
+'
+
test_expect_success '256 colors' '
color "254 bold 255" "[1;38;5;254;48;5;255m"
'
+test_expect_success '24-bit colors' '
+ color "#ff00ff black" "[38;2;255;0;255;40m"
+'
+
test_expect_success '"normal" yields no color at all"' '
color "normal black" "[40m"
'
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 5edb79a058..306e6f39ac 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -85,6 +85,7 @@ test_expect_success setup '
git format-patch --stdout first >patch1 &&
{
+ echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
echo "X-Fake-Field: Line One" &&
echo "X-Fake-Field: Line Two" &&
echo "X-Fake-Field: Line Three" &&
@@ -536,4 +537,26 @@ test_expect_success 'am empty-file does not infloop' '
test_i18ncmp expected actual
'
+test_expect_success 'am --message-id really adds the message id' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ git checkout HEAD^ &&
+ git am --message-id patch1.eml &&
+ test_path_is_missing .git/rebase-apply &&
+ git cat-file commit HEAD | tail -n1 >actual &&
+ grep Message-Id patch1.eml >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'am --message-id -s signs off after the message id' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ git checkout HEAD^ &&
+ git am -s --message-id patch1.eml &&
+ test_path_is_missing .git/rebase-apply &&
+ git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
+ grep Message-Id patch1.eml >expected &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index d01bbdc968..4b68bbafbe 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -101,7 +101,7 @@ test_expect_success \
ten=0123456789 && hundred=$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten &&
echo long filename >a/four$hundred &&
mkdir a/bin &&
- cp /bin/sh a/bin &&
+ test-genrandom "frotz" 500000 >a/bin/sh &&
printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
printf "A not substituted O" >a/substfile2 &&
if test_have_prereq SYMLINKS; then
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index 9e1ad1ca21..60df10f46a 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -35,6 +35,10 @@ do
then
check_mailinfo $mail --no-inbody-headers
fi
+ if test -f "$TEST_DIRECTORY"/t5100/msg$mail--message-id
+ then
+ check_mailinfo $mail --message-id
+ fi
'
done
diff --git a/t/t5100/info0012--message-id b/t/t5100/info0012--message-id
new file mode 100644
index 0000000000..ac1216ff75
--- /dev/null
+++ b/t/t5100/info0012--message-id
@@ -0,0 +1,5 @@
+Author: Dmitriy Blinov
+Email: bda@mnsspb.ru
+Subject: Изменён список пакетов необходимых для сборки
+Date: Wed, 12 Nov 2008 17:54:41 +0300
+
diff --git a/t/t5100/msg0012--message-id b/t/t5100/msg0012--message-id
new file mode 100644
index 0000000000..376e26e9ae
--- /dev/null
+++ b/t/t5100/msg0012--message-id
@@ -0,0 +1,8 @@
+textlive-* исправлены на texlive-*
+docutils заменён на python-docutils
+
+Действительно, оказалось, что rest2web вытягивает за собой
+python-docutils. В то время как сам rest2web не нужен.
+
+Signed-off-by: Dmitriy Blinov <bda@mnsspb.ru>
+Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
diff --git a/t/t5100/patch0012--message-id b/t/t5100/patch0012--message-id
new file mode 100644
index 0000000000..36a0b68161
--- /dev/null
+++ b/t/t5100/patch0012--message-id
@@ -0,0 +1,30 @@
+---
+ howto/build_navy.txt | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/howto/build_navy.txt b/howto/build_navy.txt
+index 3fd3afb..0ee807e 100644
+--- a/howto/build_navy.txt
++++ b/howto/build_navy.txt
+@@ -119,8 +119,8 @@
+ - libxv-dev
+ - libusplash-dev
+ - latex-make
+- - textlive-lang-cyrillic
+- - textlive-latex-extra
++ - texlive-lang-cyrillic
++ - texlive-latex-extra
+ - dia
+ - python-pyrex
+ - libtool
+@@ -128,7 +128,7 @@
+ - sox
+ - cython
+ - imagemagick
+- - docutils
++ - python-docutils
+
+ #. на машине dinar: добавить свой открытый ssh-ключ в authorized_keys2 пользователя ddev
+ #. на своей машине: отредактировать /etc/sudoers (команда ``visudo``) примерно следующим образом::
+--
+1.5.6.5
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 0736bcbcd5..04cea97f87 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -76,8 +76,7 @@ test_expect_success 'refuse pushing rewound head without --force' '
test "$victim_head" = "$pushed_head"
'
-test_expect_success \
- 'push can be used to delete a ref' '
+test_expect_success 'push can be used to delete a ref' '
( cd victim && git branch extra master ) &&
git send-pack ./victim :extra master &&
( cd victim &&
@@ -196,19 +195,6 @@ rewound_push_setup() {
)
}
-rewound_push_succeeded() {
- cmp ../parent/.git/refs/heads/master .git/refs/heads/master
-}
-
-rewound_push_failed() {
- if rewound_push_succeeded
- then
- false
- else
- true
- fi
-}
-
test_expect_success 'pushing explicit refspecs respects forcing' '
rewound_push_setup &&
parent_orig=$(cd parent && git rev-parse --verify master) &&
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index ac79dd915d..17c6330f98 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -1113,4 +1113,9 @@ test_extra_arg set-url origin newurl oldurl
# prune takes any number of args
# update takes any number of args
+test_expect_success 'add remote matching the "insteadOf" URL' '
+ git config url.xyz@example.com.insteadOf backup &&
+ git remote add backup xyz@example.com
+'
+
test_done
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index f4da20aa9b..85c7fecd22 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1330,4 +1330,108 @@ test_expect_success 'fetch into bare respects core.logallrefupdates' '
)
'
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+ git push testrepo master &&
+ (
+ cd testrepo &&
+ git reset --hard &&
+ git config receive.denyCurrentBranch updateInstead
+ ) &&
+ test_commit third path2 &&
+
+ # Try pushing into a repository with pristine working tree
+ git push testrepo master &&
+ (
+ cd testrepo &&
+ git update-index -q --refresh &&
+ git diff-files --quiet -- &&
+ git diff-index --quiet --cached HEAD -- &&
+ test third = "$(cat path2)" &&
+ test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+ ) &&
+
+ # Try pushing into a repository with working tree needing a refresh
+ (
+ cd testrepo &&
+ git reset --hard HEAD^ &&
+ test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+ test-chmtime +100 path1
+ ) &&
+ git push testrepo master &&
+ (
+ cd testrepo &&
+ git update-index -q --refresh &&
+ git diff-files --quiet -- &&
+ git diff-index --quiet --cached HEAD -- &&
+ test_cmp ../path1 path1 &&
+ test third = "$(cat path2)" &&
+ test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+ ) &&
+
+ # Update what is to be pushed
+ test_commit fourth path2 &&
+
+ # Try pushing into a repository with a dirty working tree
+ # (1) the working tree updated
+ (
+ cd testrepo &&
+ echo changed >path1
+ ) &&
+ test_must_fail git push testrepo master &&
+ (
+ cd testrepo &&
+ test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+ git diff --quiet --cached &&
+ test changed = "$(cat path1)"
+ ) &&
+
+ # (2) the index updated
+ (
+ cd testrepo &&
+ echo changed >path1 &&
+ git add path1
+ ) &&
+ test_must_fail git push testrepo master &&
+ (
+ cd testrepo &&
+ test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+ git diff --quiet &&
+ test changed = "$(cat path1)"
+ ) &&
+
+ # Introduce a new file in the update
+ test_commit fifth path3 &&
+
+ # (3) the working tree has an untracked file that would interfere
+ (
+ cd testrepo &&
+ git reset --hard &&
+ echo changed >path3
+ ) &&
+ test_must_fail git push testrepo master &&
+ (
+ cd testrepo &&
+ test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
+ git diff --quiet &&
+ git diff --quiet --cached &&
+ test changed = "$(cat path3)"
+ ) &&
+
+ # (4) the target changes to what gets pushed but it still is a change
+ (
+ cd testrepo &&
+ git reset --hard &&
+ echo fifth >path3 &&
+ git add path3
+ ) &&
+ test_must_fail git push testrepo master &&
+ (
+ cd testrepo &&
+ test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
+ git diff --quiet &&
+ test fifth = "$(cat path3)"
+ )
+
+'
+
test_done
diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh
index edea9f957e..207899a99f 100755
--- a/t/t5527-fetch-odd-refs.sh
+++ b/t/t5527-fetch-odd-refs.sh
@@ -26,4 +26,37 @@ test_expect_success 'suffix ref is ignored during fetch' '
test_cmp expect actual
'
+test_expect_success 'try to create repo with absurdly long refname' '
+ ref240=$_z40/$_z40/$_z40/$_z40/$_z40/$_z40 &&
+ ref1440=$ref240/$ref240/$ref240/$ref240/$ref240/$ref240 &&
+ git init long &&
+ (
+ cd long &&
+ test_commit long &&
+ test_commit master
+ ) &&
+ if git -C long update-ref refs/heads/$ref1440 long; then
+ test_set_prereq LONG_REF
+ else
+ echo >&2 "long refs not supported"
+ fi
+'
+
+test_expect_success LONG_REF 'fetch handles extremely long refname' '
+ git fetch long refs/heads/*:refs/remotes/long/* &&
+ cat >expect <<-\EOF &&
+ long
+ master
+ EOF
+ git for-each-ref --format="%(subject)" refs/remotes/long >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success LONG_REF 'push handles extremely long refname' '
+ git push long :refs/heads/$ref1440 &&
+ git -C long for-each-ref --format="%(subject)" refs/heads >actual &&
+ echo master >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index 6537911a43..3e783fc450 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -198,4 +198,21 @@ test_expect_success 'clone using repo pointed at by gitfile as reference' '
test_cmp expected "$base_dir/O/.git/objects/info/alternates"
'
+test_expect_success 'clone and dissociate from reference' '
+ git init P &&
+ (
+ cd P && test_commit one
+ ) &&
+ git clone P Q &&
+ (
+ cd Q && test_commit two
+ ) &&
+ git clone --no-local --reference=P Q R &&
+ git clone --no-local --reference=P --dissociate Q S &&
+ # removing the reference P would corrupt R but not S
+ rm -fr P &&
+ test_must_fail git -C R fsck &&
+ git -C S fsck
+'
+
test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 064f5cefeb..e6abe65d5c 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -779,4 +779,13 @@ test_expect_success 'bisect log: only skip commits left' '
git bisect reset
'
+test_expect_success '"git bisect bad HEAD" behaves as "git bisect bad"' '
+ git checkout parallel &&
+ git bisect start HEAD $HASH1 &&
+ git bisect good HEAD &&
+ git bisect bad HEAD &&
+ test "$HASH6" = $(git rev-parse --verify HEAD) &&
+ git bisect reset
+'
+
test_done
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index bda354c1c4..c66bf7981c 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -334,6 +334,19 @@ test_expect_success 'Check that :track[short] cannot be used with other atoms' '
test_must_fail git for-each-ref --format="%(refname:trackshort)" 2>/dev/null
'
+test_expect_success 'Check that :track[short] works when upstream is invalid' '
+ cat >expected <<-\EOF &&
+
+
+ EOF
+ test_when_finished "git config branch.master.merge refs/heads/master" &&
+ git config branch.master.merge refs/heads/does-not-exist &&
+ git for-each-ref \
+ --format="%(upstream:track)$LF%(upstream:trackshort)" \
+ refs/heads >actual &&
+ test_cmp expected actual
+'
+
cat >expected <<EOF
$(git rev-parse --short HEAD)
EOF
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 796e9f79ea..35c805a44e 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1081,7 +1081,7 @@ test_expect_success GPG \
get_tag_header rfc1991-signed-tag $commit commit $time >expect
echo "RFC1991 signed tag" >>expect
echo '-----BEGIN PGP MESSAGE-----' >>expect
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'creating a signed tag with rfc1991' '
echo "rfc1991" >gpghome/gpg.conf &&
git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit &&
@@ -1095,7 +1095,7 @@ cp "$1" actual
EOF
chmod +x fakeeditor
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'reediting a signed tag body omits signature' '
echo "rfc1991" >gpghome/gpg.conf &&
echo "RFC1991 signed tag" >expect &&
@@ -1103,13 +1103,13 @@ test_expect_success GPG \
test_cmp expect actual
'
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'verifying rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
git tag -v rfc1991-signed-tag
'
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'list tag with rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
@@ -1123,12 +1123,12 @@ test_expect_success GPG \
rm -f gpghome/gpg.conf
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'verifying rfc1991 signature without --rfc1991' '
git tag -v rfc1991-signed-tag
'
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'list tag with rfc1991 signature without --rfc1991' '
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
git tag -l -n1 rfc1991-signed-tag >actual &&
@@ -1139,7 +1139,7 @@ test_expect_success GPG \
test_cmp expect actual
'
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'reediting a signed tag body omits signature' '
echo "RFC1991 signed tag" >expect &&
GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
index 1efb88051a..bd0ab46750 100755
--- a/t/t7513-interpret-trailers.sh
+++ b/t/t7513-interpret-trailers.sh
@@ -213,7 +213,7 @@ test_expect_success 'with 2 files arguments' '
'
test_expect_success 'with message that has comments' '
- cat basic_message >>message_with_comments &&
+ cat basic_message >message_with_comments &&
sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF &&
# comment
@@ -232,12 +232,44 @@ test_expect_success 'with message that has comments' '
Reviewed-by: Johan
Cc: Peff
+ # last comment
+
EOF
cat basic_patch >>expected &&
git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual &&
test_cmp expected actual
'
+test_expect_success 'with message that has an old style conflict block' '
+ cat basic_message >message_with_comments &&
+ sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF &&
+ # comment
+
+ # other comment
+ Cc: Z
+ # yet another comment
+ Reviewed-by: Johan
+ Reviewed-by: Z
+ # last comment
+
+ Conflicts:
+
+ EOF
+ cat basic_message >expected &&
+ cat >>expected <<-\EOF &&
+ # comment
+
+ Reviewed-by: Johan
+ Cc: Peff
+ # last comment
+
+ Conflicts:
+
+ EOF
+ git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'with commit complex message and trailer args' '
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 19a3ced600..af6a3e8904 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -6,35 +6,37 @@ test_description='git send-email'
# May be altered later in the test
PREREQ="PERL"
-test_expect_success $PREREQ \
- 'prepare reference tree' \
- 'echo "1A quick brown fox jumps over the" >file &&
- echo "lazy dog" >>file &&
- git add file &&
- GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
-
-test_expect_success $PREREQ \
- 'Setup helper tool' \
- '(echo "#!$SHELL_PATH"
- echo shift
- echo output=1
- echo "while test -f commandline\$output; do output=\$((\$output+1)); done"
- echo for a
- echo do
- echo " echo \"!\$a!\""
- echo "done >commandline\$output"
- echo "cat > msgtxt\$output"
- ) >fake.sendmail &&
- chmod +x ./fake.sendmail &&
- git add fake.sendmail &&
- GIT_AUTHOR_NAME="A" git commit -a -m "Second."'
-
-clean_fake_sendmail() {
+test_expect_success $PREREQ 'prepare reference tree' '
+ echo "1A quick brown fox jumps over the" >file &&
+ echo "lazy dog" >>file &&
+ git add file &&
+ GIT_AUTHOR_NAME="A" git commit -a -m "Initial."
+'
+
+test_expect_success $PREREQ 'Setup helper tool' '
+ write_script fake.sendmail <<-\EOF &&
+ shift
+ output=1
+ while test -f commandline$output
+ do
+ output=$(($output+1))
+ done
+ for a
+ do
+ echo "!$a!"
+ done >commandline$output
+ cat >"msgtxt$output"
+ EOF
+ git add fake.sendmail &&
+ GIT_AUTHOR_NAME="A" git commit -a -m "Second."
+'
+
+clean_fake_sendmail () {
rm -f commandline* msgtxt*
}
test_expect_success $PREREQ 'Extract patches' '
- patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
+ patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
'
# Test no confirm early to ensure remaining tests will not hang
@@ -47,9 +49,9 @@ test_no_confirm () {
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
$@ \
- $patches > stdout &&
+ $patches >stdout &&
test_must_fail grep "Send this email" stdout &&
- > no_confirm_okay
+ >no_confirm_okay
}
# Exit immediately to prevent hang if a no-confirm test fails
@@ -82,61 +84,61 @@ test_expect_success $PREREQ 'No confirm with sendemail.confirm=never' '
'
test_expect_success $PREREQ 'Send patches' '
- git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+ git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+ cat >expected <<-\EOF
+ !nobody@example.com!
+ !author@example.com!
+ !one@example.com!
+ !two@example.com!
+ EOF
'
-test_expect_success $PREREQ \
- 'Verify commandline' \
- 'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+ test_cmp expected commandline1
+'
test_expect_success $PREREQ 'Send patches with --envelope-sender' '
- clean_fake_sendmail &&
- git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+ clean_fake_sendmail &&
+ git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!patch@example.com!
-!-i!
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+ cat >expected <<-\EOF
+ !patch@example.com!
+ !-i!
+ !nobody@example.com!
+ !author@example.com!
+ !one@example.com!
+ !two@example.com!
+ EOF
'
-test_expect_success $PREREQ \
- 'Verify commandline' \
- 'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+ test_cmp expected commandline1
+'
test_expect_success $PREREQ 'Send patches with --envelope-sender=auto' '
- clean_fake_sendmail &&
- git send-email --envelope-sender=auto --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+ clean_fake_sendmail &&
+ git send-email --envelope-sender=auto --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!nobody@example.com!
-!-i!
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+ cat >expected <<-\EOF
+ !nobody@example.com!
+ !-i!
+ !nobody@example.com!
+ !author@example.com!
+ !one@example.com!
+ !two@example.com!
+ EOF
'
-test_expect_success $PREREQ \
- 'Verify commandline' \
- 'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+ test_cmp expected commandline1
+'
test_expect_success $PREREQ 'setup expect' "
cat >expected-show-all-headers <<\EOF
@@ -240,6 +242,13 @@ test_expect_success $PREREQ 'non-ascii self name is suppressed' "
'non_ascii_self_suppressed'
"
+# This name is long enough to force format-patch to split it into multiple
+# encoded-words, assuming it uses UTF-8 with the "Q" encoding.
+test_expect_success $PREREQ 'long non-ascii self name is suppressed' "
+ test_suppress_self_quoted 'Ƒüñníęř €. Nâṁé' 'odd_?=mail@example.com' \
+ 'long_non_ascii_self_suppressed'
+"
+
test_expect_success $PREREQ 'sanitized self name is suppressed' "
test_suppress_self_unquoted '\"A U. Thor\"' 'author@example.com' \
'self_name_sanitized_suppressed'
@@ -307,11 +316,9 @@ test_expect_success $PREREQ 'tocmd works' '
clean_fake_sendmail &&
cp $patches tocmd.patch &&
echo tocmd--tocmd@example.com >>tocmd.patch &&
- {
- echo "#!$SHELL_PATH"
- echo sed -n -e s/^tocmd--//p \"\$1\"
- } > tocmd-sed &&
- chmod +x tocmd-sed &&
+ write_script tocmd-sed <<-\EOF &&
+ sed -n -e "s/^tocmd--//p" "$1"
+ EOF
git send-email \
--from="Example <nobody@example.com>" \
--to-cmd=./tocmd-sed \
@@ -325,11 +332,9 @@ test_expect_success $PREREQ 'cccmd works' '
clean_fake_sendmail &&
cp $patches cccmd.patch &&
echo "cccmd-- cccmd@example.com" >>cccmd.patch &&
- {
- echo "#!$SHELL_PATH"
- echo sed -n -e s/^cccmd--//p \"\$1\"
- } > cccmd-sed &&
- chmod +x cccmd-sed &&
+ write_script cccmd-sed <<-\EOF &&
+ sed -n -e "s/^cccmd--//p" "$1"
+ EOF
git send-email \
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
@@ -367,7 +372,7 @@ test_expect_success $PREREQ 'Author From: in message body' '
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
$patches &&
- sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
+ sed "1,/^\$/d" <msgtxt1 >msgbody1 &&
grep "From: A <author@example.com>" msgbody1
'
@@ -378,7 +383,7 @@ test_expect_success $PREREQ 'Author From: not in message body' '
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
$patches &&
- sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
+ sed "1,/^\$/d" <msgtxt1 >msgbody1 &&
! grep "From: A <author@example.com>" msgbody1
'
@@ -459,10 +464,9 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
'
test_expect_success $PREREQ 'setup fake editor' '
- (echo "#!$SHELL_PATH" &&
- echo "echo fake edit >>\"\$1\""
- ) >fake-editor &&
- chmod +x fake-editor
+ write_script fake-editor <<-\EOF
+ echo fake edit >>"$1"
+ EOF
'
test_set_editor "$(pwd)/fake-editor"
@@ -598,8 +602,9 @@ EOF
"
test_expect_success $PREREQ 'sendemail.cccmd' '
- echo echo cc-cmd@example.com > cccmd &&
- chmod +x cccmd &&
+ write_script cccmd <<-\EOF &&
+ echo cc-cmd@example.com
+ EOF
git config sendemail.cccmd ./cccmd &&
test_suppression cccmd
'
@@ -792,7 +797,7 @@ test_confirm () {
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
- $@ $patches > stdout &&
+ $@ $patches >stdout &&
grep "Send this email" stdout
}
@@ -840,7 +845,7 @@ test_expect_success $PREREQ 'confirm detects EOF (inform assumes y)' '
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
- outdir/*.patch < /dev/null
+ outdir/*.patch </dev/null
ret="$?"
git config sendemail.confirm ${CONFIRM:-never}
test $ret = "0"
@@ -855,7 +860,7 @@ test_expect_success $PREREQ 'confirm detects EOF (auto causes failure)' '
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
- $patches < /dev/null
+ $patches </dev/null
ret="$?"
git config sendemail.confirm ${CONFIRM:-never}
test $ret = "0"
@@ -891,39 +896,39 @@ test_expect_success $PREREQ 'utf8 Cc is rfc2047 encoded' '
test_expect_success $PREREQ '--compose adds MIME for utf8 body' '
clean_fake_sendmail &&
- (echo "#!$SHELL_PATH" &&
- echo "echo utf8 body: àéìöú >>\"\$1\""
- ) >fake-editor-utf8 &&
- chmod +x fake-editor-utf8 &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- git send-email \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8 <<-\EOF &&
+ echo "utf8 body: àéìöú" >>"$1"
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+ git send-email \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
'
test_expect_success $PREREQ '--compose respects user mime type' '
clean_fake_sendmail &&
- (echo "#!$SHELL_PATH" &&
- echo "(echo MIME-Version: 1.0"
- echo " echo Content-Type: text/plain\\; charset=iso-8859-1"
- echo " echo Content-Transfer-Encoding: 8bit"
- echo " echo Subject: foo"
- echo " echo "
- echo " echo utf8 body: àéìöú) >\"\$1\""
- ) >fake-editor-utf8-mime &&
- chmod +x fake-editor-utf8-mime &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
- git send-email \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8-mime <<-\EOF &&
+ cat >"$1" <<-\EOM
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=iso-8859-1
+ Content-Transfer-Encoding: 8bit
+ Subject: foo
+
+ utf8 body: àéìöú
+ EOM
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
+ git send-email \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 &&
! grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
@@ -931,13 +936,13 @@ test_expect_success $PREREQ '--compose respects user mime type' '
test_expect_success $PREREQ '--compose adds MIME for utf8 subject' '
clean_fake_sendmail &&
- GIT_EDITOR="\"$(pwd)/fake-editor\"" \
- git send-email \
- --compose --subject utf8-sübjëct \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+ git send-email \
+ --compose --subject utf8-sübjëct \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^fake edit" msgtxt1 &&
grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
'
@@ -949,9 +954,9 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' '
git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
git format-patch --stdout -1 >funny_name.patch &&
git send-email --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- funny_name.patch &&
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ funny_name.patch &&
grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
'
@@ -962,9 +967,9 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' '
git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
git format-patch --stdout -1 >funny_name.patch &&
git send-email --from="Füñný Nâmé <odd_?=mail@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- funny_name.patch &&
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ funny_name.patch &&
grep "^From: " msgtxt1 >msgfrom &&
test_line_count = 1 msgfrom
'
@@ -972,35 +977,33 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' '
test_expect_success $PREREQ 'sendemail.composeencoding works' '
clean_fake_sendmail &&
git config sendemail.composeencoding iso-8859-1 &&
- (echo "#!$SHELL_PATH" &&
- echo "echo utf8 body: àéìöú >>\"\$1\""
- ) >fake-editor-utf8 &&
- chmod +x fake-editor-utf8 &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- git send-email \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8 <<-\EOF &&
+ echo "utf8 body: àéìöú" >>"$1"
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+ git send-email \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
'
test_expect_success $PREREQ '--compose-encoding works' '
clean_fake_sendmail &&
- (echo "#!$SHELL_PATH" &&
- echo "echo utf8 body: àéìöú >>\"\$1\""
- ) >fake-editor-utf8 &&
- chmod +x fake-editor-utf8 &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- git send-email \
- --compose-encoding iso-8859-1 \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8 <<-\EOF &&
+ echo "utf8 body: àéìöú" >>"$1"
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+ git send-email \
+ --compose-encoding iso-8859-1 \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
'
@@ -1008,38 +1011,37 @@ test_expect_success $PREREQ '--compose-encoding works' '
test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' '
clean_fake_sendmail &&
git config sendemail.composeencoding iso-8859-1 &&
- (echo "#!$SHELL_PATH" &&
- echo "echo utf8 body: àéìöú >>\"\$1\""
- ) >fake-editor-utf8 &&
- chmod +x fake-editor-utf8 &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- git send-email \
- --compose-encoding iso-8859-2 \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8 <<-\EOF &&
+ echo "utf8 body: àéìöú" >>"$1"
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+ git send-email \
+ --compose-encoding iso-8859-2 \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1
'
test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' '
clean_fake_sendmail &&
- GIT_EDITOR="\"$(pwd)/fake-editor\"" \
- git send-email \
- --compose-encoding iso-8859-2 \
- --compose --subject utf8-sübjëct \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+ git send-email \
+ --compose-encoding iso-8859-2 \
+ --compose --subject utf8-sübjëct \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^fake edit" msgtxt1 &&
grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
'
test_expect_success $PREREQ 'detects ambiguous reference/file conflict' '
- echo master > master &&
+ echo master >master &&
git add master &&
git commit -m"add master" &&
test_must_fail git send-email --dry-run master 2>errors &&
@@ -1050,10 +1052,10 @@ test_expect_success $PREREQ 'feed two files' '
rm -fr outdir &&
git format-patch -2 -o outdir &&
git send-email \
- --dry-run \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- outdir/000?-*.patch 2>errors >out &&
+ --dry-run \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ outdir/000?-*.patch 2>errors >out &&
grep "^Subject: " out >subjects &&
test "z$(sed -n -e 1p subjects)" = "zSubject: [PATCH 1/2] Second." &&
test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master"
@@ -1197,7 +1199,7 @@ test_expect_success $PREREQ 'To headers from files reset each patch' '
'
test_expect_success $PREREQ 'setup expect' '
-cat >email-using-8bit <<EOF
+cat >email-using-8bit <<\EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
Message-Id: <bogus-message-id@example.com>
From: author@example.com
@@ -1209,9 +1211,7 @@ EOF
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<EOF
-Subject: subject goes here
-EOF
+ echo "Subject: subject goes here" >expected
'
test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' '
@@ -1226,11 +1226,11 @@ test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' '
'
test_expect_success $PREREQ 'setup expect' '
-cat >content-type-decl <<EOF
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-EOF
+ cat >content-type-decl <<-\EOF
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=UTF-8
+ Content-Transfer-Encoding: 8bit
+ EOF
'
test_expect_success $PREREQ 'asks about and fixes 8bit encodings' '
@@ -1270,21 +1270,21 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
'
test_expect_success $PREREQ 'setup expect' '
-cat >email-using-8bit <<EOF
-From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-Message-Id: <bogus-message-id@example.com>
-From: author@example.com
-Date: Sat, 12 Jun 2010 15:53:58 +0200
-Subject: Dieser Betreff enthält auch einen Umlaut!
-
-Nothing to see here.
-EOF
+ cat >email-using-8bit <<-\EOF
+ From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+ Message-Id: <bogus-message-id@example.com>
+ From: author@example.com
+ Date: Sat, 12 Jun 2010 15:53:58 +0200
+ Subject: Dieser Betreff enthält auch einen Umlaut!
+
+ Nothing to see here.
+ EOF
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<EOF
-Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?=
-EOF
+ cat >expected <<-\EOF
+ Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?=
+ EOF
'
test_expect_success $PREREQ '--8bit-encoding also treats subject' '
@@ -1298,6 +1298,163 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
test_cmp expected actual
'
+test_expect_success $PREREQ 'setup expect' '
+ cat >email-using-8bit <<-\EOF
+ From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+ Message-Id: <bogus-message-id@example.com>
+ From: A U Thor <author@example.com>
+ Date: Sat, 12 Jun 2010 15:53:58 +0200
+ Content-Type: text/plain; charset=UTF-8
+ Subject: Nothing to see here.
+
+ Dieser Betreff enthält auch einen Umlaut!
+ EOF
+'
+
+test_expect_success $PREREQ 'sendemail.transferencoding=7bit fails on 8bit data' '
+ clean_fake_sendmail &&
+ git config sendemail.transferEncoding 7bit &&
+ test_must_fail git send-email \
+ --transfer-encoding=7bit \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ grep "cannot send message as 7bit" errors &&
+ test -z "$(ls msgtxt*)"
+'
+
+test_expect_success $PREREQ '--transfer-encoding overrides sendemail.transferEncoding' '
+ clean_fake_sendmail &&
+ git config sendemail.transferEncoding 8bit
+ test_must_fail git send-email \
+ --transfer-encoding=7bit \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ grep "cannot send message as 7bit" errors &&
+ test -z "$(ls msgtxt*)"
+'
+
+test_expect_success $PREREQ 'sendemail.transferencoding=8bit' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=8bit \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ sed '1,/^$/d' email-using-8bit >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+ cat >expected <<-\EOF
+ Dieser Betreff enth=C3=A4lt auch einen Umlaut!
+ EOF
+'
+
+test_expect_success $PREREQ '8-bit and sendemail.transferencoding=quoted-printable' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=quoted-printable \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+ cat >expected <<-\EOF
+ RGllc2VyIEJldHJlZmYgZW50aMOkbHQgYXVjaCBlaW5lbiBVbWxhdXQhCg==
+ EOF
+'
+
+test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=base64 \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+ cat >email-using-qp <<-\EOF
+ From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+ Message-Id: <bogus-message-id@example.com>
+ From: A U Thor <author@example.com>
+ Date: Sat, 12 Jun 2010 15:53:58 +0200
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ Content-Type: text/plain; charset=UTF-8
+ Subject: Nothing to see here.
+
+ Dieser Betreff enth=C3=A4lt auch einen Umlaut!
+ EOF
+'
+
+test_expect_success $PREREQ 'convert from quoted-printable to base64' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=base64 \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-qp \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' "
+tr -d '\\015' | tr '%' '\\015' >email-using-crlf <<EOF
+From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+Message-Id: <bogus-message-id@example.com>
+From: A U Thor <author@example.com>
+Date: Sat, 12 Jun 2010 15:53:58 +0200
+Content-Type: text/plain; charset=UTF-8
+Subject: Nothing to see here.
+
+Look, I have a CRLF and an = sign!%
+EOF
+"
+
+test_expect_success $PREREQ 'setup expect' '
+ cat >expected <<-\EOF
+ Look, I have a CRLF and an =3D sign!=0D
+ EOF
+'
+
+test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=quoted-printable' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=quoted-printable \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-crlf \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+ cat >expected <<-\EOF
+ TG9vaywgSSBoYXZlIGEgQ1JMRiBhbmQgYW4gPSBzaWduIQ0K
+ EOF
+'
+
+test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=base64' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=base64 \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-crlf \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+
# Note that the patches in this test are deliberately out of order; we
# want to make sure it works even if the cover-letter is not in the
# first mail.
@@ -1306,13 +1463,13 @@ test_expect_success $PREREQ 'refusing to send cover letter template' '
rm -fr outdir &&
git format-patch --cover-letter -2 -o outdir &&
test_must_fail git send-email \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0002-*.patch \
- outdir/0000-*.patch \
- outdir/0001-*.patch \
- 2>errors >out &&
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0002-*.patch \
+ outdir/0000-*.patch \
+ outdir/0001-*.patch \
+ 2>errors >out &&
grep "SUBJECT HERE" errors &&
test -z "$(ls msgtxt*)"
'
@@ -1322,14 +1479,14 @@ test_expect_success $PREREQ '--force sends cover letter template anyway' '
rm -fr outdir &&
git format-patch --cover-letter -2 -o outdir &&
git send-email \
- --force \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0002-*.patch \
- outdir/0000-*.patch \
- outdir/0001-*.patch \
- 2>errors >out &&
+ --force \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0002-*.patch \
+ outdir/0000-*.patch \
+ outdir/0001-*.patch \
+ 2>errors >out &&
! grep "SUBJECT HERE" errors &&
test -n "$(ls msgtxt*)"
'
@@ -1344,15 +1501,15 @@ test_cover_addresses () {
mv $cover cover-to-edit.patch &&
perl -pe "s/^From:/$header: extra\@address.com\nFrom:/" cover-to-edit.patch >"$cover" &&
git send-email \
- --force \
- --from="Example <nobody@example.com>" \
- --no-to --no-cc \
- "$@" \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0000-*.patch \
- outdir/0001-*.patch \
- outdir/0002-*.patch \
- 2>errors >out &&
+ --force \
+ --from="Example <nobody@example.com>" \
+ --no-to --no-cc \
+ "$@" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0000-*.patch \
+ outdir/0001-*.patch \
+ outdir/0002-*.patch \
+ 2>errors >out &&
grep "^$header: extra@address.com" msgtxt1 >to1 &&
grep "^$header: extra@address.com" msgtxt2 >to2 &&
grep "^$header: extra@address.com" msgtxt3 >to3 &&
@@ -1385,11 +1542,11 @@ test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' '
git config --replace-all sendemail.aliasesfile "$(pwd)/.mailrc" &&
git config sendemail.aliasfiletype mailrc &&
git send-email \
- --from="Example <nobody@example.com>" \
- --to=sbd \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0001-*.patch \
- 2>errors >out &&
+ --from="Example <nobody@example.com>" \
+ --to=sbd \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0001-*.patch \
+ 2>errors >out &&
grep "^!somebody@example\.org!$" commandline1
'
@@ -1399,12 +1556,45 @@ test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' '
git config --replace-all sendemail.aliasesfile "~/.mailrc" &&
git config sendemail.aliasfiletype mailrc &&
git send-email \
- --from="Example <nobody@example.com>" \
- --to=sbd \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0001-*.patch \
- 2>errors >out &&
+ --from="Example <nobody@example.com>" \
+ --to=sbd \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0001-*.patch \
+ 2>errors >out &&
grep "^!someone@example\.org!$" commandline1
'
+do_xmailer_test () {
+ expected=$1 params=$2 &&
+ git format-patch -1 &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=someone@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $params \
+ 0001-*.patch \
+ 2>errors >out &&
+ { grep '^X-Mailer:' out || :; } >mailer &&
+ test_line_count = $expected mailer
+}
+
+test_expect_success $PREREQ '--[no-]xmailer without any configuration' '
+ do_xmailer_test 1 "--xmailer" &&
+ do_xmailer_test 0 "--no-xmailer"
+'
+
+test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=true' '
+ test_config sendemail.xmailer true &&
+ do_xmailer_test 1 "" &&
+ do_xmailer_test 0 "--no-xmailer" &&
+ do_xmailer_test 1 "--xmailer"
+'
+
+test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' '
+ test_config sendemail.xmailer false &&
+ do_xmailer_test 0 "" &&
+ do_xmailer_test 0 "--no-xmailer" &&
+ do_xmailer_test 1 "--xmailer"
+'
+
test_done
diff --git a/t/t9148-git-svn-propset.sh b/t/t9148-git-svn-propset.sh
new file mode 100755
index 0000000000..102639090c
--- /dev/null
+++ b/t/t9148-git-svn-propset.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# Copyright (c) 2014 Alfred Perlstein
+#
+
+test_description='git svn propset tests'
+
+. ./lib-git-svn.sh
+
+foo_subdir2="subdir/subdir2/foo_subdir2"
+
+set -e
+mkdir import &&
+(set -e ; cd import
+ mkdir subdir
+ mkdir subdir/subdir2
+ touch foo # for 'add props top level'
+ touch subdir/foo_subdir # for 'add props relative'
+ touch "$foo_subdir2" # for 'add props subdir'
+ svn_cmd import -m 'import for git svn' . "$svnrepo" >/dev/null
+)
+rm -rf import
+
+test_expect_success 'initialize git svn' '
+ git svn init "$svnrepo"
+ '
+
+test_expect_success 'fetch revisions from svn' '
+ git svn fetch
+ '
+
+set_props () {
+ subdir="$1"
+ file="$2"
+ shift;shift;
+ (cd "$subdir" &&
+ while [ $# -gt 0 ] ; do
+ git svn propset "$1" "$2" "$file" || exit 1
+ shift;shift;
+ done &&
+ echo hello >> "$file" &&
+ git commit -m "testing propset" "$file")
+}
+
+confirm_props () {
+ subdir="$1"
+ file="$2"
+ shift;shift;
+ (set -e ; cd "svn_project/$subdir" &&
+ while [ $# -gt 0 ] ; do
+ test "$(svn_cmd propget "$1" "$file")" = "$2" || exit 1
+ shift;shift;
+ done)
+}
+
+
+#The current implementation has a restriction:
+#svn propset will be taken as a delta for svn dcommit only
+#if the file content is also modified
+test_expect_success 'add props top level' '
+ set_props "." "foo" "svn:keywords" "FreeBSD=%H" &&
+ git svn dcommit &&
+ svn_cmd co "$svnrepo" svn_project &&
+ confirm_props "." "foo" "svn:keywords" "FreeBSD=%H" &&
+ rm -rf svn_project
+ '
+
+test_expect_success 'add multiple props' '
+ set_props "." "foo" \
+ "svn:keywords" "FreeBSD=%H" fbsd:nokeywords yes &&
+ git svn dcommit &&
+ svn_cmd co "$svnrepo" svn_project &&
+ confirm_props "." "foo" \
+ "svn:keywords" "FreeBSD=%H" fbsd:nokeywords yes &&
+ rm -rf svn_project
+ '
+
+test_expect_success 'add props subdir' '
+ set_props "." "$foo_subdir2" svn:keywords "FreeBSD=%H" &&
+ git svn dcommit &&
+ svn_cmd co "$svnrepo" svn_project &&
+ confirm_props "." "$foo_subdir2" "svn:keywords" "FreeBSD=%H" &&
+ rm -rf svn_project
+ '
+
+test_expect_success 'add props relative' '
+ set_props "subdir/subdir2" "../foo_subdir" \
+ svn:keywords "FreeBSD=%H" &&
+ git svn dcommit &&
+ svn_cmd co "$svnrepo" svn_project &&
+ confirm_props "subdir/subdir2" "../foo_subdir" \
+ svn:keywords "FreeBSD=%H" &&
+ rm -rf svn_project
+ '
+test_done
diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
index 9150984184..51ecd3e4c1 100755
--- a/t/t9903-bash-prompt.sh
+++ b/t/t9903-bash-prompt.sh
@@ -35,6 +35,8 @@ test_expect_success 'setup for prompt tests' '
git commit -m "another b2" file &&
echo 000 >file &&
git commit -m "yet another b2" file &&
+ mkdir ignored_dir &&
+ echo "ignored_dir/" >>.gitignore &&
git checkout master
'
@@ -588,4 +590,108 @@ test_expect_success 'prompt - zsh color pc mode' '
test_cmp expected "$actual"
'
+test_expect_success 'prompt - hide if pwd ignored - env var unset, config disabled' '
+ printf " (master)" >expected &&
+ test_config bash.hideIfPwdIgnored false &&
+ (
+ cd ignored_dir &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var unset, config disabled, pc mode' '
+ printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
+ test_config bash.hideIfPwdIgnored false &&
+ (
+ cd ignored_dir &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var unset, config unset' '
+ printf " (master)" >expected &&
+ (
+ cd ignored_dir &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var unset, config unset, pc mode' '
+ printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
+ (
+ cd ignored_dir &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var set, config disabled' '
+ printf " (master)" >expected &&
+ test_config bash.hideIfPwdIgnored false &&
+ (
+ cd ignored_dir &&
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var set, config disabled, pc mode' '
+ printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
+ test_config bash.hideIfPwdIgnored false &&
+ (
+ cd ignored_dir &&
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var set, config unset' '
+ printf "" >expected &&
+ (
+ cd ignored_dir &&
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var set, config unset, pc mode' '
+ printf "BEFORE::AFTER" >expected &&
+ (
+ cd ignored_dir &&
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - inside gitdir (stdout)' '
+ printf " (GIT_DIR!)" >expected &&
+ (
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ cd .git &&
+ __git_ps1 >"$actual" 2>/dev/null
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - inside gitdir (stderr)' '
+ printf "" >expected &&
+ (
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ cd .git &&
+ __git_ps1 >/dev/null 2>"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index cf19339cce..bb1402de94 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -140,6 +140,9 @@ else
}
fi
+: ${ASAN_OPTIONS=detect_leaks=0}
+export ASAN_OPTIONS
+
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
unset CDPATH
@@ -169,7 +172,11 @@ _z40=0000000000000000000000000000000000000000
LF='
'
-export _x05 _x40 _z40 LF
+# UTF-8 ZERO WIDTH NON-JOINER, which HFS+ ignores
+# when case-folding filenames
+u200c=$(printf '\342\200\214')
+
+export _x05 _x40 _z40 LF u200c
# Each test should start with something like this, after copyright notices:
#
@@ -177,16 +184,8 @@ export _x05 _x40 _z40 LF
# This test checks if command xyzzy does the right thing...
# '
# . ./test-lib.sh
-[ "x$ORIGINAL_TERM" != "xdumb" ] && (
- TERM=$ORIGINAL_TERM &&
- export TERM &&
- [ -t 1 ] &&
- tput bold >/dev/null 2>&1 &&
- tput setaf 1 >/dev/null 2>&1 &&
- tput sgr0 >/dev/null 2>&1
- ) &&
- color=t
+unset color
while test "$#" -ne 0
do
case "$1" in
@@ -251,40 +250,6 @@ then
verbose=t
fi
-if test -n "$color"
-then
- say_color () {
- (
- TERM=$ORIGINAL_TERM
- export TERM
- case "$1" in
- error)
- tput bold; tput setaf 1;; # bold red
- skip)
- tput setaf 4;; # blue
- warn)
- tput setaf 3;; # brown/yellow
- pass)
- tput setaf 2;; # green
- info)
- tput setaf 6;; # cyan
- *)
- test -n "$quiet" && return;;
- esac
- shift
- printf "%s" "$*"
- tput sgr0
- echo
- )
- }
-else
- say_color() {
- test -z "$1" && test -n "$quiet" && return
- shift
- printf "%s\n" "$*"
- }
-fi
-
error () {
say_color error "error: $*"
GIT_EXIT_OK=t
@@ -677,7 +642,7 @@ test_done () {
then
error "Can't use skip_all after running some tests"
fi
- [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
+ test -z "$skip_all" || skip_all=" # SKIP $skip_all"
if test $test_external_has_tap -eq 0
then
@@ -850,6 +815,52 @@ HOME="$TRASH_DIRECTORY"
GNUPGHOME="$HOME/gnupg-home-not-used"
export HOME GNUPGHOME
+# run the tput tests *after* changing HOME (in case ncurses needs
+# ~/.terminfo for $TERM)
+test -n "${color+set}" || test "x$ORIGINAL_TERM" != "xdumb" && (
+ TERM=$ORIGINAL_TERM &&
+ export TERM &&
+ test -t 1 &&
+ tput bold >/dev/null 2>&1 &&
+ tput setaf 1 >/dev/null 2>&1 &&
+ tput sgr0 >/dev/null 2>&1
+ ) &&
+ color=t
+
+if test -n "$color"
+then
+ say_color () {
+ (
+ TERM=$ORIGINAL_TERM
+ export TERM
+ case "$1" in
+ error)
+ tput bold; tput setaf 1;; # bold red
+ skip)
+ tput setaf 4;; # blue
+ warn)
+ tput setaf 3;; # brown/yellow
+ pass)
+ tput setaf 2;; # green
+ info)
+ tput setaf 6;; # cyan
+ *)
+ test -n "$quiet" && return;;
+ esac
+ shift
+ printf "%s" "$*"
+ tput sgr0
+ echo
+ )
+ }
+else
+ say_color() {
+ test -z "$1" && test -n "$quiet" && return
+ shift
+ printf "%s\n" "$*"
+ }
+fi
+
if test -z "$TEST_NO_CREATE_REPO"
then
test_create_repo "$TRASH_DIRECTORY"
diff --git a/templates/hooks--pre-push.sample b/templates/hooks--pre-push.sample
index 69e3c67b00..6187dbf439 100755
--- a/templates/hooks--pre-push.sample
+++ b/templates/hooks--pre-push.sample
@@ -24,7 +24,6 @@ url="$2"
z40=0000000000000000000000000000000000000000
-IFS=' '
while read local_ref local_sha remote_ref remote_sha
do
if [ "$local_sha" = $z40 ]
diff --git a/test-hashmap.c b/test-hashmap.c
index 07aa7ecdee..cc2891dd97 100644
--- a/test-hashmap.c
+++ b/test-hashmap.c
@@ -47,7 +47,7 @@ static struct test_entry *alloc_test_entry(int hash, char *key, int klen,
static unsigned int hash(unsigned int method, unsigned int i, const char *key)
{
- unsigned int hash;
+ unsigned int hash = 0;
switch (method & 3)
{
case HASH_METHOD_FNV:
diff --git a/trace.c b/trace.c
index 4778608941..1dc5c7c912 100644
--- a/trace.c
+++ b/trace.c
@@ -122,9 +122,7 @@ static int prepare_trace_line(const char *file, int line,
static void print_trace_line(struct trace_key *key, struct strbuf *buf)
{
- /* append newline if missing */
- if (buf->len && buf->buf[buf->len - 1] != '\n')
- strbuf_addch(buf, '\n');
+ strbuf_complete_line(buf);
write_or_whine_pipe(get_trace_fd(key), buf->buf, buf->len, err_msg);
strbuf_release(buf);
@@ -324,7 +322,7 @@ int trace_want(struct trace_key *key)
return !!get_trace_fd(key);
}
-#ifdef HAVE_CLOCK_GETTIME
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
static inline uint64_t highres_nanos(void)
{
diff --git a/trailer.c b/trailer.c
index a905f5c50c..623adeb02d 100644
--- a/trailer.c
+++ b/trailer.c
@@ -2,6 +2,7 @@
#include "string-list.h"
#include "run-command.h"
#include "string-list.h"
+#include "commit.h"
#include "trailer.h"
/*
* Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
@@ -768,6 +769,22 @@ static int find_trailer_start(struct strbuf **lines, int count)
return only_spaces ? count : 0;
}
+/* Get the index of the end of the trailers */
+static int find_trailer_end(struct strbuf **lines, int patch_start)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int i, ignore_bytes;
+
+ for (i = 0; i < patch_start; i++)
+ strbuf_addbuf(&sb, lines[i]);
+ ignore_bytes = ignore_non_trailer(&sb);
+ strbuf_release(&sb);
+ for (i = patch_start - 1; i >= 0 && ignore_bytes > 0; i--)
+ ignore_bytes -= lines[i]->len;
+
+ return i + 1;
+}
+
static int has_blank_line_before(struct strbuf **lines, int start)
{
for (;start >= 0; start--) {
@@ -790,14 +807,15 @@ static int process_input_file(struct strbuf **lines,
struct trailer_item **in_tok_last)
{
int count = 0;
- int patch_start, trailer_start, i;
+ int patch_start, trailer_start, trailer_end, i;
/* Get the line count */
while (lines[count])
count++;
patch_start = find_patch_start(lines, count);
- trailer_start = find_trailer_start(lines, patch_start);
+ trailer_end = find_trailer_end(lines, patch_start);
+ trailer_start = find_trailer_start(lines, trailer_end);
/* Print lines before the trailers as is */
print_lines(lines, 0, trailer_start);
@@ -806,14 +824,14 @@ static int process_input_file(struct strbuf **lines,
printf("\n");
/* Parse trailer lines */
- for (i = trailer_start; i < patch_start; i++) {
+ for (i = trailer_start; i < trailer_end; i++) {
if (lines[i]->buf[0] != comment_line_char) {
struct trailer_item *new = create_trailer_item(lines[i]->buf);
add_trailer_item(in_tok_first, in_tok_last, new);
}
}
- return patch_start;
+ return trailer_end;
}
static void free_all(struct trailer_item **first)
@@ -830,7 +848,7 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
struct trailer_item *in_tok_last = NULL;
struct trailer_item *arg_tok_first;
struct strbuf **lines;
- int patch_start;
+ int trailer_end;
/* Default config must be setup first */
git_config(git_trailer_default_config, NULL);
@@ -839,7 +857,7 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
lines = read_input_file(file);
/* Print the lines before the trailers */
- patch_start = process_input_file(lines, &in_tok_first, &in_tok_last);
+ trailer_end = process_input_file(lines, &in_tok_first, &in_tok_last);
arg_tok_first = process_command_line_args(trailers);
@@ -850,7 +868,7 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
free_all(&in_tok_first);
/* Print the lines after the trailers as is */
- print_lines(lines, patch_start, INT_MAX);
+ print_lines(lines, trailer_end, INT_MAX);
strbuf_list_free(lines);
}
diff --git a/transport.c b/transport.c
index 70d38e4c4b..08bcd3a4eb 100644
--- a/transport.c
+++ b/transport.c
@@ -971,9 +971,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
} else {
/* Unknown protocol in URL. Pass to external handler. */
int len = external_specification_len(url);
- char *handler = xmalloc(len + 1);
- handler[len] = 0;
- strncpy(handler, url, len);
+ char *handler = xmemdupz(url, len);
transport_helper_init(ret, handler);
}
diff --git a/tree.c b/tree.c
index bb02c1caa4..58ebfce1bc 100644
--- a/tree.c
+++ b/tree.c
@@ -30,9 +30,12 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b
return add_cache_entry(ce, opt);
}
-static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
+static int read_one_entry(const unsigned char *sha1, struct strbuf *base,
+ const char *pathname, unsigned mode, int stage,
+ void *context)
{
- return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
+ return read_one_entry_opt(sha1, base->buf, base->len, pathname,
+ mode, stage,
ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
}
@@ -40,9 +43,12 @@ static int read_one_entry(const unsigned char *sha1, const char *base, int basel
* This is used when the caller knows there is no existing entries at
* the stage that will conflict with the entry being added.
*/
-static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
+static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,
+ const char *pathname, unsigned mode, int stage,
+ void *context)
{
- return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
+ return read_one_entry_opt(sha1, base->buf, base->len, pathname,
+ mode, stage,
ADD_CACHE_JUST_APPEND);
}
@@ -70,7 +76,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
continue;
}
- switch (fn(entry.sha1, base->buf, base->len,
+ switch (fn(entry.sha1, base,
entry.path, entry.mode, stage, context)) {
case 0:
continue;
diff --git a/tree.h b/tree.h
index d84ac63e51..d24125f84f 100644
--- a/tree.h
+++ b/tree.h
@@ -4,6 +4,7 @@
#include "object.h"
extern const char *tree_type;
+struct strbuf;
struct tree {
struct object object;
@@ -22,7 +23,7 @@ void free_tree_buffer(struct tree *tree);
struct tree *parse_tree_indirect(const unsigned char *sha1);
#define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
+typedef int (*read_tree_fn_t)(const unsigned char *, struct strbuf *, const char *, unsigned int, int, void *);
extern int read_tree_recursive(struct tree *tree,
const char *base, int baselen,
diff --git a/unpack-trees.c b/unpack-trees.c
index 3a66849e38..be84ba2607 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -98,7 +98,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
opts->unpack_rejects[i].strdup_strings = 1;
}
-static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
unsigned int set, unsigned int clear)
{
clear |= CE_HASHED;
@@ -107,8 +107,8 @@ static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
set |= CE_WT_REMOVE;
ce->ce_flags = (ce->ce_flags & ~clear) | set;
- add_index_entry(&o->result, ce,
- ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+ return add_index_entry(&o->result, ce,
+ ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
static struct cache_entry *dup_entry(const struct cache_entry *ce)
@@ -609,7 +609,9 @@ static int unpack_nondirectories(int n, unsigned long mask,
for (i = 0; i < n; i++)
if (src[i] && src[i] != o->df_conflict_entry)
- do_add_entry(o, src[i], 0, 0);
+ if (do_add_entry(o, src[i], 0, 0))
+ return -1;
+
return 0;
}
diff --git a/update_unicode.sh b/update_unicode.sh
index 000b937e68..27af77c7df 100755
--- a/update_unicode.sh
+++ b/update_unicode.sh
@@ -27,11 +27,14 @@ fi &&
fi &&
make
) &&
- echo "static const struct interval zero_width[] = {" >$UNICODEWIDTH_H &&
- UNICODE_DIR=. ./uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
- grep -v plane >>$UNICODEWIDTH_H &&
- echo "};" >>$UNICODEWIDTH_H &&
- echo "static const struct interval double_width[] = {" >>$UNICODEWIDTH_H &&
- UNICODE_DIR=. ./uniset/uniset --32 eaw:F,W >>$UNICODEWIDTH_H &&
- echo "};" >>$UNICODEWIDTH_H
+ UNICODE_DIR=. && export UNICODE_DIR &&
+ cat >$UNICODEWIDTH_H <<-EOF
+ static const struct interval zero_width[] = {
+ $(uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
+ grep -v plane)
+ };
+ static const struct interval double_width[] = {
+ $(uniset/uniset --32 eaw:F,W)
+ };
+ EOF
)
diff --git a/upload-pack.c b/upload-pack.c
index ac9ac1592d..b531a325d2 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -86,7 +86,7 @@ static void create_pack_file(void)
"corruption on the remote side.";
int buffered = -1;
ssize_t sz;
- const char *argv[12];
+ const char *argv[13];
int i, arg = 0;
FILE *pipe_fd;
@@ -100,6 +100,8 @@ static void create_pack_file(void)
argv[arg++] = "--thin";
argv[arg++] = "--stdout";
+ if (shallow_nr)
+ argv[arg++] = "--shallow";
if (!no_progress)
argv[arg++] = "--progress";
if (use_ofs_delta)
diff --git a/utf8.c b/utf8.c
index 4541777949..520fbb4994 100644
--- a/utf8.c
+++ b/utf8.c
@@ -561,3 +561,75 @@ int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding)
return chrlen;
}
+
+/*
+ * Pick the next char from the stream, ignoring codepoints an HFS+ would.
+ * Note that this is _not_ complete by any means. It's just enough
+ * to make is_hfs_dotgit() work, and should not be used otherwise.
+ */
+static ucs_char_t next_hfs_char(const char **in)
+{
+ while (1) {
+ ucs_char_t out = pick_one_utf8_char(in, NULL);
+ /*
+ * check for malformed utf8. Technically this
+ * gets converted to a percent-sequence, but
+ * returning 0 is good enough for is_hfs_dotgit
+ * to realize it cannot be .git
+ */
+ if (!*in)
+ return 0;
+
+ /* these code points are ignored completely */
+ switch (out) {
+ case 0x200c: /* ZERO WIDTH NON-JOINER */
+ case 0x200d: /* ZERO WIDTH JOINER */
+ case 0x200e: /* LEFT-TO-RIGHT MARK */
+ case 0x200f: /* RIGHT-TO-LEFT MARK */
+ case 0x202a: /* LEFT-TO-RIGHT EMBEDDING */
+ case 0x202b: /* RIGHT-TO-LEFT EMBEDDING */
+ case 0x202c: /* POP DIRECTIONAL FORMATTING */
+ case 0x202d: /* LEFT-TO-RIGHT OVERRIDE */
+ case 0x202e: /* RIGHT-TO-LEFT OVERRIDE */
+ case 0x206a: /* INHIBIT SYMMETRIC SWAPPING */
+ case 0x206b: /* ACTIVATE SYMMETRIC SWAPPING */
+ case 0x206c: /* INHIBIT ARABIC FORM SHAPING */
+ case 0x206d: /* ACTIVATE ARABIC FORM SHAPING */
+ case 0x206e: /* NATIONAL DIGIT SHAPES */
+ case 0x206f: /* NOMINAL DIGIT SHAPES */
+ case 0xfeff: /* ZERO WIDTH NO-BREAK SPACE */
+ continue;
+ }
+
+ return out;
+ }
+}
+
+int is_hfs_dotgit(const char *path)
+{
+ ucs_char_t c;
+
+ c = next_hfs_char(&path);
+ if (c != '.')
+ return 0;
+ c = next_hfs_char(&path);
+
+ /*
+ * there's a great deal of other case-folding that occurs
+ * in HFS+, but this is enough to catch anything that will
+ * convert to ".git"
+ */
+ if (c != 'g' && c != 'G')
+ return 0;
+ c = next_hfs_char(&path);
+ if (c != 'i' && c != 'I')
+ return 0;
+ c = next_hfs_char(&path);
+ if (c != 't' && c != 'T')
+ return 0;
+ c = next_hfs_char(&path);
+ if (c && !is_dir_sep(c))
+ return 0;
+
+ return 1;
+}
diff --git a/utf8.h b/utf8.h
index 65d0e42b96..e4d9183c5f 100644
--- a/utf8.h
+++ b/utf8.h
@@ -42,4 +42,12 @@ static inline char *reencode_string(const char *in,
int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
+/*
+ * Returns true if the the path would match ".git" after HFS case-folding.
+ * The path should be NUL-terminated, but we will match variants of both ".git\0"
+ * and ".git/..." (but _not_ ".../.git"). This makes it suitable for both fsck
+ * and verify_path().
+ */
+int is_hfs_dotgit(const char *path);
+
#endif