Merge branch 'jk/tighten-alloc' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 10 Mar 2016 19:13:43 +0000 (11:13 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 10 Mar 2016 19:13:43 +0000 (11:13 -0800)
* jk/tighten-alloc: (23 commits)
compat/mingw: brown paper bag fix for 50a6c8e
ewah: convert to REALLOC_ARRAY, etc
convert ewah/bitmap code to use xmalloc
diff_populate_gitlink: use a strbuf
transport_anonymize_url: use xstrfmt
git-compat-util: drop mempcpy compat code
sequencer: simplify memory allocation of get_message
test-path-utils: fix normalize_path_copy output buffer size
fetch-pack: simplify add_sought_entry
fast-import: simplify allocation in start_packfile
write_untracked_extension: use FLEX_ALLOC helper
prepare_{git,shell}_cmd: use argv_array
use st_add and st_mult for allocation size computation
convert trivial cases to FLEX_ARRAY macros
use xmallocz to avoid size arithmetic
convert trivial cases to ALLOC_ARRAY
convert manual allocations to argv_array
argv-array: add detach function
add helpers for allocating flex-array structs
harden REALLOC_ARRAY and xcalloc against size_t overflow
...

63 files changed:
Documentation/RelNotes/2.7.2.txt [new file with mode: 0644]
Documentation/git-clean.txt
Documentation/git-worktree.txt
Documentation/git.txt
GIT-VERSION-GEN
RelNotes
branch.c
branch.h
builtin/am.c
builtin/blame.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/config.c
builtin/grep.c
builtin/init-db.c
builtin/remote.c
builtin/rev-parse.c
builtin/rm.c
builtin/stripspace.c
cache-tree.c
cache.h
compat/precompose_utf8.c
config.c
contrib/completion/git-completion.bash
diff.c
diff.h
fetch-pack.c
git-cvsserver.perl
git-merge-one-file.sh
merge-blobs.c
mergetools/vimdiff
pager.c
read-cache.c
remote-curl.c
remote.c
run-command.c
run-command.h
setup.c
sha1_name.c
submodule.c
t/t1501-work-tree.sh [new file with mode: 0755]
t/t1501-worktree.sh [deleted file]
t/t1509-root-work-tree.sh [new file with mode: 0755]
t/t1509-root-worktree.sh [deleted file]
t/t2019-checkout-ambiguous-ref.sh
t/t2027-worktree-list.sh
t/t3200-branch.sh
t/t5504-fetch-receive-strict.sh
t/t5505-remote.sh
t/t5533-push-cas.sh
t/t6023-merge-file.sh
t/t6133-pathspec-rev-dwim.sh [new file with mode: 0755]
t/t7409-submodule-detached-work-tree.sh [new file with mode: 0755]
t/t7409-submodule-detached-worktree.sh [deleted file]
t/test-lib-functions.sh
t/test-lib.sh
userdiff.h
worktree.c
write_or_die.c
xdiff/xdiff.h
xdiff/xemit.c
xdiff/xmerge.c
diff --git a/Documentation/RelNotes/2.7.2.txt b/Documentation/RelNotes/2.7.2.txt
new file mode 100644 (file)
index 0000000..4feef76
--- /dev/null
@@ -0,0 +1,41 @@
+Git v2.7.2 Release Notes
+========================
+
+Fixes since v2.7.1
+------------------
+
+ * The low-level merge machinery has been taught to use CRLF line
+   termination when inserting conflict markers to merged contents that
+   are themselves CRLF line-terminated.
+
+ * "git worktree" had a broken code that attempted to auto-fix
+   possible inconsistency that results from end-users moving a
+   worktree to different places without telling Git (the original
+   repository needs to maintain backpointers to its worktrees, but
+   "mv" run by end-users who are not familiar with that fact will
+   obviously not adjust them), which actually made things worse
+   when triggered.
+
+ * "git push --force-with-lease" has been taught to report if the push
+   needed to force (or fast-forwarded).
+
+ * The emulated "yes" command used in our test scripts has been
+   tweaked not to spend too much time generating unnecessary output
+   that is not used, to help those who test on Windows where it would
+   not stop until it fills the pipe buffer due to lack of SIGPIPE.
+
+ * The vimdiff backend for "git mergetool" has been tweaked to arrange
+   and number buffers in the order that would match the expectation of
+   majority of people who read left to right, then top down and assign
+   buffers 1 2 3 4 "mentally" to local base remote merge windows based
+   on that order.
+
+ * The documentation for "git clean" has been corrected; it mentioned
+   that .git/modules/* are removed by giving two "-f", which has never
+   been the case.
+
+ * Paths that have been told the index about with "add -N" are not
+   quite yet in the index, but a few commands behaved as if they
+   already are in a harmful way.
+
+Also includes tiny documentation and test updates.
index 641681f61ad360fcfd5aa98f81a9e3d49c44c8a7..51a7e26a8ec178e7e9fd0b78c00bb7ce518cd049 100644 (file)
@@ -37,9 +37,7 @@ OPTIONS
        to false, 'git clean' will refuse to delete files or directories
        unless given -f, -n or -i. Git will refuse to delete directories
        with .git sub directory or file unless a second -f
-       is given. This affects also git submodules where the storage area
-       of the removed submodule under .git/modules/ is not removed until
-       -f is given twice.
+       is given.
 
 -i::
 --interactive::
index 5b9ad0429c84d2f11b0569f6d979858c833b3768..62c76c1c8945512009c6d0ca1179cf71ec50d04e 100644 (file)
@@ -32,11 +32,9 @@ The working tree's administrative files in the repository (see
 `git worktree prune` in the main or any linked working tree to
 clean up any stale administrative files.
 
-If you move a linked working tree to another file system, or
-within a file system that does not support hard links, you need to run
-at least one git command inside the linked working tree
-(e.g. `git status`) in order to update its administrative files in the
-repository so that they do not get automatically pruned.
+If you move a linked working tree, you need to manually update the
+administrative files so that they do not get pruned automatically. See
+section "DETAILS" for more information.
 
 If a linked working tree is stored on a portable device or network share
 which is not always mounted, you can prevent its administrative files from
@@ -137,6 +135,13 @@ thumb is do not make any assumption about whether a path belongs to
 $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
 inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
 
+If you move a linked working tree, you need to update the 'gitdir' file
+in the entry's directory. For example, if a linked working tree is moved
+to `/newpath/test-next` and its `.git` file points to
+`/path/main/.git/worktrees/test-next`, then update
+`/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next`
+instead.
+
 To prevent a $GIT_DIR/worktrees entry from being pruned (which
 can be useful in some situations, such as when the
 entry's working tree is stored on a portable device), add a file named
index d987ad20c90a05932733c09812324c3d176ebbbe..68a71b46c9c5706f76e73f55f6767d9f1ba07ce4 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.7.1/git.html[documentation for release 2.7.1]
+* link:v2.7.2/git.html[documentation for release 2.7.2]
 
 * release notes for
+  link:RelNotes/2.7.2.txt[2.7.2],
   link:RelNotes/2.7.1.txt[2.7.1],
   link:RelNotes/2.7.0.txt[2.7].
 
index 330b339d1cac1af441b16e35dcdefa660da1f683..d7ab24e35617a456f1998a141f7e620eca1de431 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.7.1
+DEF_VER=v2.7.2
 
 LF='
 '
index 213c0d0850d1d2d2e8fe85860a49810f23bb150a..64e8170aa2353dccbd67ef8767299f22fb765a8e 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.7.1.txt
\ No newline at end of file
+Documentation/RelNotes/2.7.2.txt
\ No newline at end of file
index 7ff3f204964127374ae2a337819ce0bce7be9ab2..c50ea42172ceadd2a76d12833631301223607067 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -49,7 +49,13 @@ static int should_setup_rebase(const char *origin)
        return 0;
 }
 
-void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
+static const char tracking_advice[] =
+N_("\n"
+"After fixing the error cause you may try to fix up\n"
+"the remote tracking information by invoking\n"
+"\"git branch --set-upstream-to=%s%s%s\".");
+
+int install_branch_config(int flag, const char *local, const char *origin, const char *remote)
 {
        const char *shortname = NULL;
        struct strbuf key = STRBUF_INIT;
@@ -60,20 +66,23 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
            && !origin) {
                warning(_("Not setting branch %s as its own upstream."),
                        local);
-               return;
+               return 0;
        }
 
        strbuf_addf(&key, "branch.%s.remote", local);
-       git_config_set(key.buf, origin ? origin : ".");
+       if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
+               goto out_err;
 
        strbuf_reset(&key);
        strbuf_addf(&key, "branch.%s.merge", local);
-       git_config_set(key.buf, remote);
+       if (git_config_set_gently(key.buf, remote) < 0)
+               goto out_err;
 
        if (rebasing) {
                strbuf_reset(&key);
                strbuf_addf(&key, "branch.%s.rebase", local);
-               git_config_set(key.buf, "true");
+               if (git_config_set_gently(key.buf, "true") < 0)
+                       goto out_err;
        }
        strbuf_release(&key);
 
@@ -102,6 +111,19 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
                                          local, remote);
                }
        }
+
+       return 0;
+
+out_err:
+       strbuf_release(&key);
+       error(_("Unable to write upstream branch configuration"));
+
+       advise(_(tracking_advice),
+              origin ? origin : "",
+              origin ? "/" : "",
+              shortname ? shortname : remote);
+
+       return -1;
 }
 
 /*
@@ -109,8 +131,8 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
  * to infer the settings for branch.<new_ref>.{remote,merge} from the
  * config.
  */
-static int setup_tracking(const char *new_ref, const char *orig_ref,
-                         enum branch_track track, int quiet)
+static void setup_tracking(const char *new_ref, const char *orig_ref,
+                          enum branch_track track, int quiet)
 {
        struct tracking tracking;
        int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
@@ -118,7 +140,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
        memset(&tracking, 0, sizeof(tracking));
        tracking.spec.dst = (char *)orig_ref;
        if (for_each_remote(find_tracked_branch, &tracking))
-               return 1;
+               return;
 
        if (!tracking.matches)
                switch (track) {
@@ -127,18 +149,18 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
                case BRANCH_TRACK_OVERRIDE:
                        break;
                default:
-                       return 1;
+                       return;
                }
 
        if (tracking.matches > 1)
-               return error(_("Not tracking: ambiguous information for ref %s"),
-                               orig_ref);
+               die(_("Not tracking: ambiguous information for ref %s"),
+                   orig_ref);
 
-       install_branch_config(config_flags, new_ref, tracking.remote,
-                             tracking.src ? tracking.src : orig_ref);
+       if (install_branch_config(config_flags, new_ref, tracking.remote,
+                             tracking.src ? tracking.src : orig_ref) < 0)
+               exit(-1);
 
        free(tracking.src);
-       return 0;
 }
 
 int read_branch_desc(struct strbuf *buf, const char *branch_name)
index 58aa45fe72ca356a8bd3648782b36e63e207ee36..78ad4387cd326ca01f228b109b446e2049f29ee7 100644 (file)
--- a/branch.h
+++ b/branch.h
@@ -43,9 +43,10 @@ void remove_branch_state(void);
 /*
  * Configure local branch "local" as downstream to branch "remote"
  * from remote "origin".  Used by git branch --set-upstream.
+ * Returns 0 on success.
  */
 #define BRANCH_CONFIG_VERBOSE 01
-extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote);
+extern int install_branch_config(int flag, const char *local, const char *origin, const char *remote);
 
 /*
  * Read branch description
index 95decc6a594a2cf379501a478fd2cdf207cecdc5..5668e0c3a5a7e04d266b20e2a5ae60f2a7aa98cd 100644 (file)
@@ -1821,7 +1821,7 @@ static int do_interactive(struct am_state *state)
 
                        if (!pager)
                                pager = "cat";
-                       argv_array_push(&cp.args, pager);
+                       prepare_pager_args(&cp, pager);
                        argv_array_push(&cp.args, am_path(state, "patch"));
                        run_command(&cp);
                }
index e175d86e56c670f7463a1f6b00e75239c7ba1dfe..0b4f0bbb531407f6003fe66cfe16a48785b1dcf3 100644 (file)
@@ -2391,11 +2391,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 
-       /*
-        * We are not going to write this out, so this does not matter
-        * right now, but someday we might optimize diff-index --cached
-        * with cache-tree information.
-        */
        cache_tree_invalidate_path(&the_index, path);
 
        return commit;
index 3f6c825db1caf9c7cdd2ca7c1280e5ad157f9a27..7b45b6bd6b80613de9f894cfbe8e9d2dcae77b09 100644 (file)
@@ -570,7 +570,6 @@ static const char edit_description[] = "BRANCH_DESCRIPTION";
 
 static int edit_branch_description(const char *branch_name)
 {
-       int status;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf name = STRBUF_INIT;
 
@@ -595,11 +594,11 @@ static int edit_branch_description(const char *branch_name)
        strbuf_stripspace(&buf, 1);
 
        strbuf_addf(&name, "branch.%s.description", branch_name);
-       status = git_config_set(name.buf, buf.len ? buf.buf : NULL);
+       git_config_set(name.buf, buf.len ? buf.buf : NULL);
        strbuf_release(&name);
        strbuf_release(&buf);
 
-       return status;
+       return 0;
 }
 
 int cmd_branch(int argc, const char **argv, const char *prefix)
