Merge branch 'jc/maint-mergetool-style-fix' into maint-1.7.11
authorJunio C Hamano <gitster@pobox.com>
Tue, 11 Sep 2012 18:10:23 +0000 (11:10 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 11 Sep 2012 18:10:23 +0000 (11:10 -0700)
* jc/maint-mergetool-style-fix:
  mergetool: style fixes

70 files changed:
Documentation/CodingGuidelines
Documentation/RelNotes/1.7.11.6.txt [new file with mode: 0644]
Documentation/asciidoc.conf
Documentation/git-config.txt
Documentation/git-describe.txt
Documentation/git-filter-branch.txt
Documentation/git-fsck.txt
Documentation/git-lost-found.txt
Documentation/git-pack-refs.txt
Documentation/git-pull.txt
Documentation/git-replace.txt
Documentation/git-submodule.txt
Documentation/git-tag.txt
Documentation/gitcli.txt
Documentation/rev-list-options.txt
Documentation/user-manual.conf
Makefile
RelNotes
builtin.h
builtin/apply.c
builtin/blame.c
builtin/cat-file.c
builtin/checkout.c
builtin/commit.c
builtin/config.c
builtin/diff.c
builtin/merge.c
builtin/receive-pack.c
cache.h
combine-diff.c
compat/terminal.c
contrib/ciabot/INSTALL [new file with mode: 0644]
contrib/ciabot/README
contrib/ciabot/ciabot.py
contrib/ciabot/ciabot.sh
diff-lib.c
diff-no-index.c
diff.c
diff.h
diffcore-rename.c
diffcore.h
fsck.c
git-rebase--interactive.sh
git-send-email.perl
git-sh-setup.sh
git-stash.sh
git-submodule.sh
gitweb/gitweb.perl
merge-recursive.c
notes-merge.c
patch-ids.c
read-cache.c
revision.c
run-command.c
setup.c
submodule.c
t/perf/perf-lib.sh
t/t1450-fsck.sh
t/t2107-update-index-basic.sh
t/t3401-rebase-partial.sh
t/t4022-diff-rewrite.sh
t/t4054-diff-bogus-tree.sh [new file with mode: 0755]
t/t5400-send-pack.sh
t/t5551-http-fetch.sh
t/t7400-submodule-basic.sh
t/t7406-submodule-update.sh
t/t7610-mergetool.sh
t/t9001-send-email.sh
t/test-lib-functions.sh
tree-diff.c

index 4557711..57da6aa 100644 (file)
@@ -76,11 +76,19 @@ For shell scripts specifically (not exhaustive):
 
  - We do not use Process Substitution <(list) or >(list).
 
+ - Do not write control structures on a single line with semicolon.
+   "then" should be on the next line for if statements, and "do"
+   should be on the next line for "while" and "for".
+
  - We prefer "test" over "[ ... ]".
 
  - We do not write the noiseword "function" in front of shell
    functions.
 
+ - We prefer a space between the function name and the parentheses. The
+   opening "{" should also be on the same line.
+   E.g.: my_function () {
+
  - As to use of grep, stick to a subset of BRE (namely, no \{m,n\},
    [::], [==], nor [..]) for portability.
 
diff --git a/Documentation/RelNotes/1.7.11.6.txt b/Documentation/RelNotes/1.7.11.6.txt
new file mode 100644 (file)
index 0000000..84ba827
--- /dev/null
@@ -0,0 +1,62 @@
+Git v1.7.11.6 Release Notes
+===========================
+
+Fixes since v1.7.11.5
+---------------------
+
+This consists primarily of documentation updates and low-impact code
+clarification and bugfixes.
+
+ - "ciabot" script (in contrib/) has been updated with extensive
+   documentation.
+
+ - The "--rebase" option to "git pull" can be abbreviated to "-r",
+   but we didn't document it.
+
+ - It was generally understood that "--long-option"s to many of our
+   subcommands can be abbreviated to the unique prefix, but it was not
+   easy to find it described for new readers of the documentation set.
+
+ - The "--topo-order", "--date-order" (and the lack of either means
+   the default order) options to "rev-list" and "log" family of
+   commands were poorly described in the documentation.
+
+ - Older parts of the documentation described as if having a regular
+   file in .git/refs/ hierarchy were the only way to have branches and
+   tags, which is not true for quite some time.
+
+ - A utility shell function test_seq has been added as a replacement
+   for the 'seq' utility found on some platforms.
+
+ - Fallback 'getpass' implementation made unportable use of stdio API.
+
+ - "git commit --amend" let the user edit the log message and then
+   died when the human-readable committer name was given
+   insufficiently by getpwent(3).
+
+ - The reflog entries left by "git rebase" and "git rebase -i" were
+   inconsistent (the interactive one gave an abbreviated object name).
+
+ - When the user exports a non-default IFS without HT, scripts that
+   rely on being able to parse "ls-files -s | while read a b c..."
+   started to fail.  Protect them from such a misconfiguration.
+
+ - When "git push" triggered the automatic gc on the receiving end, a
+   message from "git prune" that said it was removing cruft leaked to
+   the standard output, breaking the communication protocol.
+
+ - "git diff" had a confusion between taking data from a path in the
+   working tree and taking data from an object that happens to have
+   name 0{40} recorded in a tree.
+
+ - "git send-email" did not unquote encoded words that appear on the
+   header correctly, and lost "_" from strings.
+
+ - When the user gives an argument that can be taken as both a
+   revision name and a pathname without disambiguating with "--", we
+   used to give a help message "Use '--' to separate".  The message
+   has been clarified to show where that '--' goes on the command
+   line.
+
+ - "gitweb" when used with PATH_INFO failed to notice directories with
+   SP (and other characters that need URL-style quoting) in them.
index a26d245..1273a85 100644 (file)
@@ -36,7 +36,7 @@ ifndef::git-asciidoc-no-roff[]
 # v1.72 breaks with this because it replaces dots not in roff requests.
 [listingblock]
 <example><title>{title}</title>
-<literallayout>
+<literallayout class="monospaced">
 ifdef::doctype-manpage[]
 &#10;.ft C&#10;
 endif::doctype-manpage[]
@@ -53,7 +53,7 @@ ifdef::doctype-manpage[]
 # The following two small workarounds insert a simple paragraph after screen
 [listingblock]
 <example><title>{title}</title>
-<literallayout>
+<literallayout class="monospaced">
 |
 </literallayout><simpara></simpara>
 {title#}</example>
index d9463cb..21b8f61 100644 (file)
@@ -54,16 +54,16 @@ configuration file by default, and options '--system', '--global',
 '--file <filename>' can be used to tell the command to write to
 that location (you can say '--local' but that is the default).
 
-This command will fail (with exit code ret) if:
+This command will fail with non-zero status upon error.  Some exit
+codes are:
 
 . The config file is invalid (ret=3),
 . can not write to the config file (ret=4),
 . no section or name was provided (ret=2),
 . the section or key is invalid (ret=1),
 . you try to unset an option which does not exist (ret=5),
-. you try to unset/set an option for which multiple lines match (ret=5),
-. you try to use an invalid regexp (ret=6), or
-. you use '--global' option without $HOME being properly set (ret=128).
+. you try to unset/set an option for which multiple lines match (ret=5), or
+. you try to use an invalid regexp (ret=6).
 
 On success, the command returns the exit code 0.
 
@@ -258,7 +258,7 @@ Given a .git/config like this:
 
        ; Proxy settings
        [core]
-               gitproxy="proxy-command" for kernel.org
+               gitproxy=proxy-command for kernel.org
                gitproxy=default-proxy ; for all the rest
 
 you can set the filemode to true with
@@ -333,7 +333,7 @@ To actually match only values with an exclamation mark, you have to
 To add a new proxy, without altering any of the existing ones, use
 
 ------------
-% git config core.gitproxy '"proxy-command" for example.com'
+% git config --add core.gitproxy '"proxy-command" for example.com'
 ------------
 
 An example to use customized color from the configuration in your
index 039cce2..72d6bb6 100644 (file)
@@ -36,12 +36,12 @@ OPTIONS
 
 --all::
        Instead of using only the annotated tags, use any ref
-       found in `.git/refs/`.  This option enables matching
+       found in `refs/` namespace.  This option enables matching
        any known branch, remote-tracking branch, or lightweight tag.
 
 --tags::
        Instead of using only the annotated tags, use any tag
-       found in `.git/refs/tags`.  This option enables matching
+       found in `refs/tags` namespace.  This option enables matching
        a lightweight (non-annotated) tag.
 
 --contains::
index 81f5823..15e7ac8 100644 (file)
@@ -32,7 +32,8 @@ changes, which would normally have no effect.  Nevertheless, this may be
 useful in the future for compensating for some git bugs or such,
 therefore such a usage is permitted.
 
-*NOTE*: This command honors `.git/info/grafts` and `.git/refs/replace/`.
+*NOTE*: This command honors `.git/info/grafts` file and refs in
+the `refs/replace/` namespace.
 If you have any grafts or replacement refs defined, running this command
 will make them permanent.
 
index bbb25da..da348fc 100644 (file)
@@ -23,8 +23,8 @@ OPTIONS
        An object to treat as the head of an unreachability trace.
 +
 If no objects are given, 'git fsck' defaults to using the
-index file, all SHA1 references in .git/refs/*, and all reflogs (unless
---no-reflogs is given) as heads.
+index file, all SHA1 references in `refs` namespace, and all reflogs
+(unless --no-reflogs is given) as heads.
 
 --unreachable::
        Print out objects that exist but that aren't reachable from any
index c406a11..d549328 100644 (file)
@@ -48,7 +48,8 @@ $ gitk $(cd .git/lost-found/commit && echo ??*)
 ------------
 
 After making sure you know which the object is the tag you are looking
-for, you can reconnect it to your regular .git/refs hierarchy.
+for, you can reconnect it to your regular `refs` hierarchy by using
+the `update-ref` command.
 
 ------------
 $ git cat-file -t 1ef2b196
index 10afd4e..f131677 100644 (file)
@@ -14,7 +14,8 @@ DESCRIPTION
 -----------
 
 Traditionally, tips of branches and tags (collectively known as
-'refs') were stored one file per ref under `$GIT_DIR/refs`
+'refs') were stored one file per ref in a (sub)directory
+under `$GIT_DIR/refs`
 directory.  While many branch tips tend to be updated often,
 most tags and some branch tips are never updated.  When a
 repository has hundreds or thousands of tags, this
@@ -22,13 +23,14 @@ one-file-per-ref format both wastes storage and hurts
 performance.
 
 This command is used to solve the storage and performance
-problem by stashing the refs in a single file,
+problem by storing the refs in a single file,
 `$GIT_DIR/packed-refs`.  When a ref is missing from the
-traditional `$GIT_DIR/refs` hierarchy, it is looked up in this
+traditional `$GIT_DIR/refs` directory hierarchy, it is looked
+up in this
 file and used if found.
 
 Subsequent updates to branches always create new files under
-`$GIT_DIR/refs` hierarchy.
+`$GIT_DIR/refs` directory hierarchy.
 
 A recommended practice to deal with a repository with too many
 refs is to pack its refs with `--all --prune` once, and
@@ -57,6 +59,15 @@ a repository with many branches of historical interests.
 The command usually removes loose refs under `$GIT_DIR/refs`
 hierarchy after packing them.  This option tells it not to.
 
+
+BUGS
+----
+
+Older documentation written before the packed-refs mechanism was
+introduced may still say things like ".git/refs/heads/<branch> file
+exists" when it means "branch <branch> exists".
+
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index defb544..67fa5ee 100644 (file)
@@ -101,6 +101,7 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
+-r::
 --rebase::
        Rebase the current branch on top of the upstream branch after
        fetching.  If there is a remote-tracking branch corresponding to
index 17df525..51131d0 100644 (file)
@@ -14,14 +14,13 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Adds a 'replace' reference in `.git/refs/replace/`
+Adds a 'replace' reference in `refs/replace/` namespace.
 
 The name of the 'replace' reference is the SHA1 of the object that is
 replaced. The content of the 'replace' reference is the SHA1 of the
 replacement object.
 
-Unless `-f` is given, the 'replace' reference must not yet exist in
-`.git/refs/replace/` directory.
+Unless `-f` is given, the 'replace' reference must not yet exist.
 
 Replacement references will be used by default by all git commands
 except those doing reachability traversal (prune, pack transfer and
index fbbbcb2..2de7bf0 100644 (file)
@@ -149,6 +149,11 @@ submodule with the `--init` option.
 +
 If `--recursive` is specified, this command will recurse into the
 registered submodules, and update any nested submodules within.
++
+If `--force` is specified, the submodule will be checked out (using
+`git checkout --force` if appropriate), even if the commit specified in the
+index of the containing repository already matches the commit checked out in
+the submodule.
 
 summary::
        Show commit summary between the given commit (defaults to HEAD) and
@@ -210,7 +215,9 @@ OPTIONS
        This option is only valid for add and update commands.
        When running add, allow adding an otherwise ignored submodule path.
        When running update, throw away local changes in submodules when
-       switching to a different commit.
+       switching to a different commit; and always run a checkout operation
+       in the submodule, even if the commit listed in the index of the
+       containing repository matches the commit checked out in the submodule.
 
 --cached::
        This option is only valid for status and summary commands.  These
index e36a7c3..247534e 100644 (file)
@@ -20,11 +20,10 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Add a tag reference in `.git/refs/tags/`, unless `-d/-l/-v` is given
+Add a tag reference in `refs/tags/`, unless `-d/-l/-v` is given
 to delete, list or verify tags.
 
-Unless `-f` is given, the tag to be created must not yet exist in the
-`.git/refs/tags/` directory.
+Unless `-f` is given, the named tag must not yet exist.
 
 If one of `-a`, `-s`, or `-u <key-id>` is passed, the command
 creates a 'tag' object, and requires a tag message.  Unless
index ea17f7a..3e72a5d 100644 (file)
@@ -62,6 +62,14 @@ scripting git:
    `git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
    if you happen to have a file called `HEAD` in the work tree.
 
+ * many commands allow a long option "--option" to be abbreviated
+   only to their unique prefix (e.g. if there is no other option
+   whose name begins with "opt", you may be able to spell "--opt" to
+   invoke the "--option" flag), but you should fully spell them out
+   when writing your scripts; later versions of Git may introduce a
+   new option whose name shares the same prefix, e.g. "--optimize",
+   to make a short prefix that used to be unique no longer unique.
+
 
 ENHANCED OPTION PARSER
 ----------------------
index d9b2b5b..def1340 100644 (file)
@@ -578,16 +578,33 @@ Commit Ordering
 
 By default, the commits are shown in reverse chronological order.
 
---topo-order::
+--date-order::
+       Show no parents before all of its children are shown, but
+       otherwise show commits in the commit timestamp order.
 
-       This option makes them appear in topological order (i.e.
-       descendant commits are shown before their parents).
+--topo-order::
+       Show no parents before all of its children are shown, and
+       avoid showing commits on multiple lines of history
+       intermixed.
++
+For example, in a commit history like this:
++
+----------------------------------------------------------------
 
---date-order::
+    ---1----2----4----7
+       \              \
+        3----5----6----8---
 
-       This option is similar to '--topo-order' in the sense that no
-       parent comes before all of its children, but otherwise things
-       are still ordered in the commit timestamp order.
+----------------------------------------------------------------
++
+where the numbers denote the order of commit timestamps, `git
+rev-list` and friends with `--date-order` show the commits in the
+timestamp order: 8 7 6 5 4 3 2 1.
++
+With `--topo-order`, they would show 8 6 5 3 7 4 2 1 (or 8 7 4 2 6 5
+3 1); some older commits are shown before newer ones in order to
+avoid showing the commits from two parallel development track mixed
+together.
 
 --reverse::
 
index 339b309..d87294d 100644 (file)
@@ -14,7 +14,7 @@ ifdef::backend-docbook[]
 # "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
 [listingblock]
 <example><title>{title}</title>
-<literallayout>
+<literallayout class="monospaced">
 |
 </literallayout>
 {title#}</example>
index df58303..1f72c1c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1005,6 +1005,7 @@ ifeq ($(uname_S),SunOS)
        NO_REGEX = YesPlease
        NO_FNMATCH_CASEFOLD = YesPlease
        NO_MSGFMT_EXTENDED_OPTIONS = YesPlease
+       HAVE_DEV_TTY = YesPlease
        ifeq ($(uname_R),5.6)
                SOCKLEN_T = int
                NO_HSTRERROR = YesPlease
index f6490be..d04f1ae 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.11.5.txt
\ No newline at end of file
+Documentation/RelNotes/1.7.11.6.txt
\ No newline at end of file
index e426de3..dffb34e 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -44,7 +44,7 @@ extern int check_pager_config(const char *cmd);
 struct diff_options;
 extern void setup_diff_pager(struct diff_options *);
 
-extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size);
+extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
@@ -85,7 +85,6 @@ extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix
 extern int cmd_grep(int argc, const char **argv, const char *prefix);
 extern int cmd_hash_object(int argc, const char **argv, const char *prefix);
 extern int cmd_help(int argc, const char **argv, const char *prefix);
-extern int cmd_http_fetch(int argc, const char **argv, const char *prefix);
 extern int cmd_index_pack(int argc, const char **argv, const char *prefix);
 extern int cmd_init_db(int argc, const char **argv, const char *prefix);
 extern int cmd_log(int argc, const char **argv, const char *prefix);
@@ -110,7 +109,6 @@ extern int cmd_notes(int argc, const char **argv, const char *prefix);
 extern int cmd_pack_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_pack_redundant(int argc, const char **argv, const char *prefix);
 extern int cmd_patch_id(int argc, const char **argv, const char *prefix);
-extern int cmd_pickaxe(int argc, const char **argv, const char *prefix);
 extern int cmd_prune(int argc, const char **argv, const char *prefix);
 extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
 extern int cmd_push(int argc, const char **argv, const char *prefix);
@@ -143,7 +141,6 @@ extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_update_server_info(int argc, const char **argv, const char *prefix);
 extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
 extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix);
-extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
 extern int cmd_var(int argc, const char **argv, const char *prefix);
 extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);
 extern int cmd_version(int argc, const char **argv, const char *prefix);
index b4428ea..ca54ff3 100644 (file)
@@ -184,7 +184,6 @@ struct patch {
        int is_new, is_delete;  /* -1 = unknown, 0 = false, 1 = true */
        int rejected;
        unsigned ws_rule;
-       unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
        unsigned int is_toplevel_relative:1;
index 960c58d..cad4111 100644 (file)
@@ -110,6 +110,7 @@ static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen,
 int textconv_object(const char *path,
                    unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    char **buf,
                    unsigned long *buf_size)
 {
@@ -117,7 +118,7 @@ int textconv_object(const char *path,
        struct userdiff_driver *textconv;
 
        df = alloc_filespec(path);
-       fill_filespec(df, sha1, mode);
+       fill_filespec(df, sha1, sha1_valid, mode);
        textconv = get_textconv(df);
        if (!textconv) {
                free_filespec(df);
@@ -142,7 +143,7 @@ static void fill_origin_blob(struct diff_options *opt,
 
                num_read_blob++;
                if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                   textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size))
+                   textconv_object(o->path, o->mode, o->blob_sha1, 1, &file->ptr, &file_size))
                        ;
                else
                        file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
@@ -406,8 +407,7 @@ static struct origin *find_origin(struct scoreboard *sb,
        paths[1] = NULL;
 
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        if (is_null_sha1(origin->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@ -493,8 +493,7 @@ static struct origin *find_rename(struct scoreboard *sb,
        diff_opts.single_follow = origin->path;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        if (is_null_sha1(origin->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@ -1074,8 +1073,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
 
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        /* Try "find copies harder" on new path if requested;
         * we do not want to use diffcore_rename() actually to
@@ -2123,7 +2121,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
                        if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                           textconv_object(read_from, mode, null_sha1, &buf_ptr, &buf_len))
+                           textconv_object(read_from, mode, null_sha1, 0, &buf_ptr, &buf_len))
                                strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
                                die_errno("cannot open or read '%s'", read_from);
@@ -2515,7 +2513,7 @@ parse_done:
                        die("no such path %s in %s", path, final_commit_name);
 
                if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
-                   textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf,
+                   textconv_object(path, o->mode, o->blob_sha1, 1, (char **) &sb.final_buf,
                                    &sb.final_buf_size))
                        ;
                else
index 36a9104..60568f9 100644 (file)
@@ -146,7 +146,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
                        die("git cat-file --textconv %s: <object> must be <sha1:path>",
                            obj_name);
 
-               if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
+               if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
                        die("git cat-file --textconv: unable to run textconv on %s",
                            obj_name);
                break;
index e060efb..45aa0a8 100644 (file)
@@ -315,8 +315,7 @@ static void show_local_changes(struct object *head, struct diff_options *opts)
        init_revisions(&rev, NULL);
        rev.diffopt.flags = opts->flags;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
-       if (diff_setup_done(&rev.diffopt) < 0)
-               die(_("diff_setup_done failed"));
+       diff_setup_done(&rev.diffopt);
        add_pending_object(&rev, head, NULL);
        run_diff_index(&rev, 0);
 }
index 95eeab1..20cef95 100644 (file)
@@ -725,7 +725,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        strbuf_release(&sb);
 
        /* This checks if committer ident is explicitly given */
-       strbuf_addstr(&committer_ident, git_committer_info(0));
+       strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));
        if (use_editor && include_status) {
                char *ai_tmp, *ci_tmp;
                if (whence != FROM_COMMIT)
index 33c8820..b44277c 100644 (file)
@@ -160,7 +160,7 @@ static int show_config(const char *key_, const char *value_, void *cb)
 
 static int get_value(const char *key_, const char *regex_)
 {
-       int ret = -1;
+       int ret = CONFIG_GENERIC_ERROR;
        char *global = NULL, *repo_config = NULL;
        const char *system_wide = NULL, *local;
        struct config_include_data inc = CONFIG_INCLUDE_INIT;
@@ -198,11 +198,14 @@ static int get_value(const char *key_, const char *regex_)
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid key pattern: %s\n", key_);
                        free(key);
+                       ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
        } else {
-               if (git_config_parse_key(key_, &key, NULL))
+               if (git_config_parse_key(key_, &key, NULL)) {
+                       ret = CONFIG_INVALID_KEY;
                        goto free_strings;
+               }
        }
 
        if (regex_) {
@@ -214,6 +217,7 @@ static int get_value(const char *key_, const char *regex_)
                regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid pattern: %s\n", regex_);
+                       ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
        }
index da8f6aa..9650be2 100644 (file)
@@ -29,6 +29,8 @@ static void stuff_change(struct diff_options *opt,
                         unsigned old_mode, unsigned new_mode,
                         const unsigned char *old_sha1,
                         const unsigned char *new_sha1,
+                        int old_sha1_valid,
+                        int new_sha1_valid,
                         const char *old_name,
                         const char *new_name)
 {
@@ -54,8 +56,8 @@ static void stuff_change(struct diff_options *opt,
 
        one = alloc_filespec(old_name);
        two = alloc_filespec(new_name);
-       fill_filespec(one, old_sha1, old_mode);
-       fill_filespec(two, new_sha1, new_mode);
+       fill_filespec(one, old_sha1, old_sha1_valid, old_mode);
+       fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
 
        diff_queue(&diff_queued_diff, one, two);
 }
@@ -84,6 +86,7 @@ static int builtin_diff_b_f(struct rev_info *revs,
        stuff_change(&revs->diffopt,
                     blob[0].mode, canon_mode(st.st_mode),
                     blob[0].sha1, null_sha1,
+                    1, 0,
                     path, path);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
@@ -108,6 +111,7 @@ static int builtin_diff_blobs(struct rev_info *revs,
        stuff_change(&revs->diffopt,
                     blob[0].mode, blob[1].mode,
                     blob[0].sha1, blob[1].sha1,
+                    1, 1,
                     blob[0].name, blob[1].name);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
@@ -298,8 +302,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        argc = setup_revisions(argc, argv, &rev, NULL);
        if (!rev.diffopt.output_format) {
                rev.diffopt.output_format = DIFF_FORMAT_PATCH;
-               if (diff_setup_done(&rev.diffopt) < 0)
-                       die(_("diff_setup_done failed"));
+               diff_setup_done(&rev.diffopt);
        }
 
        DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
index dd50a0c..e81fde6 100644 (file)
@@ -404,8 +404,7 @@ static void finish(struct commit *head_commit,
                opts.output_format |=
                        DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
                opts.detect_rename = DIFF_DETECT_RENAME;
-               if (diff_setup_done(&opts) < 0)
-                       die(_("diff_setup_done failed"));
+               diff_setup_done(&opts);
                diff_tree_sha1(head, new_head, "", &opts);
                diffcore_std(&opts);
                diff_flush(&opts);
index 0afb8b2..3f05d97 100644 (file)
@@ -977,7 +977,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                        const char *argv_gc_auto[] = {
                                "gc", "--auto", "--quiet", NULL,
                        };
-                       run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+                       int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR;
+                       run_command_v_opt(argv_gc_auto, opt);
                }
                if (auto_update_server_info)
                        update_server_info(0);
diff --git a/cache.h b/cache.h
index 8958104..75b3bea 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1103,6 +1103,7 @@ extern int update_server_info(int);
 #define CONFIG_NO_WRITE 4
 #define CONFIG_NOTHING_SET 5
 #define CONFIG_INVALID_PATTERN 6
+#define CONFIG_GENERIC_ERROR 7
 
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int git_default_config(const char *, const char *, void *);
index 9786680..bb1cc96 100644 (file)
@@ -111,7 +111,7 @@ static char *grab_blob(const unsigned char *sha1, unsigned int mode,
                return xcalloc(1, 1);
        } else if (textconv) {
                struct diff_filespec *df = alloc_filespec(path);
-               fill_filespec(df, sha1, mode);
+               fill_filespec(df, sha1, 1, mode);
                *size = fill_textconv(textconv, df, &blob);
                free_filespec(df);
        } else {
@@ -823,7 +823,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                                                   &result_size, NULL, NULL);
                } else if (textconv) {
                        struct diff_filespec *df = alloc_filespec(elem->path);
-                       fill_filespec(df, null_sha1, st.st_mode);
+                       fill_filespec(df, null_sha1, 0, st.st_mode);
                        result_size = fill_textconv(textconv, df, &result);
                        free_filespec(df);
                } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
index 6d16c8f..bbb038d 100644 (file)
@@ -59,6 +59,7 @@ char *git_terminal_prompt(const char *prompt, int echo)
 
        r = strbuf_getline(&buf, fh, '\n');
        if (!echo) {
+               fseek(fh, SEEK_CUR, 0);
                putc('\n', fh);
                fflush(fh);
        }
diff --git a/contrib/ciabot/INSTALL b/contrib/ciabot/INSTALL
new file mode 100644 (file)
index 0000000..7222961
--- /dev/null
@@ -0,0 +1,54 @@
+= Installation instructions =
+
+Two scripts are included.  The Python one (ciabot.py) is faster and
+more capable; the shell one (ciabot.sh) is a fallback in case Python
+gives your git hosting site indigestion. (I know of no such sites.)
+
+It is no longer necessary to modify the script in order to put it
+in place; in fact, this is now discouraged. It is entirely
+configurable with the following git config variables:
+
+ciabot.project = name of the project
+ciabot.repo = name of the project repo for gitweb/cgit purposes
+ciabot.xmlrpc  = if true, ship notifications via XML-RPC
+ciabot.revformat = format in which the revision is shown
+
+The revformat variable may have the following values
+raw -> full hex ID of commit
+short -> first 12 chars of hex ID
+describe -> describe relative to last tag, falling back to short
+
+ciabot.project defaults to the directory name of the repository toplevel.
+ciabot.repo defaults to ciabot.project lowercased.
+ciabot.xmlrpc defaults to True
+ciabot.revformat defaults to 'describe'.
+
+This means that in the normal case you need not do any configuration at all,
+however setting ciabot.project will allow the hook to run slightly faster.
+
+Once you've set these variables, try your script with -n to see the
+notification message dumped to stdout and verify that it looks sane.
+
+To live-test these scripts, your project needs to have been registered with
+the CIA site.  Here are the steps:
+
+1. Open an IRC window on irc://freenode/commits or your registered
+   project IRC channel.
+
+2. Run ciabot.py and/or ciabot.sh from any directory under git
+   control.
+
+You should see a notification on the channel for your most recent commit.
+
+After verifying correct function, install one of these scripts either
+in a post-commit hook or in an update hook.
+
+In post-commit, run it without arguments. It will query for
+current HEAD and the latest commit ID to get the information it
+needs.
+
+In update, call it with a refname followed by a list of commits:
+You want to reverse the order git rev-list emits because it lists
+from most recent to oldest.
+
+/path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
index 3b916ac..2dfe1f9 100644 (file)
@@ -8,5 +8,4 @@ You probably want the Python version; it's faster, more capable, and
 better documented.  The shell version is maintained only as a fallback
 for use on hosting sites that don't permit Python hook scripts.
 
-You will find installation instructions for each script in its comment
-header.
+See the file INSTALL for installation instructions.
index 9775dff..bd24395 100755 (executable)
 # usage: ciabot.py [-V] [-n] [-p projectname]  [refname [commits...]]
 #
 # This script is meant to be run either in a post-commit hook or in an
-# update hook.  If there's nothing unusual about your hosting setup,
-# you can specify the project name with a -p option and avoid having
-# to modify this script.  Try it with -n to see the notification mail
-# dumped to stdout and verify that it looks sane. With -V it dumps its
-# version and exits.
+# update hook. Try it with -n to see the notification mail dumped to
+# stdout and verify that it looks sane. With -V it dumps its version
+# and exits.
 #
-# In post-commit, run it without arguments (other than possibly a -p
-# option). It will query for current HEAD and the latest commit ID to
-# get the information it needs.
+# In post-commit, run it without arguments. It will query for
+# current HEAD and the latest commit ID to get the information it
+# needs.
 #
 # In update, call it with a refname followed by a list of commits:
-# You want to reverse the order git rev-list emits becxause it lists
+# You want to reverse the order git rev-list emits because it lists
 # from most recent to oldest.
 #
 # /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
 #
-# Note: this script uses mail, not XML-RPC, in order to avoid stalling
-# until timeout when the CIA XML-RPC server is down.
+# Configuration variables affecting this script:
 #
-
+# ciabot.project = name of the project
+# ciabot.repo = name of the project repo for gitweb/cgit purposes
+# ciabot.xmlrpc  = if true (default), ship notifications via XML-RPC
+# ciabot.revformat = format in which the revision is shown
 #
-# The project as known to CIA. You will either want to change this
-# or invoke the script with a -p option to set it.
+# ciabot.project defaults to the directory name of the repository toplevel.
+# ciabot.repo defaults to ciabot.project lowercased.
 #
-project=None
-
+# This means that in the normal case you need not do any configuration at all,
+# but setting the project name will speed it up slightly.
 #
-# You may not need to change these:
+# The revformat variable may have the following values
+# raw -> full hex ID of commit
+# short -> first 12 chars of hex ID
+# describe = -> describe relative to last tag, falling back to short
+# The default is 'describe'.
+#
+# Note: the CIA project now says only XML-RPC is reliable, so
+# we default to that.
 #
-import os, sys, commands, socket, urllib
-
-# Name of the repository.
-# You can hardwire this to make the script faster.
-repo = os.path.basename(os.getcwd())
 
-# Fully-qualified domain name of this host.
-# You can hardwire this to make the script faster.
-host = socket.getfqdn()
+import os, sys, commands, socket, urllib
+from xml.sax.saxutils import escape
 
 # Changeset URL prefix for your repo: when the commit ID is appended
 # to this, it should point at a CGI that will display the commit
@@ -72,7 +73,7 @@ xml = '''\
 <message>
   <generator>
     <name>CIA Python client for Git</name>
-    <version>%(gitver)s</version>
+    <version>%(version)s</version>
     <url>%(generator)s</url>
   </generator>
   <source>
@@ -98,19 +99,18 @@ xml = '''\
 # No user-serviceable parts below this line:
 #
 
-# Addresses for the e-mail. The from address is a dummy, since CIA
-# will never reply to this mail.
-fromaddr = "CIABOT-NOREPLY@" + host
-toaddr = "cia@cia.navi.cx"
+# Where to ship e-mail notifications.
+toaddr = "cia@cia.vc"
 
 # Identify the generator script.
 # Should only change when the script itself gets a new home and maintainer.
-generator="http://www.catb.org/~esr/ciabot.py"
+generator = "http://www.catb.org/~esr/ciabot.py"
+version = "3.6"
 
 def do(command):
     return commands.getstatusoutput(command)[1]
 
-def report(refname, merged):
+def report(refname, merged, xmlrpc=True):
     "Generate a commit notification to be reported to CIA"
 
     # Try to tinyfy a reference to a web view for this commit.
@@ -121,32 +121,27 @@ def report(refname, merged):
 
     branch = os.path.basename(refname)
 
-    # Compute a shortnane for the revision
-    rev = do("git describe '"+ merged +"' 2>/dev/null") or merged[:12]
-
-    # Extract the neta-information for the commit
-    rawcommit = do("git cat-file commit " + merged)
+    # Compute a description for the revision
+    if revformat == 'raw':
+        rev = merged
+    elif revformat == 'short':
+        rev = ''
+    else: # revformat == 'describe'
+        rev = do("git describe %s 2>/dev/null" % merged)
+    if not rev:
+        rev = merged[:12]
+
+    # Extract the meta-information for the commit
     files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'")
-    inheader = True
-    headers = {}
-    logmsg = ""
-    for line in rawcommit.split("\n"):
-        if inheader:
-            if line:
-                fields = line.split()
-                headers[fields[0]] = " ".join(fields[1:])
-            else:
-                inheader = False
-        else:
-            logmsg = line
-            break
-    (author, ts) = headers["author"].split(">")
+    metainfo = do("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged)
+    (author, ts, logmsg) = metainfo.split("\n")
+    logmsg = escape(logmsg)
 
-    # This discards the part of the authors addrsss after @.
-    # Might be bnicece to ship the full email address, if not
+    # This discards the part of the author's address after @.
+    # Might be be nice to ship the full email address, if not
     # for spammers' address harvesters - getting this wrong
     # would make the freenode #commits channel into harvester heaven.
-    author = author.replace("<", "").split("@")[0].split()[-1]
+    author = escape(author.replace("<", "").split("@")[0].split()[-1])
 
     # This ignores the timezone.  Not clear what to do with it...
     ts = ts.strip().split()[0]
@@ -155,8 +150,7 @@ def report(refname, merged):
     context.update(globals())
 
     out = xml % context
-
-    message = '''\
+    mail = '''\
 Message-ID: <%(merged)s.%(author)s@%(project)s>
 From: %(fromaddr)s
 To: %(toaddr)s
@@ -165,34 +159,56 @@ Subject: DeliverXML
 
 %(out)s''' % locals()
 
-    return message
+    if xmlrpc:
+        return out
+    else:
+        return mail
 
 if __name__ == "__main__":
     import getopt
 
+    # Get all config variables
+    revformat = do("git config --get ciabot.revformat")
+    project = do("git config --get ciabot.project")
+    repo = do("git config --get ciabot.repo")
+    xmlrpc = do("git config --get ciabot.xmlrpc")
+    xmlrpc = not (xmlrpc and xmlrpc == "false")
+
+    host = socket.getfqdn()
+    fromaddr = "CIABOT-NOREPLY@" + host
+
     try:
-        (options, arguments) = getopt.getopt(sys.argv[1:], "np:V")
+        (options, arguments) = getopt.getopt(sys.argv[1:], "np:xV")
     except getopt.GetoptError, msg:
         print "ciabot.py: " + str(msg)
         raise SystemExit, 1
 
-    mailit = True
+    notify = True
     for (switch, val) in options:
         if switch == '-p':
             project = val
         elif switch == '-n':
-            mailit = False
+            notify = False
+        elif switch == '-x':
+            xmlrpc = True
         elif switch == '-V':
-            print "ciabot.py: version 3.2"
+            print "ciabot.py: version", version
             sys.exit(0)
 
-    # Cough and die if user has not specified a project
+    # The project variable defaults to the name of the repository toplevel.
     if not project:
-        sys.stderr.write("ciabot.py: no project specified, bailing out.\n")
-        sys.exit(1)
-
-    # We'll need the git version number.
-    gitver = do("git --version").split()[0]
+        here = os.getcwd()
+        while True:
+            if os.path.exists(os.path.join(here, ".git")):
+                project = os.path.basename(here)
+                break
+            elif here == '/':
+                sys.stderr.write("ciabot.py: no .git below root!\n")
+                sys.exit(1)
+            here = os.path.dirname(here)
+
+    if not repo:
+        repo = project.lower()
 
     urlprefix = urlprefix % globals()
 
@@ -205,18 +221,29 @@ if __name__ == "__main__":
         refname = arguments[0]
         merges = arguments[1:]
 
-    if mailit:
-        import smtplib
-        server = smtplib.SMTP('localhost')
+    if notify:
+        if xmlrpc:
+            import xmlrpclib
+            server = xmlrpclib.Server('http://cia.vc/RPC2');
+        else:
+            import smtplib
+            server = smtplib.SMTP('localhost')
 
     for merged in merges:
-        message = report(refname, merged)
-        if mailit:
-            server.sendmail(fromaddr, [toaddr], message)
-        else:
+        message = report(refname, merged, xmlrpc)
+        if not notify:
             print message
+        elif xmlrpc:
+            try:
+                # RPC server is flaky, this can fail due to timeout.
+                server.hub.deliver(message)
+            except socket.error, e:
+                sys.stderr.write("%s\n" % e)
+        else:
+            server.sendmail(fromaddr, [toaddr], message)
 
-    if mailit:
-        server.quit()
+    if notify:
+        if not xmlrpc:
+            server.quit()
 
 #End
index eb87bba..3fbbc53 100755 (executable)
@@ -3,6 +3,8 @@
 # Copyright (c) 2006 Fernando J. Pereda <ferdy@gentoo.org>
 # Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
 # Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
+# Assistance and review by Petr Baudis, author of ciabot.pl,
+# is gratefully acknowledged.
 #
 # This is a version 3.x of ciabot.sh; use -V to find the exact
 # version.  Versions 1 and 2 were shipped in 2006 and 2008 and are not
@@ -11,6 +13,7 @@
 # Note: This script should be considered obsolete.
 # There is a faster, better-documented rewrite in Python: find it as ciabot.py
 # Use this only if your hosting site forbids Python hooks.
+# It requires: git(1), hostname(1), cut(1), sendmail(1), and wget(1).
 #
 # Originally based on Git ciabot.pl by Petr Baudis.
 # This script contains porcelain and porcelain byproducts.
 # usage: ciabot.sh [-V] [-n] [-p projectname] [refname commit]
 #
 # This script is meant to be run either in a post-commit hook or in an
-# update hook.  If there's nothing unusual about your hosting setup,
-# you can specify the project name with a -p option and avoid having
-# to modify this script.  Try it with -n first to see the notification
-# mail dumped to stdout and verify that it looks sane.  Use -V to dump
-# the version and exit.
+# update hook. Try it with -n to see the notification mail dumped to
+# stdout and verify that it looks sane. With -V it dumps its version
+# and exits.
 #
-# In post-commit, run it without arguments (other than possibly a -p
-# option). It will query for current HEAD and the latest commit ID to
-# get the information it needs.
+# In post-commit, run it without arguments. It will query for
+# current HEAD and the latest commit ID to get the information it
+# needs.
 #
 # In update, you have to call it once per merged commit:
 #
 #       oldhead=$2
 #       newhead=$3
 #       for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do
-#               /path/to/ciabot.bash ${refname} ${merged}
+#               /path/to/ciabot.sh ${refname} ${merged}
 #       done
 #
-# The reason for the tac call ids that git rev-list emits commits from
+# The reason for the tac call is that git rev-list emits commits from
 # most recent to least - better to ship notifactions from oldest to newest.
 #
-# Note: this script uses mail, not XML-RPC, in order to avoid stalling
-# until timeout when the CIA XML-RPC server is down.
+# Configuration variables affecting this script:
 #
-
+# ciabot.project = name of the project
+# ciabot.repo = name of the project repo for gitweb/cgit purposes
+# ciabot.revformat = format in which the revision is shown
 #
-# The project as known to CIA. You will either want to change this
-# or set the project name with a -p option.
+# ciabot.project defaults to the directory name of the repository toplevel.
+# ciabot.repo defaults to ciabot.project lowercased.
 #
-project=
-
+# This means that in the normal case you need not do any configuration at all,
+# but setting the project name will speed it up slightly.
 #
-# You may not need to change these:
+# The revformat variable may have the following values
+# raw -> full hex ID of commit
+# short -> first 12 chars of hex ID
+# describe = -> describe relative to last tag, falling back to short
+# The default is 'describe'.
 #
+# Note: the shell ancestors of this script used mail, not XML-RPC, in
+# order to avoid stalling until timeout when the CIA XML-RPC server is
+# down. It is unknown whether this is still an issue in 2010, but
+# XML-RPC would be annoying to do from sh in any case. (XML-RPC does
+# have the advantage that it guarantees notification of multiple commits
+# shpped from an update in their actual order.)
+#
+
+# The project as known to CIA. You can set this with a -p option,
+# or let it default to the directory name of the repo toplevel.
+project=$(git config --get ciabot.project)
+
+if [ -z $project ]
+then
+    here=`pwd`;
+    while :; do
+       if [ -d $here/.git ]
+       then
+           project=`basename $here`
+           break
+       elif [ $here = '/' ]
+       then
+           echo "ciabot.sh: no .git below root!"
+           exit 1
+       fi
+       here=`dirname $here`
+    done
+fi
 
-# Name of the repository.
-# You can hardwire this to make the script faster.
-repo="`basename ${PWD}`"
+# Name of the repo for gitweb/cgit purposes
+repo=$(git config --get ciabot.repo)
+[ -z $repo] && repo=$(echo "${project}" | tr '[A-Z]' '[a-z]')
 
-# Fully qualified domain name of the repo host.
-# You can hardwire this to make the script faster.
-host=`hostname --fqdn`
+# What revision format do we want in the summary?
+revformat=$(git config --get ciabot.revformat)
+
+# Fully qualified domain name of the repo host.  You can hardwire this
+# to make the script faster. The -f option works under Linux and FreeBSD,
+# but not OpenBSD and NetBSD. But under OpenBSD and NetBSD,
+# hostname without options gives the FQDN.
+if hostname -f >/dev/null 2>&1
+then
+    hostname=`hostname -f`
+else
+    hostname=`hostname`
+fi
 
 # Changeset URL prefix for your repo: when the commit ID is appended
 # to this, it should point at a CGI that will display the commit
@@ -73,13 +117,14 @@ urlprefix="http://${host}/cgi-bin/cgit.cgi/${repo}/commit/?id="
 # You probably will not need to change the following:
 #
 
-# Identify the script. Should change only when the script itself
-# gets a new home and maintainer.
+# Identify the script. The 'generator' variable should change only
+# when the script itself gets a new home and maintainer.
 generator="http://www.catb.org/~esr/ciabot/ciabot.sh"
+version=3.5
 
 # Addresses for the e-mail
-from="CIABOT-NOREPLY@${host}"
-to="cia@cia.navi.cx"
+from="CIABOT-NOREPLY@${hostname}"
+to="cia@cia.vc"
 
 # SMTP client to use - may need to edit the absolute pathname for your system
 sendmail="sendmail -t -f ${from}"
@@ -97,7 +142,7 @@ do
     case $opt in
        p) project=$2; shift ; shift ;;
        n) mode=dumpit; shift ;;
-       V) echo "ciabot.sh: version 3.2"; exit 0; shift ;;
+       V) echo "ciabot.sh: version $version"; exit 0; shift ;;
     esac
 done
 
@@ -128,33 +173,29 @@ fi
 
 refname=${refname##refs/heads/}
 
-gitver=$(git --version)
-gitver=${gitver##* }
-
-rev=$(git describe ${merged} 2>/dev/null)
-# ${merged:0:12} was the only bashism left in the 2008 version of this
-# script, according to checkbashisms.  Replace it with ${merged} here
-# because it was just a fallback anyway, and it's worth accepting a
-# longer fallback for faster execution and removing the bash
-# dependency.
-[ -z ${rev} ] && rev=${merged}
+case $revformat in
+raw) rev=$merged ;;
+short) rev='' ;;
+*) rev=$(git describe ${merged} 2>/dev/null) ;;
+esac
+[ -z ${rev} ] && rev=$(echo "$merged" | cut -c 1-12)
 
-# This discards the part of the author's address after @.
+# We discard the part of the author's address after @.
 # Might be nice to ship the full email address, if not
 # for spammers' address harvesters - getting this wrong
 # would make the freenode #commits channel into harvester heaven.
-rawcommit=$(git cat-file commit ${merged})
-author=$(echo "$rawcommit" | sed -n -e '/^author .*<\([^@]*\).*$/s--\1-p')
-logmessage=$(echo "$rawcommit" | sed -e '1,/^$/d' | head -n 1)
-logmessage=$(echo "$logmessage" | sed 's/\&/&amp\;/g; s/</&lt\;/g; s/>/&gt\;/g')
-ts=$(echo "$rawcommit" | sed -n -e '/^author .*> \([0-9]\+\).*$/s--\1-p')
+author=$(git log -1 '--pretty=format:%an <%ae>' $merged)
+author=$(echo "$author" | sed -n -e '/^.*<\([^@]*\).*$/s--\1-p')
+
+logmessage=$(git log -1 '--pretty=format:%s' $merged)
+ts=$(git log -1 '--pretty=format:%at' $merged)
 files=$(git diff-tree -r --name-only ${merged} | sed -e '1d' -e 's-.*-<file>&</file>-')
 
 out="
 <message>
   <generator>
     <name>CIA Shell client for Git</name>
-    <version>${gitver}</version>
+    <version>${version}</version>
     <url>${generator}</url>
   </generator>
   <source>
index fc0dff3..f35de0f 100644 (file)
@@ -206,7 +206,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                        if (silent_on_removed)
                                continue;
                        diff_addremove(&revs->diffopt, '-', ce->ce_mode,
-                                      ce->sha1, ce->name, 0);
+                                      ce->sha1, !is_null_sha1(ce->sha1),
+                                      ce->name, 0);
                        continue;
                }
                changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
@@ -220,6 +221,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                newmode = ce_mode_from_stat(ce, st.st_mode);
                diff_change(&revs->diffopt, oldmode, newmode,
                            ce->sha1, (changed ? null_sha1 : ce->sha1),
+                           !is_null_sha1(ce->sha1), (changed ? 0 : !is_null_sha1(ce->sha1)),
                            ce->name, 0, dirty_submodule);
 
        }
@@ -236,11 +238,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 static void diff_index_show_file(struct rev_info *revs,
                                 const char *prefix,
                                 struct cache_entry *ce,
-                                const unsigned char *sha1, unsigned int mode,
+                                const unsigned char *sha1, int sha1_valid,
+                                unsigned int mode,
                                 unsigned dirty_submodule)
 {
        diff_addremove(&revs->diffopt, prefix[0], mode,
-                      sha1, ce->name, dirty_submodule);
+                      sha1, sha1_valid, ce->name, dirty_submodule);
 }
 
 static int get_stat_data(struct cache_entry *ce,
@@ -295,7 +298,7 @@ static void show_new_file(struct rev_info *revs,
            &dirty_submodule, &revs->diffopt) < 0)
                return;
 
-       diff_index_show_file(revs, "+", new, sha1, mode, dirty_submodule);
+       diff_index_show_file(revs, "+", new, sha1, !is_null_sha1(sha1), mode, dirty_submodule);
 }
 
 static int show_modified(struct rev_info *revs,
@@ -312,7 +315,7 @@ static int show_modified(struct rev_info *revs,
                          &dirty_submodule, &revs->diffopt) < 0) {
                if (report_missing)
                        diff_index_show_file(revs, "-", old,
-                                            old->sha1, old->ce_mode, 0);
+                                            old->sha1, 1, old->ce_mode, 0);
                return -1;
        }
 
@@ -347,7 +350,8 @@ static int show_modified(struct rev_info *revs,
                return 0;
 
        diff_change(&revs->diffopt, oldmode, mode,
-                   old->sha1, sha1, old->name, 0, dirty_submodule);
+                   old->sha1, sha1, 1, !is_null_sha1(sha1),
+                   old->name, 0, dirty_submodule);
        return 0;
 }
 
@@ -380,7 +384,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
                struct diff_filepair *pair;
                pair = diff_unmerge(&revs->diffopt, idx->name);
                if (tree)
-                       fill_filespec(pair->one, tree->sha1, tree->ce_mode);
+                       fill_filespec(pair->one, tree->sha1, 1, tree->ce_mode);
                return;
        }
 
@@ -396,7 +400,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
         * Something removed from the tree?
         */
        if (!idx) {
-               diff_index_show_file(revs, "-", tree, tree->sha1, tree->ce_mode, 0);
+               diff_index_show_file(revs, "-", tree, tree->sha1, 1, tree->ce_mode, 0);
                return;
        }
 
index 7d805a0..74da659 100644 (file)
@@ -82,7 +82,7 @@ static struct diff_filespec *noindex_filespec(const char *name, int mode)
        if (!name)
                name = "/dev/null";
        s = alloc_filespec(name);
-       fill_filespec(s, null_sha1, mode);
+       fill_filespec(s, null_sha1, 0, mode);
        if (name == file_from_standard_input)
                populate_from_stdin(s);
        return s;
@@ -258,8 +258,7 @@ void diff_no_index(struct rev_info *revs,
        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 
        revs->max_count = -2;
-       if (diff_setup_done(&revs->diffopt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&revs->diffopt);
 
        setup_diff_pager(&revs->diffopt);
        DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
diff --git a/diff.c b/diff.c
index 62cbe14..f1b0447 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -574,6 +574,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
        if (!endp) {
                const char *plain = diff_get_color(ecb->color_diff,
                                                   DIFF_PLAIN);
+               putc('\n', ecb->opt->file);
                emit_line_0(ecb->opt, plain, reset, '\\',
                            nneof, strlen(nneof));
        }
@@ -2541,12 +2542,12 @@ void free_filespec(struct diff_filespec *spec)
 }
 
 void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
-                  unsigned short mode)
+                  int sha1_valid, unsigned short mode)
 {
        if (mode) {
                spec->mode = canon_mode(mode);
                hashcpy(spec->sha1, sha1);
-               spec->sha1_valid = !is_null_sha1(sha1);
+               spec->sha1_valid = sha1_valid;
        }
 }
 
@@ -3187,7 +3188,7 @@ void diff_setup(struct diff_options *options)
        }
 }
 
-int diff_setup_done(struct diff_options *options)
+void diff_setup_done(struct diff_options *options)
 {
        int count = 0;
 
@@ -3286,8 +3287,6 @@ int diff_setup_done(struct diff_options *options)
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        }
-
-       return 0;
 }
 
 static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
@@ -4693,6 +4692,7 @@ static int is_submodule_ignored(const char *path, struct diff_options *options)
 void diff_addremove(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    const char *concatpath, unsigned dirty_submodule)
 {
        struct diff_filespec *one, *two;
@@ -4724,9 +4724,9 @@ void diff_addremove(struct diff_options *options,
        two = alloc_filespec(concatpath);
 
        if (addremove != '+')
-               fill_filespec(one, sha1, mode);
+               fill_filespec(one, sha1, sha1_valid, mode);
        if (addremove != '-') {
-               fill_filespec(two, sha1, mode);
+               fill_filespec(two, sha1, sha1_valid, mode);
                two->dirty_submodule = dirty_submodule;
        }
 
@@ -4739,6 +4739,7 @@ void diff_change(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
+                int old_sha1_valid, int new_sha1_valid,
                 const char *concatpath,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule)
 {
@@ -4753,6 +4754,8 @@ void diff_change(struct diff_options *options,
                const unsigned char *tmp_c;
                tmp = old_mode; old_mode = new_mode; new_mode = tmp;
                tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
+               tmp = old_sha1_valid; old_sha1_valid = new_sha1_valid;
+                       new_sha1_valid = tmp;
                tmp = old_dirty_submodule; old_dirty_submodule = new_dirty_submodule;
                        new_dirty_submodule = tmp;
        }
@@ -4763,8 +4766,8 @@ void diff_change(struct diff_options *options,
 
        one = alloc_filespec(concatpath);
        two = alloc_filespec(concatpath);
-       fill_filespec(one, old_sha1, old_mode);
-       fill_filespec(two, new_sha1, new_mode);
+       fill_filespec(one, old_sha1, old_sha1_valid, old_mode);
+       fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
        one->dirty_submodule = old_dirty_submodule;
        two->dirty_submodule = new_dirty_submodule;
 
diff --git a/diff.h b/diff.h
index e027650..e25addb 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -19,12 +19,14 @@ typedef void (*change_fn_t)(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
+                int old_sha1_valid, int new_sha1_valid,
                 const char *fullpath,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule);
 
 typedef void (*add_remove_fn_t)(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    const char *fullpath, unsigned dirty_submodule);
 
 typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
@@ -214,12 +216,15 @@ extern void diff_addremove(struct diff_options *,
                           int addremove,
                           unsigned mode,
                           const unsigned char *sha1,
+                          int sha1_valid,
                           const char *fullpath, unsigned dirty_submodule);
 
 extern void diff_change(struct diff_options *,
                        unsigned mode1, unsigned mode2,
                        const unsigned char *sha1,
                        const unsigned char *sha2,
+                       int sha1_valid,
+                       int sha2_valid,
                        const char *fullpath,
                        unsigned dirty_submodule1, unsigned dirty_submodule2);
 
@@ -241,7 +246,7 @@ extern int git_diff_ui_config(const char *var, const char *value, void *cb);
 extern int diff_use_color_default;
 extern void diff_setup(struct diff_options *);
 extern int diff_opt_parse(struct diff_options *, const char **, int);
-extern int diff_setup_done(struct diff_options *);
+extern void diff_setup_done(struct diff_options *);
 
 #define DIFF_DETECT_RENAME     1
 #define DIFF_DETECT_COPY       2
index 216a7a4..512d0ac 100644 (file)
@@ -48,7 +48,7 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
                memmove(rename_dst + first + 1, rename_dst + first,
                        (rename_dst_nr - first - 1) * sizeof(*rename_dst));
        rename_dst[first].two = alloc_filespec(two->path);
-       fill_filespec(rename_dst[first].two, two->sha1, two->mode);
+       fill_filespec(rename_dst[first].two, two->sha1, two->sha1_valid, two->mode);
        rename_dst[first].pair = NULL;
        return &(rename_dst[first]);
 }
index be0739c..1c16c85 100644 (file)
@@ -55,7 +55,7 @@ struct diff_filespec {
 extern struct diff_filespec *alloc_filespec(const char *);
 extern void free_filespec(struct diff_filespec *);
 extern void fill_filespec(struct diff_filespec *, const unsigned char *,
-                         unsigned short);
+                         int, unsigned short);
 
 extern int diff_populate_filespec(struct diff_filespec *, int);
 extern void diff_free_filespec_data(struct diff_filespec *);
diff --git a/fsck.c b/fsck.c
index 4c63b2c..7395ef6 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -139,6 +139,7 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con
 static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
 {
        int retval;
+       int has_null_sha1 = 0;
        int has_full_path = 0;
        int has_empty_name = 0;
        int has_zero_pad = 0;
@@ -157,9 +158,12 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        while (desc.size) {
                unsigned mode;
                const char *name;
+               const unsigned char *sha1;
 
-               tree_entry_extract(&desc, &name, &mode);
+               sha1 = tree_entry_extract(&desc, &name, &mode);
 
+               if (is_null_sha1(sha1))
+                       has_null_sha1 = 1;
                if (strchr(name, '/'))
                        has_full_path = 1;
                if (!*name)
@@ -207,6 +211,8 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        }
 
        retval = 0;
+       if (has_null_sha1)
+               retval += error_func(&item->object, FSCK_WARN, "contains entries pointing to null sha1");
        if (has_full_path)
                retval += error_func(&item->object, FSCK_WARN, "contains full pathnames");
        if (has_empty_name)
index 0c19b7c..8492678 100644 (file)
@@ -548,11 +548,10 @@ do_next () {
        test -s "$todo" && return
 
        comment_for_reflog finish &&
-       shortonto=$(git rev-parse --short $onto) &&
        newhead=$(git rev-parse HEAD) &&
        case $head_name in
        refs/*)
-               message="$GIT_REFLOG_ACTION: $head_name onto $shortonto" &&
+               message="$GIT_REFLOG_ACTION: $head_name onto $onto" &&
                git update-ref -m "$message" $head_name $newhead $orig_head &&
                git symbolic-ref \
                  -m "$GIT_REFLOG_ACTION: returning to $head_name" \
index ef30c55..6647137 100755 (executable)
@@ -862,11 +862,13 @@ $time = time - scalar $#files;
 sub unquote_rfc2047 {
        local ($_) = @_;
        my $encoding;
-       if (s/=\?([^?]+)\?q\?(.*)\?=/$2/g) {
+       s{=\?([^?]+)\?q\?(.*?)\?=}{
                $encoding = $1;
-               s/_/ /g;
-               s/=([0-9A-F]{2})/chr(hex($1))/eg;
-       }
+               my $e = $2;
+               $e =~ s/_/ /g;
+               $e =~ s/=([0-9A-F]{2})/chr(hex($1))/eg;
+               $e;
+       }eg;
        return wantarray ? ($_, $encoding) : $_;
 }
 
index 770a86e..ee0e0bc 100644 (file)
@@ -9,8 +9,12 @@
 # you would cause "cd" to be taken to unexpected places.  If you
 # like CDPATH, define it for your interactive shell sessions without
 # exporting it.
+# But we protect ourselves from such a user mistake nevertheless.
 unset CDPATH
 
+# Similarly for IFS
+unset IFS
+
 git_broken_path_fix () {
        case ":$PATH:" in
        *:$1:*) : ok ;;
index 4e2c7f8..bbefdf6 100755 (executable)
@@ -469,6 +469,7 @@ apply_stash () {
        else
                # Merge conflict; keep the exit status from merge-recursive
                status=$?
+               git rerere
                if test -n "$INDEX_OPTION"
                then
                        gettextln "Index was not unstashed." >&2
index 30fa93a..e89b516 100755 (executable)
@@ -73,26 +73,48 @@ resolve_relative_url ()
 #
 module_list()
 {
-       git ls-files --error-unmatch --stage -- "$@" |
+       (
+               git ls-files --error-unmatch --stage -- "$@" ||
+               echo "unmatched pathspec exists"
+       ) |
        perl -e '
        my %unmerged = ();
        my ($null_sha1) = ("0" x 40);
+       my @out = ();
+       my $unmatched = 0;
        while (<STDIN>) {
+               if (/^unmatched pathspec/) {
+                       $unmatched = 1;
+                       next;
+               }
                chomp;
                my ($mode, $sha1, $stage, $path) =
                        /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/;
                next unless $mode eq "160000";
                if ($stage ne "0") {
                        if (!$unmerged{$path}++) {
-                               print "$mode $null_sha1 U\t$path\n";
+                               push @out, "$mode $null_sha1 U\t$path\n";
                        }
                        next;
                }
-               print "$_\n";
+               push @out, "$_\n";
+       }
+       if ($unmatched) {
+               print "#unmatched\n";
+       } else {
+               print for (@out);
        }
        '
 }
 
+die_if_unmatched ()
+{
+       if test "$1" = "#unmatched"
+       then
+               exit 1
+       fi
+}
+
 #
 # Map submodule path to submodule name
 #
@@ -346,6 +368,7 @@ cmd_foreach()
        module_list |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                if test -e "$sm_path"/.git
                then
                        say "$(eval_gettext "Entering '\$prefix\$sm_path'")"
@@ -398,6 +421,7 @@ cmd_init()
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
 
                # Copy url setting when it is not set yet
@@ -498,6 +522,7 @@ cmd_update()
        err=
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                if test "$stage" = U
                then
                        echo >&2 "Skipping unmerged submodule $sm_path"
@@ -539,7 +564,7 @@ Maybe you want to use 'update --init'?")"
                        die "$(eval_gettext "Unable to find current revision in submodule path '\$sm_path'")"
                fi
 
-               if test "$subsha1" != "$sha1"
+               if test "$subsha1" != "$sha1" -o -n "$force"
                then
                        subforce=$force
                        # If we don't already have a -f flag and the submodule has never been checked out
@@ -893,6 +918,7 @@ cmd_status()
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
                url=$(git config submodule."$name".url)
                displaypath="$prefix$sm_path"
@@ -961,6 +987,7 @@ cmd_sync()
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path")
                url=$(git config -f .gitmodules --get submodule."$name".url)
 
index 55e0e9e..a40ed0c 100755 (executable)
@@ -54,6 +54,11 @@ sub evaluate_uri {
        # to build the base URL ourselves:
        our $path_info = decode_utf8($ENV{"PATH_INFO"});
        if ($path_info) {
+               # $path_info has already been URL-decoded by the web server, but
+               # $my_url and $my_uri have not. URL-decode them so we can properly
+               # strip $path_info.
+               $my_url = unescape($my_url);
+               $my_uri = unescape($my_uri);
                if ($my_url =~ s,\Q$path_info\E$,, &&
                    $my_uri =~ s,\Q$path_info\E$,, &&
                    defined $ENV{'SCRIPT_NAME'}) {
index 680937c..e02da35 100644 (file)
@@ -493,8 +493,7 @@ static struct string_list *get_renames(struct merge_options *o,
        opts.rename_score = o->rename_score;
        opts.show_rename_progress = o->show_rename_progress;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opts) < 0)
-               die("diff setup failed");
+       diff_setup_done(&opts);
        diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
        diffcore_std(&opts);
        if (opts.needed_rename_limit > o->needed_rename_limit)
@@ -614,23 +613,6 @@ static char *unique_path(struct merge_options *o, const char *path, const char *
        return newpath;
 }
 
-static void flush_buffer(int fd, const char *buf, unsigned long size)
-{
-       while (size > 0) {
-               long ret = write_in_full(fd, buf, size);
-               if (ret < 0) {
-                       /* Ignore epipe */
-                       if (errno == EPIPE)
-                               break;
-                       die_errno("merge-recursive");
-               } else if (!ret) {
-                       die("merge-recursive: disk full?");
-               }
-               size -= ret;
-               buf += ret;
-       }
-}
-
 static int dir_in_way(const char *path, int check_working_copy)
 {
        int pos, pathlen = strlen(path);
@@ -789,7 +771,7 @@ static void update_file_flags(struct merge_options *o,
                        fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
                        if (fd < 0)
                                die_errno("failed to open '%s'", path);
-                       flush_buffer(fd, buf, size);
+                       write_in_full(fd, buf, size);
                        close(fd);
                } else if (S_ISLNK(mode)) {
                        char *lnk = xmemdupz(buf, size);
index 74aa77c..7d62904 100644 (file)
@@ -126,8 +126,7 @@ static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
        diff_setup(&opt);
        DIFF_OPT_SET(&opt, RECURSIVE);
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&opt);
        diff_tree_sha1(base, remote, "", &opt);
        diffcore_std(&opt);
 
@@ -190,8 +189,7 @@ static void diff_tree_local(struct notes_merge_options *o,
        diff_setup(&opt);
        DIFF_OPT_SET(&opt, RECURSIVE);
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&opt);
        diff_tree_sha1(base, local, "", &opt);
        diffcore_std(&opt);
 
index 5717257..bc8a28f 100644 (file)
@@ -39,8 +39,7 @@ int init_patch_ids(struct patch_ids *ids)
        memset(ids, 0, sizeof(*ids));
        diff_setup(&ids->diffopts);
        DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
-       if (diff_setup_done(&ids->diffopts) < 0)
-               return error("diff_setup_done failed");
+       diff_setup_done(&ids->diffopts);
        return 0;
 }
 
index b645827..d8543e4 100644 (file)
@@ -1409,11 +1409,9 @@ int read_index_from(struct index_state *istate, const char *path)
        size_t mmap_size;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 
-       errno = EBUSY;
        if (istate->initialized)
                return istate->cache_nr;
 
-       errno = ENOENT;
        istate->timestamp.sec = 0;
        istate->timestamp.nsec = 0;
        fd = open(path, O_RDONLY);
@@ -1426,15 +1424,14 @@ int read_index_from(struct index_state *istate, const char *path)
        if (fstat(fd, &st))
                die_errno("cannot stat the open index");
 
-       errno = EINVAL;
        mmap_size = xsize_t(st.st_size);
        if (mmap_size < sizeof(struct cache_header) + 20)
                die("index file smaller than expected");
 
        mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
-       close(fd);
        if (mmap == MAP_FAILED)
                die_errno("unable to map index file");
+       close(fd);
 
        hdr = mmap;
        if (verify_hdr(hdr, mmap_size) < 0)
@@ -1490,7 +1487,6 @@ int read_index_from(struct index_state *istate, const char *path)
 
 unmap:
        munmap(mmap, mmap_size);
-       errno = EINVAL;
        die("index file corrupt");
 }
 
@@ -1790,6 +1786,8 @@ int write_index(struct index_state *istate, int newfd)
                        continue;
                if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
                        ce_smudge_racily_clean_entry(ce);
+               if (is_null_sha1(ce->sha1))
+                       return error("cache entry has null sha1: %s", ce->name);
                if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
                        return -1;
        }
index 5b81a92..6d21ac7 100644 (file)
@@ -345,6 +345,7 @@ static int tree_difference = REV_TREE_SAME;
 static void file_add_remove(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    const char *fullpath, unsigned dirty_submodule)
 {
        int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD;
@@ -358,6 +359,7 @@ static void file_change(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
+                int old_sha1_valid, int new_sha1_valid,
                 const char *fullpath,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule)
 {
@@ -1853,8 +1855,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        if (revs->combine_merges)
                revs->ignore_merges = 0;
        revs->diffopt.abbrev = revs->abbrev;
-       if (diff_setup_done(&revs->diffopt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&revs->diffopt);
 
        compile_grep_patterns(&revs->grep_filter);
 
index 606791d..f9922b9 100644 (file)
@@ -139,6 +139,8 @@ int sane_execvp(const char *file, char * const argv[])
         */
        if (errno == EACCES && !strchr(file, '/'))
                errno = exists_in_PATH(file) ? EACCES : ENOENT;
+       else if (errno == ENOTDIR && !strchr(file, '/'))
+               errno = ENOENT;
        return -1;
 }
 
diff --git a/setup.c b/setup.c
index e114977..7663a4c 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -82,7 +82,7 @@ static void NORETURN die_verify_filename(const char *prefix,
 
        if (!diagnose_misspelt_rev)
                die("%s: no such path in the working tree.\n"
-                   "Use '-- <path>...' to specify paths that do not exist locally.",
+                   "Use 'git <command> -- <path>...' to specify paths that do not exist locally.",
                    arg);
        /*
         * Saying "'(icase)foo' does not exist in the index" when the
@@ -96,7 +96,8 @@ static void NORETURN die_verify_filename(const char *prefix,
 
        /* ... or fall back the most general message. */
        die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
-           "Use '--' to separate paths from revisions", arg);
+           "Use '--' to separate paths from revisions, like this:\n"
+           "'git <command> [<revision>...] -- [<file>...]'", arg);
 
 }
 
@@ -145,7 +146,8 @@ void verify_non_filename(const char *prefix, const char *arg)
        if (!check_filename(prefix, arg))
                return;
        die("ambiguous argument '%s': both revision and filename\n"
-           "Use '--' to separate filenames from revisions", arg);
+           "Use '--' to separate paths from revisions, like this:\n"
+           "'git <command> [<revision>...] -- [<file>...]'", arg);
 }
 
 /*
index 959d349..19dc6a6 100644 (file)
@@ -574,8 +574,7 @@ static void calculate_changed_submodule_paths(void)
                        DIFF_OPT_SET(&diff_opts, RECURSIVE);
                        diff_opts.output_format |= DIFF_FORMAT_CALLBACK;
                        diff_opts.format_callback = submodule_collect_changed_cb;
-                       if (diff_setup_done(&diff_opts) < 0)
-                               die("diff_setup_done failed");
+                       diff_setup_done(&diff_opts);
                        diff_tree_sha1(parent->item->object.sha1, commit->object.sha1, "", &diff_opts);
                        diffcore_std(&diff_opts);
                        diff_flush(&diff_opts);
index 5580c22..a1361e5 100644 (file)
@@ -163,7 +163,7 @@ test_perf () {
                else
                        echo "perf $test_count - $1:"
                fi
-               for i in $(seq 1 $GIT_PERF_REPEAT_COUNT); do
+               for i in $(test_seq 1 $GIT_PERF_REPEAT_COUNT); do
                        say >&3 "running: $2"
                        if test_run_perf_ "$2"
                        then
index 5b79c51..bf7a2cd 100755 (executable)
@@ -213,4 +213,30 @@ test_expect_success 'rev-list --verify-objects with bad sha1' '
        grep -q "error: sha1 mismatch 63ffffffffffffffffffffffffffffffffffffff" out
 '
 
+_bz='\0'
+_bz5="$_bz$_bz$_bz$_bz$_bz"
+_bz20="$_bz5$_bz5$_bz5$_bz5"
+
+test_expect_success 'fsck notices blob entry pointing to null sha1' '
+       (git init null-blob &&
+        cd null-blob &&
+        sha=$(printf "100644 file$_bz$_bz20" |
+              git hash-object -w --stdin -t tree) &&
+         git fsck 2>out &&
+         cat out &&
+         grep "warning.*null sha1" out
+       )
+'
+
+test_expect_success 'fsck notices submodule entry pointing to null sha1' '
+       (git init null-commit &&
+        cd null-commit &&
+        sha=$(printf "160000 submodule$_bz$_bz20" |
+              git hash-object -w --stdin -t tree) &&
+         git fsck 2>out &&
+         cat out &&
+         grep "warning.*null sha1" out
+       )
+'
+
 test_done
index 809fafe..0dbbb00 100755 (executable)
@@ -29,4 +29,23 @@ test_expect_success 'update-index -h with corrupt index' '
        grep "[Uu]sage: git update-index" broken/usage
 '
 
+test_expect_success '--cacheinfo does not accept blob null sha1' '
+       echo content >file &&
+       git add file &&
+       git rev-parse :file >expect &&
+       test_must_fail git update-index --cacheinfo 100644 $_z40 file &&
+       git rev-parse :file >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--cacheinfo does not accept gitlink null sha1' '
+       git init submodule &&
+       (cd submodule && test_commit foo) &&
+       git add submodule &&
+       git rev-parse :submodule >expect &&
+       test_must_fail git update-index --cacheinfo 160000 $_z40 submodule &&
+       git rev-parse :submodule >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 7f8693b..58f4823 100755 (executable)
@@ -47,7 +47,23 @@ test_expect_success 'rebase ignores empty commit' '
        git commit --allow-empty -m empty &&
        test_commit D &&
        git rebase C &&
-       test $(git log --format=%s C..) = "D"
+       test "$(git log --format=%s C..)" = "D"
+'
+
+test_expect_success 'rebase --keep-empty' '
+       git reset --hard D &&
+       git rebase --keep-empty C &&
+       test "$(git log --format=%s C..)" = "D
+empty"
+'
+
+test_expect_success 'rebase --keep-empty keeps empty even if already in upstream' '
+       git reset --hard A &&
+       git commit --allow-empty -m also-empty &&
+       git rebase --keep-empty D &&
+       test "$(git log --format=%s A..)" = "also-empty
+D
+empty"
 '
 
 test_done
index c00a94b..2d030a4 100755 (executable)
@@ -66,5 +66,35 @@ test_expect_success 'suppress deletion diff with -B -D' '
        grep -v "Linus Torvalds" actual
 '
 
+test_expect_success 'prepare a file that ends with an incomplete line' '
+       test_seq 1 99 >seq &&
+       printf 100 >>seq &&
+       git add seq &&
+       git commit seq -m seq
+'
+
+test_expect_success 'rewrite the middle 90% of sequence file and terminate with newline' '
+       test_seq 1 5 >seq &&
+       test_seq 9331 9420 >>seq &&
+       test_seq 96 100 >>seq
+'
+
+test_expect_success 'confirm that sequence file is considered a rewrite' '
+       git diff -B seq >res &&
+       grep "dissimilarity index" res
+'
+
+test_expect_success 'no newline at eof is on its own line without -B' '
+       git diff seq >res &&
+       grep "^\\\\ " res &&
+       ! grep "^..*\\\\ " res
+'
+
+test_expect_success 'no newline at eof is on its own line with -B' '
+       git diff -B seq >res &&
+       grep "^\\\\ " res &&
+       ! grep "^..*\\\\ " res
+'
+
 test_done
 
diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh
new file mode 100755 (executable)
index 0000000..0843c87
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+test_description='test diff with a bogus tree containing the null sha1'
+. ./test-lib.sh
+
+empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+
+test_expect_success 'create bogus tree' '
+       bogus_tree=$(
+               printf "100644 fooQQQQQQQQQQQQQQQQQQQQQ" |
+               q_to_nul |
+               git hash-object -w --stdin -t tree
+       )
+'
+
+test_expect_success 'create tree with matching file' '
+       echo bar >foo &&
+       git add foo &&
+       good_tree=$(git write-tree)
+       blob=$(git rev-parse :foo)
+'
+
+test_expect_success 'raw diff shows null sha1 (addition)' '
+       echo ":000000 100644 $_z40 $_z40 A      foo" >expect &&
+       git diff-tree $empty_tree $bogus_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (removal)' '
+       echo ":100644 000000 $_z40 $_z40 D      foo" >expect &&
+       git diff-tree $bogus_tree $empty_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (modification)' '
+       echo ":100644 100644 $blob $_z40 M      foo" >expect &&
+       git diff-tree $good_tree $bogus_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (other direction)' '
+       echo ":100644 100644 $_z40 $blob M      foo" >expect &&
+       git diff-tree $bogus_tree $good_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (reverse)' '
+       echo ":100644 100644 $_z40 $blob M      foo" >expect &&
+       git diff-tree -R $good_tree $bogus_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (index)' '
+       echo ":100644 100644 $_z40 $blob M      foo" >expect &&
+       git diff-index $bogus_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'patch fails due to bogus sha1 (addition)' '
+       test_must_fail git diff-tree -p $empty_tree $bogus_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (removal)' '
+       test_must_fail git diff-tree -p $bogus_tree $empty_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (modification)' '
+       test_must_fail git diff-tree -p $good_tree $bogus_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (other direction)' '
+       test_must_fail git diff-tree -p $bogus_tree $good_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (reverse)' '
+       test_must_fail git diff-tree -R -p $good_tree $bogus_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (index)' '
+       test_must_fail git diff-index -p $bogus_tree
+'
+
+test_done
index 0eace37..250c720 100755 (executable)
@@ -145,6 +145,41 @@ test_expect_success 'push --all excludes remote-tracking hierarchy' '
        )
 '
 
+test_expect_success 'receive-pack runs auto-gc in remote repo' '
+       rm -rf parent child &&
+       git init parent &&
+       (
+           # Setup a repo with 2 packs
+           cd parent &&
+           echo "Some text" >file.txt &&
+           git add . &&
+           git commit -m "Initial commit" &&
+           git repack -adl &&
+           echo "Some more text" >>file.txt &&
+           git commit -a -m "Second commit" &&
+           git repack
+       ) &&
+       cp -a parent child &&
+       (
+           # Set the child to auto-pack if more than one pack exists
+           cd child &&
+           git config gc.autopacklimit 1 &&
+           git branch test_auto_gc &&
+           # And create a file that follows the temporary object naming
+           # convention for the auto-gc to remove
+           : >.git/objects/tmp_test_object &&
+           test-chmtime =-1209601 .git/objects/tmp_test_object
+       ) &&
+       (
+           cd parent &&
+           echo "Even more text" >>file.txt &&
+           git commit -a -m "Third commit" &&
+           git send-pack ../child HEAD:refs/heads/test_auto_gc >output 2>&1 &&
+           grep "Auto packing the repository for optimum performance." output
+       ) &&
+       test ! -e child/.git/objects/tmp_test_object
+'
+
 rewound_push_setup() {
        rm -rf parent child &&
        mkdir parent &&
index fadf2f2..91eaf53 100755 (executable)
@@ -114,7 +114,7 @@ test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
 test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
        (
        cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
-       for i in `seq 50000`
+       for i in `test_seq 50000`
        do
                echo "commit refs/heads/too-many-refs"
                echo "mark :$i"
index 81827e6..0278f48 100755 (executable)
@@ -258,6 +258,27 @@ test_expect_success 'init should register submodule url in .git/config' '
        test_cmp expect url
 '
 
+test_failure_with_unknown_submodule () {
+       test_must_fail git submodule $1 no-such-submodule 2>output.err &&
+       grep "^error: .*no-such-submodule" output.err
+}
+
+test_expect_success 'init should fail with unknown submodule' '
+       test_failure_with_unknown_submodule init
+'
+
+test_expect_success 'update should fail with unknown submodule' '
+       test_failure_with_unknown_submodule update
+'
+
+test_expect_success 'status should fail with unknown submodule' '
+       test_failure_with_unknown_submodule status
+'
+
+test_expect_success 'sync should fail with unknown submodule' '
+       test_failure_with_unknown_submodule sync
+'
+
 test_expect_success 'update should fail when path is used by a file' '
        echo hello >expect &&
 
@@ -418,10 +439,7 @@ test_expect_success 'moving to a commit without submodule does not leave empty d
 '
 
 test_expect_success 'submodule <invalid-path> warns' '
-
-       git submodule no-such-submodule 2> output.err &&
-       grep "^error: .*no-such-submodule" output.err
-
+       test_failure_with_unknown_submodule
 '
 
 test_expect_success 'add submodules without specifying an explicit path' '
index ce61d4c..1542653 100755 (executable)
@@ -123,6 +123,18 @@ test_expect_success 'submodule update should throw away changes with --force ' '
        )
 '
 
+test_expect_success 'submodule update --force forcibly checks out submodules' '
+       (cd super &&
+        (cd submodule &&
+         rm -f file
+        ) &&
+        git submodule update --force submodule &&
+        (cd submodule &&
+         test "$(git status -s file)" = ""
+        )
+       )
+'
+
 test_expect_success 'submodule update --rebase staying on master' '
        (cd super/submodule &&
          git checkout master
@@ -367,7 +379,7 @@ test_expect_success 'submodule update continues after checkout error' '
         git submodule init &&
         git commit -am "new_submodule" &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../expect
+         git rev-parse --verify HEAD >../expect
         ) &&
         (cd submodule &&
          test_commit "update_submodule" file
@@ -384,7 +396,7 @@ test_expect_success 'submodule update continues after checkout error' '
         git checkout HEAD^ &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../actual
+         git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@ -413,7 +425,7 @@ test_expect_success 'submodule update continues after recursive checkout error'
          test_commit "update_submodule_again_again" file
         ) &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../expect &&
+         git rev-parse --verify HEAD >../expect &&
          test_commit "update_submodule2_again" file
         ) &&
         git add submodule &&
@@ -428,7 +440,7 @@ test_expect_success 'submodule update continues after recursive checkout error'
         ) &&
         test_must_fail git submodule update --recursive &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../actual
+         git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@ -460,12 +472,12 @@ test_expect_success 'submodule update exit immediately in case of merge conflict
         ) &&
         git checkout HEAD^ &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../expect
+         git rev-parse --verify HEAD >../expect
         ) &&
         git config submodule.submodule.update merge &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../actual
+         git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@ -495,12 +507,12 @@ test_expect_success 'submodule update exit immediately after recursive rebase er
         ) &&
         git checkout HEAD^ &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../expect
+         git rev-parse --verify HEAD >../expect
         ) &&
         git config submodule.submodule.update rebase &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../actual
+         git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
index f5e16fc..6fa0c70 100755 (executable)
@@ -55,6 +55,16 @@ test_expect_success 'setup' '
     git rm file12 &&
     git commit -m "branch1 changes" &&
 
+    git checkout -b stash1 master &&
+    echo stash1 change file11 >file11 &&
+    git add file11 &&
+    git commit -m "stash1 changes" &&
+
+    git checkout -b stash2 master &&
+    echo stash2 change file11 >file11 &&
+    git add file11 &&
+    git commit -m "stash2 changes" &&
+
     git checkout master &&
     git submodule update -N &&
     echo master updated >file1 &&
@@ -193,7 +203,35 @@ test_expect_success 'mergetool skips resolved paths when rerere is active' '
     git reset --hard
 '
 
+test_expect_success 'conflicted stash sets up rerere'  '
+    git config rerere.enabled true &&
+    git checkout stash1 &&
+    echo "Conflicting stash content" >file11 &&
+    git stash &&
+
+    git checkout --detach stash2 &&
+    test_must_fail git stash apply &&
+
+    test -n "$(git ls-files -u)" &&
+    conflicts="$(git rerere remaining)" &&
+    test "$conflicts" = "file11" &&
+    output="$(git mergetool --no-prompt)" &&
+    test "$output" != "No files need merging" &&
+
+    git commit -am "save the stash resolution" &&
+
+    git reset --hard stash2 &&
+    test_must_fail git stash apply &&
+
+    test -n "$(git ls-files -u)" &&
+    conflicts="$(git rerere remaining)" &&
+    test -z "$conflicts" &&
+    output="$(git mergetool --no-prompt)" &&
+    test "$output" = "No files need merging"
+'
+
 test_expect_success 'mergetool takes partial path' '
+    git reset --hard
     git config rerere.enabled false &&
     git checkout -b test12 branch1 &&
     git submodule update -N &&
index 8c12c65..0351228 100755 (executable)
@@ -841,6 +841,19 @@ test_expect_success $PREREQ '--compose adds MIME for utf8 subject' '
        grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
 '
 
+test_expect_success $PREREQ 'utf8 author is correctly passed on' '
+       clean_fake_sendmail &&
+       test_commit weird_author &&
+       test_when_finished "git reset --hard HEAD^" &&
+       git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
+       git format-patch --stdout -1 >funny_name.patch &&
+       git send-email --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         funny_name.patch &&
+       grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
+'
+
 test_expect_success $PREREQ 'detects ambiguous reference/file conflict' '
        echo master > master &&
        git add master &&
index 80daaca..9096398 100644 (file)
@@ -530,6 +530,27 @@ test_cmp() {
        $GIT_TEST_CMP "$@"
 }
 
+# Print a sequence of numbers or letters in increasing order.  This is
+# similar to GNU seq(1), but the latter might not be available
+# everywhere (and does not do letters).  It may be used like:
+#
+#      for i in `test_seq 100`; do
+#              for j in `test_seq 10 20`; do
+#                      for k in `test_seq a z`; do
+#                              echo $i-$j-$k
+#                      done
+#              done
+#      done
+
+test_seq () {
+       case $# in
+       1)      set 1 "$@" ;;
+       2)      ;;
+       *)      error "bug in the test script: not 1 or 2 parameters to test_seq" ;;
+       esac
+       "$PERL_PATH" -le 'print for $ARGV[0]..$ARGV[1]' -- "$@"
+}
+
 # This function can be used to schedule some commands to be run
 # unconditionally at the end of the test to restore sanity:
 #
index 28ad6db..ba01563 100644 (file)
@@ -49,12 +49,12 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
        if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {
                if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
                        opt->change(opt, mode1, mode2,
-                                   sha1, sha2, base->buf, 0, 0);
+                                   sha1, sha2, 1, 1, base->buf, 0, 0);
                }
                strbuf_addch(base, '/');
                diff_tree_sha1(sha1, sha2, base->buf, opt);
        } else {
-               opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0);
+               opt->change(opt, mode1, mode2, sha1, sha2, 1, 1, base->buf, 0, 0);
        }
        strbuf_setlen(base, old_baselen);
        return 0;
@@ -100,7 +100,7 @@ static void show_entry(struct diff_options *opt, const char *prefix,
                        die("corrupt tree sha %s", sha1_to_hex(sha1));
 
                if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))
-                       opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0);
+                       opt->add_remove(opt, *prefix, mode, sha1, 1, base->buf, 0);
 
                strbuf_addch(base, '/');
 
@@ -108,7 +108,7 @@ static void show_entry(struct diff_options *opt, const char *prefix,
                show_tree(opt, prefix, &inner, base);
                free(tree);
        } else
-               opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0);
+               opt->add_remove(opt, prefix[0], mode, sha1, 1, base->buf, 0);
 
        strbuf_setlen(base, old_baselen);
 }
@@ -212,8 +212,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
        diff_opts.rename_score = opt->rename_score;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("unable to set up diff options to follow renames");
+       diff_setup_done(&diff_opts);
        diff_tree(t1, t2, base, &diff_opts);
        diffcore_std(&diff_opts);
        diff_tree_release_paths(&diff_opts);