Merge branch 'jn/maint-gitweb-pathinfo-fix' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 19 Jan 2011 16:26:04 +0000 (08:26 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 19 Jan 2011 16:26:04 +0000 (08:26 -0800)
* jn/maint-gitweb-pathinfo-fix:
gitweb: Fix handling of whitespace in generated links

67 files changed:
Documentation/RelNotes/1.6.4.5.txt [new file with mode: 0644]
Documentation/RelNotes/1.6.5.9.txt [new file with mode: 0644]
Documentation/RelNotes/1.6.6.3.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.0.9.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.1.4.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.2.5.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.3.4.txt
Documentation/RelNotes/1.7.3.5.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/git-archive.txt
Documentation/git-difftool.txt
Documentation/git-fsck.txt
Documentation/git-gc.txt
Documentation/git-pull.txt
Documentation/githooks.txt
GIT-VERSION-GEN
Makefile
RelNotes
builtin/commit.c
builtin/describe.c
cache.h
diff.c
dir.c
entry.c
fast-import.c
git-am.sh
git-difftool--helper.sh
git-rebase.sh
git-submodule.sh
gitk-git/gitk [changed mode: 0644->0755]
gitweb/gitweb.perl
http-backend.c
http-fetch.c
http-push.c
http.c
http.h
ident.c
reflog-walk.c
revision.c
symlinks.c
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/lib-httpd/passwd [new file with mode: 0644]
t/t0050-filesystem.sh
t/t1412-reflog-loop.sh [new file with mode: 0755]
t/t3404-rebase-interactive.sh
t/t3407-rebase-abort.sh
t/t3419-rebase-patch-id.sh
t/t4151-am-abort.sh
t/t5407-post-rewrite-hook.sh
t/t5550-http-fetch.sh
t/t7400-submodule-basic.sh
t/t7501-commit.sh
t/t7607-merge-overwrite.sh
t/t7609-merge-co-error-msgs.sh
t/t8006-blame-textconv.sh
t/t9001-send-email.sh
t/t9119-git-svn-info.sh
t/test-lib.sh
trace.c
unpack-trees.c
unpack-trees.h
url.c
url.h
userdiff.c
wt-status.c
xdiff-interface.c
diff --git a/Documentation/RelNotes/1.6.4.5.txt b/Documentation/RelNotes/1.6.4.5.txt
new file mode 100644 (file)
index 0000000..eb6307d
--- /dev/null
@@ -0,0 +1,20 @@
+Git v1.6.4.5 Release Notes
+==========================
+
+Fixes since v1.6.4.4
+--------------------
+
+ * Simplified base85 implementation.
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git count-objects" did not handle packs larger than 4G.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.5.9.txt b/Documentation/RelNotes/1.6.5.9.txt
new file mode 100644 (file)
index 0000000..bb469dd
--- /dev/null
@@ -0,0 +1,18 @@
+Git v1.6.5.9 Release Notes
+==========================
+
+Fixes since v1.6.5.8
+--------------------
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git blame -L $start,$end" segfaulted when too large $start was given.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.6.3.txt b/Documentation/RelNotes/1.6.6.3.txt
new file mode 100644 (file)
index 0000000..11483ac
--- /dev/null
@@ -0,0 +1,23 @@
+Git v1.6.6.3 Release Notes
+==========================
+
+Fixes since v1.6.6.2
+--------------------
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git bisect $path" did not correctly diagnose an error when given a
+   non-existent path.
+
+ * "git blame -L $start,$end" segfaulted when too large $start was given.
+
+ * "git imap-send" did not write draft box with CRLF line endings per RFC.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.7.0.9.txt b/Documentation/RelNotes/1.7.0.9.txt
new file mode 100644 (file)
index 0000000..bfb3166
--- /dev/null
@@ -0,0 +1,8 @@
+Git v1.7.0.9 Release Notes
+==========================
+
+Fixes since v1.7.0.8
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
diff --git a/Documentation/RelNotes/1.7.1.4.txt b/Documentation/RelNotes/1.7.1.4.txt
new file mode 100644 (file)
index 0000000..7c734b4
--- /dev/null
@@ -0,0 +1,8 @@
+Git v1.7.1.4 Release Notes
+==========================
+
+Fixes since v1.7.1.3
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
diff --git a/Documentation/RelNotes/1.7.2.5.txt b/Documentation/RelNotes/1.7.2.5.txt
new file mode 100644 (file)
index 0000000..bf976c4
--- /dev/null
@@ -0,0 +1,8 @@
+Git v1.7.2.5 Release Notes
+==========================
+
+Fixes since v1.7.2.4
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
index 925178f6089fbeff38add340563d803bc65a7365..e57f7c176db85e3bd40862fd091ecab835c601f5 100644 (file)
@@ -14,6 +14,11 @@ Fixes since v1.7.3.3
    colon between the hours and minutes part (e.g. "-08:00" instead of
    "-0800").
 
+ * "git checkout" removed an untracked file "foo" from the working
+   tree when switching to a branch that contains a tracked path
+   "foo/bar".  Prevent this, just like the case where the conflicting
+   path were "foo" (c752e7f..7980872d).
+
  * "git cherry-pick" or "git revert" refused to work when a path that
    would be modified by the operation was stat-dirty without a real
    difference in the contents of the file.
@@ -21,12 +26,20 @@ Fixes since v1.7.3.3
  * "git diff --check" reported an incorrect line number for added
    blank lines at the end of file.
 
+ * "git imap-send" failed to build under NO_OPENSSL.
+
  * Setting log.decorate configuration variable to "0" or "1" to mean
    "false" or "true" did not work.
 
+ * "git push" over dumb HTTP protocol did not work against WebDAV
+   servers that did not terminate a collection name with a slash.
+
  * "git tag -v" did not work with GPG signatures in rfc1991 mode.
 
  * The post-receive-email sample hook was accidentally broken in 1.7.3.3
    update.
 
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
 Other minor fixes and documentation updates are also included.
diff --git a/Documentation/RelNotes/1.7.3.5.txt b/Documentation/RelNotes/1.7.3.5.txt
new file mode 100644 (file)
index 0000000..40f3ba5
--- /dev/null
@@ -0,0 +1,34 @@
+Git 1.7.3.5 Release Notes
+=========================
+
+ * The xfuncname pattern used by "git diff" and "git grep" to show the
+   last notable line in context were broken for python and ruby for a long
+   time.
+
+ * "git merge" into an unborn branch removed an untracked file "foo" from
+   the working tree when merged branch had "foo" (this fix was already in
+   1.7.3.3 but was omitted from the release notes by mistake).
+
+ * "git status -s" did not quote unprintable characters in paths as
+   documented.
+
+ * "git am --abort" used to always reset to the commit at the beginning of
+   the last "am" invocation that has stopped, losing any unrelated commits
+   that may have been made since then.  Now it refrains from doing so and
+   instead issues a warning.
+
+ * "git blame" incorrectly reused bogusly cached result of textconv
+   filter for files from the working tree.
+
+ * "git commit" used to abort after the user edited the log message
+   when the committer information was not correctly set up.  It now
+   aborts before starting the editor.
+
+ * "git commit --date=invalid" used to silently ignore the incorrectly
+   specified date; it is now diagnosed as an error.
+
+ * "git rebase --skip" to skip the last commit in a series used to fail
+   to run post-rewrite hook and to copy notes from old commits that have
+   successfully been rebased so far.  Now it do (backmerge ef88ad2).
+
+ * "gitweb" tried to show a wrong feed logo when none was specified.
index 3fd4b626fa84deb317709f11782534f36df36033..4f1e9799321380739afe96dd7ec841b768ae988b 100644 (file)
@@ -971,7 +971,7 @@ gc.packrefs::
        Running `git pack-refs` in a repository renders it
        unclonable by Git versions prior to 1.5.1.2 over dumb
        transports such as HTTP.  This variable determines whether
-       'git gc' runs `git pack-refs`. This can be set to `nobare`
+       'git gc' runs `git pack-refs`. This can be set to `notbare`
        to enable it within all non-bare repos or it can be set to a
        boolean value.  The default is `true`.
 
index 4163a1bcb1643e7f05b6a79034ac9f63135d6ac9..bf5037ab2a5042a20e9cb603f0831bb186ac3b74 100644 (file)
@@ -116,7 +116,7 @@ Note that attributes are by default taken from the `.gitattributes` files
 in the tree that is being archived.  If you want to tweak the way the
 output is generated after the fact (e.g. you committed without adding an
 appropriate export-ignore in its `.gitattributes`), adjust the checked out
-`.gitattributes` file as necessary and use `--work-tree-attributes`
+`.gitattributes` file as necessary and use `--worktree-attributes`
 option.  Alternatively you can keep necessary attributes that should apply
 while archiving any tree in your `$GIT_DIR/info/attributes` file.
 
index 8250bad2ce95245ca8e2a41c0740d0029b92ae4b..573843211112a6efb7b296bbc5b11894c01dd8cd 100644 (file)
@@ -55,14 +55,16 @@ the configured command line will be invoked with the following
 variables available: `$LOCAL` is set to the name of the temporary
 file containing the contents of the diff pre-image and `$REMOTE`
 is set to the name of the temporary file containing the contents
-of the diff post-image.  `$BASE` is provided for compatibility
-with custom merge tool commands and has the same value as `$LOCAL`.
+of the diff post-image.  `$MERGED` is the name of the file which is
+being compared. `$BASE` is provided for compatibility
+with custom merge tool commands and has the same value as `$MERGED`.
 
 -x <command>::
 --extcmd=<command>::
        Specify a custom command for viewing diffs.
        'git-difftool' ignores the configured defaults and runs
        `$command $LOCAL $REMOTE` when this option is specified.
+       Additionally, `$BASE` is set in the environment.
 
 -g::
 --gui::
index 3ad48a633663ec22af16b4737c42fd7e7664e4d2..86f9b2bf91f604cbfd175a4e241fc14fcb5828d5 100644 (file)
@@ -123,9 +123,6 @@ dangling <type> <object>::
        The <type> object <object>, is present in the database but never
        'directly' used. A dangling commit could be a root node.
 
-warning: git-fsck: tree <tree> has full pathnames in it::
-       And it shouldn't...
-
 sha1 mismatch <object>::
        The database has an object who's sha1 doesn't match the
        database value.
index 315f07ef1c6997c98c4e446af507c3e1e4566218..a01eef6763d8c0383121019e9c33c869f0300acf 100644 (file)
@@ -107,7 +107,7 @@ how long records of conflicted merge you have not resolved are
 kept.  This defaults to 15 days.
 
 The optional configuration variable 'gc.packrefs' determines if
-'git gc' runs 'git pack-refs'. This can be set to "nobare" to enable
+'git gc' runs 'git pack-refs'. This can be set to "notbare" to enable
 it within all non-bare repos or it can be set to a boolean value.
 This defaults to true.
 
index abbc3eb3e0ee208a13237cde5ae3d00d962ad62e..64009dee31e22de815c99d641fb90b49901d9ede 100644 (file)
@@ -98,8 +98,9 @@ include::merge-options.txt[]
        fetched, the rebase uses that information to avoid rebasing
        non-local changes.
 +
-See `branch.<name>.rebase` in linkgit:git-config[1] if you want to make
-`git pull` always use `{litdd}rebase` instead of merging.
+See `branch.<name>.rebase` and `branch.autosetuprebase` in
+linkgit:git-config[1] if you want to make `git pull` always use
+`{litdd}rebase` instead of merging.
 +
 [NOTE]
 This is a potentially _dangerous_ mode of operation.
index 7183aa9abbc35018dc50a7c0e5254cc72115af23..28edefa202fb0d1065f161f59787ceae39439eb3 100644 (file)
@@ -350,10 +350,6 @@ rebase::
 The commits are guaranteed to be listed in the order that they were
 processed by rebase.
 
-There is no default 'post-rewrite' hook, but see the
-`post-receive-copy-notes` script in `contrib/hooks` for an example
-that copies your git-notes to the rewritten commits.
-
 
 GIT
 ---
index 702306acd2c10d1cbe04c26bf3b89bafadb256f7..d810ec288015de8113fa388730579e4fdedbfa20 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.3.3
+DEF_VER=v1.7.3.5
 
 LF='
 '
index cd0f6481721f9ec47bdc2c0da93936fdfe806a2c..ecb4e64435b674d97d643bf04d896b26a2b505b2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1262,11 +1262,15 @@ else
        BLK_SHA1 = 1
        OPENSSL_LIBSSL =
 endif
+ifdef NO_OPENSSL
+       LIB_4_CRYPTO =
+else
 ifdef NEEDS_SSL_WITH_CRYPTO
        LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto -lssl
 else
        LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto
 endif
+endif
 ifdef NEEDS_LIBICONV
        ifdef ICONVDIR
                BASIC_CFLAGS += -I$(ICONVDIR)/include
@@ -1879,7 +1883,7 @@ builtin/tar-tree.o archive-tar.o: tar.h
 builtin/pack-objects.o: thread-utils.h
 connect.o transport.o http-backend.o: url.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
-http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h
+http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
 xdiff-interface.o $(XDIFF_OBJS): \
        xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
index a6103a01d82cdaf8081e14cd359b42b0e5098544..39dc075ee01342db1cd11c47f6de0395df605976 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.3.4.txt
\ No newline at end of file
+Documentation/RelNotes/1.7.3.5.txt
\ No newline at end of file
index 66fdd2202495b2893c79b4f92b0fc2e715f5b7bb..6e2f12accc82b02863736a10ae5c107717f96a96 100644 (file)
@@ -45,9 +45,9 @@ static const char implicit_ident_advice[] =
 "    git config --global user.name \"Your Name\"\n"
 "    git config --global user.email you@example.com\n"
 "\n"
-"If the identity used for this commit is wrong, you can fix it with:\n"
+"After doing this, you may fix the identity used for this commit with:\n"
 "\n"
-"    git commit --amend --author='Your Name <you@example.com>'\n";
+"    git commit --amend --reset-author\n";
 
 static const char empty_amend_advice[] =
 "You asked to amend the most recent commit, but doing so would make\n"
@@ -69,7 +69,6 @@ static enum {
 static const char *logfile, *force_author;
 static const char *template_file;
 static char *edit_message, *use_message;
-static char *author_name, *author_email, *author_date;
 static int all, edit_flag, also, interactive, only, amend, signoff;
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int no_post_rewrite, allow_empty_message;
@@ -459,7 +458,7 @@ static int is_a_merge(const unsigned char *sha1)
 
 static const char sign_off_header[] = "Signed-off-by: ";
 
-static void determine_author_info(void)
+static void determine_author_info(struct strbuf *author_ident)
 {
        char *name, *email, *date;
 
@@ -503,10 +502,8 @@ static void determine_author_info(void)
 
        if (force_date)
                date = force_date;
-
-       author_name = name;
-       author_email = email;
-       author_date = date;
+       strbuf_addstr(author_ident, fmt_ident(name, email, date,
+                                             IDENT_ERROR_ON_NO_NAME));
 }
 
 static int ends_rfc2822_footer(struct strbuf *sb)
@@ -550,10 +547,21 @@ static int ends_rfc2822_footer(struct strbuf *sb)
        return 1;
 }
 
+static char *cut_ident_timestamp_part(char *string)
+{
+       char *ket = strrchr(string, '>');
+       if (!ket || ket[1] != ' ')
+               die("Malformed ident string: '%s'", string);
+       *++ket = '\0';
+       return ket;
+}
+
 static int prepare_to_commit(const char *index_file, const char *prefix,
-                            struct wt_status *s)
+                            struct wt_status *s,
+                            struct strbuf *author_ident)
 {
        struct stat statbuf;
+       struct strbuf committer_ident = STRBUF_INIT;
        int commitable, saved_color_setting;
        struct strbuf sb = STRBUF_INIT;
        char *buffer;
@@ -637,14 +645,13 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 
        strbuf_release(&sb);
 
-       determine_author_info();
+       /* This checks and barfs if author is badly specified */
+       determine_author_info(author_ident);
 
        /* This checks if committer ident is explicitly given */
-       git_committer_info(0);
+       strbuf_addstr(&committer_ident, git_committer_info(0));
        if (use_editor && include_status) {
-               char *author_ident;
-               const char *committer_ident;
-
+               char *ai_tmp, *ci_tmp;
                if (in_merge)
                        fprintf(fp,
                                "#\n"
@@ -672,23 +679,21 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                if (only_include_assumed)
                        fprintf(fp, "# %s\n", only_include_assumed);
 
-               author_ident = xstrdup(fmt_name(author_name, author_email));
-               committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"),
-                                          getenv("GIT_COMMITTER_EMAIL"));
-               if (strcmp(author_ident, committer_ident))
+               ai_tmp = cut_ident_timestamp_part(author_ident->buf);
+               ci_tmp = cut_ident_timestamp_part(committer_ident.buf);
+               if (strcmp(author_ident->buf, committer_ident.buf))
                        fprintf(fp,
                                "%s"
                                "# Author:    %s\n",
                                ident_shown++ ? "" : "#\n",
-                               author_ident);
-               free(author_ident);
+                               author_ident->buf);
 
                if (!user_ident_sufficiently_given())
                        fprintf(fp,
                                "%s"
                                "# Committer: %s\n",
                                ident_shown++ ? "" : "#\n",
-                               committer_ident);
+                               committer_ident.buf);
 
                if (ident_shown)
                        fprintf(fp, "#\n");