index e8110a9243f648129ffbea0de2af039ad7791aa1..d53ab75ac9a078c821ed5112643ee896fed35a88 100644 (file)
@@ -981,7 +981,8 @@ static int parse_branchname_arg(int argc, const char **argv,
                 */
                int recover_with_dwim = dwim_new_local_branch_ok;
 
-               if (check_filename(NULL, arg) && !has_dash_dash)
+               if (!has_dash_dash &&
+                   (check_filename(NULL, arg) || !no_wildcard(arg)))
                        recover_with_dwim = 0;
                /*
                 * Accept "git checkout foo" and "git checkout foo --"
index a0b3cd9e5617b5a3a45dd01c8a2c7af0b2fd9668..8a90cad5b534adbb4d1370f8f2365de21a934248 100644 (file)
@@ -732,7 +732,7 @@ static int checkout(void)
 
 static int write_one_config(const char *key, const char *value, void *data)
 {
-       return git_config_set_multivar(key, value ? value : "true", "^$", 0);
+       return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0);
 }
 
 static void write_config(struct string_list *config)
index adc772786a7ddf9952aaccb7578b57d10396da93..c26d6e7fdd5d2896850ac909cb9ce04960520b0d 100644 (file)
@@ -582,7 +582,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1]);
-               ret = git_config_set_in_file(given_config_source.file, argv[0], value);
+               ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
                if (ret == CONFIG_NOTHING_SET)
                        error("cannot overwrite multiple values with a single value\n"
                        "       Use a regexp, --add or --replace-all to change %s.", argv[0]);
@@ -592,23 +592,23 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 2, 3);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value, argv[2], 0);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value, argv[2], 0);
        }
        else if (actions == ACTION_ADD) {
                check_write();
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value,
-                                                      CONFIG_REGEX_NONE, 0);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value,
+                                                             CONFIG_REGEX_NONE, 0);
        }
        else if (actions == ACTION_REPLACE_ALL) {
                check_write();
                check_argc(argc, 2, 3);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value, argv[2], 1);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value, argv[2], 1);
        }
        else if (actions == ACTION_GET) {
                check_argc(argc, 1, 2);
@@ -634,17 +634,17 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 1, 2);
                if (argc == 2)
-                       return git_config_set_multivar_in_file(given_config_source.file,
-                                                              argv[0], NULL, argv[1], 0);
+                       return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                                     argv[0], NULL, argv[1], 0);
                else
-                       return git_config_set_in_file(given_config_source.file,
-                                                     argv[0], NULL);
+                       return git_config_set_in_file_gently(given_config_source.file,
+                                                            argv[0], NULL);
        }
        else if (actions == ACTION_UNSET_ALL) {
                check_write();
                check_argc(argc, 1, 2);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], NULL, argv[1], 1);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], NULL, argv[1], 1);
        }
        else if (actions == ACTION_RENAME_SECTION) {
                int ret;
index 95ddf96d1e416f59dff08a9dde71b04cdb2b6ccd..65c02010c735ad6c5528dab2087d473e1c8b2362 100644 (file)
@@ -375,7 +375,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 
        for (nr = 0; nr < active_nr; nr++) {
                const struct cache_entry *ce = active_cache[nr];
-               if (!S_ISREG(ce->ce_mode))
+               if (!S_ISREG(ce->ce_mode) || ce_intent_to_add(ce))
                        continue;
                if (!ce_path_match(ce, pathspec, NULL))
                        continue;
index 07229d60f1fd0d581c8cfae2bd0b1c21f06cbc95..6223b7d46af346b0d96870ee0c647ab9a5440b33 100644 (file)
@@ -250,7 +250,7 @@ static int create_default_files(const char *template_path)
                git_config_set("core.bare", "false");
                /* allow template config file to override the default */
                if (log_all_ref_updates == -1)
-                   git_config_set("core.logallrefupdates", "true");
+                       git_config_set("core.logallrefupdates", "true");
                if (needs_work_tree_config(get_git_dir(), work_tree))
                        git_config_set("core.worktree", work_tree);
        }
index 6694cf20efdc01fb59d0b6afa41f7b1557c9b2d5..43136951b55be959d9fd6a2cc960b19f1a1484ac 100644 (file)
@@ -108,8 +108,8 @@ enum {
 #define MIRROR_PUSH 2
 #define MIRROR_BOTH (MIRROR_FETCH|MIRROR_PUSH)
 
-static int add_branch(const char *key, const char *branchname,
-               const char *remotename, int mirror, struct strbuf *tmp)
+static void add_branch(const char *key, const char *branchname,
+                      const char *remotename, int mirror, struct strbuf *tmp)
 {
        strbuf_reset(tmp);
        strbuf_addch(tmp, '+');
@@ -119,7 +119,7 @@ static int add_branch(const char *key, const char *branchname,
        else
                strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
                                branchname, remotename, branchname);
-       return git_config_set_multivar(key, tmp->buf, "^$", 0);
+       git_config_set_multivar(key, tmp->buf, "^$", 0);
 }
 
 static const char mirror_advice[] =
@@ -197,8 +197,7 @@ static int add(int argc, const char **argv)
                die(_("'%s' is not a valid remote name"), name);
 
        strbuf_addf(&buf, "remote.%s.url", name);
-       if (git_config_set(buf.buf, url))
-               return 1;
+       git_config_set(buf.buf, url);
 
        if (!mirror || mirror & MIRROR_FETCH) {
                strbuf_reset(&buf);
@@ -206,25 +205,22 @@ static int add(int argc, const char **argv)
                if (track.nr == 0)
                        string_list_append(&track, "*");
                for (i = 0; i < track.nr; i++) {
-                       if (add_branch(buf.buf, track.items[i].string,
-                                      name, mirror, &buf2))
-                               return 1;
+                       add_branch(buf.buf, track.items[i].string,
+                                  name, mirror, &buf2);
                }
        }
 
        if (mirror & MIRROR_PUSH) {
                strbuf_reset(&buf);
                strbuf_addf(&buf, "remote.%s.mirror", name);
-               if (git_config_set(buf.buf, "true"))
-                       return 1;
+               git_config_set(buf.buf, "true");
        }
 
        if (fetch_tags != TAGS_DEFAULT) {
                strbuf_reset(&buf);
                strbuf_addf(&buf, "remote.%s.tagopt", name);
-               if (git_config_set(buf.buf,
-                       fetch_tags == TAGS_SET ? "--tags" : "--no-tags"))
-                       return 1;
+               git_config_set(buf.buf,
+                              fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
        }
 
        if (fetch && fetch_remote(name))
@@ -590,25 +586,20 @@ static int migrate_file(struct remote *remote)
 
        strbuf_addf(&buf, "remote.%s.url", remote->name);
        for (i = 0; i < remote->url_nr; i++)
-               if (git_config_set_multivar(buf.buf, remote->url[i], "^$", 0))
-                       return error(_("Could not append '%s' to '%s'"),
-                                       remote->url[i], buf.buf);
+               git_config_set_multivar(buf.buf, remote->url[i], "^$", 0);
        strbuf_reset(&buf);
        strbuf_addf(&buf, "remote.%s.push", remote->name);
        for (i = 0; i < remote->push_refspec_nr; i++)
-               if (git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0))
-                       return error(_("Could not append '%s' to '%s'"),
-                                       remote->push_refspec[i], buf.buf);
+               git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0);
        strbuf_reset(&buf);
        strbuf_addf(&buf, "remote.%s.fetch", remote->name);
        for (i = 0; i < remote->fetch_refspec_nr; i++)
-               if (git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0))
-                       return error(_("Could not append '%s' to '%s'"),
-                                       remote->fetch_refspec[i], buf.buf);
+               git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0);
        if (remote->origin == REMOTE_REMOTES)
                unlink_or_warn(git_path("remotes/%s", remote->name));
        else if (remote->origin == REMOTE_BRANCHES)
                unlink_or_warn(git_path("branches/%s", remote->name));
+
        return 0;
 }
 
@@ -655,8 +646,7 @@ static int mv(int argc, const char **argv)
 
        strbuf_reset(&buf);
        strbuf_addf(&buf, "remote.%s.fetch", rename.new);
-       if (git_config_set_multivar(buf.buf, NULL, NULL, 1))
-               return error(_("Could not remove config section '%s'"), buf.buf);
+       git_config_set_multivar(buf.buf, NULL, NULL, 1);
        strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old);
        for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
                char *ptr;
@@ -676,8 +666,7 @@ static int mv(int argc, const char **argv)
                                  "\tPlease update the configuration manually if necessary."),
                                buf2.buf);
 
-               if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
-                       return error(_("Could not append '%s'"), buf.buf);
+               git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
        }
 
        read_branches();
@@ -687,9 +676,7 @@ static int mv(int argc, const char **argv)
                if (info->remote_name && !strcmp(info->remote_name, rename.old)) {
                        strbuf_reset(&buf);
                        strbuf_addf(&buf, "branch.%s.remote", item->string);
-                       if (git_config_set(buf.buf, rename.new)) {
-                               return error(_("Could not set '%s'"), buf.buf);
-                       }
+                       git_config_set(buf.buf, rename.new);
                }
        }
 
@@ -787,10 +774,7 @@ static int rm(int argc, const char **argv)
                                strbuf_reset(&buf);
                                strbuf_addf(&buf, "branch.%s.%s",
                                                item->string, *k);
-                               if (git_config_set(buf.buf, NULL)) {
-                                       strbuf_release(&buf);
-                                       return -1;
-                               }
+                               git_config_set(buf.buf, NULL);
                        }
                }
        }
@@ -1409,24 +1393,20 @@ static int update(int argc, const char **argv)
 
 static int remove_all_fetch_refspecs(const char *remote, const char *key)
 {
-       return git_config_set_multivar(key, NULL, NULL, 1);
+       return git_config_set_multivar_gently(key, NULL, NULL, 1);
 }
 
-static int add_branches(struct remote *remote, const char **branches,
-                       const char *key)
+static void add_branches(struct remote *remote, const char **branches,
+                        const char *key)
 {
        const char *remotename = remote->name;
        int mirror = remote->mirror;
        struct strbuf refspec = STRBUF_INIT;
 
        for (; *branches; branches++)
-               if (add_branch(key, *branches, remotename, mirror, &refspec)) {
-                       strbuf_release(&refspec);
-                       return 1;
-               }
+               add_branch(key, *branches, remotename, mirror, &refspec);
 
        strbuf_release(&refspec);
-       return 0;
 }
 
 static int set_remote_branches(const char *remotename, const char **branches,
@@ -1445,10 +1425,7 @@ static int set_remote_branches(const char *remotename, const char **branches,
                strbuf_release(&key);
                return 1;
        }
-       if (add_branches(remote, branches, key.buf)) {
-               strbuf_release(&key);
-               return 1;
-       }
+       add_branches(remote, branches, key.buf);
 
        strbuf_release(&key);
        return 0;
@@ -1580,10 +1557,11 @@ static int set_url(int argc, const char **argv)
        if ((!oldurl && !delete_mode) || add_mode) {
                if (add_mode)
                        git_config_set_multivar(name_buf.buf, newurl,
-                               "^$", 0);
+                                                      "^$", 0);
                else
                        git_config_set(name_buf.buf, newurl);
                strbuf_release(&name_buf);
+
                return 0;
        }
 
index 7e074aad408ee7d63d86643878ff5c5bb311f732..7a4f2c0b0ccedf958b78b2bdda217bfb269c6b23 100644 (file)
@@ -763,7 +763,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                continue;
                        }
                        if (!strcmp(arg, "--git-common-dir")) {
-                               puts(get_git_common_dir());
+                               const char *pfx = prefix ? prefix : "";
+                               puts(prefix_filename(pfx, strlen(pfx), get_git_common_dir()));
                                continue;
                        }
                        if (!strcmp(arg, "--resolve-git-dir")) {
index 80b972f92fde3201bdf1cb8bd74c2b4ff53fa5ae..8829b09d0ba5d49edbad5f37f8246123dad3fd5f 100644 (file)
@@ -211,7 +211,7 @@ static int check_local_mod(unsigned char *head, int index_only)
                 * "intent to add" entry.
                 */
                if (local_changes && staged_changes) {
-                       if (!index_only || !(ce->ce_flags & CE_INTENT_TO_ADD))
+                       if (!index_only || !ce_intent_to_add(ce))
                                string_list_append(&files_staged, name);
                }
                else if (!index_only) {
index 7ff8434f7c3cf71dbd77cbf868d5dc56dd943fdb..15e716ef4322bb53428685c349aa489ed84a6dda 100644 (file)
@@ -35,7 +35,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
                            N_("skip and remove all lines starting with comment character"),
                            STRIP_COMMENTS),
                OPT_CMDMODE('c', "comment-lines", &mode,
-                           N_("prepend comment character and blank to each line"),
+                           N_("prepend comment character and space to each line"),
                            COMMENT_LINES),
                OPT_END()
        };
