summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/Makefile11
-rw-r--r--Documentation/RelNotes/1.8.1.4.txt11
-rw-r--r--Documentation/RelNotes/1.8.1.5.txt41
-rw-r--r--Documentation/config.txt5
-rw-r--r--Documentation/git-bisect.txt7
-rw-r--r--Documentation/git-remote-helpers.txto9
-rw-r--r--Documentation/git-remote-testgit.txt2
-rw-r--r--Documentation/git-submodule.txt2
-rw-r--r--Documentation/git.txt14
-rw-r--r--Documentation/githooks.txt2
-rw-r--r--Documentation/gitremote-helpers.txt (renamed from Documentation/git-remote-helpers.txt)6
-rw-r--r--Documentation/urls.txt2
-rw-r--r--Documentation/user-manual.txt7
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile14
l---------RelNotes2
-rw-r--r--builtin/apply.c10
-rw-r--r--builtin/clean.c154
-rw-r--r--builtin/clone.c2
-rw-r--r--combine-diff.c21
-rwxr-xr-xgit-cvsimport.perl5
-rwxr-xr-xgit-difftool--helper.sh2
-rwxr-xr-xgit-mergetool.sh2
-rwxr-xr-xgitweb/gitweb.perl4
-rw-r--r--http-push.c4
-rw-r--r--http.c32
-rw-r--r--http.h2
-rw-r--r--imap-send.c67
-rw-r--r--mergetools/p4merge27
-rw-r--r--parse-options.c10
-rw-r--r--perl/Git.pm23
-rw-r--r--perl/Git/SVN.pm12
-rw-r--r--perl/Git/SVN/Log.pm8
-rw-r--r--remote-curl.c17
-rw-r--r--t/lib-httpd.sh1
-rw-r--r--t/lib-httpd/apache.conf4
-rwxr-xr-xt/lib-httpd/broken-smart-http.sh11
-rwxr-xr-xt/t4038-diff-combined.sh24
-rwxr-xr-xt/t5551-http-fetch.sh5
-rwxr-xr-xt/t7512-status-help.sh2
-rw-r--r--utf8.c21
-rw-r--r--utf8.h1
42 files changed, 477 insertions, 131 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 971977b8aa..3c538e3de7 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,7 +1,7 @@
MAN1_TXT= \
$(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
$(wildcard git-*.txt)) \
- gitk.txt gitweb.txt git.txt
+ gitk.txt gitweb.txt git.txt gitremote-helpers.txt
MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt githooks.txt \
gitrepository-layout.txt gitweb.conf.txt
MAN7_TXT=gitcli.txt gittutorial.txt gittutorial-2.txt \
@@ -13,7 +13,8 @@ MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
-DOC_HTML=$(MAN_HTML)
+OBSOLETE_HTML = git-remote-helpers.html
+DOC_HTML=$(MAN_HTML) $(OBSOLETE_HTML)
ARTICLES = howto-index
ARTICLES += everyday
@@ -261,6 +262,12 @@ $(MAN_HTML): %.html : %.txt asciidoc.conf
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
mv $@+ $@
+$(OBSOLETE_HTML): %.html : %.txto asciidoc.conf
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b xhtml11 -f asciidoc.conf \
+ $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
+ mv $@+ $@
+
manpage-base-url.xsl: manpage-base-url.xsl.in
sed "s|@@MAN_BASE_URL@@|$(MAN_BASE_URL)|" $< > $@
diff --git a/Documentation/RelNotes/1.8.1.4.txt b/Documentation/RelNotes/1.8.1.4.txt
new file mode 100644
index 0000000000..22af1d1643
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.4.txt
@@ -0,0 +1,11 @@
+Git 1.8.1.4 Release Notes
+=========================
+
+Fixes since v1.8.1.3
+--------------------
+
+ * "git imap-send" talking over imaps:// did make sure it received a
+ valid certificate from the other end, but did not check if the
+ certificate matched the host it thought it was talking to.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.5.txt b/Documentation/RelNotes/1.8.1.5.txt
new file mode 100644
index 0000000000..30d30a1cf9
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.5.txt
@@ -0,0 +1,41 @@
+Git 1.8.1.5 Release Notes
+=========================
+
+Fixes since v1.8.1.4
+--------------------
+
+ * Given a string with a multi-byte character that begins with '-' on
+ the command line where an option is expected, the option parser
+ used just one byte of the unknown letter when reporting an error.
+
+ * "git apply --summary" has been taught to make sure the similarity
+ value shown in its output is sensible, even when the input had a
+ bogus value.
+
+ * "git clean" showed what it was going to do, but sometimes ended
+ up finding that it was not allowed to do so, which resulted in a
+ confusing output (e.g. after saying that it will remove an
+ untracked directory, it found an embedded git repository there
+ which it is not allowed to remove). It now performs the actions
+ and then reports the outcome more faithfully.
+
+ * "git clone" used to allow --bare and --separate-git-dir=$there
+ options at the same time, which was nonsensical.
+
+ * "git cvsimport" mishandled timestamps at DST boundary.
+
+ * We used to have an arbitrary 32 limit for combined diff input,
+ resulting in incorrect number of leading colons shown when showing
+ the "--raw --cc" output.
+
+ * The smart HTTP clients forgot to verify the content-type that comes
+ back from the server side to make sure that the request is being
+ handled properly.
+
+ * "git help remote-helpers" failed to find the documentation.
+
+ * "gitweb" pages served over HTTPS, when configured to show picon or
+ gravatar, referred to these external resources to be fetched via
+ HTTP, resulting in mixed contents warning in browsers.
+
+Also contains various documentation fixes.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index e452ff89ba..e37ba94a72 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -168,7 +168,7 @@ advice.*::
Advice shown when linkgit:git-merge[1] refuses to
merge to avoid overwriting local changes.
resolveConflict::
- Advices shown by various commands when conflicts
+ Advice shown by various commands when conflicts
prevent the operation from being performed.
implicitIdentity::
Advice on how to set your identity configuration when
@@ -1758,7 +1758,8 @@ push.default::
+
This is currently the default, but Git 2.0 will change the default
to `simple`.
-* `upstream` - push the current branch to its upstream branch.
+* `upstream` - push the current branch to its upstream branch
+ (`tracking` is a deprecated synonym for this).
With this, `git push` will update the same remote ref as the one which
is merged by `git pull`, making `push` and `pull` symmetrical.
See "branch.<name>.merge" for how to configure the upstream branch.
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index e4f46bc18d..038514b51e 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -83,7 +83,7 @@ Bisect reset
~~~~~~~~~~~~
After a bisect session, to clean up the bisection state and return to
-the original HEAD, issue the following command:
+the original HEAD (i.e., to quit bisecting), issue the following command:
------------------------------------------------
$ git bisect reset
@@ -284,6 +284,7 @@ EXAMPLES
------------
$ git bisect start HEAD v1.2 -- # HEAD is bad, v1.2 is good
$ git bisect run make # "make" builds the app
+$ git bisect reset # quit the bisect session
------------
* Automatically bisect a test failure between origin and HEAD:
@@ -291,6 +292,7 @@ $ git bisect run make # "make" builds the app
------------
$ git bisect start HEAD origin -- # HEAD is bad, origin is good
$ git bisect run make test # "make test" builds and tests
+$ git bisect reset # quit the bisect session
------------
* Automatically bisect a broken test case:
@@ -302,6 +304,7 @@ make || exit 125 # this skips broken builds
~/check_test_case.sh # does the test case pass?
$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run ~/test.sh
+$ git bisect reset # quit the bisect session
------------
+
Here we use a "test.sh" custom script. In this script, if "make"
@@ -351,6 +354,7 @@ use `git cherry-pick` instead of `git merge`.)
------------
$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
+$ git bisect reset # quit the bisect session
------------
+
This shows that you can do without a run script if you write the test
@@ -368,6 +372,7 @@ $ git bisect run sh -c '
rm -f tmp.$$
test $rc = 0'
+$ git bisect reset # quit the bisect session
------------
+
In this case, when 'git bisect run' finishes, bisect/bad will refer to a commit that
diff --git a/Documentation/git-remote-helpers.txto b/Documentation/git-remote-helpers.txto
new file mode 100644
index 0000000000..49233f5d26
--- /dev/null
+++ b/Documentation/git-remote-helpers.txto
@@ -0,0 +1,9 @@
+git-remote-helpers
+==================
+
+This document has been moved to linkgit:gitremote-helpers[1].
+
+Please let the owners of the referring site know so that they can update the
+link you clicked to get here.
+
+Thanks.
diff --git a/Documentation/git-remote-testgit.txt b/Documentation/git-remote-testgit.txt
index 2a67d456a3..4c871b92e9 100644
--- a/Documentation/git-remote-testgit.txt
+++ b/Documentation/git-remote-testgit.txt
@@ -23,7 +23,7 @@ The best way to learn more is to read the comments and source code in
SEE ALSO
--------
-linkgit:git-remote-helpers[1]
+linkgit:gitremote-helpers[1]
GIT
---
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index b1de3bade7..349378448c 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -13,7 +13,7 @@ SYNOPSIS
[--reference <repository>] [--] <repository> [<path>]
'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
-'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
+'git submodule' [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase]
[--reference <repository>] [--merge] [--recursive] [--] [<path>...]
'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
[commit] [--] [<path>...]
diff --git a/Documentation/git.txt b/Documentation/git.txt
index c7f211e81b..cbac7711ea 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.8.1.3/git.html[documentation for release 1.8.1.3]
+* link:v1.8.1.4/git.html[documentation for release 1.8.1.4]
* release notes for
+ link:RelNotes/1.8.1.4.txt[1.8.1.4],
link:RelNotes/1.8.1.3.txt[1.8.1.3],
link:RelNotes/1.8.1.2.txt[1.8.1.2],
link:RelNotes/1.8.1.1.txt[1.8.1.1],
@@ -530,10 +531,9 @@ include::cmds-purehelpers.txt[]
Configuration Mechanism
-----------------------
-Starting from 0.99.9 (actually mid 0.99.8.GIT), `.git/config` file
-is used to hold per-repository configuration options. It is a
-simple text file modeled after `.ini` format familiar to some
-people. Here is an example:
+Git uses a simple text format to store customizations that are per
+repository and are per user. Such a configuration file may look
+like this:
------------
#
@@ -548,13 +548,13 @@ people. Here is an example:
; user identity
[user]
name = "Junio C Hamano"
- email = "junkio@twinsun.com"
+ email = "gitster@pobox.com"
------------
Various commands read from the configuration file and adjust
their operation accordingly. See linkgit:git-config[1] for a
-list.
+list and more details about the configuration mechanism.
Identifier Terminology
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index b9003fed24..4e0d2a08a1 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -336,7 +336,7 @@ preceding SP is also omitted. Currently, no commands pass any
'extra-info'.
The hook always runs after the automatic note copying (see
-"notes.rewrite.<command>" in linkgit:git-config.txt) has happened, and
+"notes.rewrite.<command>" in linkgit:git-config.txt[1]) has happened, and
thus has access to these notes.
The following command-specific comments apply:
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/gitremote-helpers.txt
index 6d696e0f90..0f21367ca5 100644
--- a/Documentation/git-remote-helpers.txt
+++ b/Documentation/gitremote-helpers.txt
@@ -1,9 +1,9 @@
-git-remote-helpers(1)
-=====================
+gitremote-helpers(1)
+====================
NAME
----
-git-remote-helpers - Helper programs to interact with remote repositories
+gitremote-helpers - Helper programs to interact with remote repositories
SYNOPSIS
--------
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index 1d15ee7e52..cea5462ff8 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -55,7 +55,7 @@ may be used:
where <address> may be a path, a server and path, or an arbitrary
URL-like string recognized by the specific remote helper being
-invoked. See linkgit:git-remote-helpers[1] for details.
+invoked. See linkgit:gitremote-helpers[1] for details.
If there are a large number of similarly-named remote repositories and
you want to use a different format for them (such that the URLs you
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index bb03bc88b8..988c13ff4c 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -2004,9 +2004,10 @@ handling this case.
Note that the target of a "push" is normally a
<<def_bare_repository,bare>> repository. You can also push to a
-repository that has a checked-out working tree, but the working tree
-will not be updated by the push. This may lead to unexpected results if
-the branch you push to is the currently checked-out branch!
+repository that has a checked-out working tree, but a push to update the
+currently checked-out branch is denied by default to prevent confusion.
+See the description of the receive.denyCurrentBranch option
+in linkgit:git-config[1] for details.
As with `git fetch`, you may also set up configuration options to
save typing; so, for example:
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 07685f4697..dcd3595f27 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.1.3
+DEF_VER=v1.8.1.4
LF='
'
diff --git a/Makefile b/Makefile
index 4bb3cf1367..ec58d5c93b 100644
--- a/Makefile
+++ b/Makefile
@@ -2272,12 +2272,14 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh
mv $@+ $@
endif # NO_PYTHON
+CONFIGURE_RECIPE = $(RM) configure configure.ac+ && \
+ sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+ configure.ac >configure.ac+ && \
+ autoconf -o configure configure.ac+ && \
+ $(RM) configure.ac+
+
configure: configure.ac GIT-VERSION-FILE
- $(QUIET_GEN)$(RM) $@ $<+ && \
- sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
- $< > $<+ && \
- autoconf -o $@ $<+ && \
- $(RM) $<+
+ $(QUIET_GEN)$(CONFIGURE_RECIPE)
ifdef AUTOCONFIGURED
# We avoid depending on 'configure' here, because it gets rebuilt
@@ -2286,7 +2288,7 @@ ifdef AUTOCONFIGURED
# do want to recheck when the platform/environment detection logic
# changes, hence this depends on configure.ac.
config.status: configure.ac
- $(QUIET_GEN)$(MAKE) configure && \
+ $(QUIET_GEN)$(CONFIGURE_RECIPE) && \
if test -f config.status; then \
./config.status --recheck; \
else \
diff --git a/RelNotes b/RelNotes
index ce97a3befb..3c65929a74 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.1.3.txt \ No newline at end of file
+Documentation/RelNotes/1.8.1.5.txt \ No newline at end of file
diff --git a/builtin/apply.c b/builtin/apply.c
index 9706ca73ab..080ce2ea3e 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1041,15 +1041,17 @@ static int gitdiff_renamedst(const char *line, struct patch *patch)
static int gitdiff_similarity(const char *line, struct patch *patch)
{
- if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
- patch->score = 0;
+ unsigned long val = strtoul(line, NULL, 10);
+ if (val <= 100)
+ patch->score = val;
return 0;
}
static int gitdiff_dissimilarity(const char *line, struct patch *patch)
{
- if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
- patch->score = 0;
+ unsigned long val = strtoul(line, NULL, 10);
+ if (val <= 100)
+ patch->score = val;
return 0;
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 69c1cda906..f4b760bf3d 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -10,6 +10,7 @@
#include "cache.h"
#include "dir.h"
#include "parse-options.h"
+#include "refs.h"
#include "string-list.h"
#include "quote.h"
@@ -20,6 +21,12 @@ static const char *const builtin_clean_usage[] = {
NULL
};
+static const char *msg_remove = N_("Removing %s\n");
+static const char *msg_would_remove = N_("Would remove %s\n");
+static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
+static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
+static const char *msg_warn_remove_failed = N_("failed to remove %s");
+
static int git_clean_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "clean.requireforce"))
@@ -34,11 +41,112 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
+ int dry_run, int quiet, int *dir_gone)
+{
+ DIR *dir;
+ struct strbuf quoted = STRBUF_INIT;
+ struct dirent *e;
+ int res = 0, ret = 0, gone = 1, original_len = path->len, len, i;
+ unsigned char submodule_head[20];
+ struct string_list dels = STRING_LIST_INIT_DUP;
+
+ *dir_gone = 1;
+
+ if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
+ !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
+ if (!quiet) {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
+ quoted.buf);
+ }
+
+ *dir_gone = 0;
+ return 0;
+ }
+
+ dir = opendir(path->buf);
+ if (!dir) {
+ /* an empty dir could be removed even if it is unreadble */
+ res = dry_run ? 0 : rmdir(path->buf);
+ if (res) {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ warning(_(msg_warn_remove_failed), quoted.buf);
+ *dir_gone = 0;
+ }
+ return res;
+ }
+
+ if (path->buf[original_len - 1] != '/')
+ strbuf_addch(path, '/');
+
+ len = path->len;
+ while ((e = readdir(dir)) != NULL) {
+ struct stat st;
+ if (is_dot_or_dotdot(e->d_name))
+ continue;
+
+ strbuf_setlen(path, len);
+ strbuf_addstr(path, e->d_name);
+ if (lstat(path->buf, &st))
+ ; /* fall thru */
+ else if (S_ISDIR(st.st_mode)) {
+ if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
+ ret = 1;
+ if (gone) {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ string_list_append(&dels, quoted.buf);
+ } else
+ *dir_gone = 0;
+ continue;
+ } else {
+ res = dry_run ? 0 : unlink(path->buf);
+ if (!res) {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ string_list_append(&dels, quoted.buf);
+ } else {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ warning(_(msg_warn_remove_failed), quoted.buf);
+ *dir_gone = 0;
+ ret = 1;
+ }
+ continue;
+ }
+
+ /* path too long, stat fails, or non-directory still exists */
+ *dir_gone = 0;
+ ret = 1;
+ break;
+ }
+ closedir(dir);
+
+ strbuf_setlen(path, original_len);
+
+ if (*dir_gone) {
+ res = dry_run ? 0 : rmdir(path->buf);
+ if (!res)
+ *dir_gone = 1;
+ else {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ warning(_(msg_warn_remove_failed), quoted.buf);
+ *dir_gone = 0;
+ ret = 1;
+ }
+ }
+
+ if (!*dir_gone && !quiet) {
+ for (i = 0; i < dels.nr; i++)
+ printf(dry_run ? _(msg_would_remove) : _(msg_remove), dels.items[i].string);
+ }
+ string_list_clear(&dels, 0);
+ return ret;
+}
+
int cmd_clean(int argc, const char **argv, const char *prefix)
{
- int i;
- int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
- int ignored_only = 0, config_set = 0, errors = 0;
+ int i, res;
+ int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
+ int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
@@ -49,7 +157,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
char *seen = NULL;
struct option options[] = {
OPT__QUIET(&quiet, N_("do not print names of files removed")),
- OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__DRY_RUN(&dry_run, N_("dry run")),
OPT__FORCE(&force, N_("force")),
OPT_BOOLEAN('d', NULL, &remove_directories,
N_("remove whole directories")),
@@ -77,7 +185,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (ignored && ignored_only)
die(_("-x and -X cannot be used together"));
- if (!show_only && !force) {
+ if (!dry_run && !force) {
if (config_set)
die(_("clean.requireForce set to true and neither -n nor -f given; "
"refusing to clean"));
@@ -149,38 +257,26 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (S_ISDIR(st.st_mode)) {
strbuf_addstr(&directory, ent->name);
- qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
- if (show_only && (remove_directories ||
- (matches == MATCHED_EXACTLY))) {
- printf(_("Would remove %s\n"), qname);
- } else if (remove_directories ||
- (matches == MATCHED_EXACTLY)) {
- if (!quiet)
- printf(_("Removing %s\n"), qname);
- if (remove_dir_recursively(&directory,
- rm_flags) != 0) {
- warning(_("failed to remove %s"), qname);
+ if (remove_directories || (matches == MATCHED_EXACTLY)) {
+ if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone))
errors++;
+ if (gone && !quiet) {
+ qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
+ printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
- } else if (show_only) {
- printf(_("Would not remove %s\n"), qname);
- } else {
- printf(_("Not removing %s\n"), qname);
}
strbuf_reset(&directory);
} else {
if (pathspec && !matches)
continue;
- qname = quote_path_relative(ent->name, -1, &buf, prefix);
- if (show_only) {
- printf(_("Would remove %s\n"), qname);
- continue;
- } else if (!quiet) {
- printf(_("Removing %s\n"), qname);
- }
- if (unlink(ent->name) != 0) {
- warning(_("failed to remove %s"), qname);
+ res = dry_run ? 0 : unlink(ent->name);
+ if (res) {
+ qname = quote_path_relative(ent->name, -1, &buf, prefix);
+ warning(_(msg_warn_remove_failed), qname);
errors++;
+ } else if (!quiet) {
+ qname = quote_path_relative(ent->name, -1, &buf, prefix);
+ printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
}
}
diff --git a/builtin/clone.c b/builtin/clone.c
index 8d23a62e8a..36ec99db3f 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -704,6 +704,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_origin)
die(_("--bare and --origin %s options are incompatible."),
option_origin);
+ if (real_git_dir)
+ die(_("--bare and --separate-git-dir are incompatible."));
option_no_checkout = 1;
}
diff --git a/combine-diff.c b/combine-diff.c
index bb1cc96c4e..7f6187f9cd 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -982,14 +982,10 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
free(sline);
}
-#define COLONS "::::::::::::::::::::::::::::::::"
-
static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
- int i, offset;
- const char *prefix;
- int line_termination, inter_name_termination;
+ int line_termination, inter_name_termination, i;
line_termination = opt->line_termination;
inter_name_termination = '\t';
@@ -1000,17 +996,14 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
show_log(rev);
if (opt->output_format & DIFF_FORMAT_RAW) {
- offset = strlen(COLONS) - num_parent;
- if (offset < 0)
- offset = 0;
- prefix = COLONS + offset;
+ /* As many colons as there are parents */
+ for (i = 0; i < num_parent; i++)
+ putchar(':');
/* Show the modes */
- for (i = 0; i < num_parent; i++) {
- printf("%s%06o", prefix, p->parent[i].mode);
- prefix = " ";
- }
- printf("%s%06o", prefix, p->mode);
+ for (i = 0; i < num_parent; i++)
+ printf("%06o ", p->parent[i].mode);
+ printf("%06o", p->mode);
/* Show sha1's */
for (i = 0; i < num_parent; i++)
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 0a31ebd820..344f1206d1 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -26,6 +26,7 @@ use IO::Socket;
use IO::Pipe;
use POSIX qw(strftime tzset dup2 ENOENT);
use IPC::Open2;
+use Git qw(get_tz_offset);
$SIG{'PIPE'}="IGNORE";
set_timezone('UTC');
@@ -864,7 +865,9 @@ sub commit {
}
set_timezone($author_tz);
- my $commit_date = strftime("%s %z", localtime($date));
+ # $date is in the seconds since epoch format
+ my $tz_offset = get_tz_offset($date);
+ my $commit_date = "$date $tz_offset";
set_timezone('UTC');
$ENV{GIT_AUTHOR_NAME} = $author_name;
$ENV{GIT_AUTHOR_EMAIL} = $author_email;
diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
index 3d0fe0cd93..b00ed95dba 100755
--- a/git-difftool--helper.sh
+++ b/git-difftool--helper.sh
@@ -40,7 +40,7 @@ launch_merge_tool () {
# the user with the real $MERGED name before launching $merge_tool.
if should_prompt
then
- printf "\nViewing: '$MERGED'\n"
+ printf "\nViewing: '%s'\n" "$MERGED"
if use_ext_cmd
then
printf "Launch '%s' [Y/n]: " \
diff --git a/git-mergetool.sh b/git-mergetool.sh
index c50e18a899..012afa5549 100755
--- a/git-mergetool.sh
+++ b/git-mergetool.sh
@@ -440,7 +440,7 @@ then
fi
printf "Merging:\n"
-printf "$files\n"
+printf "%s\n" "$files"
IFS='
'
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index c6bafe6ead..1309196d27 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -2068,7 +2068,7 @@ sub picon_url {
if (!$avatar_cache{$email}) {
my ($user, $domain) = split('@', $email);
$avatar_cache{$email} =
- "http://www.cs.indiana.edu/cgi-pub/kinzler/piconsearch.cgi/" .
+ "//www.cs.indiana.edu/cgi-pub/kinzler/piconsearch.cgi/" .
"$domain/$user/" .
"users+domains+unknown/up/single";
}
@@ -2083,7 +2083,7 @@ sub gravatar_url {
my $email = lc shift;
my $size = shift;
$avatar_cache{$email} ||=
- "http://www.gravatar.com/avatar/" .
+ "//www.gravatar.com/avatar/" .
Digest::MD5::md5_hex($email) . "?s=";
return $avatar_cache{$email} . $size;
}
diff --git a/http-push.c b/http-push.c
index 8701c1215d..ba45b7b501 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1560,7 +1560,7 @@ static int remote_exists(const char *path)
sprintf(url, "%s%s", repo->url, path);
- switch (http_get_strbuf(url, NULL, 0)) {
+ switch (http_get_strbuf(url, NULL, NULL, 0)) {
case HTTP_OK:
ret = 1;
break;
@@ -1584,7 +1584,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
url = xmalloc(strlen(repo->url) + strlen(path) + 1);
sprintf(url, "%s%s", repo->url, path);
- if (http_get_strbuf(url, &buffer, 0) != HTTP_OK)
+ if (http_get_strbuf(url, NULL, &buffer, 0) != HTTP_OK)
die("Couldn't get %s for remote symref\n%s", url,
curl_errorstr);
free(url);
diff --git a/http.c b/http.c
index 44f35256e4..d9d1aad3be 100644
--- a/http.c
+++ b/http.c
@@ -788,7 +788,8 @@ int handle_curl_result(struct slot_results *results)
#define HTTP_REQUEST_STRBUF 0
#define HTTP_REQUEST_FILE 1
-static int http_request(const char *url, void *result, int target, int options)
+static int http_request(const char *url, struct strbuf *type,
+ void *result, int target, int options)
{
struct active_request_slot *slot;
struct slot_results results;
@@ -838,24 +839,37 @@ static int http_request(const char *url, void *result, int target, int options)
ret = HTTP_START_FAILED;
}
+ if (type) {
+ char *t;
+ strbuf_reset(type);
+ curl_easy_getinfo(slot->curl, CURLINFO_CONTENT_TYPE, &t);
+ if (t)
+ strbuf_addstr(type, t);
+ }
+
curl_slist_free_all(headers);
strbuf_release(&buf);
return ret;
}
-static int http_request_reauth(const char *url, void *result, int target,
+static int http_request_reauth(const char *url,
+ struct strbuf *type,
+ void *result, int target,
int options)
{
- int ret = http_request(url, result, target, options);
+ int ret = http_request(url, type, result, target, options);
if (ret != HTTP_REAUTH)
return ret;
- return http_request(url, result, target, options);
+ return http_request(url, type, result, target, options);
}
-int http_get_strbuf(const char *url, struct strbuf *result, int options)
+int http_get_strbuf(const char *url,
+ struct strbuf *type,
+ struct strbuf *result, int options)
{
- return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options);
+ return http_request_reauth(url, type, result,
+ HTTP_REQUEST_STRBUF, options);
}
/*
@@ -878,7 +892,7 @@ static int http_get_file(const char *url, const char *filename, int options)
goto cleanup;
}
- ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
+ ret = http_request_reauth(url, NULL, result, HTTP_REQUEST_FILE, options);
fclose(result);
if ((ret == HTTP_OK) && move_temp_to_file(tmpfile.buf, filename))
@@ -904,7 +918,7 @@ int http_fetch_ref(const char *base, struct ref *ref)
int ret = -1;
url = quote_ref_url(base, ref->name);
- if (http_get_strbuf(url, &buffer, HTTP_NO_CACHE) == HTTP_OK) {
+ if (http_get_strbuf(url, NULL, &buffer, HTTP_NO_CACHE) == HTTP_OK) {
strbuf_rtrim(&buffer);
if (buffer.len == 40)
ret = get_sha1_hex(buffer.buf, ref->old_sha1);
@@ -997,7 +1011,7 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
strbuf_addstr(&buf, "objects/info/packs");
url = strbuf_detach(&buf, NULL);
- ret = http_get_strbuf(url, &buf, HTTP_NO_CACHE);
+ ret = http_get_strbuf(url, NULL, &buf, HTTP_NO_CACHE);
if (ret != HTTP_OK)
goto cleanup;
diff --git a/http.h b/http.h
index 0a80d303e3..25d1931398 100644
--- a/http.h
+++ b/http.h
@@ -132,7 +132,7 @@ extern char *get_remote_object_url(const char *url, const char *hex,
*
* If the result pointer is NULL, a HTTP HEAD request is made instead of GET.
*/
-int http_get_strbuf(const char *url, struct strbuf *result, int options);
+int http_get_strbuf(const char *url, struct strbuf *content_type, struct strbuf *result, int options);
/*
* Prints an error message using error() containing url and curl_errorstr,
diff --git a/imap-send.c b/imap-send.c
index d42e471297..ef500111ec 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -31,6 +31,7 @@ typedef void *SSL;
#else
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include <openssl/x509v3.h>
#endif
struct store_conf {
@@ -266,12 +267,64 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
}
}
+#ifdef NO_OPENSSL
static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
{
-#ifdef NO_OPENSSL
fprintf(stderr, "SSL requested but SSL support not compiled in\n");
return -1;
+}
+
#else
+
+static int host_matches(const char *host, const char *pattern)
+{
+ if (pattern[0] == '*' && pattern[1] == '.') {
+ pattern += 2;
+ if (!(host = strchr(host, '.')))
+ return 0;
+ host++;
+ }
+
+ return *host && *pattern && !strcasecmp(host, pattern);
+}
+
+static int verify_hostname(X509 *cert, const char *hostname)
+{
+ int len;
+ X509_NAME *subj;
+ char cname[1000];
+ int i, found;
+ STACK_OF(GENERAL_NAME) *subj_alt_names;
+
+ /* try the DNS subjectAltNames */
+ found = 0;
+ if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) {
+ int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names);
+ for (i = 0; !found && i < num_subj_alt_names; i++) {
+ GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
+ if (subj_alt_name->type == GEN_DNS &&
+ strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length &&
+ host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data)))
+ found = 1;
+ }
+ sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
+ }
+ if (found)
+ return 0;
+
+ /* try the common name */
+ if (!(subj = X509_get_subject_name(cert)))
+ return error("cannot get certificate subject");
+ if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0)
+ return error("cannot get certificate common name");
+ if (strlen(cname) == (size_t)len && host_matches(hostname, cname))
+ return 0;
+ return error("certificate owner '%s' does not match hostname '%s'",
+ cname, hostname);
+}
+
+static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
+{
#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
const SSL_METHOD *meth;
#else
@@ -279,6 +332,7 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
#endif
SSL_CTX *ctx;
int ret;
+ X509 *cert;
SSL_library_init();
SSL_load_error_strings();
@@ -322,9 +376,18 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
return -1;
}
+ if (verify) {
+ /* make sure the hostname matches that of the certificate */
+ cert = SSL_get_peer_certificate(sock->ssl);
+ if (!cert)
+ return error("unable to get peer certificate.");
+ if (verify_hostname(cert, server.host) < 0)
+ return -1;
+ }
+
return 0;
-#endif
}
+#endif
static int socket_read(struct imap_socket *sock, char *buf, int len)
{
diff --git a/mergetools/p4merge b/mergetools/p4merge
index 295361a8aa..8a36916567 100644
--- a/mergetools/p4merge
+++ b/mergetools/p4merge
@@ -1,29 +1,21 @@
diff_cmd () {
+ empty_file=
+
# p4merge does not like /dev/null
- rm_local=
- rm_remote=
if test "/dev/null" = "$LOCAL"
then
- LOCAL="./p4merge-dev-null.LOCAL.$$"
- >"$LOCAL"
- rm_local=true
+ LOCAL="$(create_empty_file)"
fi
if test "/dev/null" = "$REMOTE"
then
- REMOTE="./p4merge-dev-null.REMOTE.$$"
- >"$REMOTE"
- rm_remote=true
+ REMOTE="$(create_empty_file)"
fi
"$merge_tool_path" "$LOCAL" "$REMOTE"
- if test -n "$rm_local"
- then
- rm -f "$LOCAL"
- fi
- if test -n "$rm_remote"
+ if test -n "$empty_file"
then
- rm -f "$REMOTE"
+ rm -f "$empty_file"
fi
}
@@ -33,3 +25,10 @@ merge_cmd () {
"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
check_unchanged
}
+
+create_empty_file () {
+ empty_file="${TMPDIR:-/tmp}/git-difftool-p4merge-empty-file.$$"
+ >"$empty_file"
+
+ printf "%s" "$empty_file"
+}
diff --git a/parse-options.c b/parse-options.c
index c1c66bd408..7ca8f2caef 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -3,6 +3,7 @@
#include "cache.h"
#include "commit.h"
#include "color.h"
+#include "utf8.h"
static int parse_options_usage(struct parse_opt_ctx_t *ctx,
const char * const *usagestr,
@@ -470,8 +471,11 @@ int parse_options(int argc, const char **argv, const char *prefix,
default: /* PARSE_OPT_UNKNOWN */
if (ctx.argv[0][1] == '-') {
error("unknown option `%s'", ctx.argv[0] + 2);
- } else {
+ } else if (isascii(*ctx.opt)) {
error("unknown switch `%c'", *ctx.opt);
+ } else {
+ error("unknown non-ascii option in string: `%s'",
+ ctx.argv[0]);
}
usage_with_options(usagestr, options);
}
@@ -491,7 +495,7 @@ static int usage_argh(const struct option *opts, FILE *outfile)
s = literal ? "[%s]" : "[<%s>]";
else
s = literal ? " %s" : " <%s>";
- return fprintf(outfile, s, opts->argh ? _(opts->argh) : _("..."));
+ return utf8_fprintf(outfile, s, opts->argh ? _(opts->argh) : _("..."));
}
#define USAGE_OPTS_WIDTH 24
@@ -550,7 +554,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
if (opts->long_name)
pos += fprintf(outfile, "--%s", opts->long_name);
if (opts->type == OPTION_NUMBER)
- pos += fprintf(outfile, "-NUM");
+ pos += utf8_fprintf(outfile, _("-NUM"));
if ((opts->flags & PARSE_OPT_LITERAL_ARGHELP) ||
!(opts->flags & PARSE_OPT_NOARG))
diff --git a/perl/Git.pm b/perl/Git.pm
index 931047c51d..a56d1e76f7 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -59,6 +59,7 @@ require Exporter;
command_bidi_pipe command_close_bidi_pipe
version exec_path html_path hash_object git_cmd_try
remote_refs prompt
+ get_tz_offset
temp_acquire temp_release temp_reset temp_path);
@@ -102,6 +103,7 @@ use Error qw(:try);
use Cwd qw(abs_path cwd);
use IPC::Open2 qw(open2);
use Fcntl qw(SEEK_SET SEEK_CUR);
+use Time::Local qw(timegm);
}
@@ -511,6 +513,27 @@ C<git --html-path>). Useful mostly only internally.
sub html_path { command_oneline('--html-path') }
+
+=item get_tz_offset ( TIME )
+
+Return the time zone offset from GMT in the form +/-HHMM where HH is
+the number of hours from GMT and MM is the number of minutes. This is
+the equivalent of what strftime("%z", ...) would provide on a GNU
+platform.
+
+If TIME is not supplied, the current local time is used.
+
+=cut
+
+sub get_tz_offset {
+ # some systmes don't handle or mishandle %z, so be creative.
+ my $t = shift || time;
+ my $gm = timegm(localtime($t));
+ my $sign = qw( + + - )[ $gm <=> $t ];
+ return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
+}
+
+
=item prompt ( PROMPT , ISPASSWORD )
Query user C<PROMPT> and return answer from user.
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
index 59215fa86e..8c84560a49 100644
--- a/perl/Git/SVN.pm
+++ b/perl/Git/SVN.pm
@@ -11,7 +11,6 @@ use Carp qw/croak/;
use File::Path qw/mkpath/;
use File::Copy qw/copy/;
use IPC::Open3;
-use Time::Local;
use Memoize; # core since 5.8.0, Jul 2002
use Memoize::Storable;
use POSIX qw(:signal_h);
@@ -22,6 +21,7 @@ use Git qw(
command_noisy
command_output_pipe
command_close_pipe
+ get_tz_offset
);
use Git::SVN::Utils qw(
fatal
@@ -1311,14 +1311,6 @@ sub get_untracked {
\@out;
}
-sub get_tz {
- # some systmes don't handle or mishandle %z, so be creative.
- my $t = shift || time;
- my $gm = timelocal(gmtime($t));
- my $sign = qw( + + - )[ $t <=> $gm ];
- return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
-}
-
# parse_svn_date(DATE)
# --------------------
# Given a date (in UTC) from Subversion, return a string in the format
@@ -1351,7 +1343,7 @@ sub parse_svn_date {
delete $ENV{TZ};
}
- my $our_TZ = get_tz();
+ my $our_TZ = get_tz_offset();
# This converts $epoch_in_UTC into our local timezone.
my ($sec, $min, $hour, $mday, $mon, $year,
diff --git a/perl/Git/SVN/Log.pm b/perl/Git/SVN/Log.pm
index 3cc1c6f081..3f8350a57d 100644
--- a/perl/Git/SVN/Log.pm
+++ b/perl/Git/SVN/Log.pm
@@ -2,7 +2,11 @@ package Git::SVN::Log;
use strict;
use warnings;
use Git::SVN::Utils qw(fatal);
-use Git qw(command command_oneline command_output_pipe command_close_pipe);
+use Git qw(command
+ command_oneline
+ command_output_pipe
+ command_close_pipe
+ get_tz_offset);
use POSIX qw/strftime/;
use constant commit_log_separator => ('-' x 72) . "\n";
use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
@@ -119,7 +123,7 @@ sub run_pager {
sub format_svn_date {
my $t = shift || time;
require Git::SVN;
- my $gmoff = Git::SVN::get_tz($t);
+ my $gmoff = get_tz_offset($t);
return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
}
diff --git a/remote-curl.c b/remote-curl.c
index 9a8b123507..933c69ac26 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -92,6 +92,8 @@ static void free_discovery(struct discovery *d)
static struct discovery* discover_refs(const char *service)
{
+ struct strbuf exp = STRBUF_INIT;
+ struct strbuf type = STRBUF_INIT;
struct strbuf buffer = STRBUF_INIT;
struct discovery *last = last_discovery;
char *refs_url;
@@ -113,7 +115,7 @@ static struct discovery* discover_refs(const char *service)
}
refs_url = strbuf_detach(&buffer, NULL);
- http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
+ http_ret = http_get_strbuf(refs_url, &type, &buffer, HTTP_NO_CACHE);
switch (http_ret) {
case HTTP_OK:
break;
@@ -132,17 +134,20 @@ static struct discovery* discover_refs(const char *service)
last->buf_alloc = strbuf_detach(&buffer, &last->len);
last->buf = last->buf_alloc;
- if (maybe_smart && 5 <= last->len && last->buf[4] == '#') {
- /* smart HTTP response; validate that the service
+ strbuf_addf(&exp, "application/x-%s-advertisement", service);
+ if (maybe_smart &&
+ (5 <= last->len && last->buf[4] == '#') &&
+ !strbuf_cmp(&exp, &type)) {
+ /*
+ * smart HTTP response; validate that the service
* pkt-line matches our request.
*/
- struct strbuf exp = STRBUF_INIT;
-
if (packet_get_line(&buffer, &last->buf, &last->len) <= 0)
die("%s has invalid packet header", refs_url);
if (buffer.len && buffer.buf[buffer.len - 1] == '\n')
strbuf_setlen(&buffer, buffer.len - 1);
+ strbuf_reset(&exp);
strbuf_addf(&exp, "# service=%s", service);
if (strbuf_cmp(&exp, &buffer))
die("invalid server response; got '%s'", buffer.buf);
@@ -160,6 +165,8 @@ static struct discovery* discover_refs(const char *service)
}
free(refs_url);
+ strbuf_release(&exp);
+ strbuf_release(&type);
strbuf_release(&buffer);
last_discovery = last;
return last;
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 02f442bfad..895b9258b0 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -80,6 +80,7 @@ fi
prepare_httpd() {
mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH"
cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH"
+ cp "$TEST_PATH"/broken-smart-http.sh "$HTTPD_ROOT_PATH"
ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index fe76e84b74..938b4cf803 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -62,9 +62,13 @@ Alias /auth/dumb/ www/auth/dumb/
SetEnv GIT_COMMITTER_EMAIL custom@example.com
</LocationMatch>
ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
+ScriptAlias /broken_smart/ broken-smart-http.sh/
<Directory ${GIT_EXEC_PATH}>
Options FollowSymlinks
</Directory>
+<Files broken-smart-http.sh>
+ Options ExecCGI
+</Files>
<Files ${GIT_EXEC_PATH}/git-http-backend>
Options ExecCGI
</Files>
diff --git a/t/lib-httpd/broken-smart-http.sh b/t/lib-httpd/broken-smart-http.sh
new file mode 100755
index 0000000000..f7ebfffa80
--- /dev/null
+++ b/t/lib-httpd/broken-smart-http.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+printf "Content-Type: text/%s\n" "html"
+echo
+printf "%s\n" "001e# service=git-upload-pack"
+printf "%s" "0000"
+printf "%s%c%s%s\n" \
+ "00a58681d9f286a48b08f37b3a095330da16689e3693 HEAD" \
+ 0 \
+ " include-tag multi_ack_detailed multi_ack ofs-delta" \
+ " side-band side-band-64k thin-pack no-progress shallow no-done "
+printf "%s" "0000"
diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh
index 40277c77aa..614425adac 100755
--- a/t/t4038-diff-combined.sh
+++ b/t/t4038-diff-combined.sh
@@ -89,4 +89,28 @@ test_expect_success 'diagnose truncated file' '
grep "diff --cc file" out
'
+test_expect_success 'setup for --cc --raw' '
+ blob=$(echo file | git hash-object --stdin -w) &&
+ base_tree=$(echo "100644 blob $blob file" | git mktree) &&
+ trees= &&
+ for i in `test_seq 1 40`
+ do
+ blob=$(echo file$i | git hash-object --stdin -w) &&
+ trees="$trees$(echo "100644 blob $blob file" | git mktree)$LF"
+ done
+'
+
+test_expect_success 'check --cc --raw with four trees' '
+ four_trees=$(echo "$trees" | sed -e 4q) &&
+ git diff --cc --raw $four_trees $base_tree >out &&
+ # Check for four leading colons in the output:
+ grep "^::::[^:]" out
+'
+
+test_expect_success 'check --cc --raw with forty trees' '
+ git diff --cc --raw $trees $base_tree >out &&
+ # Check for forty leading colons in the output:
+ grep "^::::::::::::::::::::::::::::::::::::::::[^:]" out
+'
+
test_done
diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh
index c5cd2e348c..47eb76921d 100755
--- a/t/t5551-http-fetch.sh
+++ b/t/t5551-http-fetch.sh
@@ -157,6 +157,11 @@ test_expect_success 'GIT_SMART_HTTP can disable smart http' '
test_must_fail git fetch)
'
+test_expect_success 'invalid Content-Type rejected' '
+ test_must_fail git clone $HTTPD_URL/broken_smart/repo.git 2>actual
+ grep "not valid:" actual
+'
+
test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index b3f6eb9c68..95d651080f 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -5,7 +5,7 @@
# Grenoble INP Ensimag
#
-test_description='git status advices'
+test_description='git status advice'
. ./test-lib.sh
diff --git a/utf8.c b/utf8.c
index a4ee6650ef..1087870c51 100644
--- a/utf8.c
+++ b/utf8.c
@@ -430,6 +430,27 @@ int same_encoding(const char *src, const char *dst)
}
/*
+ * Wrapper for fprintf and returns the total number of columns required
+ * for the printed string, assuming that the string is utf8.
+ */
+int utf8_fprintf(FILE *stream, const char *format, ...)
+{
+ struct strbuf buf = STRBUF_INIT;
+ va_list arg;
+ int columns;
+
+ va_start(arg, format);
+ strbuf_vaddf(&buf, format, arg);
+ va_end(arg);
+
+ columns = fputs(buf.buf, stream);
+ if (0 <= columns) /* keep the error from the I/O */
+ columns = utf8_strwidth(buf.buf);
+ strbuf_release(&buf);
+ return columns;
+}
+
+/*
* Given a buffer and its encoding, return it re-encoded
* with iconv. If the conversion fails, returns NULL.
*/
diff --git a/utf8.h b/utf8.h
index a214238bdd..501b2bd9c4 100644
--- a/utf8.h
+++ b/utf8.h
@@ -8,6 +8,7 @@ int utf8_strwidth(const char *string);
int is_utf8(const char *text);
int is_encoding_utf8(const char *name);
int same_encoding(const char *, const char *);
+int utf8_fprintf(FILE *, const char *, ...);
void strbuf_add_wrapped_text(struct strbuf *buf,
const char *text, int indent, int indent2, int width);