@@ -697,6 +702,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                s->use_color = 0;
                commitable = run_status(fp, index_file, prefix, 1, s);
                s->use_color = saved_color_setting;
+
+               *ai_tmp = ' ';
+               *ci_tmp = ' ';
        } else {
                unsigned char sha1[20];
                const char *parent = "HEAD";
@@ -712,6 +720,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                else
                        commitable = index_differs_from(parent, 0);
        }
+       strbuf_release(&committer_ident);
 
        fclose(fp);
 
@@ -1246,6 +1255,7 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
 int cmd_commit(int argc, const char **argv, const char *prefix)
 {
        struct strbuf sb = STRBUF_INIT;
+       struct strbuf author_ident = STRBUF_INIT;
        const char *index_file, *reflog_msg;
        char *nl, *p;
        unsigned char commit_sha1[20];
@@ -1273,7 +1283,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        /* Set up everything for writing the commit object.  This includes
           running hooks, writing the trees, and interacting with the user.  */
-       if (!prepare_to_commit(index_file, prefix, &s)) {
+       if (!prepare_to_commit(index_file, prefix, &s, &author_ident)) {
                rollback_index_files();
                return 1;
        }
@@ -1352,11 +1362,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        }
 
        if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1,
-                       fmt_ident(author_name, author_email, author_date,
-                               IDENT_ERROR_ON_NO_NAME))) {
+                       author_ident.buf)) {
                rollback_index_files();
                die("failed to write commit object");
        }
+       strbuf_release(&author_ident);
 
        ref_lock = lock_any_ref_for_update("HEAD",
                                           initial_commit ? NULL : head_sha1,
index 43caff2ffe185df6ab224b93b4fd9ce3d82de2d0..a0f52c1b72b2ffd95e781abffb78d7b66ec583c7 100644 (file)
@@ -6,6 +6,7 @@
 #include "exec_cmd.h"
 #include "parse-options.h"
 #include "diff.h"
+#include "hash.h"
 
 #define SEEN           (1u<<0)
 #define MAX_TAGS       (FLAG_BITS - 1)
@@ -22,7 +23,8 @@ static int tags;      /* Allow lightweight tags */
 static int longformat;
 static int abbrev = DEFAULT_ABBREV;
 static int max_candidates = 10;
-static int found_names;
+static struct hash_table names;
+static int have_util;
 static const char *pattern;
 static int always;
 static const char *dirty;
@@ -34,16 +36,44 @@ static const char *diff_index_args[] = {
 
 
 struct commit_name {
+       struct commit_name *next;
+       unsigned char peeled[20];
        struct tag *tag;
        unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
        unsigned name_checked:1;
        unsigned char sha1[20];
-       char path[FLEX_ARRAY]; /* more */
+       const char *path;
 };
 static const char *prio_names[] = {
        "head", "lightweight", "annotated",
 };
 
+static inline unsigned int hash_sha1(const unsigned char *sha1)
+{
+       unsigned int hash;
+       memcpy(&hash, sha1, sizeof(hash));
+       return hash;
+}
+
+static inline struct commit_name *find_commit_name(const unsigned char *peeled)
+{
+       struct commit_name *n = lookup_hash(hash_sha1(peeled), &names);
+       while (n && !!hashcmp(peeled, n->peeled))
+               n = n->next;
+       return n;
+}
+
+static int set_util(void *chain)
+{
+       struct commit_name *n;
+       for (n = chain; n; n = n->next) {
+               struct commit *c = lookup_commit_reference_gently(n->peeled, 1);
+               if (c)
+                       c->util = n;
+       }
+       return 0;
+}
+
 static int replace_name(struct commit_name *e,
                               int prio,
                               const unsigned char *sha1,
@@ -78,31 +108,36 @@ static int replace_name(struct commit_name *e,
 }
 
 static void add_to_known_names(const char *path,
-                              struct commit *commit,
+                              const unsigned char *peeled,
                               int prio,
                               const unsigned char *sha1)
 {
-       struct commit_name *e = commit->util;
+       struct commit_name *e = find_commit_name(peeled);
        struct tag *tag = NULL;
        if (replace_name(e, prio, sha1, &tag)) {
-               size_t len = strlen(path)+1;
-               free(e);
-               e = xmalloc(sizeof(struct commit_name) + len);
+               if (!e) {
+                       void **pos;
+                       e = xmalloc(sizeof(struct commit_name));
+                       hashcpy(e->peeled, peeled);
+                       pos = insert_hash(hash_sha1(peeled), e, &names);
+                       if (pos) {
+                               e->next = *pos;
+                               *pos = e;
+                       } else {
+                               e->next = NULL;
+                       }
+               }
                e->tag = tag;
                e->prio = prio;
                e->name_checked = 0;
                hashcpy(e->sha1, sha1);
-               memcpy(e->path, path, len);
-               commit->util = e;
+               e->path = path;
        }
-       found_names = 1;
 }
 
 static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
        int might_be_tag = !prefixcmp(path, "refs/tags/");
-       struct commit *commit;
-       struct object *object;
        unsigned char peeled[20];
        int is_tag, prio;
 
@@ -110,16 +145,10 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
                return 0;
 
        if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) {
-               commit = lookup_commit_reference_gently(peeled, 1);
-               if (!commit)
-                       return 0;
-               is_tag = !!hashcmp(sha1, commit->object.sha1);
+               is_tag = !!hashcmp(sha1, peeled);
        } else {
-               commit = lookup_commit_reference_gently(sha1, 1);
-               object = parse_object(sha1);
-               if (!commit || !object)
-                       return 0;
-               is_tag = object->type == OBJ_TAG;
+               hashcpy(peeled, sha1);
+               is_tag = 0;
        }
 
        /* If --all, then any refs are used.
@@ -142,7 +171,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
                if (!prio)
                        return 0;
        }
-       add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1);
+       add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1);
        return 0;
 }
 
@@ -240,7 +269,7 @@ static void describe(const char *arg, int last_one)
        if (!cmit)
                die("%s is not a valid '%s' object", arg, commit_type);
 
-       n = cmit->util;
+       n = find_commit_name(cmit->object.sha1);
        if (n && (tags || all || n->prio == 2)) {
                /*
                 * Exact match to an existing ref.
@@ -259,6 +288,11 @@ static void describe(const char *arg, int last_one)
        if (debug)
                fprintf(stderr, "searching to describe %s\n", arg);
 
+       if (!have_util) {
+               for_each_hash(&names, set_util);
+               have_util = 1;
+       }
+
        list = NULL;
        cmit->object.flags = SEEN;
        commit_list_insert(cmit, &list);
@@ -418,8 +452,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                return cmd_name_rev(i + argc, args, prefix);
        }
 
-       for_each_ref(get_name, NULL);
-       if (!found_names && !always)
+       init_hash(&names);
+       for_each_rawref(get_name, NULL);
+       if (!names.nr && !always)
                die("No names found, cannot describe anything.");
 
        if (argc == 0) {
diff --git a/cache.h b/cache.h
index 33decd942d4985c8efc1c75fd3fa2f4adf4a56ca..d85ce86f7fd72ee90553241316c1cf6d84a2898d 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -859,7 +859,7 @@ struct cache_def {
 
 extern int has_symlink_leading_path(const char *name, int len);
 extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
-extern int has_symlink_or_noent_leading_path(const char *name, int len);
+extern int check_leading_path(const char *name, int len);
 extern int has_dirs_only_path(const char *name, int len, int prefix_len);
 extern void schedule_dir_for_removal(const char *name, int len);
 extern void remove_scheduled_dirs(void);
diff --git a/diff.c b/diff.c
index 8256f313e4a680308a7959bdd6544f5bd461846c..fa3b29d92e39cd35b30c1572acd06e2ba2708edd 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -4388,7 +4388,7 @@ size_t fill_textconv(struct userdiff_driver *driver,
                return df->size;
        }
 
-       if (driver->textconv_cache) {
+       if (driver->textconv_cache && df->sha1_valid) {
                *outbuf = notes_cache_get(driver->textconv_cache, df->sha1,
                                          &size);
                if (*outbuf)
@@ -4399,7 +4399,7 @@ size_t fill_textconv(struct userdiff_driver *driver,
        if (!*outbuf)
                die("unable to read files to diff");
 
-       if (driver->textconv_cache) {
+       if (driver->textconv_cache && df->sha1_valid) {
                /* ignore errors, as we might be in a readonly repository */
                notes_cache_put(driver->textconv_cache, df->sha1, *outbuf,
                                size);
diff --git a/dir.c b/dir.c
index b2dfb69eb5606a7538cc5e1876a91f703ec4969c..b68750450cdec89df9ea7595ab9a7022619e6e58 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -965,6 +965,12 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
        case '/':
                return cwd + 1;
        default:
+               /*
+                * dir can end with a path separator when it's root
+                * directory. Return proper prefix in that case.
+                */
+               if (dir[-1] == '/')
+                       return cwd;
                return NULL;
        }
 }