index 1fbe79a0032d898404580246800c3a7f6250ae6d..3ebf9c3aa44eb2ab25f573192b6449f63311ffd7 100644 (file)
@@ -375,7 +375,7 @@ static int update_one(struct cache_tree *it,
                 * they are not part of generated trees. Invalidate up
                 * to root to force cache-tree users to read elsewhere.
                 */
-               if (ce->ce_flags & CE_INTENT_TO_ADD) {
+               if (ce_intent_to_add(ce)) {
                        to_invalidate = 1;
                        continue;
                }
diff --git a/cache.h b/cache.h
index 3efd7ac703061fe30576ac3629ce16eaf0a5c9bb..1f145c2c6a9bcefe21caf1e681267b4e86911136 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -228,7 +228,9 @@ struct cache_entry {
 #error "CE_EXTENDED_FLAGS out of range"
 #endif
 
+/* Forward structure decls */
 struct pathspec;
+struct child_process;
 
 /*
  * Copy the sha1 and stat state of a cache entry from one to
@@ -259,6 +261,7 @@ static inline unsigned create_ce_flags(unsigned stage)
 #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
 #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
 #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
+#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD)
 
 #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
 static inline unsigned int create_ce_mode(unsigned int mode)
@@ -1484,7 +1487,7 @@ extern int update_server_info(int);
 /* git_config_parse_key() returns these negated: */
 #define CONFIG_INVALID_KEY 1
 #define CONFIG_NO_SECTION_OR_NAME 2
-/* git_config_set(), git_config_set_multivar() return the above or these: */
+/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
 #define CONFIG_NO_LOCK -1
 #define CONFIG_INVALID_FILE 3
 #define CONFIG_NO_WRITE 4
@@ -1522,12 +1525,16 @@ extern int git_config_bool(const char *, const char *);
 extern int git_config_maybe_bool(const char *, const char *);
 extern int git_config_string(const char **, const char *, const char *);
 extern int git_config_pathname(const char **, const char *, const char *);
-extern int git_config_set_in_file(const char *, const char *, const char *);
-extern int git_config_set(const char *, const char *);
+extern int git_config_set_in_file_gently(const char *, const char *, const char *);
+extern void git_config_set_in_file(const char *, const char *, const char *);
+extern int git_config_set_gently(const char *, const char *);
+extern void git_config_set(const char *, const char *);
 extern int git_config_parse_key(const char *, char **, int *);
 extern int git_config_key_is_valid(const char *key);
-extern int git_config_set_multivar(const char *, const char *, const char *, int);
-extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
+extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);
+extern void git_config_set_multivar(const char *, const char *, const char *, int);
+extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
+extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
 extern int git_config_rename_section(const char *, const char *);
 extern int git_config_rename_section_in_file(const char *, const char *, const char *);
 extern const char *git_etc_gitconfig(void);
@@ -1674,6 +1681,7 @@ extern int pager_use_color;
 extern int term_columns(void);
 extern int decimal_width(uintmax_t);
 extern int check_pager_config(const char *cmd);
+extern void prepare_pager_args(struct child_process *, const char *pager);
 
 extern const char *editor_program;
 extern const char *askpass_program;
index 079070ff1d4bd629712eff5f6f6e239898640963..dfbe6d84081c8b8eea50450a4c23c9a80b3b57a7 100644 (file)
@@ -50,7 +50,8 @@ void probe_utf8_pathname_composition(void)
                close(output_fd);
                git_path_buf(&path, "%s", auml_nfd);
                precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
-               git_config_set("core.precomposeunicode", precomposed_unicode ? "true" : "false");
+               git_config_set("core.precomposeunicode",
+                              precomposed_unicode ? "true" : "false");
                git_path_buf(&path, "%s", auml_nfc);
                if (unlink(path.buf))
                        die_errno(_("failed to unlink '%s'"), path.buf);
index ba8fd1376587848f0691883e7d1d71ad4d75d599..03544e7a3f68f858e2fed5492a4460bd05b75602 100644 (file)
--- a/config.c
+++ b/config.c
@@ -1825,15 +1825,26 @@ static ssize_t find_beginning_of_line(const char *contents, size_t size,
        return offset;
 }
 
-int git_config_set_in_file(const char *config_filename,
-                       const char *key, const char *value)
+int git_config_set_in_file_gently(const char *config_filename,
+                                 const char *key, const char *value)
 {
-       return git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
+       return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
 }
 
-int git_config_set(const char *key, const char *value)
+void git_config_set_in_file(const char *config_filename,
+                           const char *key, const char *value)
 {
-       return git_config_set_multivar(key, value, NULL, 0);
+       git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
+}
+
+int git_config_set_gently(const char *key, const char *value)
+{
+       return git_config_set_multivar_gently(key, value, NULL, 0);
+}
+
+void git_config_set(const char *key, const char *value)
+{
+       git_config_set_multivar(key, value, NULL, 0);
 }
 
 /*
@@ -1948,9 +1959,10 @@ int git_config_key_is_valid(const char *key)
  * - the config file is removed and the lock file rename()d to it.
  *
  */
-int git_config_set_multivar_in_file(const char *config_filename,
-                               const char *key, const char *value,
-                               const char *value_regex, int multi_replace)
+int git_config_set_multivar_in_file_gently(const char *config_filename,
+                                          const char *key, const char *value,
+                                          const char *value_regex,
+                                          int multi_replace)
 {
        int fd = -1, in_fd = -1;
        int ret;
@@ -2177,11 +2189,27 @@ int git_config_set_multivar_in_file(const char *config_filename,
 
 }
 
-int git_config_set_multivar(const char *key, const char *value,
-                       const char *value_regex, int multi_replace)
+void git_config_set_multivar_in_file(const char *config_filename,
+                                    const char *key, const char *value,
+                                    const char *value_regex, int multi_replace)
+{
+       if (git_config_set_multivar_in_file_gently(config_filename, key, value,
+                                                  value_regex, multi_replace) < 0)
+               die(_("Could not set '%s' to '%s'"), key, value);
+}
+
+int git_config_set_multivar_gently(const char *key, const char *value,
+                                  const char *value_regex, int multi_replace)
+{
+       return git_config_set_multivar_in_file_gently(NULL, key, value, value_regex,
+                                                     multi_replace);
+}
+
+void git_config_set_multivar(const char *key, const char *value,
+                            const char *value_regex, int multi_replace)
 {
-       return git_config_set_multivar_in_file(NULL, key, value, value_regex,
-                                              multi_replace);
+       git_config_set_multivar_in_file(NULL, key, value, value_regex,
+                                       multi_replace);
 }
 
 static int section_name_match (const char *buf, const char *name)
index 63f5c046a2c7058692657ffa4e97f20367bafedc..00d729996fab5be89696bf4841205d45c49c7794 100644 (file)
@@ -2413,8 +2413,8 @@ _git_stash ()
                show,--*|branch,--*)
                        ;;
                branch,*)
-                 if [ $cword -eq 3 ]; then
-                       __gitcomp_nl "$(__git_refs)";
+                       if [ $cword -eq 3 ]; then
+                               __gitcomp_nl "$(__git_refs)";
                        else
                                __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \
                                                | sed -n -e 's/:.*//p')"
diff --git a/diff.c b/diff.c
index a70ec6ef1a613a63482b0f7cf8d997af685793d9..059123c5dcef4129763895b0f2ad5a54728b0c07 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -5082,7 +5082,7 @@ size_t fill_textconv(struct userdiff_driver *driver,
 {
        size_t size;
 
-       if (!driver || !driver->textconv) {
+       if (!driver) {
                if (!DIFF_FILE_VALID(df)) {
                        *outbuf = "";
                        return 0;
@@ -5093,6 +5093,9 @@ size_t fill_textconv(struct userdiff_driver *driver,
                return df->size;
        }
 
+       if (!driver->textconv)
+               die("BUG: fill_textconv called with non-textconv driver");
+
        if (driver->textconv_cache && df->sha1_valid) {
                *outbuf = notes_cache_get(driver->textconv_cache, df->sha1,
                                          &size);
diff --git a/diff.h b/diff.h
index beafbbdec763f9ac7fb6a41f225a97fa8d0ae580..e7d68edaf9d4744ce3c48356e1835c5506d5322d 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -349,10 +349,26 @@ extern void diff_no_index(struct rev_info *, int, const char **);
 
 extern int index_differs_from(const char *def, int diff_flags);
 
+/*
+ * Fill the contents of the filespec "df", respecting any textconv defined by
+ * its userdiff driver.  The "driver" parameter must come from a
+ * previous call to get_textconv(), and therefore should either be NULL or have
+ * textconv enabled.
+ *
+ * Note that the memory ownership of the resulting buffer depends on whether
+ * the driver field is NULL. If it is, then the memory belongs to the filespec
+ * struct. If it is non-NULL, then "outbuf" points to a newly allocated buffer
+ * that should be freed by the caller.
+ */
 extern size_t fill_textconv(struct userdiff_driver *driver,
                            struct diff_filespec *df,
                            char **outbuf);
 
+/*
+ * Look up the userdiff driver for the given filespec, and return it if
+ * and only if it has textconv enabled (otherwise return NULL). The result
+ * can be passed to fill_textconv().
+ */
 extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
 
 extern int parse_rename_score(const char **cp_p);
index 01e34b689b975799610eabc15fc9138990706ff8..f96f6dfb35afb419ac38fcec9b4013fbf0e6d36d 100644 (file)
@@ -15,6 +15,7 @@
 #include "version.h"
 #include "prio-queue.h"
 #include "sha1-array.h"
+#include "sigchain.h"
 
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
@@ -671,9 +672,12 @@ static int everything_local(struct fetch_pack_args *args,
 static int sideband_demux(int in, int out, void *data)
 {
        int *xd = data;
+       int ret;
 
-       int ret = recv_sideband("fetch-pack", xd[0], out);
+       sigchain_push(SIGPIPE, SIG_IGN);
+       ret = recv_sideband("fetch-pack", xd[0], out);
        close(out);
+       sigchain_pop(SIGPIPE);
        return ret;
 }
 
index 95e69b19a70ba63f2055d6a2ec3f9af0092a0832..02c0445be1057619e01e56bd6792f78fc011dc42 100755 (executable)
@@ -2664,7 +2664,7 @@ sub argsfromdir
     #   co  # Obtain list directly.
     #   remove # HERE: TEST: MAYBE client does the recursion for us,
     #          # since it only makes sense to remove stuff already in
-    #          # the sandobx?
+    #          # the sandbox?
     #   ci # HERE: Similar to remove...
     #      # Don't try to implement the confusing/weird
     #      # ci -r bug er.."feature".
index cdc02af517c9d77a081d7918480f8d0a2c6a29d0..424b034e34b4b40e7c44da16ddf83a31dee6f6a0 100755 (executable)
@@ -120,8 +120,7 @@ case "${1:-.}${2:-.}${3:-.}" in
        case "$1" in
        '')
                echo "Added $4 in both, but differently."
-               orig=$(git-unpack-file $2)
-               create_virtual_base "$orig" "$src2"
+               orig=$(git-unpack-file e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)
                ;;
        *)
                echo "Auto-merging $4"
index ddca601c77fcab7d9d68362ce5c4f252ab7ccf51..9b6eac22e4256d8f2bf82961b6e4f320d89fdeba 100644 (file)
@@ -48,40 +48,6 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our
        return res.ptr;
 }
 
-static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf)
-{
-       int i;
-       mmfile_t *dst = priv_;
-
-       for (i = 0; i < nbuf; i++) {
-               memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size);
-               dst->size += mb[i].size;
-       }
-       return 0;
-}
-
-static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
-{
-       unsigned long size = f1->size < f2->size ? f1->size : f2->size;
-       void *ptr = xmalloc(size);
-       xpparam_t xpp;
-       xdemitconf_t xecfg;
-       xdemitcb_t ecb;
-
-       memset(&xpp, 0, sizeof(xpp));
-       xpp.flags = 0;
-       memset(&xecfg, 0, sizeof(xecfg));
-       xecfg.ctxlen = 3;
-       xecfg.flags = XDL_EMIT_COMMON;
-       ecb.outf = common_outf;
-
-       res->ptr = ptr;
-       res->size = 0;
-
-       ecb.priv = res;
-       return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
-}
-
 void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
 {
        void *res = NULL;
@@ -112,8 +78,8 @@ void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct
                if (fill_mmfile_blob(&common, base) < 0)
                        goto out_free_f2_f1;
        } else {
-               if (generate_common_file(&common, &f1, &f2) < 0)
-                       goto out_free_f2_f1;
+               common.ptr = xstrdup("");
+               common.size = 0;
        }
        res = three_way_filemerge(path, &common, &f1, &f2, size);
        free_mmfile(&common);
index 1ddfbfcd782d3b8d0e479cb0c5e29abce86e63c9..74ea6d54793f62188cd88e93f1adfe74c5957dda 100644 (file)
@@ -9,8 +9,8 @@ merge_cmd () {
        gvimdiff|vimdiff)
                if $base_present
                then
-                       "$merge_tool_path" -f -d -c 'wincmd J' \
-                               "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
+                       "$merge_tool_path" -f -d -c '4wincmd w | wincmd J' \
+                               "$LOCAL" "$BASE" "$REMOTE" "$MERGED"
                else
                        "$merge_tool_path" -f -d -c 'wincmd l' \
                                "$LOCAL" "$MERGED" "$REMOTE"
diff --git a/pager.c b/pager.c
index e425070528f4f9fbf0953c9056d1ea43686e176f..4bc048148e043eabf1315bbcbae8ea4c6363b330 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -11,7 +11,6 @@
  * something different on Windows.
  */
 
-static const char *pager_argv[] = { NULL, NULL };
 static struct child_process pager_process = CHILD_PROCESS_INIT;
 
 static void wait_for_pager(int in_signal)
@@ -64,6 +63,16 @@ const char *git_pager(int stdout_is_tty)
        return pager;
 }
 
+void prepare_pager_args(struct child_process *pager_process, const char *pager)
+{
+       argv_array_push(&pager_process->args, pager);
+       pager_process->use_shell = 1;
+       if (!getenv("LESS"))
+               argv_array_push(&pager_process->env_array, "LESS=FRX");
+       if (!getenv("LV"))
+               argv_array_push(&pager_process->env_array, "LV=-c");
+}
+
 void setup_pager(void)
 {
        const char *pager = git_pager(isatty(1));
@@ -80,14 +89,8 @@ void setup_pager(void)
        setenv("GIT_PAGER_IN_USE", "true", 1);
 
        /* spawn the pager */
-       pager_argv[0] = pager;
-       pager_process.use_shell = 1;
-       pager_process.argv = pager_argv;
+       prepare_pager_args(&pager_process, pager);
        pager_process.in = -1;
-       if (!getenv("LESS"))
-               argv_array_push(&pager_process.env_array, "LESS=FRX");
-       if (!getenv("LV"))
-               argv_array_push(&pager_process.env_array, "LV=-c");
        argv_array_push(&pager_process.env_array, "GIT_PAGER_IN_USE");
        if (start_command(&pager_process))
                return;
index 84616c8e219bf3cf902643a8da62a2060d335c36..5be7cd1dbf50c850ee5e02dcfde69d7611c181b5 100644 (file)
@@ -327,7 +327,7 @@ int ie_match_stat(const struct index_state *istate,
         * by definition never matches what is in the work tree until it
         * actually gets added.
         */
-       if (ce->ce_flags & CE_INTENT_TO_ADD)
+       if (ce_intent_to_add(ce))
                return DATA_CHANGED | TYPE_CHANGED | MODE_CHANGED;
 
        changed = ce_match_stat_basic(ce, st);
@@ -1237,7 +1237,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,
 
                        if (cache_errno == ENOENT)
                                fmt = deleted_fmt;
-                       else if (ce->ce_flags & CE_INTENT_TO_ADD)
+                       else if (ce_intent_to_add(ce))
                                fmt = added_fmt; /* must be before other checks */
                        else if (changed & TYPE_CHANGED)
                                fmt = typechange_fmt;
index e85333a51b0b6a88bfcb212d40d39802eca74a1d..e65ea597641d9b7a0f83b7d09a3b45f82394d1ef 100644 (file)
@@ -439,8 +439,20 @@ static int run_slot(struct active_request_slot *slot,
        err = run_one_slot(slot, results);
 
        if (err != HTTP_OK && err != HTTP_REAUTH) {
-               error("RPC failed; result=%d, HTTP code = %ld",
-                     results->curl_result, results->http_code);
+               struct strbuf msg = STRBUF_INIT;
+               if (results->http_code && results->http_code != 200)
+                       strbuf_addf(&msg, "HTTP %ld", results->http_code);
+               if (results->curl_result != CURLE_OK) {
+                       if (msg.len)
+                               strbuf_addch(&msg, ' ');
+                       strbuf_addf(&msg, "curl %d", results->curl_result);
+                       if (curl_errorstr[0]) {
+                               strbuf_addch(&msg, ' ');
+                               strbuf_addstr(&msg, curl_errorstr);
+                       }
+               }
+               error("RPC failed; %s", msg.buf);
+               strbuf_release(&msg);
        }
 
        return err;
index f182382c834ee93f8ddc4b78750b6ce2ac5fa4f7..6e5c1a876f5044ffdea71531695ce04305b072f1 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1545,11 +1545,8 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                }
 
                /*
-                * Bypass the usual "must fast-forward" check but
-                * replace it with a weaker "the old value must be
-                * this value we observed".  If the remote ref has
-                * moved and is now different from what we expect,
-                * reject any push.
+                * If the remote ref has moved and is now different
+                * from what we expect, reject any push.
                 *
                 * It also is an error if the user told us to check
                 * with the remote-tracking branch to find the value
@@ -1560,10 +1557,14 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                        if (ref->expect_old_no_trackback ||
                            oidcmp(&ref->old_oid, &ref->old_oid_expect))
                                reject_reason = REF_STATUS_REJECT_STALE;
+                       else
+                               /* If the ref isn't stale then force the update. */
+                               force_ref_update = 1;
                }
 
                /*
-                * The usual "must fast-forward" rules.
+                * If the update isn't already rejected then check
+                * the usual "must fast-forward" rules.
                 *
                 * Decide whether an individual refspec A:B can be
                 * pushed.  The push will succeed if any of the
@@ -1582,7 +1583,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                 *     passing the --force argument
                 */
 
-               else if (!ref->deletion && !is_null_oid(&ref->old_oid)) {
+               if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) {
                        if (starts_with(ref->name, "refs/tags/"))
                                reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
                        else if (!has_object_file(&ref->old_oid))
index 171cbaa944adc0352eac635029cd22c78144a65e..2392b1efe829bf40ab1f896d160ac28c9bc057e0 100644 (file)
@@ -623,6 +623,11 @@ int in_async(void)
        return !pthread_equal(main_thread, pthread_self());
 }
 
+void NORETURN async_exit(int code)
+{
+       pthread_exit((void *)(intptr_t)code);
+}
+
 #else
 
 static struct {
@@ -668,6 +673,11 @@ int in_async(void)
        return process_is_async;
 }
 
+void NORETURN async_exit(int code)
+{
+       exit(code);
+}
+
 #endif
 
 int start_async(struct async *async)
index 12bb26c2a6155750203babfec47b08e8bde0ad27..c0969c7695f6b550b382b5704ceb9b2c23b3e3e0 100644 (file)
@@ -121,5 +121,6 @@ struct async {
 int start_async(struct async *async);
 int finish_async(struct async *async);
 int in_async(void);
+void NORETURN async_exit(int code);
 
 #endif
diff --git a/setup.c b/setup.c
index 669062a0906ce7a78810582332a2b6bb72c3d0c5..de1a2a7ea5973fef256328a26730117466c15172 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -139,9 +139,7 @@ int check_filename(const char *prefix, const char *arg)
                if (arg[2] == '\0') /* ":/" is root dir, always exists */
                        return 1;
                name = arg + 2;
-       } else if (!no_wildcard(arg))
-               return 1;
-       else if (prefix)
+       } else if (prefix)
                name = prefix_filename(prefix, strlen(prefix), arg);
        else
                name = arg;
@@ -202,7 +200,7 @@ void verify_filename(const char *prefix,
 {
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
-       if (check_filename(prefix, arg))
+       if (check_filename(prefix, arg) || !no_wildcard(arg))
                return;
        die_verify_filename(prefix, arg, diagnose_misspelt_rev);
 }
@@ -451,17 +449,6 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
        return ret;
 }
 
-static void update_linked_gitdir(const char *gitfile, const char *gitdir)
-{
-       struct strbuf path = STRBUF_INIT;
-       struct stat st;
-
-       strbuf_addf(&path, "%s/gitdir", gitdir);
-       if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
-               write_file(path.buf, "%s", gitfile);
-       strbuf_release(&path);
-}
-
 /*
  * Try to read the location of the git directory from the .git file,
  * return path to git directory if found.
@@ -530,7 +517,6 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
                error_code = READ_GITFILE_ERR_NOT_A_REPO;
                goto cleanup_return;
        }
-       update_linked_gitdir(path, dir);
        path = real_path(dir);
 
 cleanup_return:
index 532db4fdc6dcf905e99470e773a6166be2f903ed..ab5a163c9bab7f5799011b984715ed1ca9deed10 100644 (file)
@@ -881,12 +881,12 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
 
        if (prefix[0] == '!') {
                if (prefix[1] != '!')
-                       die ("Invalid search pattern: %s", prefix);
+                       return -1;
                prefix++;
        }
 
        if (regcomp(&regex, prefix, REG_EXTENDED))
-               die("Invalid search pattern: %s", prefix);
+               return -1;
 
        for (l = list; l; l = l->next) {
                l->item->object.flags |= ONELINE_SEEN;
index bd97b15a9284c45f8a64a43a32deaf190cd243ea..2a6cc9e8bab8f8ac198d7621131bcd70b38956a3 100644 (file)
@@ -68,7 +68,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
        strbuf_addstr(&entry, "submodule.");
        strbuf_addstr(&entry, submodule->name);
        strbuf_addstr(&entry, ".path");
-       if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
+       if (git_config_set_in_file_gently(".gitmodules", entry.buf, newpath) < 0) {
                /* Maybe the user already did that, don't error out here */
                warning(_("Could not update .gitmodules entry %s"), entry.buf);
                strbuf_release(&entry);
@@ -1034,11 +1034,9 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)
        /* Update core.worktree setting */
        strbuf_reset(&file_name);
        strbuf_addf(&file_name, "%s/config", git_dir);
