aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/Makefile11
-rw-r--r--Documentation/RelNotes/1.8.1.4.txt11
-rw-r--r--Documentation/config.txt2
-rw-r--r--Documentation/git-add.txt10
-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.txt3
-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.txt123
-rwxr-xr-xGIT-VERSION-GEN2
l---------RelNotes2
-rw-r--r--builtin/add.c2
-rw-r--r--builtin/apply.c10
-rw-r--r--builtin/clean.c154
-rw-r--r--builtin/clone.c2
-rw-r--r--builtin/commit.c4
-rw-r--r--combine-diff.c21
-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.c5
-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
37 files changed, 450 insertions, 164 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 971977b8a..3c538e3de 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 000000000..22af1d164
--- /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/config.txt b/Documentation/config.txt
index e452ff89b..dbb2faf60 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
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index fd9e36b99..d0cdb0784 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -11,7 +11,7 @@ SYNOPSIS
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
[--refresh] [--ignore-errors] [--ignore-missing] [--]
- [<filepattern>...]
+ [<pathspec>...]
DESCRIPTION
-----------
@@ -49,7 +49,7 @@ commit.
OPTIONS
-------
-<filepattern>...::
+<pathspec>...::
Files to add content from. Fileglobs (e.g. `*.c`) can
be given to add all matching files. Also a
leading directory name (e.g. `dir` to add `dir/file1`
@@ -100,20 +100,20 @@ apply to the index. See EDITING PATCHES below.
-u::
--update::
- Only match <filepattern> against already tracked files in
+ Only match <pathspec> against already tracked files in
the index rather than the working tree. That means that it
will never stage new files, but that it will stage modified
new contents of tracked files and that it will remove files
from the index if the corresponding files in the working tree
have been removed.
+
-If no <filepattern> is given, default to "."; in other words,
+If no <pathspec> is given, default to "."; in other words,
update all tracked files in the current directory and its
subdirectories.
-A::
--all::
- Like `-u`, but match <filepattern> against files in the
+ Like `-u`, but match <pathspec> against files in the
working tree in addition to the index. That means that it
will find new files as well as staging modified content and
removing files that are no longer in the working tree.
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index e4f46bc18..038514b51 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 000000000..49233f5d2
--- /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 2a67d456a..4c871b92e 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.txt b/Documentation/git.txt
index c7f211e81..da0115f3d 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],
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/gitremote-helpers.txt
index 6d696e0f9..0f21367ca 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 1d15ee7e5..cea5462ff 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 1b377dc20..52c8523c7 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -782,7 +782,7 @@ e05db0fd4f31dde7005f075a84f96b360d05984b
Or you could recall that the ... operator selects all commits
contained reachable from either one reference or the other but not
-both: so
+both; so
-------------------------------------------------
$ git log origin...master
@@ -931,11 +931,20 @@ The linkgit:git-archive[1] command can create a tar or zip archive from
any version of a project; for example:
-------------------------------------------------
-$ git archive --format=tar --prefix=project/ HEAD | gzip >latest.tar.gz
+$ git archive -o latest.tar.gz --prefix=project/ HEAD
-------------------------------------------------
-will use HEAD to produce a tar archive in which each filename is
-preceded by "project/".
+will use HEAD to produce a gzipped tar archive in which each filename
+is preceded by `project/`. The output file format is inferred from
+the output file extension if possible, see linkgit:git-archive[1] for
+details.
+
+Versions of Git older than 1.7.7 don't know about the 'tar.gz' format,
+you'll need to use gzip explicitly:
+
+-------------------------------------------------
+$ git archive --format=tar --prefix=project/ HEAD | gzip >latest.tar.gz
+-------------------------------------------------
If you're releasing a new version of a software project, you may want
to simultaneously make a changelog to include in the release
@@ -991,9 +1000,16 @@ Developing with git
Telling git your name
---------------------
-Before creating any commits, you should introduce yourself to git. The
-easiest way to do so is to make sure the following lines appear in a
-file named .gitconfig in your home directory:
+Before creating any commits, you should introduce yourself to Git.
+The easiest way to do so is to use linkgit:git-config[1]:
+
+------------------------------------------------
+$ git config --global user.name 'Your Name Comes Here'
+$ git config --global user.email 'you@yourdomain.example.com'
+------------------------------------------------
+
+Which will add the following to a file named `.gitconfig` in your
+home directory:
------------------------------------------------
[user]
@@ -1001,8 +1017,9 @@ file named .gitconfig in your home directory:
email = you@yourdomain.example.com
------------------------------------------------
-(See the "CONFIGURATION FILE" section of linkgit:git-config[1] for
-details on the configuration file.)
+See the "CONFIGURATION FILE" section of linkgit:git-config[1] for
+details on the configuration file. The file is plain text, so you can
+also edit it with your favorite editor.
[[creating-a-new-repository]]
@@ -1561,18 +1578,12 @@ $ git stash pop
Ensuring good performance
-------------------------
-On large repositories, git depends on compression to keep the history
-information from taking up too much space on disk or in memory.
-
-This compression is not performed automatically. Therefore you
-should occasionally run linkgit:git-gc[1]:
-
--------------------------------------------------
-$ git gc
--------------------------------------------------
-
-to recompress the archive. This can be very time-consuming, so
-you may prefer to run `git gc` when you are not doing other work.
+On large repositories, Git depends on compression to keep the history
+information from taking up too much space on disk or in memory. Some
+git commands may automatically run linkgit:git-gc[1], so you don't
+have to worry about running it manually. However, compressing a large
+repository may take a while, so you may want to call `gc` explicitly
+to avoid automatic compression kicking in when it is not convenient.
[[ensuring-reliability]]
@@ -1931,11 +1942,11 @@ linkgit:git-daemon[1] man page for details. (See especially the
examples section.)
[[exporting-via-http]]
-Exporting a git repository via http
+Exporting a git repository via HTTP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The git protocol gives better performance and reliability, but on a
-host with a web server set up, http exports may be simpler to set up.
+host with a web server set up, HTTP exports may be simpler to set up.
All you need to do is place the newly created bare git repository in
a directory that is exported by the web server, and make some
@@ -1961,7 +1972,7 @@ $ git clone http://yourserver.com/~you/proj.git
(See also
link:howto/setup-git-server-over-http.txt[setup-git-server-over-http]
for a slightly more sophisticated setup using WebDAV which also
-allows pushing over http.)
+allows pushing over HTTP.)
[[pushing-changes-to-a-public-repository]]
Pushing changes to a public repository
@@ -1998,16 +2009,21 @@ 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!
As with `git fetch`, you may also set up configuration options to
-save typing; so, for example, after
+save typing; so, for example:
+
+-------------------------------------------------
+$ git remote add public-repo ssh://yourserver.com/~you/proj.git
+-------------------------------------------------
+
+adds the following to `.git/config`:
-------------------------------------------------
-$ cat >>.git/config <<EOF
[remote "public-repo"]
- url = ssh://yourserver.com/~you/proj.git
-EOF
+ url = yourserver.com:proj.git
+ fetch = +refs/heads/*:refs/remotes/example/*
-------------------------------------------------
-you should be able to perform the above push with just
+which lets you do the same push with just
-------------------------------------------------
$ git push public-repo master
@@ -2046,6 +2062,13 @@ branch name with a plus sign:
$ git push ssh://yourserver.com/~you/proj.git +master
-------------------------------------------------
+Note the addition of the `+` sign. Alternatively, you can use the
+`-f` flag to force the remote update, as in:
+
+-------------------------------------------------
+$ git push -f ssh://yourserver.com/~you/proj.git master
+-------------------------------------------------
+
Normally whenever a branch head in a public repository is modified, it
is modified to point to a descendant of the commit that it pointed to
before. By forcing a push in this situation, you break that convention.
@@ -2850,48 +2873,34 @@ branch.master.merge=refs/heads/master
If there are other repositories that you also use frequently, you can
create similar configuration options to save typing; for example,
-after
-------------------------------------------------
-$ git config remote.example.url git://example.com/proj.git
+$ git remote add example git://example.com/proj.git
-------------------------------------------------
-then the following two commands will do the same thing:
+adds the following to `.git/config`:
-------------------------------------------------
-$ git fetch git://example.com/proj.git master:refs/remotes/example/master
-$ git fetch example master:refs/remotes/example/master
+[remote "example"]
+ url = git://example.com/proj.git
+ fetch = +refs/heads/*:refs/remotes/example/*
-------------------------------------------------
-Even better, if you add one more option:
+Also note that the above configuration can be performed by directly
+editing the file `.git/config` instead of using linkgit:git-remote[1].
--------------------------------------------------
-$ git config remote.example.fetch master:refs/remotes/example/master
--------------------------------------------------
-
-then the following commands will all do the same thing:
+After configuring the remote, the following three commands will do the
+same thing:
-------------------------------------------------
-$ git fetch git://example.com/proj.git master:refs/remotes/example/master
-$ git fetch example master:refs/remotes/example/master
+$ git fetch git://example.com/proj.git +refs/heads/*:refs/remotes/example/*
+$ git fetch example +refs/heads/*:refs/remotes/example/*
$ git fetch example
-------------------------------------------------
-You can also add a "+" to force the update each time:
-
--------------------------------------------------
-$ git config remote.example.fetch +master:refs/remotes/example/master
--------------------------------------------------
-
-Don't do this unless you're sure you won't mind "git fetch" possibly
-throwing away commits on 'example/master'.
-
-Also note that all of the above configuration can be performed by
-directly editing the file .git/config instead of using
-linkgit:git-config[1].
-
See linkgit:git-config[1] for more details on the configuration
-options mentioned above.
+options mentioned above and linkgit:git-fetch[1] for more details on
+the refspec syntax.
[[git-concepts]]
@@ -3396,7 +3405,7 @@ $ git log --raw --all
------------------------------------------------
and just looked for the sha of the missing object (4b9458b..) in that
-whole thing. It's up to you - git does *have* a lot of information, it is
+whole thing. It's up to you--Git does *have* a lot of information, it is
just missing one particular blob version.
[[the-index]]
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 07685f469..dcd3595f2 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/RelNotes b/RelNotes
index ce97a3bef..ad613ead7 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.4.txt \ No newline at end of file
diff --git a/builtin/add.c b/builtin/add.c
index e664100c7..632594768 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -16,7 +16,7 @@
#include "bulk-checkin.h"
static const char * const builtin_add_usage[] = {
- N_("git add [options] [--] <filepattern>..."),
+ N_("git add [options] [--] <pathspec>..."),
NULL
};
static int patch_interactive, add_interactive, edit_interactive;
diff --git a/builtin/apply.c b/builtin/apply.c
index 9706ca73a..080ce2ea3 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 69c1cda90..f4b760bf3 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 8d23a62e8..36ec99db3 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/builtin/commit.c b/builtin/commit.c
index d6dd3df8b..96684108e 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -31,12 +31,12 @@
#include "sequencer.h"
static const char * const builtin_commit_usage[] = {
- N_("git commit [options] [--] <filepattern>..."),
+ N_("git commit [options] [--] <pathspec>..."),
NULL
};
static const char * const builtin_status_usage[] = {
- N_("git status [options] [--] <filepattern>..."),
+ N_("git status [options] [--] <pathspec>..."),
NULL
};
diff --git a/combine-diff.c b/combine-diff.c
index bb1cc96c4..7f6187f9c 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-difftool--helper.sh b/git-difftool--helper.sh
index 3d0fe0cd9..b00ed95db 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 c50e18a89..012afa554 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 c6bafe6ea..1309196d2 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 8701c1215..ba45b7b50 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 44f35256e..d9d1aad3b 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 0a80d303e..25d193139 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 d42e47129..ef500111e 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 295361a8a..52f7c8f70 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 "$empty_file"
+}
diff --git a/parse-options.c b/parse-options.c
index c1c66bd40..670bf09b4 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,
@@ -491,7 +492,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 +551,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/remote-curl.c b/remote-curl.c
index 9a8b12350..933c69ac2 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 02f442bfa..895b9258b 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 fe76e84b7..938b4cf80 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 000000000..f7ebfffa8
--- /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 40277c77a..614425ada 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 c5cd2e348..47eb76921 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 b3f6eb9c6..95d651080 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 a4ee6650e..1087870c5 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 a214238bd..501b2bd9c 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);