diff --git a/entry.c b/entry.c
index 004182c99d27a6a5825d2429f9104fc7a8f1dc80..b017167f2015623fb9c721e91d0a940abd1d5196 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -106,14 +106,14 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
        case S_IFLNK:
                new = read_blob_entry(ce, &size);
                if (!new)
-                       return error("git checkout-index: unable to read sha1 file of %s (%s)",
+                       return error("unable to read sha1 file of %s (%s)",
                                path, sha1_to_hex(ce->sha1));
 
                if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) {
                        ret = symlink(new, path);
                        free(new);
                        if (ret)
-                               return error("git checkout-index: unable to create symlink %s (%s)",
+                               return error("unable to create symlink %s (%s)",
                                             path, strerror(errno));
                        break;
                }
@@ -141,7 +141,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
                }
                if (fd < 0) {
                        free(new);
-                       return error("git checkout-index: unable to create file %s (%s)",
+                       return error("unable to create file %s (%s)",
                                path, strerror(errno));
                }
 
@@ -155,16 +155,16 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
                close(fd);
                free(new);
                if (wrote != size)
-                       return error("git checkout-index: unable to write file %s", path);
+                       return error("unable to write file %s", path);
                break;
        case S_IFGITLINK:
                if (to_tempfile)
-                       return error("git checkout-index: cannot create temporary subproject %s", path);
+                       return error("cannot create temporary subproject %s", path);
                if (mkdir(path, 0777) < 0)
-                       return error("git checkout-index: cannot create subproject directory %s", path);
+                       return error("cannot create subproject directory %s", path);
                break;
        default:
-               return error("git checkout-index: unknown file mode for %s", path);
+               return error("unknown file mode for %s in index", path);
        }
 
        if (state->refresh_cache) {
@@ -211,7 +211,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
                        return 0;
                if (!state->force) {
                        if (!state->quiet)
-                               fprintf(stderr, "git-checkout-index: %s already exists\n", path);
+                               fprintf(stderr, "%s already exists, no checkout\n", path);
                        return -1;
                }
 
index eab68d58c394a67f4805d77b0007b583e79e24b9..613623be14c4c647e11b20fefb382b3f7438fb3c 100644 (file)
@@ -539,22 +539,17 @@ static struct object_entry *insert_object(unsigned char *sha1)
 {
        unsigned int h = sha1[0] << 8 | sha1[1];
        struct object_entry *e = object_table[h];
-       struct object_entry *p = NULL;
 
        while (e) {
                if (!hashcmp(sha1, e->idx.sha1))
                        return e;
-               p = e;
                e = e->next;
        }
 
        e = new_object(sha1);
-       e->next = NULL;
+       e->next = object_table[h];
        e->idx.offset = 0;
-       if (p)
-               p->next = e;
-       else
-               object_table[h] = e;
+       object_table[h] = e;
        return e;
 }
 
index de116a29ef091a23f60603a28f1260ba60f054ac..f4db17d93424c18c1db53e9bf84cdeee8219fa10 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -68,9 +68,31 @@ sq () {
 
 stop_here () {
     echo "$1" >"$dotest/next"
+    git rev-parse --verify -q HEAD >"$dotest/abort-safety"
     exit 1
 }
 
+safe_to_abort () {
+       if test -f "$dotest/dirtyindex"
+       then
+               return 1
+       fi
+
+       if ! test -s "$dotest/abort-safety"
+       then
+               return 0
+       fi
+
+       abort_safety=$(cat "$dotest/abort-safety")
+       if test "z$(git rev-parse --verify -q HEAD)" = "z$abort_safety"
+       then
+               return 0
+       fi
+       echo >&2 "You seem to have moved HEAD since the last 'am' failure."
+       echo >&2 "Not rewinding to ORIG_HEAD"
+       return 1
+}
+
 stop_here_user_resolve () {
     if [ -n "$resolvemsg" ]; then
            printf '%s\n' "$resolvemsg"
@@ -419,10 +441,11 @@ then
                        exec git rebase --abort
                fi
                git rerere clear
-               test -f "$dotest/dirtyindex" || {
+               if safe_to_abort
+               then
                        git read-tree --reset -u HEAD ORIG_HEAD
                        git reset ORIG_HEAD
-               }
+               fi
                rm -fr "$dotest"
                exit ;;
        esac
@@ -554,13 +577,6 @@ then
        resume=
 fi
 
-if test "$this" -gt "$last"
-then
-       say Nothing to do.
-       rm -fr "$dotest"
-       exit
-fi
-
 while test "$this" -le "$last"
 do
        msgnum=`printf "%0${prec}d" $this`
index 524f5ea8ab14bb44e5a8e6393e40c0ec5c1ddaa2..0594bf7ca54c6b91d5f96dd86d8962e93459d004 100755 (executable)
@@ -49,6 +49,7 @@ launch_merge_tool () {
        fi
 
        if use_ext_cmd; then
+               export BASE
                eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"'
        else
                run_merge_tool "$merge_tool"
index 10a238ae3cc942bc021db18195b7098e2866c266..6a7e5e0b1884358566544cc8cd0d94c941dac5fc 100755 (executable)
@@ -49,7 +49,8 @@ do_merge=
 dotest="$GIT_DIR"/rebase-merge
 prec=4
 verbose=
-diffstat=$(git config --bool rebase.stat)
+diffstat=
+test "$(git config --bool rebase.stat)" = true && diffstat=t
 git_am_opt=
 rebase_root=
 force_rebase=
@@ -274,15 +275,16 @@ do
                        die "No rebase in progress?"
 
                git rerere clear
-               if test -d "$dotest"
-               then
-                       GIT_QUIET=$(cat "$dotest/quiet")
-                       move_to_original_branch
-               else
-                       dotest="$GIT_DIR"/rebase-apply
-                       GIT_QUIET=$(cat "$dotest/quiet")
-                       move_to_original_branch
-               fi
+
+               test -d "$dotest" || dotest="$GIT_DIR"/rebase-apply
+
+               head_name="$(cat "$dotest"/head-name)" &&
+               case "$head_name" in
+               refs/*)
+                       git symbolic-ref HEAD $head_name ||
+                       die "Could not move back to $head_name"
+                       ;;
+               esac
                git reset --hard $(cat "$dotest/orig-head")
                rm -r "$dotest"
                exit
index c291eed59cca35d4b08285133acaca29bd80d372..6af1f7e7fd894d48bc22c1ad73d84b00664b26bb 100755 (executable)
@@ -93,20 +93,6 @@ module_clone()
        url=$2
        reference="$3"
 
-       # If there already is a directory at the submodule path,
-       # expect it to be empty (since that is the default checkout
-       # action) and try to remove it.
-       # Note: if $path is a symlink to a directory the test will
-       # succeed but the rmdir will fail. We might want to fix this.
-       if test -d "$path"
-       then
-               rmdir "$path" 2>/dev/null ||
-               die "Directory '$path' exists, but is neither empty nor a git repository"
-       fi
-
-       test -e "$path" &&
-       die "A file already exist at path '$path'"
-
        if test -n "$reference"
        then
                git-clone "$reference" -n "$url" "$path"
@@ -241,7 +227,7 @@ cmd_add()
                        # ash fails to wordsplit ${branch:+-b "$branch"...}
                        case "$branch" in
                        '') git checkout -f -q ;;
-                       ?*) git checkout -f -q -b "$branch" "origin/$branch" ;;
+                       ?*) git checkout -f -q -B "$branch" "origin/$branch" ;;
                        esac
                ) || die "Unable to checkout submodule '$path'"
        fi
old mode 100644 (file)
new mode 100755 (executable)
index 75cef245a26f24d4aefd19a7b9b6edea9676b2ba..fda9d30f37ce40b6da55b9558eee8848b20ebef9 100755 (executable)
@@ -1371,6 +1371,13 @@ sub esc_url {
        return $str;
 }
 
+# quote unsafe characters in HTML attributes
+sub esc_attr {
+
+       # for XHTML conformance escaping '"' to '&quot;' is not enough
+       return esc_html(@_);
+}
+
 # replace invalid utf8 character with SUBSTITUTION sequence
 sub esc_html {
        my $str = shift;
@@ -1776,7 +1783,7 @@ sub format_ref_marker {
                                        hash=>$dest
                                )}, $name);
 
-                       $markers .= " <span class=\"$class\" title=\"$ref\">" .
+                       $markers .= " <span class=\"".esc_attr($class)."\" title=\"".esc_attr($ref)."\">" .
                                $link . "</span>";
                }
        }
@@ -1860,7 +1867,7 @@ sub git_get_avatar {
                return $pre_white .
                       "<img width=\"$size\" " .
                            "class=\"avatar\" " .
-                           "src=\"$url\" " .
+                           "src=\"".esc_url($url)."\" " .
                            "alt=\"\" " .
                       "/>" . $post_white;
        } else {
@@ -2571,7 +2578,7 @@ sub git_show_project_tagcloud {
        } else {
                my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
                return '<p align="center">' . join (', ', map {
-                       "<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>"
+                       $cgi->a({-href=>"$home_link?by_tag=$_"}, $cloud->{$_}->{topname})
                } splice(@tags, 0, $count)) . '</p>';
        }
 }
@@ -3402,6 +3409,51 @@ sub get_page_title {
        return $title;
 }
 
+sub print_feed_meta {
+       if (defined $project) {
+               my %href_params = get_feed_info();
+               if (!exists $href_params{'-title'}) {
+                       $href_params{'-title'} = 'log';
+               }
+
+               foreach my $format qw(RSS Atom) {
+                       my $type = lc($format);
+                       my %link_attr = (
+                               '-rel' => 'alternate',
+                               '-title' => esc_attr("$project - $href_params{'-title'} - $format feed"),
+                               '-type' => "application/$type+xml"
+                       );
+
+                       $href_params{'action'} = $type;
+                       $link_attr{'-href'} = href(%href_params);
+                       print "<link ".
+                             "rel=\"$link_attr{'-rel'}\" ".
+                             "title=\"$link_attr{'-title'}\" ".
+                             "href=\"$link_attr{'-href'}\" ".
+                             "type=\"$link_attr{'-type'}\" ".
+                             "/>\n";
+
+                       $href_params{'extra_options'} = '--no-merges';
+                       $link_attr{'-href'} = href(%href_params);
+                       $link_attr{'-title'} .= ' (no merges)';
+                       print "<link ".
+                             "rel=\"$link_attr{'-rel'}\" ".
+                             "title=\"$link_attr{'-title'}\" ".
+                             "href=\"$link_attr{'-href'}\" ".
+                             "type=\"$link_attr{'-type'}\" ".
+                             "/>\n";
+               }
+
+       } else {
+               printf('<link rel="alternate" title="%s projects list" '.
+                      'href="%s" type="text/plain; charset=utf-8" />'."\n",
+                      esc_attr($site_name), href(project=>undef, action=>"project_index"));
+               printf('<link rel="alternate" title="%s projects feeds" '.
+                      'href="%s" type="text/x-opml" />'."\n",
+                      esc_attr($site_name), href(project=>undef, action=>"opml"));
+       }
+}
+
 sub git_header_html {
        my $status = shift || "200 OK";
        my $expires = shift;
@@ -3444,57 +3496,17 @@ sub git_header_html {
        # print out each stylesheet that exist, providing backwards capability
        # for those people who defined $stylesheet in a config file
        if (defined $stylesheet) {
-               print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n";
+               print '<link rel="stylesheet" type="text/css" href="'.esc_url($stylesheet).'"/>'."\n";
        } else {
                foreach my $stylesheet (@stylesheets) {
                        next unless $stylesheet;
-                       print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n";
+                       print '<link rel="stylesheet" type="text/css" href="'.esc_url($stylesheet).'"/>'."\n";
                }
        }
-       if (defined $project) {
-               my %href_params = get_feed_info();
-               if (!exists $href_params{'-title'}) {
-                       $href_params{'-title'} = 'log';
-               }
-
-               foreach my $format qw(RSS Atom) {
-                       my $type = lc($format);
-                       my %link_attr = (
-                               '-rel' => 'alternate',
-                               '-title' => "$project - $href_params{'-title'} - $format feed",
-                               '-type' => "application/$type+xml"
-                       );
-
-                       $href_params{'action'} = $type;
-                       $link_attr{'-href'} = href(%href_params);
-                       print "<link ".
-                             "rel=\"$link_attr{'-rel'}\" ".
-                             "title=\"$link_attr{'-title'}\" ".
-                             "href=\"$link_attr{'-href'}\" ".
-                             "type=\"$link_attr{'-type'}\" ".
-                             "/>\n";
-
-                       $href_params{'extra_options'} = '--no-merges';
-                       $link_attr{'-href'} = href(%href_params);
-                       $link_attr{'-title'} .= ' (no merges)';
-                       print "<link ".
-                             "rel=\"$link_attr{'-rel'}\" ".
-                             "title=\"$link_attr{'-title'}\" ".
-                             "href=\"$link_attr{'-href'}\" ".
-                             "type=\"$link_attr{'-type'}\" ".
-                             "/>\n";
-               }
-
-       } else {
-               printf('<link rel="alternate" title="%s projects list" '.
-                      'href="%s" type="text/plain; charset=utf-8" />'."\n",
-                      $site_name, href(project=>undef, action=>"project_index"));
-               printf('<link rel="alternate" title="%s projects feeds" '.
-                      'href="%s" type="text/x-opml" />'."\n",
-                      $site_name, href(project=>undef, action=>"opml"));
-       }
+       print_feed_meta()
+               if ($status eq '200 OK');
        if (defined $favicon) {
-               print qq(<link rel="shortcut icon" href="$favicon" type="image/png" />\n);
+               print qq(<link rel="shortcut icon" href=").esc_url($favicon).qq(" type="image/png" />\n);
        }
 
        print "</head>\n" .
@@ -3507,7 +3519,7 @@ sub git_header_html {
        print "<div class=\"page_header\">\n" .
              $cgi->a({-href => esc_url($logo_url),
                       -title => $logo_label},
-                     qq(<img src="$logo" width="72" height="27" alt="git" class="logo"/>));
+                     qq(<img src=").esc_url($logo).qq(" width="72" height="27" alt="git" class="logo"/>));
        print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
        if (defined $project) {
                print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
@@ -3605,7 +3617,7 @@ sub git_footer_html {
                insert_file($site_footer);
        }
 
-       print qq!<script type="text/javascript" src="$javascript"></script>\n!;
+       print qq!<script type="text/javascript" src="!.esc_url($javascript).qq!"></script>\n!;
        if (defined $action &&
            $action eq 'blame_incremental') {
                print qq!<script type="text/javascript">\n!.
@@ -5625,14 +5637,14 @@ sub git_blob {
        } else {
                print "<div class=\"page_nav\">\n" .
                      "<br/><br/></div>\n" .
-                     "<div class=\"title\">$hash</div>\n";
+                     "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        git_print_page_path($file_name, "blob", $hash_base);
        print "<div class=\"page_body\">\n";
        if ($mimetype =~ m!^image/!) {
-               print qq!<img type="$mimetype"!;
+               print qq!<img type="!.esc_attr($mimetype).qq!"!;
                if ($file_name) {
-                       print qq! alt="$file_name" title="$file_name"!;
+                       print qq! alt="!.esc_attr($file_name).qq!" title="!.esc_attr($file_name).qq!"!;
                }
                print qq! src="! .
                      href(action=>"blob_plain", hash=>$hash,
@@ -5645,7 +5657,7 @@ sub git_blob {
                        $nr++;
                        $line = untabify($line);
                        printf qq!<div class="pre"><a id="l%i" href="%s#l%i" class="linenr">%4i</a> %s</div>\n!,
-                              $nr, href(-replay => 1), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1);
+                              $nr, esc_attr(href(-replay => 1)), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1);
                }
        }
        close $fd
@@ -5707,7 +5719,7 @@ sub git_tree {
                undef $hash_base;
                print "<div class=\"page_nav\">\n";
                print "<br/><br/></div>\n";
-               print "<div class=\"title\">$hash</div>\n";
+               print "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        if (defined $file_name) {
                $basedir = $file_name;
@@ -6175,7 +6187,7 @@ sub git_blobdiff {
                        git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
                } else {
                        print "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n";
-                       print "<div class=\"title\">$hash vs $hash_parent</div>\n";
+                       print "<div class=\"title\">".esc_html("$hash vs $hash_parent")."</div>\n";
                }
                if (defined $file_name) {
                        git_print_page_path($file_name, "blob", $hash_base);
@@ -6873,7 +6885,7 @@ sub git_feed {
                if (defined $favicon) {
                        print "<icon>" . esc_url($favicon) . "</icon>\n";
                }
-               if (defined $logo_url) {
+               if (defined $logo) {
                        # not twice as wide as tall: 72 x 27 pixels
                        print "<logo>" . esc_url($logo) . "</logo>\n";
                }
index 14c90c2e84afd9997e1a6453f0065b3f59b32e57..85015048dd466fb2f2afe12086379ecf579d0a56 100644 (file)
@@ -510,9 +510,7 @@ static char* getdir(void)
                        die("GIT_PROJECT_ROOT is set but PATH_INFO is not");
                if (daemon_avoid_alias(pathinfo))
                        die("'%s': aliased", pathinfo);
-               strbuf_addstr(&buf, root);
-               if (buf.buf[buf.len - 1] != '/')
-                       strbuf_addch(&buf, '/');
+               end_url_with_slash(&buf, root);
                if (pathinfo[0] == '/')
                        pathinfo++;
                strbuf_addstr(&buf, pathinfo);
index 762c750d7af3651287c147034d3dead469453e7c..923904f97f9274d09a0a0b08543492f78a141f79 100644 (file)
@@ -14,8 +14,7 @@ int main(int argc, const char **argv)
        int commits;
        const char **write_ref = NULL;
        char **commit_id;
-       const char *url;
-       char *rewritten_url = NULL;
+       char *url = NULL;
        int arg = 1;
        int rc = 0;
        int get_tree = 0;
@@ -57,19 +56,14 @@ int main(int argc, const char **argv)
                commit_id = (char **) &argv[arg++];
                commits = 1;
        }
-       url = argv[arg];
+
+       if (argv[arg])
+               str_end_url_with_slash(argv[arg], &url);
 
        prefix = setup_git_directory();
 
        git_config(git_default_config, NULL);
 
-       if (url && url[strlen(url)-1] != '/') {
-               rewritten_url = xmalloc(strlen(url)+2);
-               strcpy(rewritten_url, url);
-               strcat(rewritten_url, "/");
-               url = rewritten_url;
-       }
-
        http_init(NULL);
        walker = get_http_walker(url);
        walker->get_tree = get_tree;
@@ -93,7 +87,7 @@ int main(int argc, const char **argv)
        walker_free(walker);
        http_cleanup();
 
-       free(rewritten_url);
+       free(url);
 
        return rc;
 }
index c9bcd116975635cabf30eceb7909abfc7f341948..ff41a0e183dd3a449f5136c6d1488a31b4a8960b 100644 (file)
@@ -1090,6 +1090,10 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
        if (tag_closed) {
                if (!strcmp(ctx->name, DAV_PROPFIND_RESP) && ls->dentry_name) {
                        if (ls->dentry_flags & IS_DIR) {
+
+                               /* ensure collection names end with slash */
+                               str_end_url_with_slash(ls->dentry_name, &ls->dentry_name);
+
                                if (ls->flags & PROCESS_DIRS) {
                                        ls->userFunc(ls);
                                }
@@ -1112,8 +1116,16 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
                                }
                        }
                        if (path) {
-                               path += repo->path_len;
-                               ls->dentry_name = xstrdup(path);
+                               const char *url = repo->url;
+                               if (repo->path)
+                                       url = repo->path;
+                               if (strncmp(path, url, repo->path_len))
+                                       error("Parsed path '%s' does not match url: '%s'\n",
+                                             path, url);
+                               else {
+                                       path += repo->path_len;
+                                       ls->dentry_name = xstrdup(path);
+                               }
                        }
                } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
                        ls->dentry_flags |= IS_DIR;
@@ -1789,7 +1801,6 @@ int main(int argc, char **argv)
        int new_refs;
        struct ref *ref, *local_refs;
        struct remote *remote;
-       char *rewritten_url = NULL;
 
        git_extract_argv0_path(argv[0]);
 
@@ -1835,8 +1846,8 @@ int main(int argc, char **argv)
                }
                if (!repo->url) {
                        char *path = strstr(arg, "//");
-                       repo->url = arg;
-                       repo->path_len = strlen(arg);
+                       str_end_url_with_slash(arg, &repo->url);
+                       repo->path_len = strlen(repo->url);
                        if (path) {
                                repo->path = strchr(path+2, '/');
                                if (repo->path)
@@ -1872,15 +1883,6 @@ int main(int argc, char **argv)
        remote->url[remote->url_nr++] = repo->url;
        http_init(remote);
 
-       if (repo->url && repo->url[strlen(repo->url)-1] != '/') {
-               rewritten_url = xmalloc(strlen(repo->url)+2);
-               strcpy(rewritten_url, repo->url);
-               strcat(rewritten_url, "/");
-               repo->path = rewritten_url + (repo->path - repo->url);
-               repo->path_len++;
-               repo->url = rewritten_url;
-       }
-
 #ifdef USE_CURL_MULTI
        is_running_queue = 0;
 #endif
@@ -2088,7 +2090,6 @@ int main(int argc, char **argv)
        }
 
  cleanup:
-       free(rewritten_url);
        if (info_ref_lock)
                unlock_remote(info_ref_lock);
        free(repo);
diff --git a/http.c b/http.c
index 17bcf19c5001d309bdbf524e7d3817cf3482a3c3..9e767723ed1045445e91e79489cb8ec8bb861965 100644 (file)
--- a/http.c
+++ b/http.c
@@ -2,6 +2,7 @@
 #include "pack.h"
 #include "sideband.h"
 #include "run-command.h"
+#include "url.h"
 
 int data_received;
 int active_requests;
@@ -302,7 +303,7 @@ static CURL *get_curl_handle(void)
 
 static void http_auth_init(const char *url)
 {
-       char *at, *colon, *cp, *slash;
+       char *at, *colon, *cp, *slash, *decoded;
        int len;
 
        cp = strstr(url, "://");
@@ -327,16 +328,25 @@ static void http_auth_init(const char *url)
                user_name = xmalloc(len + 1);
                memcpy(user_name, cp, len);
                user_name[len] = '\0';
+               decoded = url_decode(user_name);
+               free(user_name);
+               user_name = decoded;
                user_pass = NULL;
        } else {
                len = colon - cp;
                user_name = xmalloc(len + 1);
                memcpy(user_name, cp, len);
                user_name[len] = '\0';
+               decoded = url_decode(user_name);
+               free(user_name);
+               user_name = decoded;
                len = at - (colon + 1);
                user_pass = xmalloc(len + 1);
                memcpy(user_pass, colon + 1, len);
                user_pass[len] = '\0';
+               decoded = url_decode(user_pass);
+               free(user_pass);
+               user_pass = decoded;
        }
 }
 