-       if (git_config_set_in_file(file_name.buf, "core.worktree",
-                                  relative_path(real_work_tree, git_dir,
-                                                &rel_path)))
-               die(_("Could not set core.worktree in %s"),
-                   file_name.buf);
+       git_config_set_in_file(file_name.buf, "core.worktree",
+                              relative_path(real_work_tree, git_dir,
+                                            &rel_path));
 
        strbuf_release(&file_name);
        strbuf_release(&rel_path);
diff --git a/t/t1501-work-tree.sh b/t/t1501-work-tree.sh
new file mode 100755 (executable)
index 0000000..cc5b870
--- /dev/null
@@ -0,0 +1,426 @@
+#!/bin/sh
+
+test_description='test separate work tree'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       EMPTY_TREE=$(git write-tree) &&
+       EMPTY_BLOB=$(git hash-object -t blob --stdin </dev/null) &&
+       CHANGED_BLOB=$(echo changed | git hash-object -t blob --stdin) &&
+       EMPTY_BLOB7=$(echo $EMPTY_BLOB | sed "s/\(.......\).*/\1/") &&
+       CHANGED_BLOB7=$(echo $CHANGED_BLOB | sed "s/\(.......\).*/\1/") &&
+
+       mkdir -p work/sub/dir &&
+       mkdir -p work2 &&
+       mv .git repo.git
+'
+
+test_expect_success 'setup: helper for testing rev-parse' '
+       test_rev_parse() {
+               echo $1 >expected.bare &&
+               echo $2 >expected.inside-git &&
+               echo $3 >expected.inside-worktree &&
+               if test $# -ge 4
+               then
+                       echo $4 >expected.prefix
+               fi &&
+
+               git rev-parse --is-bare-repository >actual.bare &&
+               git rev-parse --is-inside-git-dir >actual.inside-git &&
+               git rev-parse --is-inside-work-tree >actual.inside-worktree &&
+               if test $# -ge 4
+               then
+                       git rev-parse --show-prefix >actual.prefix
+               fi &&
+
+               test_cmp expected.bare actual.bare &&
+               test_cmp expected.inside-git actual.inside-git &&
+               test_cmp expected.inside-worktree actual.inside-worktree &&
+               if test $# -ge 4
+               then
+                       # rev-parse --show-prefix should output
+                       # a single newline when at the top of the work tree,
+                       # but we test for that separately.
+                       test -z "$4" && ! test -s actual.prefix ||
+                       test_cmp expected.prefix actual.prefix
+               fi
+       }
+'
+
+test_expect_success 'setup: core.worktree = relative path' '
+       sane_unset GIT_WORK_TREE &&
+       GIT_DIR=repo.git &&
+       GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
+       export GIT_DIR GIT_CONFIG &&
+       git config core.worktree ../work
+'
+
+test_expect_success 'outside' '
+       test_rev_parse false false false
+'
+
+test_expect_success 'inside work tree' '
+       (
+               cd work &&
+               GIT_DIR=../repo.git &&
+               GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
+               test_rev_parse false false true ""
+       )
+'
+
+test_expect_success 'empty prefix is actually written out' '
+       echo >expected &&
+       (
+               cd work &&
+               GIT_DIR=../repo.git &&
+               GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
+               git rev-parse --show-prefix >../actual
+       ) &&
+       test_cmp expected actual
+'
+
+test_expect_success 'subdir of work tree' '
+       (
+               cd work/sub/dir &&
+               GIT_DIR=../../../repo.git &&
+               GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
+               test_rev_parse false false true sub/dir/
+       )
+'
+
+test_expect_success 'setup: core.worktree = absolute path' '
+       sane_unset GIT_WORK_TREE &&
+       GIT_DIR=$(pwd)/repo.git &&
+       GIT_CONFIG=$GIT_DIR/config &&
+       export GIT_DIR GIT_CONFIG &&
+       git config core.worktree "$(pwd)/work"
+'
+
+test_expect_success 'outside' '
+       test_rev_parse false false false &&
+       (
+               cd work2 &&
+               test_rev_parse false false false
+       )
+'
+
+test_expect_success 'inside work tree' '
+       (
+               cd work &&
+               test_rev_parse false false true ""
+       )
+'
+
+test_expect_success 'subdir of work tree' '
+       (
+               cd work/sub/dir &&
+               test_rev_parse false false true sub/dir/
+       )
+'
+
+test_expect_success 'setup: GIT_WORK_TREE=relative (override core.worktree)' '
+       GIT_DIR=$(pwd)/repo.git &&
+       GIT_CONFIG=$GIT_DIR/config &&
+       git config core.worktree non-existent &&
+       GIT_WORK_TREE=work &&
+       export GIT_DIR GIT_CONFIG GIT_WORK_TREE
+'
+
+test_expect_success 'outside' '
+       test_rev_parse false false false &&
+       (
+               cd work2 &&
+               test_rev_parse false false false
+       )
+'
+
+test_expect_success 'inside work tree' '
+       (
+               cd work &&
+               GIT_WORK_TREE=. &&
+               test_rev_parse false false true ""
+       )
+'
+
+test_expect_success 'subdir of work tree' '
+       (
+               cd work/sub/dir &&
+               GIT_WORK_TREE=../.. &&
+               test_rev_parse false false true sub/dir/
+       )
+'
+
+test_expect_success 'setup: GIT_WORK_TREE=absolute, below git dir' '
+       mv work repo.git/work &&
+       mv work2 repo.git/work2 &&
+       GIT_DIR=$(pwd)/repo.git &&
+       GIT_CONFIG=$GIT_DIR/config &&
+       GIT_WORK_TREE=$(pwd)/repo.git/work &&
+       export GIT_DIR GIT_CONFIG GIT_WORK_TREE
+'
+
+test_expect_success 'outside' '
+       echo outside &&
+       test_rev_parse false false false
+'
+
+test_expect_success 'in repo.git' '
+       (
+               cd repo.git &&
+               test_rev_parse false true false
+       ) &&
+       (
+               cd repo.git/objects &&
+               test_rev_parse false true false
+       ) &&
+       (
+               cd repo.git/work2 &&
+               test_rev_parse false true false
+       )
+'
+
+test_expect_success 'inside work tree' '
+       (
+               cd repo.git/work &&
+               test_rev_parse false true true ""
+       )
+'
+
+test_expect_success 'subdir of work tree' '
+       (
+               cd repo.git/work/sub/dir &&
+               test_rev_parse false true true sub/dir/
+       )
+'
+
+test_expect_success 'find work tree from repo' '
+       echo sub/dir/untracked >expected &&
+       cat <<-\EOF >repo.git/work/.gitignore &&
+       expected.*
+       actual.*
+       .gitignore
+       EOF
+       >repo.git/work/sub/dir/untracked &&
+       (
+               cd repo.git &&
+               git ls-files --others --exclude-standard >../actual
+       ) &&
+       test_cmp expected actual
+'
+
+test_expect_success 'find work tree from work tree' '
+       echo sub/dir/tracked >expected &&
+       >repo.git/work/sub/dir/tracked &&
+       (
+               cd repo.git/work/sub/dir &&
+               git --git-dir=../../.. add tracked
+       ) &&
+       (
+               cd repo.git &&
+               git ls-files >../actual
+       ) &&
+       test_cmp expected actual
+'
+
+test_expect_success '_gently() groks relative GIT_DIR & GIT_WORK_TREE' '
+       (
+               cd repo.git/work/sub/dir &&
+               GIT_DIR=../../.. &&
+               GIT_WORK_TREE=../.. &&
+               GIT_PAGER= &&
+               export GIT_DIR GIT_WORK_TREE GIT_PAGER &&
+
+               git diff --exit-code tracked &&
+               echo changed >tracked &&
+               test_must_fail git diff --exit-code tracked
+       )
+'
+
+test_expect_success 'diff-index respects work tree under .git dir' '
+       cat >diff-index-cached.expected <<-EOF &&
+       :000000 100644 $_z40 $EMPTY_BLOB A      sub/dir/tracked
+       EOF
+       cat >diff-index.expected <<-EOF &&
+       :000000 100644 $_z40 $_z40 A    sub/dir/tracked
+       EOF
+
+       (
+               GIT_DIR=repo.git &&
+               GIT_WORK_TREE=repo.git/work &&
+               export GIT_DIR GIT_WORK_TREE &&
+               git diff-index $EMPTY_TREE >diff-index.actual &&
+               git diff-index --cached $EMPTY_TREE >diff-index-cached.actual
+       ) &&
+       test_cmp diff-index.expected diff-index.actual &&
+       test_cmp diff-index-cached.expected diff-index-cached.actual
+'
+
+test_expect_success 'diff-files respects work tree under .git dir' '
+       cat >diff-files.expected <<-EOF &&
+       :100644 100644 $EMPTY_BLOB $_z40 M      sub/dir/tracked
+       EOF
+
+       (
+               GIT_DIR=repo.git &&
+               GIT_WORK_TREE=repo.git/work &&
+               export GIT_DIR GIT_WORK_TREE &&
+               git diff-files >diff-files.actual
+       ) &&
+       test_cmp diff-files.expected diff-files.actual
+'
+
+test_expect_success 'git diff respects work tree under .git dir' '
+       cat >diff-TREE.expected <<-EOF &&
+       diff --git a/sub/dir/tracked b/sub/dir/tracked
+       new file mode 100644
+       index 0000000..$CHANGED_BLOB7
+       --- /dev/null
+       +++ b/sub/dir/tracked
+       @@ -0,0 +1 @@
+       +changed
+       EOF
+       cat >diff-TREE-cached.expected <<-EOF &&
+       diff --git a/sub/dir/tracked b/sub/dir/tracked
+       new file mode 100644
+       index 0000000..$EMPTY_BLOB7
+       EOF
+       cat >diff-FILES.expected <<-EOF &&
+       diff --git a/sub/dir/tracked b/sub/dir/tracked
+       index $EMPTY_BLOB7..$CHANGED_BLOB7 100644
+       --- a/sub/dir/tracked
+       +++ b/sub/dir/tracked
+       @@ -0,0 +1 @@
+       +changed
+       EOF
+
+       (
+               GIT_DIR=repo.git &&
+               GIT_WORK_TREE=repo.git/work &&
+               export GIT_DIR GIT_WORK_TREE &&
+               git diff $EMPTY_TREE >diff-TREE.actual &&
+               git diff --cached $EMPTY_TREE >diff-TREE-cached.actual &&
+               git diff >diff-FILES.actual
+       ) &&
+       test_cmp diff-TREE.expected diff-TREE.actual &&
+       test_cmp diff-TREE-cached.expected diff-TREE-cached.actual &&
+       test_cmp diff-FILES.expected diff-FILES.actual
+'
+
+test_expect_success 'git grep' '
+       echo dir/tracked >expected.grep &&
+       (
+               cd repo.git/work/sub &&
+               GIT_DIR=../.. &&
+               GIT_WORK_TREE=.. &&
+               export GIT_DIR GIT_WORK_TREE &&
+               git grep -l changed >../../../actual.grep
+       ) &&
+       test_cmp expected.grep actual.grep
+'
+
+test_expect_success 'git commit' '
+       (
+               cd repo.git &&
+               GIT_DIR=. GIT_WORK_TREE=work git commit -a -m done
+       )
+'
+
+test_expect_success 'absolute pathspec should fail gracefully' '
+       (
+               cd repo.git &&
+               test_might_fail git config --unset core.worktree &&
+               test_must_fail git log HEAD -- /home
+       )
+'
+
+test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
+       >dummy_file &&
+       echo git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file &&
+       git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
+'
+
+test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
+       GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
+       test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&
+       echo "$(pwd)/repo.git/work" >expected &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Multi-worktree setup' '
+       mkdir work &&
+       mkdir -p repo.git/repos/foo &&
+       cp repo.git/HEAD repo.git/index repo.git/repos/foo &&
+       test_might_fail cp repo.git/sharedindex.* repo.git/repos/foo &&
+       sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE
+'
+
+test_expect_success 'GIT_DIR set (1)' '
+       echo "gitdir: repo.git/repos/foo" >gitfile &&
+       echo ../.. >repo.git/repos/foo/commondir &&
+       (
+               cd work &&
+               GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
+               test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'GIT_DIR set (2)' '
+       echo "gitdir: repo.git/repos/foo" >gitfile &&
+       echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir &&
+       (
+               cd work &&
+               GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
+               test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'Auto discovery' '
+       echo "gitdir: repo.git/repos/foo" >.git &&
+       echo ../.. >repo.git/repos/foo/commondir &&
+       (
+               cd work &&
+               git rev-parse --git-common-dir >actual &&
+               test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
+               test_cmp expect actual &&
+               echo haha >data1 &&
+               git add data1 &&
+               git ls-files --full-name :/ | grep data1 >actual &&
+               echo work/data1 >expect &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success '$GIT_DIR/common overrides core.worktree' '
+       mkdir elsewhere &&
+       git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" &&
+       echo "gitdir: repo.git/repos/foo" >.git &&
+       echo ../.. >repo.git/repos/foo/commondir &&
+       (
+               cd work &&
+               git rev-parse --git-common-dir >actual &&
+               test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
+               test_cmp expect actual &&
+               echo haha >data2 &&
+               git add data2 &&
+               git ls-files --full-name :/ | grep data2 >actual &&
+               echo work/data2 >expect &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' '
+       echo "gitdir: repo.git/repos/foo" >.git &&
+       echo ../.. >repo.git/repos/foo/commondir &&
+       (
+               cd work &&
+               echo haha >data3 &&
+               git --git-dir=../.git --work-tree=. add data3 &&
+               git ls-files --full-name -- :/ | grep data3 >actual &&
+               echo data3 >expect &&
+               test_cmp expect actual
+       )
+'
+
+test_done
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
deleted file mode 100755 (executable)
index cc5b870..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-#!/bin/sh
-
-test_description='test separate work tree'
-. ./test-lib.sh
-
-test_expect_success 'setup' '
-       EMPTY_TREE=$(git write-tree) &&
-       EMPTY_BLOB=$(git hash-object -t blob --stdin </dev/null) &&
-       CHANGED_BLOB=$(echo changed | git hash-object -t blob --stdin) &&
-       EMPTY_BLOB7=$(echo $EMPTY_BLOB | sed "s/\(.......\).*/\1/") &&
-       CHANGED_BLOB7=$(echo $CHANGED_BLOB | sed "s/\(.......\).*/\1/") &&
-
-       mkdir -p work/sub/dir &&
-       mkdir -p work2 &&
-       mv .git repo.git
-'
-
-test_expect_success 'setup: helper for testing rev-parse' '
-       test_rev_parse() {
-               echo $1 >expected.bare &&
-               echo $2 >expected.inside-git &&
-               echo $3 >expected.inside-worktree &&
-               if test $# -ge 4
-               then
-                       echo $4 >expected.prefix
-               fi &&
-
-               git rev-parse --is-bare-repository >actual.bare &&
-               git rev-parse --is-inside-git-dir >actual.inside-git &&
-               git rev-parse --is-inside-work-tree >actual.inside-worktree &&
-               if test $# -ge 4
-               then
-                       git rev-parse --show-prefix >actual.prefix
-               fi &&
-
-               test_cmp expected.bare actual.bare &&
-               test_cmp expected.inside-git actual.inside-git &&
-               test_cmp expected.inside-worktree actual.inside-worktree &&
-               if test $# -ge 4
-               then
-                       # rev-parse --show-prefix should output
-                       # a single newline when at the top of the work tree,
-                       # but we test for that separately.
-                       test -z "$4" && ! test -s actual.prefix ||
-                       test_cmp expected.prefix actual.prefix
-               fi
-       }
-'
-
-test_expect_success 'setup: core.worktree = relative path' '
-       sane_unset GIT_WORK_TREE &&
-       GIT_DIR=repo.git &&
-       GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
-       export GIT_DIR GIT_CONFIG &&
-       git config core.worktree ../work
-'
-
-test_expect_success 'outside' '
-       test_rev_parse false false false
-'
-
-test_expect_success 'inside work tree' '
-       (
-               cd work &&
-               GIT_DIR=../repo.git &&
-               GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
-               test_rev_parse false false true ""
-       )
-'
-
-test_expect_success 'empty prefix is actually written out' '
-       echo >expected &&
-       (
-               cd work &&
-               GIT_DIR=../repo.git &&
-               GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
-               git rev-parse --show-prefix >../actual
-       ) &&
-       test_cmp expected actual
-'
-
-test_expect_success 'subdir of work tree' '
-       (
-               cd work/sub/dir &&
-               GIT_DIR=../../../repo.git &&
-               GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
-               test_rev_parse false false true sub/dir/
-       )
-'
-
-test_expect_success 'setup: core.worktree = absolute path' '
-       sane_unset GIT_WORK_TREE &&
-       GIT_DIR=$(pwd)/repo.git &&
-       GIT_CONFIG=$GIT_DIR/config &&
-       export GIT_DIR GIT_CONFIG &&
-       git config core.worktree "$(pwd)/work"
-'
-
-test_expect_success 'outside' '
-       test_rev_parse false false false &&
-       (
-               cd work2 &&
-               test_rev_parse false false false
-       )
-'
-
-test_expect_success 'inside work tree' '
-       (
-               cd work &&
-               test_rev_parse false false true ""
-       )
-'
-
-test_expect_success 'subdir of work tree' '
-       (
-               cd work/sub/dir &&
-               test_rev_parse false false true sub/dir/
-       )
-'
-
-test_expect_success 'setup: GIT_WORK_TREE=relative (override core.worktree)' '
-       GIT_DIR=$(pwd)/repo.git &&
-       GIT_CONFIG=$GIT_DIR/config &&
-       git config core.worktree non-existent &&
-       GIT_WORK_TREE=work &&
-       export GIT_DIR GIT_CONFIG GIT_WORK_TREE
-'
-
-test_expect_success 'outside' '
-       test_rev_parse false false false &&
-       (
-               cd work2 &&
-               test_rev_parse false false false
-       )
-'
-
-test_expect_success 'inside work tree' '
-       (
-               cd work &&
-               GIT_WORK_TREE=. &&
-               test_rev_parse false false true ""
-       )
-'
-
-test_expect_success 'subdir of work tree' '
-       (
-               cd work/sub/dir &&
-               GIT_WORK_TREE=../.. &&
-               test_rev_parse false false true sub/dir/
-       )
-'
-
-test_expect_success 'setup: GIT_WORK_TREE=absolute, below git dir' '
-       mv work repo.git/work &&
-       mv work2 repo.git/work2 &&
-       GIT_DIR=$(pwd)/repo.git &&
-       GIT_CONFIG=$GIT_DIR/config &&
-       GIT_WORK_TREE=$(pwd)/repo.git/work &&
-       export GIT_DIR GIT_CONFIG GIT_WORK_TREE
-'
-
-test_expect_success 'outside' '
-       echo outside &&
-       test_rev_parse false false false
-'
-
-test_expect_success 'in repo.git' '
-       (
-               cd repo.git &&
-               test_rev_parse false true false
-       ) &&
-       (
-               cd repo.git/objects &&
-               test_rev_parse false true false
-       ) &&
-       (
-               cd repo.git/work2 &&
-               test_rev_parse false true false
-       )
-'
-
-test_expect_success 'inside work tree' '
-       (
-               cd repo.git/work &&
-               test_rev_parse false true true ""
-       )
-'
-
-test_expect_success 'subdir of work tree' '
-       (
-               cd repo.git/work/sub/dir &&
-               test_rev_parse false true true sub/dir/
-       )
-'
-
-test_expect_success 'find work tree from repo' '
-       echo sub/dir/untracked >expected &&
-       cat <<-\EOF >repo.git/work/.gitignore &&
-       expected.*
-       actual.*
-       .gitignore
-       EOF
-       >repo.git/work/sub/dir/untracked &&
-       (
-               cd repo.git &&
-               git ls-files --others --exclude-standard >../actual
-       ) &&
-       test_cmp expected actual
-'
-
-test_expect_success 'find work tree from work tree' '
-       echo sub/dir/tracked >expected &&
-       >repo.git/work/sub/dir/tracked &&
-       (
-               cd repo.git/work/sub/dir &&
-               git --git-dir=../../.. add tracked
-       ) &&
-       (
-               cd repo.git &&
-               git ls-files >../actual
-       ) &&
-       test_cmp expected actual
-'
-
-test_expect_success '_gently() groks relative GIT_DIR & GIT_WORK_TREE' '
-       (
-               cd repo.git/work/sub/dir &&
-               GIT_DIR=../../.. &&
-               GIT_WORK_TREE=../.. &&
-               GIT_PAGER= &&
-               export GIT_DIR GIT_WORK_TREE GIT_PAGER &&
-
-               git diff --exit-code tracked &&
-               echo changed >tracked &&
-               test_must_fail git diff --exit-code tracked
-       )
-'
-
-test_expect_success 'diff-index respects work tree under .git dir' '
-       cat >diff-index-cached.expected <<-EOF &&
-       :000000 100644 $_z40 $EMPTY_BLOB A      sub/dir/tracked
-       EOF
-       cat >diff-index.expected <<-EOF &&
-       :000000 100644 $_z40 $_z40 A    sub/dir/tracked
-       EOF
-
-       (
-               GIT_DIR=repo.git &&
-               GIT_WORK_TREE=repo.git/work &&
-               export GIT_DIR GIT_WORK_TREE &&
-               git diff-index $EMPTY_TREE >diff-index.actual &&
-               git diff-index --cached $EMPTY_TREE >diff-index-cached.actual
-       ) &&
-       test_cmp diff-index.expected diff-index.actual &&
-       test_cmp diff-index-cached.expected diff-index-cached.actual
-'
-
-test_expect_success 'diff-files respects work tree under .git dir' '
-       cat >diff-files.expected <<-EOF &&
-       :100644 100644 $EMPTY_BLOB $_z40 M      sub/dir/tracked
-       EOF
-
-       (
-               GIT_DIR=repo.git &&
-               GIT_WORK_TREE=repo.git/work &&
-               export GIT_DIR GIT_WORK_TREE &&
-               git diff-files >diff-files.actual
-       ) &&
-       test_cmp diff-files.expected diff-files.actual
-'
-
-test_expect_success 'git diff respects work tree under .git dir' '
-       cat >diff-TREE.expected <<-EOF &&
-       diff --git a/sub/dir/tracked b/sub/dir/tracked
-       new file mode 100644
-       index 0000000..$CHANGED_BLOB7
-       --- /dev/null
-       +++ b/sub/dir/tracked
-       @@ -0,0 +1 @@
-       +changed
-       EOF
-       cat >diff-TREE-cached.expected <<-EOF &&
-       diff --git a/sub/dir/tracked b/sub/dir/tracked
-       new file mode 100644
-       index 0000000..$EMPTY_BLOB7
-       EOF
-       cat >diff-FILES.expected <<-EOF &&
-       diff --git a/sub/dir/tracked b/sub/dir/tracked
-       index $EMPTY_BLOB7..$CHANGED_BLOB7 100644
-       --- a/sub/dir/tracked
-       +++ b/sub/dir/tracked
-       @@ -0,0 +1 @@
-       +changed
-       EOF
-
-       (
-               GIT_DIR=repo.git &&
-               GIT_WORK_TREE=repo.git/work &&
-               export GIT_DIR GIT_WORK_TREE &&
-               git diff $EMPTY_TREE >diff-TREE.actual &&
-               git diff --cached $EMPTY_TREE >diff-TREE-cached.actual &&
-               git diff >diff-FILES.actual
-       ) &&
-       test_cmp diff-TREE.expected diff-TREE.actual &&
-       test_cmp diff-TREE-cached.expected diff-TREE-cached.actual &&
-       test_cmp diff-FILES.expected diff-FILES.actual
-'
-
-test_expect_success 'git grep' '
-       echo dir/tracked >expected.grep &&
-       (
-               cd repo.git/work/sub &&
-               GIT_DIR=../.. &&
-               GIT_WORK_TREE=.. &&
-               export GIT_DIR GIT_WORK_TREE &&
-               git grep -l changed >../../../actual.grep
-       ) &&
-       test_cmp expected.grep actual.grep
-'
-
-test_expect_success 'git commit' '
-       (
-               cd repo.git &&
-               GIT_DIR=. GIT_WORK_TREE=work git commit -a -m done
-       )
-'
-
-test_expect_success 'absolute pathspec should fail gracefully' '
-       (
-               cd repo.git &&
-               test_might_fail git config --unset core.worktree &&
-               test_must_fail git log HEAD -- /home
-       )
-'
-
-test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
-       >dummy_file &&
-       echo git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file &&
-       git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
-'
-
-test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
-       GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
-       test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&
-       echo "$(pwd)/repo.git/work" >expected &&
-       test_cmp expected actual
-'
-
-test_expect_success 'Multi-worktree setup' '
-       mkdir work &&
-       mkdir -p repo.git/repos/foo &&
-       cp repo.git/HEAD repo.git/index repo.git/repos/foo &&
-       test_might_fail cp repo.git/sharedindex.* repo.git/repos/foo &&
-       sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE
-'
-
-test_expect_success 'GIT_DIR set (1)' '
-       echo "gitdir: repo.git/repos/foo" >gitfile &&
-       echo ../.. >repo.git/repos/foo/commondir &&
-       (
-               cd work &&
-               GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
-               test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
-               test_cmp expect actual
-       )
-'
-
-test_expect_success 'GIT_DIR set (2)' '
-       echo "gitdir: repo.git/repos/foo" >gitfile &&
-       echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir &&
-       (
-               cd work &&
-               GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
-               test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
-               test_cmp expect actual
-       )
-'
-
-test_expect_success 'Auto discovery' '
-       echo "gitdir: repo.git/repos/foo" >.git &&
-       echo ../.. >repo.git/repos/foo/commondir &&
-       (
-               cd work &&
-               git rev-parse --git-common-dir >actual &&
-               test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
-               test_cmp expect actual &&
-               echo haha >data1 &&
-               git add data1 &&
-               git ls-files --full-name :/ | grep data1 >actual &&
-               echo work/data1 >expect &&
-               test_cmp expect actual
-       )
-'
-
-test_expect_success '$GIT_DIR/common overrides core.worktree' '
-       mkdir elsewhere &&
-       git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" &&
-       echo "gitdir: repo.git/repos/foo" >.git &&
-       echo ../.. >repo.git/repos/foo/commondir &&
-       (
-               cd work &&
-               git rev-parse --git-common-dir >actual &&
-               test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
-               test_cmp expect actual &&
-               echo haha >data2 &&
-               git add data2 &&
-               git ls-files --full-name :/ | grep data2 >actual &&
-               echo work/data2 >expect &&
-               test_cmp expect actual
-       )
-'
-
-test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' '
-       echo "gitdir: repo.git/repos/foo" >.git &&
-       echo ../.. >repo.git/repos/foo/commondir &&
-       (
-               cd work &&
-               echo haha >data3 &&
-               git --git-dir=../.git --work-tree=. add data3 &&
-               git ls-files --full-name -- :/ | grep data3 >actual &&
-               echo data3 >expect &&
-               test_cmp expect actual
-       )
-'
-
-test_done
diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh
new file mode 100755 (executable)
index 0000000..553a3f6
--- /dev/null
@@ -0,0 +1,258 @@
+#!/bin/sh
+
+test_description='Test Git when git repository is located at root
+
+This test requires write access in root. Do not bother if you do not
+have a throwaway chroot or VM.
+
+Script t1509/prepare-chroot.sh may help you setup chroot, then you
+can chroot in and execute this test from there.
+'
+
+. ./test-lib.sh
+
+test_cmp_val() {
+       echo "$1" > expected
+       echo "$2" > result
+       test_cmp expected result
+}
+
+test_vars() {
+       test_expect_success "$1: gitdir" '
+               test_cmp_val "'"$2"'" "$(git rev-parse --git-dir)"
+       '
+
+       test_expect_success "$1: worktree" '
+               test_cmp_val "'"$3"'" "$(git rev-parse --show-toplevel)"
+       '
+
+       test_expect_success "$1: prefix" '
+               test_cmp_val "'"$4"'" "$(git rev-parse --show-prefix)"
+       '
+}
+
+test_foobar_root() {
+       test_expect_success 'add relative' '
+               test -z "$(cd / && git ls-files)" &&
+               git add foo/foome &&
+               git add foo/bar/barme &&
+               git add me &&
+               ( cd / && git ls-files --stage ) > result &&
+               test_cmp /ls.expected result &&
+               rm "$(git rev-parse --git-dir)/index"
+       '
+
+       test_expect_success 'add absolute' '
+               test -z "$(cd / && git ls-files)" &&
+               git add /foo/foome &&
+               git add /foo/bar/barme &&
+               git add /me &&
+               ( cd / && git ls-files --stage ) > result &&
+               test_cmp /ls.expected result &&
+               rm "$(git rev-parse --git-dir)/index"
+       '
+
+}
+
+test_foobar_foo() {
+       test_expect_success 'add relative' '
+               test -z "$(cd / && git ls-files)" &&
+               git add foome &&
+               git add bar/barme &&
+               git add ../me &&
+               ( cd / && git ls-files --stage ) > result &&
+               test_cmp /ls.expected result &&
+               rm "$(git rev-parse --git-dir)/index"
+       '
+
+       test_expect_success 'add absolute' '
+               test -z "$(cd / && git ls-files)" &&
+               git add /foo/foome &&
+               git add /foo/bar/barme &&
+               git add /me &&
+               ( cd / && git ls-files --stage ) > result &&
+               test_cmp /ls.expected result &&
+               rm "$(git rev-parse --git-dir)/index"
+       '
+}
+
+test_foobar_foobar() {
+       test_expect_success 'add relative' '
+               test -z "$(cd / && git ls-files)" &&
+               git add ../foome &&
+               git add barme &&
+               git add ../../me &&
+               ( cd / && git ls-files --stage ) > result &&
+               test_cmp /ls.expected result &&
+               rm "$(git rev-parse --git-dir)/index"
+       '
+
+       test_expect_success 'add absolute' '
+               test -z "$(cd / && git ls-files)" &&
+               git add /foo/foome &&
+               git add /foo/bar/barme &&
+               git add /me &&
+               ( cd / && git ls-files --stage ) > result &&
+               test_cmp /ls.expected result &&
+               rm "$(git rev-parse --git-dir)/index"
+       '
+}
+
+if ! test -w /
+then
+       skip_all="Test requiring writable / skipped. Read this test if you want to run it"
+       test_done
+fi
+
+if  test -e /refs || test -e /objects || test -e /info || test -e /hooks ||
+    test -e /.git || test -e /foo || test -e /me
+then
+       skip_all="Skip test that clobbers existing files in /"
+       test_done
+fi
+
+if [ "$IKNOWWHATIAMDOING" != "YES" ]; then
+       skip_all="You must set env var IKNOWWHATIAMDOING=YES in order to run this test"
+       test_done
+fi
+
+if ! test_have_prereq NOT_ROOT
+then
+       skip_all="No you can't run this as root"
+       test_done
+fi
+
+ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d
+
+test_expect_success 'setup' '
+       rm -rf /foo &&
+       mkdir /foo &&
+       mkdir /foo/bar &&
+       echo 1 > /foo/foome &&
+       echo 1 > /foo/bar/barme &&
+       echo 1 > /me
+'
+
+say "GIT_DIR absolute, GIT_WORK_TREE set"
+
+test_expect_success 'go to /' 'cd /'
+
+cat >ls.expected <<EOF
+100644 $ONE_SHA1 0     foo/bar/barme
+100644 $ONE_SHA1 0     foo/foome
+100644 $ONE_SHA1 0     me
+EOF
+
+GIT_DIR="$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=/ && export GIT_WORK_TREE
+
+test_vars 'abs gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+test_vars 'abs gitdir, foo' "$GIT_DIR" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+test_vars 'abs gitdir, foo/bar' "$GIT_DIR" "/" "foo/bar/"
+test_foobar_foobar
+
+say "GIT_DIR relative, GIT_WORK_TREE set"
+
+test_expect_success 'go to /' 'cd /'
+
+GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git" && export GIT_DIR
+GIT_WORK_TREE=/ && export GIT_WORK_TREE
+
+test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+GIT_DIR="../$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=/ && export GIT_WORK_TREE
+
+test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+GIT_DIR="../../$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=/ && export GIT_WORK_TREE
+
+test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+say "GIT_DIR relative, GIT_WORK_TREE relative"
+
+test_expect_success 'go to /' 'cd /'
+
+GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git" && export GIT_DIR
+GIT_WORK_TREE=. && export GIT_WORK_TREE
+
+test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /' 'cd /foo'
+
+GIT_DIR="../$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=.. && export GIT_WORK_TREE
+
+test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+
+GIT_DIR="../../$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=../.. && export GIT_WORK_TREE
+
+test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+say ".git at root"
+
+unset GIT_DIR
+unset GIT_WORK_TREE
+
+test_expect_success 'go to /' 'cd /'
+test_expect_success 'setup' '
+       rm -rf /.git &&
+       echo "Initialized empty Git repository in /.git/" > expected &&
+       git init > result &&
+       test_cmp expected result
+'
+
+test_vars 'auto gitdir, root' ".git" "/" ""
+test_foobar_root
+
+test_expect_success 'go to /foo' 'cd /foo'
+test_vars 'auto gitdir, foo' "/.git" "/" "foo/"
+test_foobar_foo
+
+test_expect_success 'go to /foo/bar' 'cd /foo/bar'
+test_vars 'auto gitdir, foo/bar' "/.git" "/" "foo/bar/"
+test_foobar_foobar
+
+test_expect_success 'cleanup' 'rm -rf /.git'
+
+say "auto bare gitdir"
+
+# DESTROYYYYY!!!!!
+test_expect_success 'setup' '
+       rm -rf /refs /objects /info /hooks &&
+       rm -f /expected /ls.expected /me /result &&
+       cd / &&
+       echo "Initialized empty Git repository in /" > expected &&
+       git init --bare > result &&
+       test_cmp expected result
+'
+
+test_vars 'auto gitdir, root' "." "" ""
+
+test_expect_success 'go to /foo' 'cd /foo'
+
+test_vars 'auto gitdir, root' "/" "" ""
+
+test_done
diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh
deleted file mode 100755 (executable)
index 553a3f6..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-#!/bin/sh
-
-test_description='Test Git when git repository is located at root
-
-This test requires write access in root. Do not bother if you do not
-have a throwaway chroot or VM.
-
-Script t1509/prepare-chroot.sh may help you setup chroot, then you
-can chroot in and execute this test from there.
-'
-
-. ./test-lib.sh
-
-test_cmp_val() {
-       echo "$1" > expected
-       echo "$2" > result
-       test_cmp expected result
-}
-
-test_vars() {
-       test_expect_success "$1: gitdir" '
-               test_cmp_val "'"$2"'" "$(git rev-parse --git-dir)"
-       '
-
-       test_expect_success "$1: worktree" '
-               test_cmp_val "'"$3"'" "$(git rev-parse --show-toplevel)"
-       '
-
-       test_expect_success "$1: prefix" '
-               test_cmp_val "'"$4"'" "$(git rev-parse --show-prefix)"
-       '
-}
-
-test_foobar_root() {
-       test_expect_success 'add relative' '
-               test -z "$(cd / && git ls-files)" &&
-               git add foo/foome &&
-               git add foo/bar/barme &&
-               git add me &&
-               ( cd / && git ls-files --stage ) > result &&
-               test_cmp /ls.expected result &&
-               rm "$(git rev-parse --git-dir)/index"
-       '
-
-       test_expect_success 'add absolute' '
-               test -z "$(cd / && git ls-files)" &&
-               git add /foo/foome &&
-               git add /foo/bar/barme &&
-               git add /me &&
-               ( cd / && git ls-files --stage ) > result &&
-               test_cmp /ls.expected result &&
-               rm "$(git rev-parse --git-dir)/index"
-       '
-
-}
-
-test_foobar_foo() {
-       test_expect_success 'add relative' '
-               test -z "$(cd / && git ls-files)" &&
-               git add foome &&
-               git add bar/barme &&
-               git add ../me &&
-               ( cd / && git ls-files --stage ) > result &&
-               test_cmp /ls.expected result &&
-               rm "$(git rev-parse --git-dir)/index"
-       '
-
-       test_expect_success 'add absolute' '
-               test -z "$(cd / && git ls-files)" &&
-               git add /foo/foome &&
-               git add /foo/bar/barme &&
-               git add /me &&
-               ( cd / && git ls-files --stage ) > result &&
-               test_cmp /ls.expected result &&
-               rm "$(git rev-parse --git-dir)/index"
-       '
-}
-
-test_foobar_foobar() {
-       test_expect_success 'add relative' '
-               test -z "$(cd / && git ls-files)" &&
-               git add ../foome &&
-               git add barme &&
-               git add ../../me &&
-               ( cd / && git ls-files --stage ) > result &&
-               test_cmp /ls.expected result &&
-               rm "$(git rev-parse --git-dir)/index"
-       '
-
-       test_expect_success 'add absolute' '
-               test -z "$(cd / && git ls-files)" &&
-               git add /foo/foome &&
-               git add /foo/bar/barme &&
-               git add /me &&
-               ( cd / && git ls-files --stage ) > result &&
-               test_cmp /ls.expected result &&
-               rm "$(git rev-parse --git-dir)/index"
-       '
-}
-
-if ! test -w /
-then
-       skip_all="Test requiring writable / skipped. Read this test if you want to run it"
-       test_done
-fi
-
-if  test -e /refs || test -e /objects || test -e /info || test -e /hooks ||
-    test -e /.git || test -e /foo || test -e /me
-then
-       skip_all="Skip test that clobbers existing files in /"
-       test_done
-fi
-
-if [ "$IKNOWWHATIAMDOING" != "YES" ]; then
-       skip_all="You must set env var IKNOWWHATIAMDOING=YES in order to run this test"
-       test_done
-fi
-
-if ! test_have_prereq NOT_ROOT
-then
-       skip_all="No you can't run this as root"
-       test_done
-fi
-
-ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d
-
-test_expect_success 'setup' '
-       rm -rf /foo &&
-       mkdir /foo &&
-       mkdir /foo/bar &&
-       echo 1 > /foo/foome &&
-       echo 1 > /foo/bar/barme &&
-       echo 1 > /me
-'
-
-say "GIT_DIR absolute, GIT_WORK_TREE set"
-
-test_expect_success 'go to /' 'cd /'
-
-cat >ls.expected <<EOF
-100644 $ONE_SHA1 0     foo/bar/barme
-100644 $ONE_SHA1 0     foo/foome
-100644 $ONE_SHA1 0     me
-EOF
-
-GIT_DIR="$TRASH_DIRECTORY/.git" && export GIT_DIR
-GIT_WORK_TREE=/ && export GIT_WORK_TREE
-
-test_vars 'abs gitdir, root' "$GIT_DIR" "/" ""
-test_foobar_root
-
-test_expect_success 'go to /foo' 'cd /foo'
-
-test_vars 'abs gitdir, foo' "$GIT_DIR" "/" "foo/"
-test_foobar_foo
-
-test_expect_success 'go to /foo/bar' 'cd /foo/bar'
-
-test_vars 'abs gitdir, foo/bar' "$GIT_DIR" "/" "foo/bar/"
-test_foobar_foobar
-
-say "GIT_DIR relative, GIT_WORK_TREE set"
-
-test_expect_success 'go to /' 'cd /'
-
-GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git" && export GIT_DIR
-GIT_WORK_TREE=/ && export GIT_WORK_TREE
-
-test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
-test_foobar_root
-
-test_expect_success 'go to /foo' 'cd /foo'
-
-GIT_DIR="../$TRASH_DIRECTORY/.git" && export GIT_DIR
-GIT_WORK_TREE=/ && export GIT_WORK_TREE
-
-test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
-test_foobar_foo
-
-test_expect_success 'go to /foo/bar' 'cd /foo/bar'
-
-GIT_DIR="../../$TRASH_DIRECTORY/.git" && export GIT_DIR
-GIT_WORK_TREE=/ && export GIT_WORK_TREE
-
-test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
-test_foobar_foobar
-
-say "GIT_DIR relative, GIT_WORK_TREE relative"
-
-test_expect_success 'go to /' 'cd /'
-
-GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git" && export GIT_DIR
-GIT_WORK_TREE=. && export GIT_WORK_TREE
-
-test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
-test_foobar_root
-
-test_expect_success 'go to /' 'cd /foo'
-
-GIT_DIR="../$TRASH_DIRECTORY/.git" && export GIT_DIR
-GIT_WORK_TREE=.. && export GIT_WORK_TREE
-
-test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
-test_foobar_foo
-
-test_expect_success 'go to /foo/bar' 'cd /foo/bar'
-
-GIT_DIR="../../$TRASH_DIRECTORY/.git" && export GIT_DIR
-GIT_WORK_TREE=../.. && export GIT_WORK_TREE
-
-test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
-test_foobar_foobar
-
-say ".git at root"
-
-unset GIT_DIR
-unset GIT_WORK_TREE
-
-test_expect_success 'go to /' 'cd /'
-test_expect_success 'setup' '
-       rm -rf /.git &&
-       echo "Initialized empty Git repository in /.git/" > expected &&
-       git init > result &&
-       test_cmp expected result
-'
-
-test_vars 'auto gitdir, root' ".git" "/" ""
-test_foobar_root
-
-test_expect_success 'go to /foo' 'cd /foo'
-test_vars 'auto gitdir, foo' "/.git" "/" "foo/"
-test_foobar_foo
-
-test_expect_success 'go to /foo/bar' 'cd /foo/bar'
-test_vars 'auto gitdir, foo/bar' "/.git" "/" "foo/bar/"
-test_foobar_foobar
-
-test_expect_success 'cleanup' 'rm -rf /.git'
-
-say "auto bare gitdir"
-
-# DESTROYYYYY!!!!!
-test_expect_success 'setup' '
-       rm -rf /refs /objects /info /hooks &&
-       rm -f /expected /ls.expected /me /result &&
-       cd / &&
-       echo "Initialized empty Git repository in /" > expected &&
-       git init --bare > result &&
-       test_cmp expected result
-'
-
-test_vars 'auto gitdir, root' "." "" ""
-
-test_expect_success 'go to /foo' 'cd /foo'
-
-test_vars 'auto gitdir, root' "/" "" ""
-
-test_done
index 199b22d85e92535f148eaaca4d3856dbdfb6bcec..b99d5192a96ec77ef6a99cb86518375c447b48a9 100755 (executable)
@@ -56,30 +56,4 @@ test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' '
        test_i18ngrep ! "^HEAD is now at" stderr
 '
 
-test_expect_success 'wildcard ambiguation, paths win' '
-       git init ambi &&
-       (
-               cd ambi &&
-               echo a >a.c &&
-               git add a.c &&
-               echo b >a.c &&
-               git checkout "*.c" &&
-               echo a >expect &&
-               test_cmp expect a.c
-       )
-'
-
-test_expect_success !MINGW 'wildcard ambiguation, refs lose' '
-       git init ambi2 &&
-       (
-               cd ambi2 &&
-               echo a >"*.c" &&
-               git add . &&
-               test_must_fail git show :"*.c" &&
-               git show :"*.c" -- >actual &&
-               echo a >expect &&
-               test_cmp expect actual
-       )
-'
-
 test_done
index 75ebb1b4a0f79faa6f92cc9575eeef6b10ae27d3..1b1b65a6b0fc7ace4e18e8642a6c47631d7e6a43 100755 (executable)
@@ -8,6 +8,16 @@ test_expect_success 'setup' '
        test_commit init
 '
 
+test_expect_success 'rev-parse --git-common-dir on main worktree' '
+       git rev-parse --git-common-dir >actual &&
+       echo .git >expected &&
+       test_cmp expected actual &&
+       mkdir sub &&
+       git -C sub rev-parse --git-common-dir >actual2 &&
+       echo sub/.git >expected2 &&
+       test_cmp expected2 actual2
+'
+
 test_expect_success '"list" all worktrees from main' '
        echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
        test_when_finished "rm -rf here && git worktree prune" &&
index cdaf6f64ec78830def2f082b72604075e15496f6..a897248490650ebef1a33a60a1aa9cf4431f06ff 100755 (executable)
@@ -446,6 +446,13 @@ test_expect_success '--set-upstream-to fails on a non-ref' '
        test_must_fail git branch --set-upstream-to HEAD^{}
 '
 
+test_expect_success '--set-upstream-to fails on locked config' '
+       test_when_finished "rm -f .git/config.lock" &&
+       >.git/config.lock &&
+       git branch locked &&
+       test_must_fail git branch --set-upstream-to locked
+'
+
 test_expect_success 'use --set-upstream-to modify HEAD' '
        test_config branch.master.remote foo &&
        test_config branch.master.merge foo &&
@@ -466,6 +473,13 @@ test_expect_success '--unset-upstream should fail if given a non-existent branch
        test_must_fail git branch --unset-upstream i-dont-exist
 '
 
+test_expect_success '--unset-upstream should fail if config is locked' '
+       test_when_finished "rm -f .git/config.lock" &&
+       git branch --set-upstream-to locked &&
+       >.git/config.lock &&
+       test_must_fail git branch --unset-upstream
+'
+
 test_expect_success 'test --unset-upstream on HEAD' '
        git branch my14 &&
        test_config branch.master.remote foo &&
@@ -579,7 +593,7 @@ test_expect_success 'avoid ambiguous track' '
        git config remote.ambi1.fetch refs/heads/lalala:refs/heads/master &&
        git config remote.ambi2.url lilili &&
        git config remote.ambi2.fetch refs/heads/lilili:refs/heads/master &&
-       git branch all1 master &&
+       test_must_fail git branch all1 master &&
        test -z "$(git config branch.all1.merge)"
 '
 
index 89224edcc582e6610fdefd63a8d40048bfe10da0..a3e12d295afedb170b3a917ce9d23122c1a0bc1d 100755 (executable)
@@ -101,7 +101,10 @@ test_expect_success 'push with receive.fsckobjects' '
                git config transfer.fsckobjects false
        ) &&
        test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act &&
-       test_cmp exp act
+       {
+               test_cmp exp act ||
+               ! test -s act
+       }
 '
 
 test_expect_success 'push with transfer.fsckobjects' '
index dfaf9d9f68939f0c39a512c478265b4aa227c973..013e03dee2651f6891782325671f0764bb02f41f 100755 (executable)
@@ -932,6 +932,15 @@ test_expect_success 'get-url on new remote' '
        echo foo | get_url_test --push --all someremote
 '
 
+test_expect_success 'remote set-url with locked config' '
+       test_when_finished "rm -f .git/config.lock" &&
+       git config --get-all remote.someremote.url >expect &&
+       >.git/config.lock &&
+       test_must_fail git remote set-url someremote baz &&
+       git config --get-all remote.someremote.url >actual &&
+       cmp expect actual
+'
+
 test_expect_success 'remote set-url bar' '
        git remote set-url someremote bar &&
        echo bar >expect &&
index c402d8d3d7c7e053373ffd98491ae0160481f3ba..c7320121ecfa74dce8389d3790364501c8bb12b8 100755 (executable)
@@ -25,7 +25,8 @@ test_expect_success 'push to update (protected)' '
        (
                cd dst &&
                test_commit D &&
-               test_must_fail git push --force-with-lease=master:master origin master
+               test_must_fail git push --force-with-lease=master:master origin master 2>err &&
+               grep "stale info" err
        ) &&
        git ls-remote . refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -37,7 +38,8 @@ test_expect_success 'push to update (protected, forced)' '
        (
                cd dst &&
                test_commit D &&
-               git push --force --force-with-lease=master:master origin master
+               git push --force --force-with-lease=master:master origin master 2>err &&
+               grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -101,7 +103,8 @@ test_expect_success 'push to update (allowed, tracking)' '
        (
                cd dst &&
                test_commit D &&
-               git push --force-with-lease=master origin master
+               git push --force-with-lease=master origin master 2>err &&
+               ! grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -114,7 +117,8 @@ test_expect_success 'push to update (allowed even though no-ff)' '
                cd dst &&
                git reset --hard HEAD^ &&
                test_commit D &&
-               git push --force-with-lease=master origin master
+               git push --force-with-lease=master origin master 2>err &&
+               grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -147,7 +151,8 @@ test_expect_success 'push to delete (allowed)' '
        setup_srcdst_basic &&
        (
                cd dst &&
-               git push --force-with-lease=master origin :master
+               git push --force-with-lease=master origin :master 2>err &&
+               grep deleted err
        ) &&
        >expect &&
        git ls-remote src refs/heads/master >actual &&
index 190ee903cf6269071809e82d61d6065f1de679c6..20aee43f95ab3cc38b8671a233089873fe374777 100755 (executable)
@@ -346,4 +346,17 @@ test_expect_success 'conflict at EOF without LF resolved by --union' \
         printf "line1\nline2\nline3x\nline3y" >expect.txt &&
         test_cmp expect.txt output.txt'
 
+test_expect_success 'conflict sections match existing line endings' '
+       printf "1\\r\\n2\\r\\n3" >crlf-orig.txt &&
+       printf "1\\r\\n2\\r\\n4" >crlf-diff1.txt &&
+       printf "1\\r\\n2\\r\\n5" >crlf-diff2.txt &&
+       test_must_fail git -c core.eol=crlf merge-file -p \
+               crlf-diff1.txt crlf-orig.txt crlf-diff2.txt >crlf.txt &&
+       test $(tr "\015" Q <crlf.txt | grep "^[<=>].*Q$" | wc -l) = 3 &&
+       test $(tr "\015" Q <crlf.txt | grep "[345]Q$" | wc -l) = 3 &&
+       test_must_fail git -c core.eol=crlf merge-file -p \
+               nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >nolf.txt &&
+       test $(tr "\015" Q <nolf.txt | grep "^[<=>].*Q$" | wc -l) = 0
+'
+
 test_done
diff --git a/t/t6133-pathspec-rev-dwim.sh b/t/t6133-pathspec-rev-dwim.sh
new file mode 100755 (executable)
index 0000000..a290ffc
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+test_description='test dwim of revs versus pathspecs in revision parser'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit base &&
+       echo content >"br[ack]ets" &&
+       git add . &&
+       test_tick &&
+       git commit -m brackets
+'
+
+test_expect_success 'non-rev wildcard dwims to pathspec' '
+       git log -- "*.t" >expect &&
+       git log    "*.t" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'tree:path with metacharacters dwims to rev' '
+       git show "HEAD:br[ack]ets" -- >expect &&
+       git show "HEAD:br[ack]ets"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '^{foo} with metacharacters dwims to rev' '
+       git log "HEAD^{/b.*}" -- >expect &&
+       git log "HEAD^{/b.*}"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '@{foo} with metacharacters dwims to rev' '
+       git log "HEAD@{now [or thereabouts]}" -- >expect &&
+       git log "HEAD@{now [or thereabouts]}"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success ':/*.t from a subdir dwims to a pathspec' '
+       mkdir subdir &&
+       (
+               cd subdir &&
+               git log -- ":/*.t" >expect &&
+               git log    ":/*.t" >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_done
diff --git a/t/t7409-submodule-detached-work-tree.sh b/t/t7409-submodule-detached-work-tree.sh
new file mode 100755 (executable)
index 0000000..c207171
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Daniel Graña
+#
+
+test_description='Test submodules on detached working tree
+
+This test verifies that "git submodule" initialization, update and addition works
+on detahced working trees
+'
+
+TEST_NO_CREATE_REPO=1
+. ./test-lib.sh
+
+test_expect_success 'submodule on detached working tree' '
+       git init --bare remote &&
+       test_create_repo bundle1 &&
+       (
+               cd bundle1 &&
+               test_commit "shoot" &&
+               git rev-parse --verify HEAD >../expect
+       ) &&
+       mkdir home &&
+       (
+               cd home &&
+               GIT_WORK_TREE="$(pwd)" &&
+               GIT_DIR="$(pwd)/.dotfiles" &&
+               export GIT_WORK_TREE GIT_DIR &&
+               git clone --bare ../remote .dotfiles &&
+               git submodule add ../bundle1 .vim/bundle/sogood &&
+               test_commit "sogood" &&
+               (
+                       unset GIT_WORK_TREE GIT_DIR &&
+                       cd .vim/bundle/sogood &&
+                       git rev-parse --verify HEAD >actual &&
+                       test_cmp ../../../../expect actual
+               ) &&
+               git push origin master
+       ) &&
+       mkdir home2 &&
+       (
+               cd home2 &&
+               git clone --bare ../remote .dotfiles &&
+               GIT_WORK_TREE="$(pwd)" &&
+               GIT_DIR="$(pwd)/.dotfiles" &&
+               export GIT_WORK_TREE GIT_DIR &&
+               git checkout master &&
+               git submodule update --init &&
+               (
+                       unset GIT_WORK_TREE GIT_DIR &&
+                       cd .vim/bundle/sogood &&
+                       git rev-parse --verify HEAD >actual &&
+                       test_cmp ../../../../expect actual
+               )
+       )
+'
+
+test_expect_success 'submodule on detached working pointed by core.worktree' '
+       mkdir home3 &&
+       (
+               cd home3 &&
+               GIT_DIR="$(pwd)/.dotfiles" &&
+               export GIT_DIR &&
+               git clone --bare ../remote "$GIT_DIR" &&
+               git config core.bare false &&
+               git config core.worktree .. &&
+               git checkout master &&
+               git submodule add ../bundle1 .vim/bundle/dupe &&
+               test_commit "dupe" &&
+               git push origin master
+       ) &&
+       (
+               cd home &&
+               GIT_DIR="$(pwd)/.dotfiles" &&
+               export GIT_DIR &&
+               git config core.bare false &&
+               git config core.worktree .. &&
+               git pull &&
+               git submodule update --init &&
+               test -f .vim/bundle/dupe/shoot.t
+       )
+'
+
+test_done
diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh
deleted file mode 100755 (executable)
index c207171..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2012 Daniel Graña
-#
-
-test_description='Test submodules on detached working tree
-
-This test verifies that "git submodule" initialization, update and addition works
-on detahced working trees
-'
-
-TEST_NO_CREATE_REPO=1
-. ./test-lib.sh
-
-test_expect_success 'submodule on detached working tree' '
-       git init --bare remote &&
-       test_create_repo bundle1 &&
-       (
-               cd bundle1 &&
-               test_commit "shoot" &&
-               git rev-parse --verify HEAD >../expect
-       ) &&
-       mkdir home &&
-       (
-               cd home &&
-               GIT_WORK_TREE="$(pwd)" &&
-               GIT_DIR="$(pwd)/.dotfiles" &&
-               export GIT_WORK_TREE GIT_DIR &&
-               git clone --bare ../remote .dotfiles &&
-               git submodule add ../bundle1 .vim/bundle/sogood &&
-               test_commit "sogood" &&
-               (
-                       unset GIT_WORK_TREE GIT_DIR &&
-                       cd .vim/bundle/sogood &&
-                       git rev-parse --verify HEAD >actual &&
-                       test_cmp ../../../../expect actual
-               ) &&
-               git push origin master
-       ) &&
-       mkdir home2 &&
-       (
-               cd home2 &&
-               git clone --bare ../remote .dotfiles &&
-               GIT_WORK_TREE="$(pwd)" &&
-               GIT_DIR="$(pwd)/.dotfiles" &&
-               export GIT_WORK_TREE GIT_DIR &&
-               git checkout master &&
-               git submodule update --init &&
-               (
-                       unset GIT_WORK_TREE GIT_DIR &&
-                       cd .vim/bundle/sogood &&
-                       git rev-parse --verify HEAD >actual &&
-                       test_cmp ../../../../expect actual
-               )
-       )
-'
-
-test_expect_success 'submodule on detached working pointed by core.worktree' '
-       mkdir home3 &&
-       (
-               cd home3 &&
-               GIT_DIR="$(pwd)/.dotfiles" &&
-               export GIT_DIR &&
-               git clone --bare ../remote "$GIT_DIR" &&
-               git config core.bare false &&
-               git config core.worktree .. &&
-               git checkout master &&
-               git submodule add ../bundle1 .vim/bundle/dupe &&
-               test_commit "dupe" &&
-               git push origin master
-       ) &&
-       (
-               cd home &&
-               GIT_DIR="$(pwd)/.dotfiles" &&
-               export GIT_DIR &&
-               git config core.bare false &&
-               git config core.worktree .. &&
-               git pull &&
-               git submodule update --init &&
-               test -f .vim/bundle/dupe/shoot.t
-       )
-'
-
-test_done
index c64e5a50258d1b3d3655e2dfcf8f391977c5e758..8d99eb303fd62a1c179ab31f471a3376898586b0 100644 (file)
@@ -617,7 +617,7 @@ test_must_fail () {
                return 0
        elif test $exit_code -gt 129 && test $exit_code -le 192
        then
-               echo >&2 "test_must_fail: died by signal: $*"
+               echo >&2 "test_must_fail: died by signal $(($exit_code - 128)): $*"
                return 1
        elif test $exit_code -eq 127
        then
index bd4b02e9dbf9560cf1285bb6607be83964ecc40a..51e4a88c333463e23957eb07139b01a3de1a1a0e 100644 (file)
@@ -907,9 +907,11 @@ yes () {
                y="$*"
        fi
 
-       while echo "$y"
+       i=0
+       while test $i -lt 99
        do
-               :
+               echo "$y"
+               i=$(($i+1))
        done
 }
 
index 4a7e78ffbcc6d552a39dcccd9008d6c11919e432..2ef0ce545278ea2f40526c42303c541736643bd5 100644 (file)
@@ -23,6 +23,10 @@ int userdiff_config(const char *k, const char *v);
 struct userdiff_driver *userdiff_find_by_name(const char *name);
 struct userdiff_driver *userdiff_find_by_path(const char *path);
 
+/*
+ * Initialize any textconv-related fields in the driver and return it, or NULL
+ * if it does not have textconv enabled at all.
+ */
 struct userdiff_driver *userdiff_get_textconv(struct userdiff_driver *driver);
 
 #endif /* USERDIFF */
index 981f810e80008d878d6a5af1331c89dc093c5927..6181a66f1ee2e1e45d7d8b2c88d312746473661f 100644 (file)
@@ -176,10 +176,10 @@ struct worktree **get_worktrees(void)
                        if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                                continue;
 
-                               if ((linked = get_linked_worktree(d->d_name))) {
-                                       ALLOC_GROW(list, counter + 1, alloc);
-                                       list[counter++] = linked;
-                               }
+                       if ((linked = get_linked_worktree(d->d_name))) {
+                               ALLOC_GROW(list, counter + 1, alloc);
+                               list[counter++] = linked;
+                       }
                }
                closedir(dir);
        }
index e7afe7a295e586d58313e82e87b22de347aef7a1..49e80aa222132c3c151b79bd37749d92a12f745a 100644 (file)
@@ -1,8 +1,12 @@
 #include "cache.h"
+#include "run-command.h"
 
 static void check_pipe(int err)
 {
        if (err == EPIPE) {
+               if (in_async())
+                       async_exit(141);
+
                signal(SIGPIPE, SIG_DFL);
                raise(SIGPIPE);
                /* Should never happen, but just in case... */
index c0339919ccf78c4fe7d78123f9c3e891075d0602..4fb7e79410c22fba1fb390af2e09008e932f5ea8 100644 (file)
@@ -42,7 +42,6 @@ extern "C" {
 #define XDF_IGNORE_BLANK_LINES (1 << 7)
 
 #define XDL_EMIT_FUNCNAMES (1 << 0)
-#define XDL_EMIT_COMMON (1 << 1)
 #define XDL_EMIT_FUNCCONTEXT (1 << 2)
 
 #define XDL_MMB_READONLY (1 << 0)
index 4266ada23f3c37c1989c7fa4283b423d16c0891b..993724b11c40bacffee8df927018e5790a265bd4 100644 (file)
@@ -120,21 +120,6 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
        return -1;
 }
 
-static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
-                           xdemitconf_t const *xecfg) {
-       xdfile_t *xdf = &xe->xdf2;
-       const char *rchg = xdf->rchg;
-       long ix;
-
-       for (ix = 0; ix < xdf->nrec; ix++) {
-               if (rchg[ix])
-                       continue;
-               if (xdl_emit_record(xdf, ix, "", ecb))
-                       return -1;
-       }
-       return 0;
-}
-
 struct func_line {
        long len;
        char buf[80];
@@ -170,9 +155,6 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
        long funclineprev = -1;
        struct func_line func_line = { 0 };
 
-       if (xecfg->flags & XDL_EMIT_COMMON)
-               return xdl_emit_common(xe, xscr, ecb, xecfg);
-
        for (xch = xscr; xch; xch = xche->next) {
                xche = xdl_get_hunk(&xch, xecfg);
                if (!xch)
index 625198e0585c52c20c778790c82126efd1b57009..d98f430c912bead3ee5381eafd195dde4d709c47 100644 (file)
@@ -109,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
        return 0;
 }
 
-static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
 {
        xrecord_t **recs;
        int size = 0;
@@ -125,6 +125,12 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add
        if (add_nl) {
                i = recs[count - 1]->size;
                if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') {
+                       if (needs_cr) {
+                               if (dest)
+                                       dest[size] = '\r';
+                               size++;
+                       }
+
                        if (dest)
                                dest[size] = '\n';
                        size++;
@@ -133,14 +139,58 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add
        return size;
 }
 
-static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
+{
+       return xdl_recs_copy_0(0, xe, i, count, needs_cr, add_nl, dest);
+}
+
+static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
+{
+       return xdl_recs_copy_0(1, xe, i, count, needs_cr, add_nl, dest);
+}
+
+/*
+ * Returns 1 if the i'th line ends in CR/LF (if it is the last line and
+ * has no eol, the preceding line, if any), 0 if it ends in LF-only, and
+ * -1 if the line ending cannot be determined.
+ */
+static int is_eol_crlf(xdfile_t *file, int i)
 {
-       return xdl_recs_copy_0(0, xe, i, count, add_nl, dest);
+       long size;
+
+       if (i < file->nrec - 1)
+               /* All lines before the last *must* end in LF */
+               return (size = file->recs[i]->size) > 1 &&
+                       file->recs[i]->ptr[size - 2] == '\r';
+       if (!file->nrec)
+               /* Cannot determine eol style from empty file */
+               return -1;
+       if ((size = file->recs[i]->size) &&
+                       file->recs[i]->ptr[size - 1] == '\n')
+               /* Last line; ends in LF; Is it CR/LF? */
+               return size > 1 &&
+                       file->recs[i]->ptr[size - 2] == '\r';
+       if (!i)
+               /* The only line has no eol */
+               return -1;
+       /* Determine eol from second-to-last line */
+       return (size = file->recs[i - 1]->size) > 1 &&
+               file->recs[i - 1]->ptr[size - 2] == '\r';
 }
 
-static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)
 {
-       return xdl_recs_copy_0(1, xe, i, count, add_nl, dest);
+       int needs_cr;
+
+       /* Match post-images' preceding, or first, lines' end-of-line style */
+       needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0);
+       if (needs_cr)
+               needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0);
+       /* Look at pre-image's first line, unless we already settled on LF */
+       if (needs_cr)
+               needs_cr = is_eol_crlf(&xe1->xdf1, 0);
+       /* If still undecided, use LF-only */
+       return needs_cr < 0 ? 0 : needs_cr;
 }
 
 static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
@@ -152,16 +202,17 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        int marker1_size = (name1 ? strlen(name1) + 1 : 0);
        int marker2_size = (name2 ? strlen(name2) + 1 : 0);
        int marker3_size = (name3 ? strlen(name3) + 1 : 0);
+       int needs_cr = is_cr_needed(xe1, xe2, m);
 
        if (marker_size <= 0)
                marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
 
        /* Before conflicting part */
-       size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
+       size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
                              dest ? dest + size : NULL);
 
        if (!dest) {
-               size += marker_size + 1 + marker1_size;
+               size += marker_size + 1 + needs_cr + marker1_size;
        } else {
                memset(dest + size, '<', marker_size);
                size += marker_size;
@@ -170,17 +221,19 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                        memcpy(dest + size + 1, name1, marker1_size - 1);
                        size += marker1_size;
                }
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
 
        /* Postimage from side #1 */
-       size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
+       size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1,
                              dest ? dest + size : NULL);
 
        if (style == XDL_MERGE_DIFF3) {
                /* Shared preimage */
                if (!dest) {
-                       size += marker_size + 1 + marker3_size;
+                       size += marker_size + 1 + needs_cr + marker3_size;
                } else {
                        memset(dest + size, '|', marker_size);
                        size += marker_size;
@@ -189,25 +242,29 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                                memcpy(dest + size + 1, name3, marker3_size - 1);
                                size += marker3_size;
                        }
+                       if (needs_cr)
+                               dest[size++] = '\r';
                        dest[size++] = '\n';
                }
-               size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
+               size += xdl_orig_copy(xe1, m->i0, m->chg0, needs_cr, 1,
                                      dest ? dest + size : NULL);
        }
 
        if (!dest) {
-               size += marker_size + 1;
+               size += marker_size + 1 + needs_cr;
        } else {
                memset(dest + size, '=', marker_size);
                size += marker_size;
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
 
        /* Postimage from side #2 */
-       size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
+       size += xdl_recs_copy(xe2, m->i2, m->chg2, needs_cr, 1,
                              dest ? dest + size : NULL);
        if (!dest) {
-               size += marker_size + 1 + marker2_size;
+               size += marker_size + 1 + needs_cr + marker2_size;
        } else {
                memset(dest + size, '>', marker_size);
                size += marker_size;
@@ -216,6 +273,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                        memcpy(dest + size + 1, name2, marker2_size - 1);
                        size += marker2_size;
                }
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
        return size;
@@ -241,21 +300,24 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
                                                  marker_size);
                else if (m->mode & 3) {
                        /* Before conflicting part */
-                       size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
+                       size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
                                              dest ? dest + size : NULL);
                        /* Postimage from side #1 */
-                       if (m->mode & 1)
-                               size += xdl_recs_copy(xe1, m->i1, m->chg1, (m->mode & 2),
+                       if (m->mode & 1) {
+                               int needs_cr = is_cr_needed(xe1, xe2, m);
+
+                               size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, (m->mode & 2),
                                                      dest ? dest + size : NULL);
+                       }
                        /* Postimage from side #2 */
                        if (m->mode & 2)
-                               size += xdl_recs_copy(xe2, m->i2, m->chg2, 0,
+                               size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, 0,
                                                      dest ? dest + size : NULL);
                } else
                        continue;
                i = m->i1 + m->chg1;
        }
-       size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0,
+       size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, 0,
                              dest ? dest + size : NULL);
        return size;
 }