@@ -733,13 +743,6 @@ static inline int hex(int v)
                return 'A' + v - 10;
 }
 
-void end_url_with_slash(struct strbuf *buf, const char *url)
-{
-       strbuf_addstr(buf, url);
-       if (buf->len && buf->buf[buf->len - 1] != '/')
-               strbuf_addstr(buf, "/");
-}
-
 static char *quote_ref_url(const char *base, const char *ref)
 {
        struct strbuf buf = STRBUF_INIT;
diff --git a/http.h b/http.h
index 173f74c8298c3fa3989f88b06e2085127fe96db8..5c6e243dde3c654a3c0a705146fb15395c27fb95 100644 (file)
--- a/http.h
+++ b/http.h
@@ -8,6 +8,7 @@
 
 #include "strbuf.h"
 #include "remote.h"
+#include "url.h"
 
 /*
  * We detect based on the cURL version if multi-transfer is
@@ -117,7 +118,6 @@ extern void append_remote_object_url(struct strbuf *buf, const char *url,
                                     int only_two_digit_prefix);
 extern char *get_remote_object_url(const char *url, const char *hex,
                                   int only_two_digit_prefix);
-extern void end_url_with_slash(struct strbuf *buf, const char *url);
 
 /* Options for http_request_*() */
 #define HTTP_NO_CACHE          1
diff --git a/ident.c b/ident.c
index 9e2438826dfce158e04549933d5c588dd6abcf5c..1c4adb0a9a7e94936ba64d286cedd65f4b8255a6 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -217,8 +217,10 @@ const char *fmt_ident(const char *name, const char *email,
        }
 
        strcpy(date, git_default_date);
-       if (!name_addr_only && date_str)
-               parse_date(date_str, date, sizeof(date));
+       if (!name_addr_only && date_str && date_str[0]) {
+               if (parse_date(date_str, date, sizeof(date)) < 0)
+                       die("invalid date format: %s", date_str);
+       }
 
        i = copy(buffer, sizeof(buffer), 0, name);
        i = add_raw(buffer, sizeof(buffer), i, " <");
index 4879615cad7527dc5346cd1a85bd56b9d11e052b..5d81d39a525830f6bacba88143ab6a4552748441 100644 (file)
@@ -239,7 +239,6 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
 
        commit->parents = xcalloc(sizeof(struct commit_list), 1);
        commit->parents->item = commit_info->commit;
-       commit->object.flags &= ~(ADDED | SEEN | SHOWN);
 }
 
 void get_reflog_selector(struct strbuf *sb,
index b1c18906badc5fc4ce3af48daa7c226365e3c08f..ded881263ba0ff703d9fd468e6785270ea68df5f 100644 (file)
@@ -2030,8 +2030,10 @@ static struct commit *get_revision_1(struct rev_info *revs)
                revs->commits = entry->next;
                free(entry);
 
-               if (revs->reflog_info)
+               if (revs->reflog_info) {
                        fake_reflog_parent(revs->reflog_info, commit);
+                       commit->object.flags &= ~(ADDED | SEEN | SHOWN);
+               }
 
                /*
                 * If we haven't done the list limiting, we need to look at
index 88601200114f857a57214a9bf0d02ffd39a83504..3cacebd91adc2958e81d952523bd7cfe0078078c 100644 (file)
@@ -64,11 +64,13 @@ static inline void reset_lstat_cache(struct cache_def *cache)
  * of the prefix, where the cache should use the stat() function
  * instead of the lstat() function to test each path component.
  */
-static int lstat_cache(struct cache_def *cache, const char *name, int len,
-                      int track_flags, int prefix_len_stat_func)
+static int lstat_cache_matchlen(struct cache_def *cache,
+                               const char *name, int len,
+                               int *ret_flags, int track_flags,
+                               int prefix_len_stat_func)
 {
        int match_len, last_slash, last_slash_dir, previous_slash;
-       int match_flags, ret_flags, save_flags, max_len, ret;
+       int save_flags, max_len, ret;
        struct stat st;
 
        if (cache->track_flags != track_flags ||
@@ -90,13 +92,13 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len,
                match_len = last_slash =
                        longest_path_match(name, len, cache->path, cache->len,
                                           &previous_slash);
-               match_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);
+               *ret_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);
 
                if (!(track_flags & FL_FULLPATH) && match_len == len)
                        match_len = last_slash = previous_slash;
 
-               if (match_flags && match_len == cache->len)
-                       return match_flags;
+               if (*ret_flags && match_len == cache->len)
+                       return match_len;
                /*
                 * If we now have match_len > 0, we would know that
                 * the matched part will always be a directory.
@@ -105,16 +107,16 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len,
                 * a substring of the cache on a path component basis,
                 * we can return immediately.
                 */
-               match_flags = track_flags & FL_DIR;
-               if (match_flags && len == match_len)
-                       return match_flags;
+               *ret_flags = track_flags & FL_DIR;
+               if (*ret_flags && len == match_len)
+                       return match_len;
        }
 
        /*
         * Okay, no match from the cache so far, so now we have to
         * check the rest of the path components.
         */
-       ret_flags = FL_DIR;
+       *ret_flags = FL_DIR;
        last_slash_dir = last_slash;
        max_len = len < PATH_MAX ? len : PATH_MAX;
        while (match_len < max_len) {
@@ -133,16 +135,16 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len,
                        ret = lstat(cache->path, &st);
 
                if (ret) {
-                       ret_flags = FL_LSTATERR;
+                       *ret_flags = FL_LSTATERR;
                        if (errno == ENOENT)
-                               ret_flags |= FL_NOENT;
+                               *ret_flags |= FL_NOENT;
                } else if (S_ISDIR(st.st_mode)) {
                        last_slash_dir = last_slash;
                        continue;
                } else if (S_ISLNK(st.st_mode)) {
-                       ret_flags = FL_SYMLINK;
+                       *ret_flags = FL_SYMLINK;
                } else {
-                       ret_flags = FL_ERR;
+                       *ret_flags = FL_ERR;
                }
                break;
        }
@@ -152,7 +154,7 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len,
         * path types, FL_NOENT, FL_SYMLINK and FL_DIR, can be cached
         * for the moment!
         */
-       save_flags = ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
+       save_flags = *ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
        if (save_flags && last_slash > 0 && last_slash <= PATH_MAX) {
                cache->path[last_slash] = '\0';
                cache->len = last_slash;
@@ -176,7 +178,16 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len,
        } else {
                reset_lstat_cache(cache);
        }
-       return ret_flags;
+       return match_len;
+}
+
+static int lstat_cache(struct cache_def *cache, const char *name, int len,
+                      int track_flags, int prefix_len_stat_func)
+{
+       int flags;
+       (void)lstat_cache_matchlen(cache, name, len, &flags, track_flags,
+                       prefix_len_stat_func);
+       return flags;
 }
 
 #define USE_ONLY_LSTAT  0
@@ -198,15 +209,26 @@ int has_symlink_leading_path(const char *name, int len)
 }
 
 /*
- * Return non-zero if path 'name' has a leading symlink component or
+ * Return zero if path 'name' has a leading symlink component or
  * if some leading path component does not exists.
+ *
+ * Return -1 if leading path exists and is a directory.
+ *
+ * Return path length if leading path exists and is neither a
+ * directory nor a symlink.
  */
-int has_symlink_or_noent_leading_path(const char *name, int len)
+int check_leading_path(const char *name, int len)
 {
        struct cache_def *cache = &default_cache;       /* FIXME */
-       return lstat_cache(cache, name, len,
-                          FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) &
-               (FL_SYMLINK|FL_NOENT);
+       int flags;
+       int match_len = lstat_cache_matchlen(cache, name, len, &flags,
+                          FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT);
+       if (flags & (FL_SYMLINK|FL_NOENT))
+               return 0;
+       else if (flags & FL_DIR)
+               return -1;
+       else
+               return match_len;
 }
 
 /*
index e733f6516fdf98e48d5c7cd36ecc89d36166eea1..3f24384371bf227126e38da61f3b7efd3961ede8 100644 (file)
@@ -75,12 +75,14 @@ fi
 
 prepare_httpd() {
        mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH"
+       cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH"
 
        ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
 
        if test -n "$LIB_HTTPD_SSL"
        then
                HTTPD_URL=https://127.0.0.1:$LIB_HTTPD_PORT
+               AUTH_HTTPD_URL=https://user%40host:user%40host@127.0.0.1:$LIB_HTTPD_PORT
 
                RANDFILE_PATH="$HTTPD_ROOT_PATH"/.rnd openssl req \
                        -config "$TEST_PATH/ssl.cnf" \
@@ -92,6 +94,7 @@ prepare_httpd() {
                HTTPD_PARA="$HTTPD_PARA -DSSL"
        else
                HTTPD_URL=http://127.0.0.1:$LIB_HTTPD_PORT
+               AUTH_HTTPD_URL=http://user%40host:user%40host@127.0.0.1:$LIB_HTTPD_PORT
        fi
 
        if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN"
index f41c7c674c497825d714a0fe9be3c9bc0a0f30c6..0a4cdfa93ece7d8a4177835b5569583c22303564 100644 (file)
@@ -20,8 +20,30 @@ ErrorLog error.log
 <IfModule !mod_rewrite.c>
        LoadModule rewrite_module modules/mod_rewrite.so
 </IFModule>
+<IfModule !mod_version.c>
+       LoadModule version_module modules/mod_version.so
+</IfModule>
+
+<IfVersion < 2.1>
+<IfModule !mod_auth.c>
+       LoadModule auth_module modules/mod_auth.so
+</IfModule>
+</IfVersion>
+
+<IfVersion >= 2.1>
+<IfModule !mod_auth_basic.c>
+       LoadModule auth_basic_module modules/mod_auth_basic.so
+</IfModule>
+<IfModule !mod_authn_file.c>
+       LoadModule authn_file_module modules/mod_authn_file.so
+</IfModule>
+<IfModule !mod_authz_user.c>
+       LoadModule authz_user_module modules/mod_authz_user.so
+</IfModule>
+</IfVersion>
 
 Alias /dumb/ www/
+Alias /auth/ www/auth/
 
 <Location /smart/>
        SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
@@ -55,6 +77,13 @@ SSLMutex file:ssl_mutex
 SSLEngine On
 </IfDefine>
 
+<Location /auth/>
+       AuthType Basic
+       AuthName "git-auth"
+       AuthUserFile passwd
+       Require valid-user
+</Location>
+
 <IfDefine DAV>
        LoadModule dav_module modules/mod_dav.so
        LoadModule dav_fs_module modules/mod_dav_fs.so
diff --git a/t/lib-httpd/passwd b/t/lib-httpd/passwd
new file mode 100644 (file)
index 0000000..f2fbcad
--- /dev/null
@@ -0,0 +1 @@
+user@host:nKpa8pZUHx/ic
index 41df6bcf279a1abc4462e63866076094cfbdedd8..07357ee1fc2902d72cd4f524404862036d06f613 100755 (executable)
@@ -4,8 +4,8 @@ test_description='Various filesystem issues'
 
 . ./test-lib.sh
 
-auml=`printf '\xc3\xa4'`
-aumlcdiar=`printf '\x61\xcc\x88'`
+auml=$(printf '\303\244')
+aumlcdiar=$(printf '\141\314\210')
 
 case_insensitive=
 unibad=
diff --git a/t/t1412-reflog-loop.sh b/t/t1412-reflog-loop.sh
new file mode 100755 (executable)
index 0000000..7f519e5
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+test_description='reflog walk shows repeated commits again'
+. ./test-lib.sh
+
+test_expect_success 'setup commits' '
+       test_tick &&
+       echo content >file && git add file && git commit -m one &&
+       git tag one &&
+       echo content >>file && git add file && git commit -m two &&
+       git tag two
+'
+
+test_expect_success 'setup reflog with alternating commits' '
+       git checkout -b topic &&
+       git reset one &&
+       git reset two &&
+       git reset one &&
+       git reset two
+'
+
+test_expect_success 'reflog shows all entries' '
+       cat >expect <<-\EOF
+               topic@{0} two: updating HEAD
+               topic@{1} one: updating HEAD
+               topic@{2} two: updating HEAD
+               topic@{3} one: updating HEAD
+               topic@{4} branch: Created from HEAD
+       EOF
+       git log -g --format="%gd %gs" topic >actual &&
+       test_cmp expect actual
+'
+
+test_done
index 7d20a74c5ca1331ff241d1596bcb114e48a5907d..9e9474e9447c8835eb4ef30714b577896a06924d 100755 (executable)
@@ -67,8 +67,9 @@ test_expect_success 'setup' '
 # "exec" commands are ran with the user shell by default, but this may
 # be non-POSIX. For example, if SHELL=zsh then ">file" doesn't work
 # to create a file. Unseting SHELL avoids such non-portable behavior
-# in tests.
+# in tests. It must be exported for it to take effect where needed.
 SHELL=
+export SHELL
 
 test_expect_success 'rebase -i with the exec command' '
        git checkout master &&
index fbb3f2e0dfcf1a0673dbd2022a4ed843990fce52..e573dc845b3d72004b2a96f344528c68977c52e1 100755 (executable)
@@ -72,6 +72,18 @@ testrebase() {
                test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
                test ! -d "$dotest"
        '
+
+       test_expect_success "rebase$type --abort does not update reflog" '
+               cd "$work_dir" &&
+               # Clean up the state from the previous one
+               git reset --hard pre-rebase &&
+               git reflog show to-rebase > reflog_before &&
+               test_must_fail git rebase$type master &&
+               git rebase --abort &&
+               git reflog show to-rebase > reflog_after &&
+               test_cmp reflog_before reflog_after &&
+               rm reflog_before reflog_after
+       '
 }
 
 testrebase "" .git/rebase-apply
index 1aee4835105afa8658536120892b63580b36f462..bd8efaf005a9708f153ea873850acca994c64f29 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
 test_description='git rebase - test patch id computation'
 
@@ -27,7 +27,7 @@ scramble()
                then
                        echo "$x"
                fi
-               i=$(((i+1) % 10))
+               i=$((($i+1) % 10))
        done < "$1" > "$1.new"
        mv -f "$1.new" "$1"
 }
index b55c4117884744db8eda17e42fe05e0e65216215..c95c4ccc393d0863ad53b6a2a684893282d7d9e6 100755 (executable)
@@ -62,4 +62,13 @@ do
 
 done
 
+test_expect_success 'am --abort will keep the local commits intact' '
+       test_must_fail git am 0004-*.patch &&
+       test_commit unrelated &&
+       git rev-parse HEAD >expect &&
+       git am --abort &&
+       git rev-parse HEAD >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 552da65a61e8f78d40f8e19cfc5b73696ebcf283..baa670cea5d8a9d8b4b4578de69917fe76f71d46 100755 (executable)
@@ -10,7 +10,11 @@ test_expect_success 'setup' '
        test_commit A foo A &&
        test_commit B foo B &&
        test_commit C foo C &&
-       test_commit D foo D
+       test_commit D foo D &&
+       git checkout A^0 &&
+       test_commit E bar E &&
+       test_commit F foo F &&
+       git checkout master
 '
 
 mkdir .git/hooks
@@ -79,6 +83,18 @@ EOF
        verify_hook_input
 '
 
+test_expect_success 'git rebase --skip the last one' '
+       git reset --hard F &&
+       clear_hook_input &&
+       test_must_fail git rebase --onto D A &&
+       git rebase --skip &&
+       echo rebase >expected.args &&
+       cat >expected.data <<EOF &&
+$(git rev-parse E) $(git rev-parse HEAD)
+EOF
+       verify_hook_input
+'
+
 test_expect_success 'git rebase -m' '
        git reset --hard D &&
        clear_hook_input &&
index 2fb48d09edb47129d9cea8b9686e46a6d8f35615..a1883ca6b649a236e5e08a5e4b76d1479353dcac 100755 (executable)
@@ -30,18 +30,37 @@ test_expect_success 'create http-accessible bare repository' '
 '
 
 test_expect_success 'clone http repository' '
-       git clone $HTTPD_URL/dumb/repo.git clone &&
+       git clone $HTTPD_URL/dumb/repo.git clone-tmpl &&
+       cp -R clone-tmpl clone &&
        test_cmp file clone/file
 '
 
+test_expect_success 'clone http repository with authentication' '
+       mkdir "$HTTPD_DOCUMENT_ROOT_PATH/auth/" &&
+       cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" "$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git" &&
+       git clone $AUTH_HTTPD_URL/auth/repo.git clone-auth &&
+       test_cmp file clone-auth/file
+'
+
 test_expect_success 'fetch changes via http' '
        echo content >>file &&
        git commit -a -m two &&
-       git push public
+       git push public &&
        (cd clone && git pull) &&
        test_cmp file clone/file
 '
 
+test_expect_success 'fetch changes via manual http-fetch' '
+       cp -R clone-tmpl clone2 &&
+
+       HEAD=$(git rev-parse --verify HEAD) &&
+       (cd clone2 &&
+        git http-fetch -a -w heads/master-new $HEAD $(git config remote.origin.url) &&
+        git checkout master-new &&
+        test $HEAD = $(git rev-parse --verify HEAD)) &&
+       test_cmp file clone2/file
+'
+
 test_expect_success 'http remote detects correct HEAD' '
        git push public master:other &&
        (cd clone &&
index 782b0a3ece7724bf8df7cf4d405715a42ad21d44..2c49db9f6244225db7f82b574f21f05b58bfdc26 100755 (executable)
@@ -421,11 +421,29 @@ test_expect_success 'add submodules without specifying an explicit path' '
                git commit -m "repo commit 1"
        ) &&
        git clone --bare repo/ bare.git &&
-       cd addtest &&
-       git submodule add "$submodurl/repo" &&
-       git config -f .gitmodules submodule.repo.path repo &&
-       git submodule add "$submodurl/bare.git" &&
-       git config -f .gitmodules submodule.bare.path bare
+       (
+               cd addtest &&
+               git submodule add "$submodurl/repo" &&
+               git config -f .gitmodules submodule.repo.path repo &&
+               git submodule add "$submodurl/bare.git" &&
+               git config -f .gitmodules submodule.bare.path bare
+       )
+'
+
+test_expect_success 'add should fail when path is used by a file' '
+       (
+               cd addtest &&
+               touch file &&
+               test_must_fail  git submodule add "$submodurl/repo" file
+       )
+'
+
+test_expect_success 'add should fail when path is used by an existing directory' '
+       (
+               cd addtest &&
+               mkdir empty-dir &&
+               test_must_fail git submodule add "$submodurl/repo" empty-dir
+       )
 '
 
 test_done
index 8297cb4f1e6e2d903dfbf6fde825d2c787082e58..8980738c7540b79eaa566d6054f3e76b202bd27e 100755 (executable)
@@ -230,6 +230,10 @@ test_expect_success 'amend commit to fix date' '
 
 '
 
+test_expect_success 'commit complains about bogus date' '
+       test_must_fail git commit --amend --date=10.11.2010
+'
+
 test_expect_success 'sign off (1)' '
 
        echo 1 >positive &&
index 3988900fc33f0f5f9cdd416096df619aec2d577e..4d5ce4e682c1ea69034c3f7789a8ac0c89b12466 100755 (executable)
@@ -7,48 +7,54 @@ Do not overwrite changes.'
 . ./test-lib.sh
 
 test_expect_success 'setup' '
-       echo c0 > c0.c &&
-       git add c0.c &&
-       git commit -m c0 &&
-       git tag c0 &&
-       echo c1 > c1.c &&
-       git add c1.c &&
-       git commit -m c1 &&
-       git tag c1 &&
+       test_commit c0 c0.c &&
+       test_commit c1 c1.c &&
+       test_commit c1a c1.c "c1 a" &&
        git reset --hard c0 &&
-       echo c2 > c2.c &&
-       git add c2.c &&
-       git commit -m c2 &&
-       git tag c2 &&
-       git reset --hard c1 &&
-       echo "c1 a" > c1.c &&
-       git add c1.c &&
-       git commit -m "c1 a" &&
-       git tag c1a &&
+       test_commit c2 c2.c &&
+       git reset --hard c0 &&
+       mkdir sub &&
+       echo "sub/f" > sub/f &&
+       mkdir sub2 &&
+       echo "sub2/f" > sub2/f &&
+       git add sub/f sub2/f &&
+       git commit -m sub &&
+       git tag sub &&
        echo "VERY IMPORTANT CHANGES" > important
 '
 
 test_expect_success 'will not overwrite untracked file' '
        git reset --hard c1 &&
-       cat important > c2.c &&
+       cp important c2.c &&
        test_must_fail git merge c2 &&
+       test_path_is_missing .git/MERGE_HEAD &&
        test_cmp important c2.c
 '
 
+test_expect_success 'will overwrite tracked file' '
+       git reset --hard c1 &&
+       cp important c2.c &&
+       git add c2.c &&
+       git commit -m important &&
+       git checkout c2
+'
+
 test_expect_success 'will not overwrite new file' '
        git reset --hard c1 &&
-       cat important > c2.c &&
+       cp important c2.c &&
        git add c2.c &&
        test_must_fail git merge c2 &&
+       test_path_is_missing .git/MERGE_HEAD &&
        test_cmp important c2.c
 '
 
 test_expect_success 'will not overwrite staged changes' '
        git reset --hard c1 &&
-       cat important > c2.c &&
+       cp important c2.c &&
        git add c2.c &&
        rm c2.c &&
        test_must_fail git merge c2 &&
+       test_path_is_missing .git/MERGE_HEAD &&
        git checkout c2.c &&
        test_cmp important c2.c
 '
@@ -57,7 +63,7 @@ test_expect_success 'will not overwrite removed file' '
        git reset --hard c1 &&
        git rm c1.c &&
        git commit -m "rm c1.c" &&
-       cat important > c1.c &&
+       cp important c1.c &&
        test_must_fail git merge c1a &&
        test_cmp important c1.c
 '
@@ -66,9 +72,10 @@ test_expect_success 'will not overwrite re-added file' '
        git reset --hard c1 &&
        git rm c1.c &&
        git commit -m "rm c1.c" &&
-       cat important > c1.c &&
+       cp important c1.c &&
        git add c1.c &&
        test_must_fail git merge c1a &&
+       test_path_is_missing .git/MERGE_HEAD &&
        test_cmp important c1.c
 '
 
@@ -76,14 +83,63 @@ test_expect_success 'will not overwrite removed file with staged changes' '
        git reset --hard c1 &&
        git rm c1.c &&
        git commit -m "rm c1.c" &&
-       cat important > c1.c &&
+       cp important c1.c &&
        git add c1.c &&
        rm c1.c &&
        test_must_fail git merge c1a &&
+       test_path_is_missing .git/MERGE_HEAD &&
        git checkout c1.c &&
        test_cmp important c1.c
 '
 
+test_expect_success 'will not overwrite untracked subtree' '
+       git reset --hard c0 &&
+       rm -rf sub &&
+       mkdir -p sub/f &&
+       cp important sub/f/important &&
+       test_must_fail git merge sub &&
+       test_path_is_missing .git/MERGE_HEAD &&
+       test_cmp important sub/f/important
+'
+
+cat >expect <<\EOF
+error: The following untracked working tree files would be overwritten by merge:
+       sub
+       sub2
+Please move or remove them before you can merge.
+EOF
+
+test_expect_success 'will not overwrite untracked file in leading path' '
+       git reset --hard c0 &&
+       rm -rf sub &&
+       cp important sub &&
+       cp important sub2 &&
+       test_must_fail git merge sub 2>out &&
+       test_cmp out expect &&
+       test_path_is_missing .git/MERGE_HEAD &&
+       test_cmp important sub &&
+       test_cmp important sub2 &&
+       rm -f sub sub2
+'
+
+test_expect_failure SYMLINKS 'will not overwrite untracked symlink in leading path' '
+       git reset --hard c0 &&
+       rm -rf sub &&
+       mkdir sub2 &&
+       ln -s sub2 sub &&
+       test_must_fail git merge sub &&
+       test_path_is_missing .git/MERGE_HEAD
+'
+
+test_expect_success SYMLINKS 'will not be confused by symlink in leading path' '
+       git reset --hard c0 &&
+       rm -rf sub &&
+       ln -s sub2 sub &&
+       git add sub &&
+       git commit -m ln &&
+       git checkout sub
+'
+
 cat >expect <<\EOF
 error: Untracked working tree file 'c0.c' would be overwritten by merge.
 fatal: read-tree failed
index 114d2bd7855f71ec1d48f2017438f897c5255d36..c994836c53224dd0a8302f7a6ab63b35f8b493e3 100755 (executable)
@@ -27,10 +27,10 @@ test_expect_success 'setup' '
 
 cat >expect <<\EOF
 error: The following untracked working tree files would be overwritten by merge:
-       two
-       three
-       four
        five
+       four
+       three
+       two
 Please move or remove them before you can merge.
 EOF
 
@@ -49,9 +49,9 @@ test_expect_success 'untracked files overwritten by merge (fast and non-fast for
 
 cat >expect <<\EOF
 error: Your local changes to the following files would be overwritten by merge:
-       two
-       three
        four
+       three
+       two
 Please, commit your changes or stash them before you can merge.
 error: The following untracked working tree files would be overwritten by merge:
        five
@@ -68,8 +68,8 @@ test_expect_success 'untracked files or local changes ovewritten by merge' '
 
 cat >expect <<\EOF
 error: Your local changes to the following files would be overwritten by checkout:
-       rep/two
        rep/one
+       rep/two
 Please, commit your changes or stash them before you can switch branches.
 EOF
 
@@ -89,8 +89,8 @@ test_expect_success 'cannot switch branches because of local changes' '
 
 cat >expect <<\EOF
 error: Your local changes to the following files would be overwritten by checkout:
-       rep/two
        rep/one
+       rep/two
 Please, commit your changes or stash them before you can switch branches.
 EOF
 
@@ -102,8 +102,8 @@ test_expect_success 'not uptodate file porcelain checkout error' '
 
 cat >expect <<\EOF
 error: Updating the following directories would lose untracked files in it:
-       rep2
        rep
+       rep2
 
 EOF
 
index dbf623bce5598860800fa463c26ec8145d6e2400..ea64cd8d0f02a3a08dca7742a29331c85e7da384 100755 (executable)
@@ -73,6 +73,27 @@ test_expect_success 'blame --textconv going through revisions' '
        test_cmp expected result
 '
 
+test_expect_success 'setup +cachetextconv' '
+       git config diff.test.cachetextconv true
+'
+
+cat >expected_one <<EOF
+(Number2 2010-01-01 20:00:00 +0000 1) converted: test 1 version 2
+EOF
+
+test_expect_success 'blame --textconv works with textconvcache' '
+       git blame --textconv two.bin >blame &&
+       find_blame <blame >result &&
+       test_cmp expected result &&
+       git blame --textconv one.bin >blame &&
+       find_blame  <blame >result &&
+       test_cmp expected_one result
+'
+
+test_expect_success 'setup -cachetextconv' '
+       git config diff.test.cachetextconv false
+'
+
 test_expect_success 'make a new commit' '
        echo "bin: test number 2 version 3" >>two.bin &&
        GIT_AUTHOR_NAME=Number3 git commit -a -m Third --date="2010-01-01 22:00:00"
index a298eb04373f622473e3d33c9a46c6734f8a8fc8..f1047d2ef3ee473a924f5819441dd1a7b1829768 100755 (executable)
@@ -1035,7 +1035,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
 # 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.
-test_expect_success 'refusing to send cover letter template' '
+test_expect_success $PREREQ 'refusing to send cover letter template' '
        clean_fake_sendmail &&
        rm -fr outdir &&
        git format-patch --cover-letter -2 -o outdir &&
@@ -1051,7 +1051,7 @@ test_expect_success 'refusing to send cover letter template' '
        test -z "$(ls msgtxt*)"
 '
 
-test_expect_success '--force sends cover letter template anyway' '
+test_expect_success $PREREQ '--force sends cover letter template anyway' '
        clean_fake_sendmail &&
        rm -fr outdir &&
        git format-patch --cover-letter -2 -o outdir &&
index f3f397cdda4766ce6c02beac13e492d406ca14c4..ff19695e776f803aef03a18e70067c89aa3be218 100755 (executable)
@@ -18,21 +18,14 @@ case $v in
        ;;
 esac
 
-ptouch() {
-       perl -w -e '
-               use strict;
-               use POSIX qw(mktime);
-               die "ptouch requires exactly 2 arguments" if @ARGV != 2;
-               my $text_last_updated = shift @ARGV;
-               my $git_file = shift @ARGV;
-               die "\"$git_file\" does not exist" if ! -e $git_file;
-               if ($text_last_updated
-                   =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/) {
-                       my $mtime = mktime($6, $5, $4, $3, $2 - 1, $1 - 1900);
-                       my $atime = $mtime;
-                       utime $atime, $mtime, $git_file;
-               }
-       ' "`svn_cmd info $2 | grep '^Text Last Updated:'`" "$1"
+# On the "Text Last Updated" line, "git svn info" does not return the
+# same value as "svn info" (i.e. the commit timestamp that touched the
+# path most recently); do not expect that field to match.
+test_cmp_info () {
+       sed -e '/^Text Last Updated:/d' "$1" >tmp.expect
+       sed -e '/^Text Last Updated:/d' "$2" >tmp.actual
+       test_cmp tmp.expect tmp.actual &&
+       rm -f tmp.expect tmp.actual
 }
 
 quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')"
@@ -62,17 +55,13 @@ test_expect_success 'setup repository and import' '
                cd gitwc &&
                git svn init "$svnrepo" &&
                git svn fetch
-       ) &&
-       ptouch gitwc/file svnwc/file &&
-       ptouch gitwc/directory svnwc/directory &&
-       ptouch gitwc/symlink-file svnwc/symlink-file &&
-       ptouch gitwc/symlink-directory svnwc/symlink-directory
+       )
        '
 
 test_expect_success 'info' "
        (cd svnwc; svn info) > expected.info &&
        (cd gitwc; git svn info) > actual.info &&
-       test_cmp expected.info actual.info
+       test_cmp_info expected.info actual.info
        "
 
 test_expect_success 'info --url' '
@@ -82,7 +71,7 @@ test_expect_success 'info --url' '
 test_expect_success 'info .' "
        (cd svnwc; svn info .) > expected.info-dot &&
        (cd gitwc; git svn info .) > actual.info-dot &&
-       test_cmp expected.info-dot actual.info-dot
+       test_cmp_info expected.info-dot actual.info-dot
        "
 
 test_expect_success 'info --url .' '
@@ -92,7 +81,7 @@ test_expect_success 'info --url .' '
 test_expect_success 'info file' "
        (cd svnwc; svn info file) > expected.info-file &&
        (cd gitwc; git svn info file) > actual.info-file &&
-       test_cmp expected.info-file actual.info-file
+       test_cmp_info expected.info-file actual.info-file
        "
 
 test_expect_success 'info --url file' '
@@ -102,13 +91,13 @@ test_expect_success 'info --url file' '
 test_expect_success 'info directory' "
        (cd svnwc; svn info directory) > expected.info-directory &&
        (cd gitwc; git svn info directory) > actual.info-directory &&
-       test_cmp expected.info-directory actual.info-directory
+       test_cmp_info expected.info-directory actual.info-directory
        "
 
 test_expect_success 'info inside directory' "
        (cd svnwc/directory; svn info) > expected.info-inside-directory &&
        (cd gitwc/directory; git svn info) > actual.info-inside-directory &&
-       test_cmp expected.info-inside-directory actual.info-inside-directory
+       test_cmp_info expected.info-inside-directory actual.info-inside-directory
        "
 
 test_expect_success 'info --url directory' '
@@ -118,7 +107,7 @@ test_expect_success 'info --url directory' '
 test_expect_success 'info symlink-file' "
        (cd svnwc; svn info symlink-file) > expected.info-symlink-file &&
        (cd gitwc; git svn info symlink-file) > actual.info-symlink-file &&
-       test_cmp expected.info-symlink-file actual.info-symlink-file
+       test_cmp_info expected.info-symlink-file actual.info-symlink-file
        "
 
 test_expect_success 'info --url symlink-file' '
@@ -131,7 +120,7 @@ test_expect_success 'info symlink-directory' "
                > expected.info-symlink-directory &&
        (cd gitwc; git svn info symlink-directory) \
                > actual.info-symlink-directory &&
-       test_cmp expected.info-symlink-directory actual.info-symlink-directory
+       test_cmp_info expected.info-symlink-directory actual.info-symlink-directory
        "
 
 test_expect_success 'info --url symlink-directory' '
@@ -146,14 +135,13 @@ test_expect_success 'info added-file' "
                git add added-file
        ) &&
        cp gitwc/added-file svnwc/added-file &&
-       ptouch gitwc/added-file svnwc/added-file &&
        (
                cd svnwc &&
                svn_cmd add added-file > /dev/null
        ) &&
        (cd svnwc; svn info added-file) > expected.info-added-file &&
        (cd gitwc; git svn info added-file) > actual.info-added-file &&
-       test_cmp expected.info-added-file actual.info-added-file
+       test_cmp_info expected.info-added-file actual.info-added-file
        "
 
 test_expect_success 'info --url added-file' '
@@ -163,7 +151,6 @@ test_expect_success 'info --url added-file' '
 
 test_expect_success 'info added-directory' "
        mkdir gitwc/added-directory svnwc/added-directory &&
-       ptouch gitwc/added-directory svnwc/added-directory &&
        touch gitwc/added-directory/.placeholder &&
        (
                cd svnwc &&
@@ -177,7 +164,7 @@ test_expect_success 'info added-directory' "
                > expected.info-added-directory &&
        (cd gitwc; git svn info added-directory) \
                > actual.info-added-directory &&
-       test_cmp expected.info-added-directory actual.info-added-directory
+       test_cmp_info expected.info-added-directory actual.info-added-directory
        "
 
 test_expect_success 'info --url added-directory' '
@@ -196,13 +183,12 @@ test_expect_success 'info added-symlink-file' "
                ln -s added-file added-symlink-file &&
                svn_cmd add added-symlink-file > /dev/null
        ) &&
-       ptouch gitwc/added-symlink-file svnwc/added-symlink-file &&
        (cd svnwc; svn info added-symlink-file) \
                > expected.info-added-symlink-file &&
        (cd gitwc; git svn info added-symlink-file) \
                > actual.info-added-symlink-file &&
-       test_cmp expected.info-added-symlink-file \
-                actual.info-added-symlink-file
+       test_cmp_info expected.info-added-symlink-file \
+               actual.info-added-symlink-file
        "
 
 test_expect_success 'info --url added-symlink-file' '
@@ -221,13 +207,12 @@ test_expect_success 'info added-symlink-directory' "
                ln -s added-directory added-symlink-directory &&
                svn_cmd add added-symlink-directory > /dev/null
        ) &&
-       ptouch gitwc/added-symlink-directory svnwc/added-symlink-directory &&
        (cd svnwc; svn info added-symlink-directory) \
                > expected.info-added-symlink-directory &&
        (cd gitwc; git svn info added-symlink-directory) \
                > actual.info-added-symlink-directory &&
-       test_cmp expected.info-added-symlink-directory \
-                actual.info-added-symlink-directory
+       test_cmp_info expected.info-added-symlink-directory \
+               actual.info-added-symlink-directory
        "
 
 test_expect_success 'info --url added-symlink-directory' '
@@ -235,11 +220,6 @@ test_expect_success 'info --url added-symlink-directory' '
             = "$quoted_svnrepo/added-symlink-directory"
        '
 
-# The next few tests replace the "Text Last Updated" value with a
-# placeholder since git doesn't have a way to know the date that a
-# now-deleted file was last checked out locally.  Internally it
-# simply reuses the Last Changed Date.
-
 test_expect_success 'info deleted-file' "
        (
                cd gitwc &&
@@ -249,13 +229,9 @@ test_expect_success 'info deleted-file' "
                cd svnwc &&
                svn_cmd rm --force file > /dev/null
        ) &&
-       (cd svnwc; svn info file) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > expected.info-deleted-file &&
-       (cd gitwc; git svn info file) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > actual.info-deleted-file &&
-       test_cmp expected.info-deleted-file actual.info-deleted-file
+       (cd svnwc; svn info file) >expected.info-deleted-file &&
+       (cd gitwc; git svn info file) >actual.info-deleted-file &&
+       test_cmp_info expected.info-deleted-file actual.info-deleted-file
        "
 
 test_expect_success 'info --url file (deleted)' '
@@ -272,13 +248,9 @@ test_expect_success 'info deleted-directory' "
                cd svnwc &&
                svn_cmd rm --force directory > /dev/null
        ) &&
-       (cd svnwc; svn info directory) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > expected.info-deleted-directory &&
-       (cd gitwc; git svn info directory) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > actual.info-deleted-directory &&
-       test_cmp expected.info-deleted-directory actual.info-deleted-directory
+       (cd svnwc; svn info directory) >expected.info-deleted-directory &&
+       (cd gitwc; git svn info directory) >actual.info-deleted-directory &&
+       test_cmp_info expected.info-deleted-directory actual.info-deleted-directory
        "
 
 test_expect_success 'info --url directory (deleted)' '
@@ -295,14 +267,9 @@ test_expect_success 'info deleted-symlink-file' "
                cd svnwc &&
                svn_cmd rm --force symlink-file > /dev/null
        ) &&
-       (cd svnwc; svn info symlink-file) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > expected.info-deleted-symlink-file &&
-       (cd gitwc; git svn info symlink-file) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > actual.info-deleted-symlink-file &&
-       test_cmp expected.info-deleted-symlink-file \
-                actual.info-deleted-symlink-file
+       (cd svnwc; svn info symlink-file) >expected.info-deleted-symlink-file &&
+       (cd gitwc; git svn info symlink-file) >actual.info-deleted-symlink-file &&
+       test_cmp_info expected.info-deleted-symlink-file actual.info-deleted-symlink-file
        "
 
 test_expect_success 'info --url symlink-file (deleted)' '
@@ -319,14 +286,9 @@ test_expect_success 'info deleted-symlink-directory' "
                cd svnwc &&
                svn_cmd rm --force symlink-directory > /dev/null
        ) &&
-       (cd svnwc; svn info symlink-directory) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-                > expected.info-deleted-symlink-directory &&
-       (cd gitwc; git svn info symlink-directory) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-                > actual.info-deleted-symlink-directory &&
-       test_cmp expected.info-deleted-symlink-directory \
-                actual.info-deleted-symlink-directory
+       (cd svnwc; svn info symlink-directory) >expected.info-deleted-symlink-directory &&
+       (cd gitwc; git svn info symlink-directory) >actual.info-deleted-symlink-directory &&
+       test_cmp_info expected.info-deleted-symlink-directory actual.info-deleted-symlink-directory
        "
 
 test_expect_success 'info --url symlink-directory (deleted)' '
index c6afebb00d02808f2a990347c8b0479d825cce5b..1fb76abd14e358afb42774f0ffe1d4e70b749074 100644 (file)
@@ -260,7 +260,7 @@ test_decode_color () {
                        if (n == 47) return "BWHITE";
                }
                {
-                       while (match($0, /\x1b\[[0-9;]*m/) != 0) {
+                       while (match($0, /\033\[[0-9;]*m/) != 0) {
                                printf "%s<", substr($0, 1, RSTART-1);
                                codes = substr($0, RSTART+2, RLENGTH-3);
                                if (length(codes) == 0)
diff --git a/trace.c b/trace.c
index 1e560cb0b977e19beeb095497c8e4f6280b7f0d6..62586fa371b22e9b0b2d8f4e7eb9a4e3e100ac9f 100644 (file)
--- a/trace.c
+++ b/trace.c
@@ -25,7 +25,7 @@
 #include "cache.h"
 #include "quote.h"
 
-void do_nothing(size_t unused)
+static void do_nothing(size_t unused)
 {
 }
 
index 803445aa7be140c3707bcebc72aaf6fc6af45e4b..d5a453079a02ff8b7a63a3453d07935e0807c005 100644 (file)
@@ -53,6 +53,7 @@ const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
 void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                                  const char *cmd)
 {
+       int i;
        const char **msgs = opts->msgs;
        const char *msg;
        char *tmp;
@@ -96,6 +97,9 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                "The following Working tree files would be removed by sparse checkout update:\n%s";
 
        opts->show_all_errors = 1;
+       /* rejected paths may not have a static buffer */
+       for (i = 0; i < ARRAY_SIZE(opts->unpack_rejects); i++)
+               opts->unpack_rejects[i].strdup_strings = 1;
 }
 
 static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
@@ -124,7 +128,6 @@ static int add_rejected_path(struct unpack_trees_options *o,
                             enum unpack_trees_error_types e,
                             const char *path)
 {
-       struct rejected_paths_list *newentry;
        if (!o->show_all_errors)
                return error(ERRORMSG(o, e), path);
 
@@ -132,45 +135,28 @@ static int add_rejected_path(struct unpack_trees_options *o,
         * Otherwise, insert in a list for future display by
         * display_error_msgs()
         */
-       newentry = xmalloc(sizeof(struct rejected_paths_list));
-       newentry->path = (char *)path;
-       newentry->next = o->unpack_rejects[e];
-       o->unpack_rejects[e] = newentry;
+       string_list_append(&o->unpack_rejects[e], path);
        return -1;
 }
 
-/*
- * free all the structures allocated for the error <e>
- */
-static void free_rejected_paths(struct unpack_trees_options *o,
-                               enum unpack_trees_error_types e)
-{
-       while (o->unpack_rejects[e]) {
-               struct rejected_paths_list *del = o->unpack_rejects[e];
-               o->unpack_rejects[e] = o->unpack_rejects[e]->next;
-               free(del);
-       }
-       free(o->unpack_rejects[e]);
-}
-
 /*
  * display all the error messages stored in a nice way
  */
 static void display_error_msgs(struct unpack_trees_options *o)
 {
-       int e;
+       int e, i;
        int something_displayed = 0;
        for (e = 0; e < NB_UNPACK_TREES_ERROR_TYPES; e++) {
-               if (o->unpack_rejects[e]) {
-                       struct rejected_paths_list *rp;
+               struct string_list *rejects = &o->unpack_rejects[e];
+               if (rejects->nr > 0) {
                        struct strbuf path = STRBUF_INIT;
                        something_displayed = 1;
-                       for (rp = o->unpack_rejects[e]; rp; rp = rp->next)
-                               strbuf_addf(&path, "\t%s\n", rp->path);
+                       for (i = 0; i < rejects->nr; i++)
+                               strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
                        error(ERRORMSG(o, e), path.buf);
                        strbuf_release(&path);
-                       free_rejected_paths(o, e);
                }
+               string_list_clear(rejects, 0);
        }
        if (something_displayed)
                printf("Aborting\n");
@@ -182,7 +168,7 @@ static void display_error_msgs(struct unpack_trees_options *o)
  */
 static void unlink_entry(struct cache_entry *ce)
 {
-       if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
+       if (!check_leading_path(ce->name, ce_namelen(ce)))
                return;
        if (remove_or_warn(ce->ce_mode, ce->name))
                return;
@@ -1127,14 +1113,65 @@ static int verify_clean_subdirectory(struct cache_entry *ce,
  * See if we can find a case-insensitive match in the index that also
  * matches the stat information, and assume it's that other file!
  */
-static int icase_exists(struct unpack_trees_options *o, struct cache_entry *dst, struct stat *st)
+static int icase_exists(struct unpack_trees_options *o, const char *name, int len, struct stat *st)
 {
        struct cache_entry *src;
 
-       src = index_name_exists(o->src_index, dst->name, ce_namelen(dst), 1);
+       src = index_name_exists(o->src_index, name, len, 1);
        return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
 }
 
+static int check_ok_to_remove(const char *name, int len, int dtype,
+                             struct cache_entry *ce, struct stat *st,
+                             enum unpack_trees_error_types error_type,
+                             struct unpack_trees_options *o)
+{
+       struct cache_entry *result;
+
+       /*
+        * It may be that the 'lstat()' succeeded even though
+        * target 'ce' was absent, because there is an old
+        * entry that is different only in case..
+        *
+        * Ignore that lstat() if it matches.
+        */
+       if (ignore_case && icase_exists(o, name, len, st))
+               return 0;
+
+       if (o->dir && excluded(o->dir, name, &dtype))
+               /*
+                * ce->name is explicitly excluded, so it is Ok to
+                * overwrite it.
+                */
+               return 0;
+       if (S_ISDIR(st->st_mode)) {
+               /*
+                * We are checking out path "foo" and
+                * found "foo/." in the working tree.
+                * This is tricky -- if we have modified
+                * files that are in "foo/" we would lose
+                * them.
+                */
+               if (verify_clean_subdirectory(ce, error_type, o) < 0)
+                       return -1;
+               return 0;
+       }
+
+       /*
+        * The previous round may already have decided to
+        * delete this path, which is in a subdirectory that
+        * is being replaced with a blob.
+        */
+       result = index_name_exists(&o->result, name, len, 0);
+       if (result) {
+               if (result->ce_flags & CE_REMOVE)
+                       return 0;
+       }
+
+       return o->gently ? -1 :
+               add_rejected_path(o, error_type, name);
+}
+
 /*
  * We do not want to remove or overwrite a working tree file that
  * is not tracked, unless it is ignored.
@@ -1143,63 +1180,31 @@ static int verify_absent_1(struct cache_entry *ce,
                                 enum unpack_trees_error_types error_type,
                                 struct unpack_trees_options *o)
 {
+       int len;
        struct stat st;
 
        if (o->index_only || o->reset || !o->update)
                return 0;
 
-       if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
+       len = check_leading_path(ce->name, ce_namelen(ce));
+       if (!len)
                return 0;
+       else if (len > 0) {
+               char path[PATH_MAX + 1];
+               memcpy(path, ce->name, len);
+               path[len] = 0;
+               lstat(path, &st);
+
+               return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st,
+                               error_type, o);
+       } else if (!lstat(ce->name, &st))
+               return check_ok_to_remove(ce->name, ce_namelen(ce),
+                               ce_to_dtype(ce), ce, &st,
+                               error_type, o);
 
-       if (!lstat(ce->name, &st)) {
-               int dtype = ce_to_dtype(ce);
-               struct cache_entry *result;
-
-               /*
-                * It may be that the 'lstat()' succeeded even though
-                * target 'ce' was absent, because there is an old
-                * entry that is different only in case..
-                *
-                * Ignore that lstat() if it matches.
-                */
-               if (ignore_case && icase_exists(o, ce, &st))
-                       return 0;
-
-               if (o->dir && excluded(o->dir, ce->name, &dtype))
-                       /*
-                        * ce->name is explicitly excluded, so it is Ok to
-                        * overwrite it.
-                        */
-                       return 0;
-               if (S_ISDIR(st.st_mode)) {
-                       /*
-                        * We are checking out path "foo" and
-                        * found "foo/." in the working tree.
-                        * This is tricky -- if we have modified
-                        * files that are in "foo/" we would lose
-                        * them.
-                        */
-                       if (verify_clean_subdirectory(ce, error_type, o) < 0)
-                               return -1;
-                       return 0;
-               }
-
-               /*
-                * The previous round may already have decided to
-                * delete this path, which is in a subdirectory that
-                * is being replaced with a blob.
-                */
-               result = index_name_exists(&o->result, ce->name, ce_namelen(ce), 0);
-               if (result) {
-                       if (result->ce_flags & CE_REMOVE)
-                               return 0;
-               }
-
-               return o->gently ? -1 :
-                       add_rejected_path(o, error_type, ce->name);
-       }
        return 0;
 }
+
 static int verify_absent(struct cache_entry *ce,
                         enum unpack_trees_error_types error_type,
                         struct unpack_trees_options *o)
index 7c0187d11adaa5f0b9a8642070d8dfc2db41dfdf..cd11a08365ab3e27b1321b3df87bcab6b9278f90 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef UNPACK_TREES_H
 #define UNPACK_TREES_H
 
+#include "string-list.h"
+
 #define MAX_UNPACK_TREES 8
 
 struct unpack_trees_options;
@@ -29,11 +31,6 @@ enum unpack_trees_error_types {
 void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                                  const char *cmd);
 
-struct rejected_paths_list {
-       char *path;
-       struct rejected_paths_list *next;
-};
-
 struct unpack_trees_options {
        unsigned int reset,
                     merge,
@@ -59,7 +56,7 @@ struct unpack_trees_options {
         * Store error messages in an array, each case
         * corresponding to a error message type
         */
-       struct rejected_paths_list *unpack_rejects[NB_UNPACK_TREES_ERROR_TYPES];
+       struct string_list unpack_rejects[NB_UNPACK_TREES_ERROR_TYPES];
 
        int head_idx;
        int merge_size;
diff --git a/url.c b/url.c
index cd8f74f00c345294f94cb25e4e00849a0618168b..6a5495960f03ded65f0f5f8b8bd5c7cd98c0b05e 100644 (file)
--- a/url.c
+++ b/url.c
@@ -125,3 +125,17 @@ char *url_decode_parameter_value(const char **query)
        struct strbuf out = STRBUF_INIT;
        return url_decode_internal(query, "&", &out, 1);
 }
+
+void end_url_with_slash(struct strbuf *buf, const char *url)
+{
+       strbuf_addstr(buf, url);
+       if (buf->len && buf->buf[buf->len - 1] != '/')
+               strbuf_addstr(buf, "/");
+}
+
+void str_end_url_with_slash(const char *url, char **dest) {
+       struct strbuf buf = STRBUF_INIT;
+       end_url_with_slash(&buf, url);
+       free(*dest);
+       *dest = strbuf_detach(&buf, NULL);
+}
diff --git a/url.h b/url.h
index 15817f8f9385c217b22706df64117fcc53c8a87f..7100e3215a97b234c8ab93b76f7f86518f7c3382 100644 (file)
--- a/url.h
+++ b/url.h
@@ -7,4 +7,7 @@ extern char *url_decode(const char *url);
 extern char *url_decode_parameter_name(const char **query);
 extern char *url_decode_parameter_value(const char **query);
 
+extern void end_url_with_slash(struct strbuf *buf, const char *url);
+extern void str_end_url_with_slash(const char *url, char **dest);
+
 #endif /* URL_H */
index f9e05b548c2fdbc349a1d47d81619e266ec9fb83..2d5453697aaf5287f524b72d0088ee15679e0691 100644 (file)
@@ -74,14 +74,14 @@ PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$",
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?"
         "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"
-        "|[^[:space:]|[\x80-\xff]+"),
+        "|[^[:space:]]|[\x80-\xff]+"),
         /* -- */
 PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$",
         /* -- */
         "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?."
         "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~"
-        "|[^[:space:]|[\x80-\xff]+"),
+        "|[^[:space:]]|[\x80-\xff]+"),
 PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
         "[={}\"]|[^={}\" \t]+"),
 PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
index fc2438f60b0e0e87772db2a9f3e407f351bb03d0..9624865e21739139a9fef5ebc31196cbcd22011a 100644 (file)
@@ -744,10 +744,20 @@ static void wt_shortstatus_status(int null_termination, struct string_list_item
                const char *one;
                if (d->head_path) {
                        one = quote_path(d->head_path, -1, &onebuf, s->prefix);
+                       if (*one != '"' && strchr(one, ' ') != NULL) {
+                               putchar('"');
+                               strbuf_addch(&onebuf, '"');
+                               one = onebuf.buf;
+                       }
                        printf("%s -> ", one);
                        strbuf_release(&onebuf);
                }
                one = quote_path(it->string, -1, &onebuf, s->prefix);
+               if (*one != '"' && strchr(one, ' ') != NULL) {
+                       putchar('"');
+                       strbuf_addch(&onebuf, '"');
+                       one = onebuf.buf;
+               }
                printf("%s\n", one);
                strbuf_release(&onebuf);
        }
index e1e054e4d982de30d8a9c8c4109c6d62448f62a9..164581f87f49935f0d1b1885420960a4d11dea56 100644 (file)
@@ -212,8 +212,10 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
                return error("Could not open %s", filename);
        sz = xsize_t(st.st_size);
        ptr->ptr = xmalloc(sz ? sz : 1);
-       if (sz && fread(ptr->ptr, sz, 1, f) != 1)
+       if (sz && fread(ptr->ptr, sz, 1, f) != 1) {
+               fclose(f);
                return error("Could not read %s", filename);
+       }
        fclose(f);
        ptr->size = sz;
        return 0;