Merge branch 'jt/submodule-tests-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Wed, 15 Nov 2017 03:14:31 +0000 (12:14 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 15 Nov 2017 03:14:31 +0000 (12:14 +0900)
* jt/submodule-tests-cleanup:
Tests: clean up and document submodule helpers

81 files changed:
.mailmap
.travis.yml
Documentation/RelNotes/2.15.0.txt
Documentation/RelNotes/2.16.0.txt
Documentation/config.txt
Documentation/git-status.txt
Documentation/git.txt
Documentation/technical/api-directory-listing.txt
Makefile
bisect.c
bisect.h
blame.c
builtin/add.c
builtin/am.c
builtin/blame.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/diff.c
builtin/fast-export.c
builtin/log.c
builtin/merge-ours.c
builtin/notes.c
builtin/remote.c
builtin/reset.c
builtin/rev-list.c
builtin/symbolic-ref.c
builtin/update-ref.c
cache.h
ci/install-dependencies.sh
ci/lib-travisci.sh
combine-diff.c
compat/mingw.c
contrib/credential/libsecret/git-credential-libsecret.c
contrib/credential/wincred/git-credential-wincred.c
contrib/mw-to-git/Git/Mediawiki.pm
diff-lib.c
diff-no-index.c
diff.c
diff.h
diffcore-pickaxe.c
diffcore-rename.c
dir.c
dir.h
git.rc
hex.c
http-push.c
imap-send.c
log-tree.c
merge-recursive.c
notes-merge.c
notes.c
patch-ids.c
perl/Git/Packet.pm [new file with mode: 0644]
perl/Makefile
refs.c
refs.h
refs/files-backend.c
refs/packed-backend.c
refs/packed-backend.h
refs/ref-cache.c
refs/refs-internal.h
revision.c
sequencer.c
setup.c
sha1_file.c
submodule.c
t/lib-credential.sh
t/t0001-init.sh
t/t0021/rot13-filter.pl
t/t1409-avoid-packing-refs.sh [new file with mode: 0755]
t/t3426-rebase-submodule.sh
t/t3600-rm.sh
t/t5580-clone-push-unc.sh
t/t7001-mv.sh
t/t7521-ignored-mode.sh [new file with mode: 0755]
tree-diff.c
wrapper.c
wt-status.c
wt-status.h
index 224db83887e7e875422742048e3f68274917291d..7c71e88ea51c52d453b0d6c08a3415f4c03de22b 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -113,6 +113,7 @@ Junio C Hamano <gitster@pobox.com> <junio@pobox.com>
 Junio C Hamano <gitster@pobox.com> <junio@twinsun.com>
 Junio C Hamano <gitster@pobox.com> <junkio@cox.net>
 Junio C Hamano <gitster@pobox.com> <junkio@twinsun.com>
+Kaartic Sivaraam <kaartic.sivaraam@gmail.com> <kaarticsivaraam91196@gmail.com>
 Karl Wiberg <kha@treskal.com> Karl  Hasselström
 Karl Wiberg <kha@treskal.com> <kha@yoghurt.hemma.treskal.com>
 Karsten Blees <blees@dcon.de> <karsten.blees@dcon.de>
index fead995eddd15460b6be81e6a5f7c8f0648368ca..281f101f3154e3884e71cde6184b59fd2b21c154 100644 (file)
@@ -71,7 +71,7 @@ matrix:
           packages:
           - coccinelle
       before_install:
-      # "before_script" that builds Git is inherited from base job
+      before_script:
       script: ci/run-static-analysis.sh
       after_failure:
     - env: Documentation
index 248ba70c3dc1c6959f24ded8db7ce0119f811ad4..cdd761bcc2072cc88523194311604f53d90dd41b 100644 (file)
@@ -65,7 +65,7 @@ UI, Workflows & Features
    learned to take the 'unfold' and 'only' modifiers to normalize its
    output, e.g. "git log --format=%(trailers:only,unfold)".
 
- * "gitweb" shows a link to visit the 'raw' contents of blbos in the
+ * "gitweb" shows a link to visit the 'raw' contents of blobs in the
    history overview page.
 
  * "[gc] rerereResolved = 5.days" used to be invalid, as the variable
@@ -109,13 +109,13 @@ Performance, Internal Implementation, Development Support etc.
  * Conversion from uchar[20] to struct object_id continues.
 
  * Start using selected c99 constructs in small, stable and
-   essentialpart of the system to catch people who care about
+   essential part of the system to catch people who care about
    older compilers that do not grok them.
 
  * The filter-process interface learned to allow a process with long
    latency give a "delayed" response.
 
- * Many uses of comparision callback function the hashmap API uses
+ * Many uses of comparison callback function the hashmap API uses
    cast the callback function type when registering it to
    hashmap_init(), which defeats the compile time type checking when
    the callback interface changes (e.g. gaining more parameters).
index c7bd0f7e961d1210f3ee8c42c1e27ccad6b9283e..e46197f478583a85cde69d55a1944cb1ddaf1ba3 100644 (file)
@@ -59,6 +59,16 @@ Performance, Internal Implementation, Development Support etc.
 
  * Conversion from uchar[20] to struct object_id continues.
 
+ * Code cleanup.
+   (merge 62a24c8923 rs/hex-to-bytes-cleanup later to maint).
+
+ * A single-word "unsigned flags" in the diff options is being split
+   into a structure with many bitfields.
+   (merge 0d1e0e7801 bw/diff-opt-impl-to-bitfields later to maint).
+
+ * TravisCI build updates.
+   (merge c2154953b8 sg/travis-fixes later to maint).
+
 
 Also contains various documentation updates and code clean-ups.
 
@@ -122,5 +132,35 @@ Fixes since v2.15
  * Command line completion (in contrib/) update.
    (merge 6357d9d004 tb/complete-checkout later to maint).
 
+ * Description of blame.{showroot,blankboundary,showemail,date}
+   configuration variables have been added to "git config --help".
+   (merge de0bc11d13 sb/blame-config-doc later to maint).
+
+ * After an error from lstat(), diff_populate_filespec() function
+   sometimes still went ahead and used invalid data in struct stat,
+   which has been fixed.
+   (merge 10e0ca843d ao/diff-populate-filespec-lstat-errorpath-fix later to maint).
+
+ * UNC paths are also relevant in Cygwin builds and they are now
+   tested just like Mingw builds.
+   (merge f21d60b429 ad/5580-unc-tests-on-cygwin later to maint).
+
+ * Correct start-up sequence so that a repository could be placed
+   immediately under the root directory again (which was broken at
+   around Git 2.13).
+   (merge fa4d8c783d js/early-config later to maint).
+
+ * The credential helper for libsecret (in contrib/) has been improved
+   to allow possibly prompting the end user to unlock secrets that are
+   currently locked (otherwise the secrets may not be loaded).
+   (merge 9c109e9bbc dk/libsecret-unlock-to-load-fix later to maint).
+
+ * MinGW updates.
+   (merge 39bb86b4e5 js/mingw-full-version-in-resources later to maint).
+   (merge 601e1e7897 js/wincred-empty-cred later to maint).
+   (merge b2f55717c7 js/mingw-redirect-std-handles later to maint).
+
  * Other minor doc, test and build updates and code cleanups.
    (merge bab76141da cn/diff-indent-no-longer-is-experimental later to maint).
+   (merge 8684dde10d jm/relnotes-2.15-typofix later to maint).
+   (merge cd3f8e2fc2 ks/mailmap later to maint).
index 5f0d62753d09ddd57eb580dd014b403a1f46d26d..671fcbaa0fd16d0a8478f9b2dc9f9af38244b595 100644 (file)
@@ -952,6 +952,23 @@ apply.whitespace::
        Tells 'git apply' how to handle whitespaces, in the same way
        as the `--whitespace` option. See linkgit:git-apply[1].
 
+blame.showRoot::
+       Do not treat root commits as boundaries in linkgit:git-blame[1].
+       This option defaults to false.
+
+blame.blankBoundary::
+       Show blank commit object name for boundary commits in
+       linkgit:git-blame[1]. This option defaults to false.
+
+blame.showEmail::
+       Show the author email instead of author name in linkgit:git-blame[1].
+       This option defaults to false.
+
+blame.date::
+       Specifies the format used to output dates in linkgit:git-blame[1].
+       If unset the iso format is used. For supported values,
+       see the discussion of the `--date` option at linkgit:git-log[1].
+
 branch.autoSetupMerge::
        Tells 'git branch' and 'git checkout' to set up new branches
        so that linkgit:git-pull[1] will appropriately merge from the
index 9f3a78a36c48c55318ee0eea8e96a64ccce5bfa2..fc282e0a920c84f491d24e3cf765ca634b54c425 100644 (file)
@@ -97,8 +97,27 @@ configuration variable documented in linkgit:git-config[1].
        (and suppresses the output of submodule summaries when the config option
        `status.submoduleSummary` is set).
 
---ignored::
+--ignored[=<mode>]::
        Show ignored files as well.
++
+The mode parameter is used to specify the handling of ignored files.
+It is optional: it defaults to 'traditional'.
++
+The possible options are:
++
+       - 'traditional' - Shows ignored files and directories, unless
+                         --untracked-files=all is specifed, in which case
+                         individual files in ignored directories are
+                         displayed.
+       - 'no'          - Show no ignored files.
+       - 'matching'    - Shows ignored files and directories matching an
+                         ignore pattern.
++
+When 'matching' mode is specified, paths that explicity match an
+ignored pattern are shown. If a directory matches an ignore pattern,
+then it is shown, but not paths contained in the ignored directory. If
+a directory does not match an ignore pattern, but all contents are
+ignored, then the directory is not shown, but all contents are shown.
 
 -z::
        Terminate entries with NUL, instead of LF.  This implies
index 7a1d629ca068059d274da66728eb7f886b43081d..463b0eb0f5c3c8e694a509d3e06aee29056f970d 100644 (file)
@@ -709,6 +709,24 @@ of clones and fetches.
        the background which do not want to cause lock contention with
        other operations on the repository.  Defaults to `1`.
 
+`GIT_REDIRECT_STDIN`::
+`GIT_REDIRECT_STDOUT`::
+`GIT_REDIRECT_STDERR`::
+       Windows-only: allow redirecting the standard input/output/error
+       handles to paths specified by the environment variables. This is
+       particularly useful in multi-threaded applications where the
+       canonical way to pass standard handles via `CreateProcess()` is
+       not an option because it would require the handles to be marked
+       inheritable (and consequently *every* spawned process would
+       inherit them, possibly blocking regular Git operations). The
+       primary intended use case is to use named pipes for communication
+       (e.g. `\\.\pipe\my-git-stdin-123`).
++
+Two special values are supported: `off` will simply close the
+corresponding standard handle, and if `GIT_REDIRECT_STDERR` is
+`2>&1`, standard error will be redirected to the same handle as
+standard output.
+
 Discussion[[Discussion]]
 ------------------------
 
index 6c77b4920c92a0b327fb88d2b461ec0d918ec99a..7fae00f44fe1798da82bfdbb902479a03d583843 100644 (file)
@@ -22,16 +22,20 @@ The notable options are:
 
 `flags`::
 
-       A bit-field of options (the `*IGNORED*` flags are mutually exclusive):
+       A bit-field of options:
 
 `DIR_SHOW_IGNORED`:::
 
-       Return just ignored files in `entries[]`, not untracked files.
+       Return just ignored files in `entries[]`, not untracked
+       files. This flag is mutually exclusive with
+       `DIR_SHOW_IGNORED_TOO`.
 
 `DIR_SHOW_IGNORED_TOO`:::
 
-       Similar to `DIR_SHOW_IGNORED`, but return ignored files in `ignored[]`
-       in addition to untracked files in `entries[]`.
+       Similar to `DIR_SHOW_IGNORED`, but return ignored files in
+       `ignored[]` in addition to untracked files in
+       `entries[]`. This flag is mutually exclusive with
+       `DIR_SHOW_IGNORED`.
 
 `DIR_KEEP_UNTRACKED_CONTENTS`:::
 
@@ -39,6 +43,21 @@ The notable options are:
        untracked contents of untracked directories are also returned in
        `entries[]`.
 
+`DIR_SHOW_IGNORED_TOO_MODE_MATCHING`:::
+
+       Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if
+       this is set, returns ignored files and directories that match
+       an exclude pattern. If a directory matches an exclude pattern,
+       then the directory is returned and the contained paths are
+       not. A directory that does not match an exclude pattern will
+       not be returned even if all of its contents are ignored. In
+       this case, the contents are returned as individual entries.
++
+If this is set, files and directories that explicity match an ignore
+pattern are reported. Implicity ignored directories (directories that
+do not match an ignore pattern, but whose contents are all ignored)
+are not reported, instead all of the contents are reported.
+
 `DIR_COLLECT_IGNORED`:::
 
        Special mode for git-add. Return ignored files in `ignored[]` and
index cd75985991f4535c45e2589222a9e6a38fb1d613..ee9d5eb11ee213e61d395bac6f2420278698389c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1940,7 +1940,8 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
 
 git.res: git.rc GIT-VERSION-FILE
        $(QUIET_RC)$(RC) \
-         $(join -DMAJOR= -DMINOR=, $(wordlist 1,2,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
+         $(join -DMAJOR= -DMINOR= -DMICRO= -DPATCHLEVEL=, $(wordlist 1, 4, \
+           $(shell echo $(GIT_VERSION) 0 0 0 0 | tr '.a-zA-Z-' ' '))) \
          -DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" -i $< -o $@
 
 # This makes sure we depend on the NO_PERL setting itself.
index fda2c4a186e8a937a53a4114bb24f3196b8b941b..0fca17c02bba89d6c65df95e03e88ef6dd02971e 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -226,10 +226,11 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
                add_name_decoration(DECORATION_NONE, buf.buf, obj);
 
                p->item = array[i].commit;
-               p = p->next;
+               if (i < cnt - 1)
+                       p = p->next;
        }
-       if (p)
-               p->next = NULL;
+       free_commit_list(p->next);
+       p->next = NULL;
        strbuf_release(&buf);
        free(array);
        return list;
@@ -360,28 +361,29 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
                return best_bisection_sorted(list, nr);
 }
 
-struct commit_list *find_bisection(struct commit_list *list,
-                                         int *reaches, int *all,
-                                         int find_all)
+void find_bisection(struct commit_list **commit_list, int *reaches,
+                   int *all, int find_all)
 {
        int nr, on_list;
-       struct commit_list *p, *best, *next, *last;
+       struct commit_list *list, *p, *best, *next, *last;
        int *weights;
 
-       show_list("bisection 2 entry", 0, 0, list);
+       show_list("bisection 2 entry", 0, 0, *commit_list);
 
        /*
         * Count the number of total and tree-changing items on the
         * list, while reversing the list.
         */
-       for (nr = on_list = 0, last = NULL, p = list;
+       for (nr = on_list = 0, last = NULL, p = *commit_list;
             p;
             p = next) {
                unsigned flags = p->item->object.flags;
 
                next = p->next;
-               if (flags & UNINTERESTING)
+               if (flags & UNINTERESTING) {
+                       free(p);
                        continue;
+               }
                p->next = last;
                last = p;
                if (!(flags & TREESAME))
@@ -397,12 +399,16 @@ struct commit_list *find_bisection(struct commit_list *list,
        /* Do the real work of finding bisection commit. */
        best = do_find_bisection(list, nr, weights, find_all);
        if (best) {
-               if (!find_all)
+               if (!find_all) {
+                       list->item = best->item;
+                       free_commit_list(list->next);
+                       best = list;
                        best->next = NULL;
+               }
                *reaches = weight(best);
        }
        free(weights);
-       return best;
+       *commit_list = best;
 }
 
 static int register_ref(const char *refname, const struct object_id *oid,
@@ -960,8 +966,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
 
        bisect_common(&revs);
 
-       revs.commits = find_bisection(revs.commits, &reaches, &all,
-                                      !!skipped_revs.nr);
+       find_bisection(&revs.commits, &reaches, &all, !!skipped_revs.nr);
        revs.commits = managed_skipped(revs.commits, &tried);
 
        if (!revs.commits) {
@@ -1068,7 +1073,7 @@ int bisect_clean_state(void)
        struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
        for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal);
        string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
-       result = delete_refs("bisect: remove", &refs_for_removal, REF_NODEREF);
+       result = delete_refs("bisect: remove", &refs_for_removal, REF_NO_DEREF);
        refs_for_removal.strdup_strings = 1;
        string_list_clear(&refs_for_removal, 0);
        unlink_or_warn(git_path_bisect_expected_rev());
index 0ae63d4616dc69712faff17930e39d4c521927e5..a5d9248a47675194e7e0d16aed37018cbb67eb33 100644 (file)
--- a/bisect.h
+++ b/bisect.h
@@ -1,9 +1,15 @@
 #ifndef BISECT_H
 #define BISECT_H
 
-extern struct commit_list *find_bisection(struct commit_list *list,
-                                         int *reaches, int *all,
-                                         int find_all);
+/*
+ * Find bisection. If something is found, `reaches` will be the number of
+ * commits that the best commit reaches. `all` will be the count of
+ * non-SAMETREE commits. If nothing is found, `list` will be NULL.
+ * Otherwise, it will be either all non-SAMETREE commits or the single
+ * best commit, as chosen by `find_all`.
+ */
+extern void find_bisection(struct commit_list **list, int *reaches, int *all,
+                          int find_all);
 
 extern struct commit_list *filter_skipped(struct commit_list *list,
                                          struct commit_list **tried,
diff --git a/blame.c b/blame.c
index c3060de2f87f9cdc598019663186755b52a31953..2893f3c1030aab91a42ff9e0daf8a54ba8c3ef3c 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -209,7 +209,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
-                       if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
+                       if (opt->flags.allow_textconv &&
                            textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
                                strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
@@ -293,7 +293,7 @@ static void fill_origin_blob(struct diff_options *opt,
                unsigned long file_size;
 
                (*num_read_blob)++;
-               if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
+               if (opt->flags.allow_textconv &&
                    textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
                        ;
                else
@@ -541,7 +541,7 @@ static struct blame_origin *find_origin(struct commit *parent,
         * same and diff-tree is fairly efficient about this.
         */
        diff_setup(&diff_opts);
-       DIFF_OPT_SET(&diff_opts, RECURSIVE);
+       diff_opts.flags.recursive = 1;
        diff_opts.detect_rename = 0;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        paths[0] = origin->path;
@@ -615,7 +615,7 @@ static struct blame_origin *find_rename(struct commit *parent,
        int i;
 
        diff_setup(&diff_opts);
-       DIFF_OPT_SET(&diff_opts, RECURSIVE);
+       diff_opts.flags.recursive = 1;
        diff_opts.detect_rename = DIFF_DETECT_RENAME;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = origin->path;
@@ -1238,7 +1238,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
                return; /* nothing remains for this target */
 
        diff_setup(&diff_opts);
-       DIFF_OPT_SET(&diff_opts, RECURSIVE);
+       diff_opts.flags.recursive = 1;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 
        diff_setup_done(&diff_opts);
@@ -1253,7 +1253,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
        if ((opt & PICKAXE_BLAME_COPY_HARDEST)
            || ((opt & PICKAXE_BLAME_COPY_HARDER)
                && (!porigin || strcmp(target->path, porigin->path))))
-               DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
+               diff_opts.flags.find_copies_harder = 1;
 
        if (is_null_oid(&target->commit->object.oid))
                do_diff_cache(&parent->tree->object.oid, &diff_opts);
@@ -1262,7 +1262,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
                              &target->commit->tree->object.oid,
                              "", &diff_opts);
 
-       if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
+       if (!diff_opts.flags.find_copies_harder)
                diffcore_std(&diff_opts);
 
        do {
@@ -1825,7 +1825,7 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
                if (fill_blob_sha1_and_mode(o))
                        die(_("no such path %s in %s"), path, final_commit_name);
 
-               if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) &&
+               if (sb->revs->diffopt.flags.allow_textconv &&
                    textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
                                    &sb->final_buf_size))
                        ;
index a648cf4c56c9f56eb60a97ca50ccf0b191dc50ff..8d08e99e92c1fa12e1dcd4b079097b2b63d69089 100644 (file)
@@ -116,7 +116,7 @@ int add_files_to_cache(const char *prefix,
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
        rev.diffopt.format_callback_data = &data;
-       rev.diffopt.flags |= DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+       rev.diffopt.flags.override_submodule_config = 1;
        rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
        run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
        clear_pathspec(&rev.prune_data);
@@ -218,7 +218,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        argc = setup_revisions(argc, argv, &rev, NULL);
        rev.diffopt.output_format = DIFF_FORMAT_PATCH;
        rev.diffopt.use_color = 0;
-       DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
+       rev.diffopt.flags.ignore_dirty_submodules = 1;
        out = open(file, O_CREAT | O_WRONLY, 0666);
        if (out < 0)
                die(_("Could not open '%s' for writing."), file);
index 4b6f1534f88407cf569c7f8e4c4b1df4ba3fc1e0..02853b3e05bfef638963dbfe91a7eccf3d40b9e6 100644 (file)
@@ -1157,9 +1157,9 @@ static int index_has_changes(struct strbuf *sb)
                struct diff_options opt;
 
                diff_setup(&opt);
-               DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
+               opt.flags.exit_with_status = 1;
                if (!sb)
-                       DIFF_OPT_SET(&opt, QUICK);
+                       opt.flags.quick = 1;
                do_diff_cache(&head, &opt);
                diffcore_std(&opt);
                for (i = 0; sb && i < diff_queued_diff.nr; i++) {
@@ -1168,7 +1168,7 @@ static int index_has_changes(struct strbuf *sb)
                        strbuf_addstr(sb, diff_queued_diff.queue[i]->two->path);
                }
                diff_flush(&opt);
-               return DIFF_OPT_TST(&opt, HAS_CHANGES) != 0;
+               return opt.flags.has_changes != 0;
        } else {
                for (i = 0; sb && i < active_nr; i++) {
                        if (i)
@@ -1409,8 +1409,8 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm
        rev_info.show_root_diff = 1;
        rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
        rev_info.no_commit_id = 1;
-       DIFF_OPT_SET(&rev_info.diffopt, BINARY);
-       DIFF_OPT_SET(&rev_info.diffopt, FULL_INDEX);
+       rev_info.diffopt.flags.binary = 1;
+       rev_info.diffopt.flags.full_index = 1;
        rev_info.diffopt.use_color = 0;
        rev_info.diffopt.file = fp;
        rev_info.diffopt.close_file = 1;
@@ -2148,7 +2148,7 @@ static void am_abort(struct am_state *state)
                           has_curr_head ? &curr_head : NULL, 0,
                           UPDATE_REFS_DIE_ON_ERR);
        else if (curr_branch)
-               delete_ref(NULL, curr_branch, NULL, REF_NODEREF);
+               delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);
 
        free(curr_branch);
        am_destroy(state);
index 67adaef4d80ee4e2fcd28755255935f0fcae6c03..005f55aaa257fc34f81517650223a3c195c03178 100644 (file)
@@ -708,8 +708,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        git_config(git_blame_config, &output_option);
        init_revisions(&revs, NULL);
        revs.date_mode = blame_date_mode;
-       DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
-       DIFF_OPT_SET(&revs.diffopt, FOLLOW_RENAMES);
+       revs.diffopt.flags.allow_textconv = 1;
+       revs.diffopt.flags.follow_renames = 1;
 
        save_commit_buffer = 0;
        dashdash_pos = 0;
@@ -734,9 +734,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                parse_revision_opt(&revs, &ctx, options, blame_opt_usage);
        }
 parse_done:
-       no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES);
+       no_whole_file_rename = !revs.diffopt.flags.follow_renames;
        xdl_opts |= revs.diffopt.xdl_opts & XDF_INDENT_HEURISTIC;
-       DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES);
+       revs.diffopt.flags.follow_renames = 0;
        argc = parse_options_end(&ctx);
 
        if (incremental || (output_option & OUTPUT_PORCELAIN)) {
@@ -803,7 +803,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        }
        blame_date_width -= 1; /* strip the null */
 
-       if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER))
+       if (revs.diffopt.flags.find_copies_harder)
                opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
                        PICKAXE_BLAME_COPY_HARDER);
 
index b1ed649300db7d803cf0107561a72e3e57a21658..33fd5fcfd10be978f4d8ccdb6869eb05e86eb956 100644 (file)
@@ -258,7 +258,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                }
 
                if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : &oid,
-                              REF_NODEREF)) {
+                              REF_NO_DEREF)) {
                        error(remote_branch
                              ? _("Error deleting remote-tracking branch '%s'")
                              : _("Error deleting branch '%s'"),
index 6c2b4cd419a4a588e73a3f12a9ebdd6c1365ce78..7d8bcc3833512bc262bd0a8d86db9169d991b320 100644 (file)
@@ -663,7 +663,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
                /* Nothing to do. */
        } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
                update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL,
-                          REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+                          REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
                if (!opts->quiet) {
                        if (old->path &&
                            advice_detached_head && !opts->force_detach)
index cf6eddc9c56b9fda95ff8d9764a2d5f09b7d20b4..b22845738afe68e61d45883e89a470213de921ef 100644 (file)
@@ -689,7 +689,7 @@ static void update_head(const struct ref *our, const struct ref *remote,
        } else if (our) {
                struct commit *c = lookup_commit_reference(&our->old_oid);
                /* --branch specifies a non-branch (i.e. tags), detach HEAD */
-               update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NODEREF,
+               update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
                           UPDATE_REFS_DIE_ON_ERR);
        } else if (remote) {
                /*
@@ -697,7 +697,7 @@ static void update_head(const struct ref *our, const struct ref *remote,
                 * HEAD points to a branch but we don't know which one.
                 * Detach HEAD in all these cases.
                 */
-               update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NODEREF,
+               update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
                           UPDATE_REFS_DIE_ON_ERR);
        }
 }
index c38542ee468c11c744cecf1c8b74ecc09e21f58d..cfb78fcf680f4aea96035d0158b2855a1358d674 100644 (file)
@@ -118,7 +118,7 @@ static int edit_flag = -1; /* unspecified */
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int config_commit_verbose = -1; /* unspecified */
 static int no_post_rewrite, allow_empty_message;
-static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
+static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
 static char *sign_commit;
 
 /*
@@ -139,7 +139,7 @@ static const char *cleanup_arg;
 static enum commit_whence whence;
 static int sequencer_in_use;
 static int use_editor = 1, include_status = 1;
-static int show_ignored_in_status, have_option_m;
+static int have_option_m;
 static struct strbuf message = STRBUF_INIT;
 
 static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
@@ -912,11 +912,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                         * submodules which were manually staged, which would
                         * be really confusing.
                         */
-                       int diff_flags = DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+                       struct diff_flags flags = DIFF_FLAGS_INIT;
+                       flags.override_submodule_config = 1;
                        if (ignore_submodule_arg &&
                            !strcmp(ignore_submodule_arg, "all"))
-                               diff_flags |= DIFF_OPT_IGNORE_SUBMODULES;
-                       commitable = index_differs_from(parent, diff_flags, 1);
+                               flags.ignore_submodules = 1;
+                       commitable = index_differs_from(parent, &flags, 1);
                }
        }
        strbuf_release(&committer_ident);
@@ -1075,6 +1076,19 @@ static const char *find_author_by_nickname(const char *name)
        die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
 }
 
+static void handle_ignored_arg(struct wt_status *s)
+{
+       if (!ignored_arg)
+               ; /* default already initialized */
+       else if (!strcmp(ignored_arg, "traditional"))
+               s->show_ignored_mode = SHOW_TRADITIONAL_IGNORED;
+       else if (!strcmp(ignored_arg, "no"))
+               s->show_ignored_mode = SHOW_NO_IGNORED;
+       else if (!strcmp(ignored_arg, "matching"))
+               s->show_ignored_mode = SHOW_MATCHING_IGNORED;
+       else
+               die(_("Invalid ignored mode '%s'"), ignored_arg);
+}
 
 static void handle_untracked_files_arg(struct wt_status *s)
 {
@@ -1363,8 +1377,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                  N_("mode"),
                  N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
-               OPT_BOOL(0, "ignored", &show_ignored_in_status,
-                        N_("show ignored files")),
+               { OPTION_STRING, 0, "ignored", &ignored_arg,
+                 N_("mode"),
+                 N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"),
+                 PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" },
                { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
                  N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
@@ -1383,8 +1399,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        finalize_deferred_config(&s);
 
        handle_untracked_files_arg(&s);
-       if (show_ignored_in_status)
-               s.show_ignored_files = 1;
+       handle_ignored_arg(&s);
+
+       if (s.show_ignored_mode == SHOW_MATCHING_IGNORED &&
+           s.show_untracked_files == SHOW_NO_UNTRACKED_FILES)
+               die(_("Unsupported combination of ignored and untracked-files arguments"));
+
        parse_pathspec(&s.pathspec, 0,
                       PATHSPEC_PREFER_FULL,
                       prefix, argv);
index aa6f746795fb82feb4de1ff28f8f0350ee18092c..9808d062a80a2ff07699fb0ea4cbd29f560630d3 100644 (file)
@@ -44,7 +44,7 @@ static void stuff_change(struct diff_options *opt,
            !oidcmp(old_oid, new_oid) && (old_mode == new_mode))
                return;
 
-       if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
+       if (opt->flags.reverse_diff) {
                SWAP(old_mode, new_mode);
                SWAP(old_oid, new_oid);
                SWAP(old_path, new_path);
@@ -349,8 +349,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        rev.diffopt.stat_graph_width = -1;
 
        /* Default to let external and textconv be used */
-       DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
-       DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
+       rev.diffopt.flags.allow_external = 1;
+       rev.diffopt.flags.allow_textconv = 1;
 
        if (nongit)
                die(_("Not a git repository"));
@@ -360,7 +360,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                diff_setup_done(&rev.diffopt);
        }
 
-       DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
+       rev.diffopt.flags.recursive = 1;
 
        setup_diff_pager(&rev.diffopt);
 
index d74c73f7776fcf76bc66679b1e34513d7c75d41a..f8fe04ca5332541213dc059dd02fdf09e0c6cf85 100644 (file)
@@ -1066,7 +1066,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                die("revision walk setup failed");
        revs.diffopt.format_callback = show_filemodify;
        revs.diffopt.format_callback_data = &paths_of_changed_objects;
-       DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
+       revs.diffopt.flags.recursive = 1;
        while ((commit = get_revision(&revs))) {
                if (has_unshown_parent(commit)) {
                        add_object_array(&commit->object, NULL, &commits);
index ba9d4cd7863b54ec02c62b73220883a8fca3a33f..6c1fa896ad01a8de0dcd99be80827d436d2cc857 100644 (file)
@@ -121,20 +121,19 @@ static void cmd_log_init_defaults(struct rev_info *rev)
        if (fmt_pretty)
                get_commit_format(fmt_pretty, rev);
        if (default_follow)
-               DIFF_OPT_SET(&rev->diffopt, DEFAULT_FOLLOW_RENAMES);
+               rev->diffopt.flags.default_follow_renames = 1;
        rev->verbose_header = 1;
-       DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
+       rev->diffopt.flags.recursive = 1;
        rev->diffopt.stat_width = -1; /* use full terminal width */
        rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
        rev->abbrev_commit = default_abbrev_commit;
        rev->show_root_diff = default_show_root;
        rev->subject_prefix = fmt_patch_subject_prefix;
        rev->show_signature = default_show_signature;
-       DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
+       rev->diffopt.flags.allow_textconv = 1;
 
        if (default_date_mode)
                parse_date_format(default_date_mode, &rev->date_mode);
-       rev->diffopt.touched_flags = 0;
 }
 
 static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
@@ -182,7 +181,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
                init_display_notes(&rev->notes_opt);
 
        if (rev->diffopt.pickaxe || rev->diffopt.filter ||
-           DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES))
+           rev->diffopt.flags.follow_renames)
                rev->always_show_header = 0;
 
        if (source)
@@ -392,7 +391,7 @@ static int cmd_log_walk(struct rev_info *rev)
                fclose(rev->diffopt.file);
 
        if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
-           DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
+           rev->diffopt.flags.check_failed) {
                return 02;
        }
        return diff_result_code(&rev->diffopt, 0);
@@ -484,8 +483,8 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
        unsigned long size;
 
        fflush(rev->diffopt.file);
-       if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
-           !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
+       if (!rev->diffopt.flags.textconv_set_via_cmdline ||
+           !rev->diffopt.flags.allow_textconv)
                return stream_blob_to_fd(1, oid, NULL, 0);
 
        if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
@@ -667,9 +666,9 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
 static void log_setup_revisions_tweak(struct rev_info *rev,
                                      struct setup_revision_opt *opt)
 {
-       if (DIFF_OPT_TST(&rev->diffopt, DEFAULT_FOLLOW_RENAMES) &&
+       if (rev->diffopt.flags.default_follow_renames &&
            rev->prune_data.nr == 1)
-               DIFF_OPT_SET(&rev->diffopt, FOLLOW_RENAMES);
+               rev->diffopt.flags.follow_renames = 1;
 
        /* Turn --cc/-c into -p --cc/-c when -p was not given */
        if (!rev->diffopt.output_format && rev->combine_merges)
@@ -1341,7 +1340,7 @@ static void prepare_bases(struct base_tree_info *bases,
                return;
 
        diff_setup(&diffopt);
-       DIFF_OPT_SET(&diffopt, RECURSIVE);
+       diffopt.flags.recursive = 1;
        diff_setup_done(&diffopt);
 
        oidcpy(&bases->base_commit, &base->object.oid);
@@ -1512,7 +1511,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        rev.verbose_header = 1;
        rev.diff = 1;
        rev.max_parents = 1;
-       DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
+       rev.diffopt.flags.recursive = 1;
        rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
        s_r_opt.def = "HEAD";
@@ -1613,8 +1612,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
        rev.zero_commit = zero_commit;
 
-       if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)
-               DIFF_OPT_SET(&rev.diffopt, BINARY);
+       if (!rev.diffopt.flags.text && !no_binary_diff)
+               rev.diffopt.flags.binary = 1;
 
        if (rev.show_notes)
                init_display_notes(&rev.notes_opt);
index beb0623d56323a0ea8912e54e94e66fa07268156..c84c6e05e922f09692b9b133cd391b850c7951df 100644 (file)
@@ -26,7 +26,7 @@ int cmd_merge_ours(int argc, const char **argv, const char *prefix)
         */
        if (read_cache() < 0)
                die_errno("read_cache failed");
-       if (index_differs_from("HEAD", 0, 0))
+       if (index_differs_from("HEAD", NULL, 0))
                exit(2);
        exit(0);
 }
index 12afdf19075f3e3de39d487a5f6b2b7e2bbe922e..d7754db143e21ed92e03a29ea7932aec599ea63f 100644 (file)
@@ -686,7 +686,7 @@ static int merge_abort(struct notes_merge_options *o)
 
        if (delete_ref(NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
                ret += error(_("failed to delete ref NOTES_MERGE_PARTIAL"));
-       if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NODEREF))
+       if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
                ret += error(_("failed to delete ref NOTES_MERGE_REF"));
        if (notes_merge_abort(o))
                ret += error(_("failed to remove 'git notes merge' worktree"));
index a04ea50e403931aa5e8cd35828f93de97493604e..d95bf904c3b3fb40438335198a2729e45a9897cb 100644 (file)
@@ -693,7 +693,7 @@ static int mv(int argc, const char **argv)
                read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag);
                if (!(flag & REF_ISSYMREF))
                        continue;
-               if (delete_ref(NULL, item->string, NULL, REF_NODEREF))
+               if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
                        die(_("deleting '%s' failed"), item->string);
        }
        for (i = 0; i < remote_branches.nr; i++) {
@@ -788,7 +788,7 @@ static int rm(int argc, const char **argv)
        strbuf_release(&buf);
 
        if (!result)
-               result = delete_refs("remote: remove", &branches, REF_NODEREF);
+               result = delete_refs("remote: remove", &branches, REF_NO_DEREF);
        string_list_clear(&branches, 0);
 
        if (skipped.nr) {
@@ -1255,7 +1255,7 @@ static int set_head(int argc, const char **argv)
                        head_name = xstrdup(states.heads.items[0].string);
                free_remote_ref_states(&states);
        } else if (opt_d && !opt_a && argc == 1) {
-               if (delete_ref(NULL, buf.buf, NULL, REF_NODEREF))
+               if (delete_ref(NULL, buf.buf, NULL, REF_NO_DEREF))
                        result |= error(_("Could not delete %s"), buf.buf);
        } else
                usage_with_options(builtin_remote_sethead_usage, options);
index d4003f76abcc5cbf469d3d5f029f328717508fa7..906e5416582301233cb275fb102a63cb6d1dd139 100644 (file)
@@ -166,7 +166,7 @@ static int read_from_tree(const struct pathspec *pathspec,
        opt.output_format = DIFF_FORMAT_CALLBACK;
        opt.format_callback = update_index_from_diff;
        opt.format_callback_data = &intent_to_add;
-       opt.flags |= DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+       opt.flags.override_submodule_config = 1;
 
        if (do_diff_cache(tree_oid, &opt))
                return 1;
index 9bf8d5991cb78f56f0c29230483a0b925e8ade58..4032eb381158942b83e9ce12a5c984fceb239b20 100644 (file)
@@ -294,7 +294,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        if (revs.bisect)
                bisect_list = 1;
 
-       if (DIFF_OPT_TST(&revs.diffopt, QUICK))
+       if (revs.diffopt.flags.quick)
                info.flags |= REV_LIST_QUIET;
        for (i = 1 ; i < argc; i++) {
                const char *arg = argv[i];
@@ -397,8 +397,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        if (bisect_list) {
                int reaches = reaches, all = all;
 
-               revs.commits = find_bisection(revs.commits, &reaches, &all,
-                                             bisect_find_all);
+               find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
 
                if (bisect_show_vars)
                        return show_bisect_vars(&info, reaches, all);
index 17aabaa679d599090ef5eb01d0c3650108c4f79c..80237f0df10f442181814900a93d797f965ec3de 100644 (file)
@@ -58,7 +58,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
                        die("Cannot delete %s, not a symbolic ref", argv[0]);
                if (!strcmp(argv[0], "HEAD"))
                        die("deleting '%s' is not allowed", argv[0]);
-               return delete_ref(NULL, argv[0], NULL, REF_NODEREF);
+               return delete_ref(NULL, argv[0], NULL, REF_NO_DEREF);
        }
 
        switch (argc) {
index cf1552b47850f5f74b07051e6c114d6351d590be..4b4714b3fd82ca9510b9b241867e497cdae92e76 100644 (file)
@@ -312,7 +312,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
 static const char *parse_cmd_option(struct strbuf *input, const char *next)
 {
        if (!strncmp(next, "no-deref", 8) && next[8] == line_termination)
-               update_flags |= REF_NODEREF;
+               update_flags |= REF_NO_DEREF;
        else
                die("option unknown: %s", next);
        return next + 8;
@@ -427,7 +427,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
        }
 
        if (no_deref)
-               flags = REF_NODEREF;
+               flags = REF_NO_DEREF;
        if (delete)
                /*
                 * For purposes of backwards compatibility, we treat
diff --git a/cache.h b/cache.h
index d74f00d8db2035c5109e2bf00a1ea25c14c7f24c..cb7fb7c004beb0b228269469a2c389c248bb72d1 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1340,6 +1340,13 @@ extern int set_disambiguate_hint_config(const char *var, const char *value);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern int get_oid_hex(const char *hex, struct object_id *sha1);
 
+/*
+ * Read `len` pairs of hexadecimal digits from `hex` and write the
+ * values to `binary` as `len` bytes. Return 0 on success, or -1 if
+ * the input does not consist of hex digits).
+ */
+extern int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
+
 /*
  * Convert a binary sha1 to its hex equivalent. The `_r` variant is reentrant,
  * and writes the NUL-terminated output to the buffer `out`, which must be at
index a29246af3580dc9ef7af584cb53a2fc6e084d09a..5bd06fe900d44916fd11875fa5641e9b97e90540 100755 (executable)
@@ -12,20 +12,18 @@ case "${TRAVIS_OS_NAME:-linux}" in
 linux)
        export GIT_TEST_HTTPD=YesPlease
 
-       mkdir --parents custom/p4
-       pushd custom/p4
+       mkdir --parents "$P4_PATH"
+       pushd "$P4_PATH"
                wget --quiet "$P4WHENCE/bin.linux26x86_64/p4d"
                wget --quiet "$P4WHENCE/bin.linux26x86_64/p4"
                chmod u+x p4d
                chmod u+x p4
-               export PATH="$(pwd):$PATH"
        popd
-       mkdir --parents custom/git-lfs
-       pushd custom/git-lfs
+       mkdir --parents "$GIT_LFS_PATH"
+       pushd "$GIT_LFS_PATH"
                wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
                tar --extract --gunzip --file "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
                cp git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs .
-               export PATH="$(pwd):$PATH"
        popd
        ;;
 osx)
index b3ed0a0ddac4261307a31a99f3cd18fb7aabc4fc..ac05f1f4694347bbd96fe1911aa33450d43ae24f 100755 (executable)
@@ -26,3 +26,11 @@ skip_branch_tip_with_tag () {
 set -e
 
 skip_branch_tip_with_tag
+
+case "${TRAVIS_OS_NAME:-linux}" in
+linux)
+       P4_PATH="$(pwd)/custom/p4"
+       GIT_LFS_PATH="$(pwd)/custom/git-lfs"
+       export PATH="$GIT_LFS_PATH:$P4_PATH:$PATH"
+       ;;
+esac
index 82f6070977cf8316fd630cc86fbf9d393d03ba3a..2505de119a2be37e9dfb313a2e44db68595ad13f 100644 (file)
@@ -898,7 +898,7 @@ static void show_combined_header(struct combine_diff_path *elem,
                                 int show_file_header)
 {
        struct diff_options *opt = &rev->diffopt;
-       int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV;
+       int abbrev = opt->flags.full_index ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV;
        const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/";
        const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/";
        const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO);
@@ -987,7 +987,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        userdiff = userdiff_find_by_path(elem->path);
        if (!userdiff)
                userdiff = userdiff_find_by_name("default");
-       if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV))
+       if (opt->flags.allow_textconv)
                textconv = userdiff_get_textconv(userdiff);
 
        /* Read the result of merge first */
@@ -1413,8 +1413,8 @@ void diff_tree_combined(const struct object_id *oid,
 
        diffopts = *opt;
        copy_pathspec(&diffopts.pathspec, &opt->pathspec);
-       DIFF_OPT_SET(&diffopts, RECURSIVE);
-       DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
+       diffopts.flags.recursive = 1;
+       diffopts.flags.allow_external = 0;
 
        /* find set of paths that everybody touches
         *
@@ -1435,7 +1435,7 @@ void diff_tree_combined(const struct object_id *oid,
         * NOTE please keep this semantically in sync with diffcore_std()
         */
        need_generic_pathscan = opt->skip_stat_unmatch  ||
-                       DIFF_OPT_TST(opt, FOLLOW_RENAMES)       ||
+                       opt->flags.follow_renames       ||
                        opt->break_opt != -1    ||
                        opt->detect_rename      ||
                        opt->pickaxe            ||
index 8b6fa0db446aee9888ff6484560131143c7e22e5..2d44d21aca8d31f67b16cb9a90245b4db526ff76 100644 (file)
@@ -2139,6 +2139,62 @@ static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
        return memcpy(malloc_startup(len), buffer, len);
 }
 
+static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
+                                     DWORD desired_access, DWORD flags)
+{
+       DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
+       wchar_t buf[MAX_PATH];
+       DWORD max = ARRAY_SIZE(buf);
+       HANDLE handle;
+       DWORD ret = GetEnvironmentVariableW(key, buf, max);
+
+       if (!ret || ret >= max)
+               return;
+
+       /* make sure this does not leak into child processes */
+       SetEnvironmentVariableW(key, NULL);
+       if (!wcscmp(buf, L"off")) {
+               close(fd);
+               handle = GetStdHandle(std_id);
+               if (handle != INVALID_HANDLE_VALUE)
+                       CloseHandle(handle);
+               return;
+       }
+       if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) {
+               handle = GetStdHandle(STD_OUTPUT_HANDLE);
+               if (handle == INVALID_HANDLE_VALUE) {
+                       close(fd);
+                       handle = GetStdHandle(std_id);
+                       if (handle != INVALID_HANDLE_VALUE)
+                               CloseHandle(handle);
+               } else {
+                       int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+                       SetStdHandle(std_id, handle);
+                       dup2(new_fd, fd);
+                       /* do *not* close the new_fd: that would close stdout */
+               }
+               return;
+       }
+       handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
+                            flags, NULL);
+       if (handle != INVALID_HANDLE_VALUE) {
+               int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+               SetStdHandle(std_id, handle);
+               dup2(new_fd, fd);
+               close(new_fd);
+       }
+}
+
+static void maybe_redirect_std_handles(void)
+{
+       maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
+                                 GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
+       maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
+                                 GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
+       maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
+                                 GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
+}
+
 void mingw_startup(void)
 {
        int i, maxlen, argc;
@@ -2146,6 +2202,8 @@ void mingw_startup(void)
        wchar_t **wenv, **wargv;
        _startupinfo si;
 
+       maybe_redirect_std_handles();
+
        /* get wide char arguments and environment */
        si.newmode = 0;
        if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
index 4c56979d8a08baf5ecfe5922a3239b8e183ba9c0..b4750c9ee89d29e16102a0fa0134c2b6cfe74cd0 100644 (file)
@@ -104,7 +104,7 @@ static int keyring_get(struct credential *c)
        items = secret_service_search_sync(service,
                                           SECRET_SCHEMA_COMPAT_NETWORK,
                                           attributes,
-                                          SECRET_SEARCH_LOAD_SECRETS,
+                                          SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_UNLOCK,
                                           NULL,
                                           &error);
        g_hash_table_unref(attributes);
index 006134043a472edd54720d6d4237e9484476d3a3..86518cd93d9c58d8b9f02d7cb8a67adf7b3fb3b6 100644 (file)
@@ -94,6 +94,12 @@ static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
 static void write_item(const char *what, LPCWSTR wbuf, int wlen)
 {
        char *buf;
+
+       if (!wbuf || !wlen) {
+               printf("%s=\n", what);
+               return;
+       }
+
        int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NULL, 0, NULL,
            FALSE);
        buf = xmalloc(len);
@@ -160,7 +166,7 @@ static int match_part_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
 static int match_cred(const CREDENTIALW *cred)
 {
        LPCWSTR target = cred->TargetName;
-       if (wusername && wcscmp(wusername, cred->UserName))
+       if (wusername && wcscmp(wusername, cred->UserName ? cred->UserName : L""))
                return 0;
 
        return match_part(&target, L"git", L":") &&
@@ -183,7 +189,7 @@ static void get_credential(void)
        for (i = 0; i < num_creds; ++i)
                if (match_cred(creds[i])) {
                        write_item("username", creds[i]->UserName,
-                               wcslen(creds[i]->UserName));
+                               creds[i]->UserName ? wcslen(creds[i]->UserName) : 0);
                        write_item("password",
                                (LPCWSTR)creds[i]->CredentialBlob,
                                creds[i]->CredentialBlobSize / sizeof(WCHAR));
index d13c4dfa7d746a827879bb0445aff33de4541e6a..917d9e2d3222c12f2d0dc043a1434acae2b398ae 100644 (file)
@@ -2,6 +2,7 @@ package Git::Mediawiki;
 
 use 5.008;
 use strict;
+use POSIX;
 use Git;
 
 BEGIN {
@@ -52,7 +53,7 @@ sub smudge_filename {
        $filename =~ s/ /_/g;
        # Decode forbidden characters encoded in clean_filename
        $filename =~ s/_%_([0-9a-fA-F][0-9a-fA-F])/sprintf('%c', hex($1))/ge;
-       return $filename;
+       return substr($filename, 0, NAME_MAX-length('.mw'));
 }
 
 sub connect_maybe {
index d2ea02f4d7c9074aff577d9529640315db9c5af7..731f0886d6e4146ca526f222381de50406957b30 100644 (file)
@@ -71,14 +71,15 @@ static int match_stat_with_submodule(struct diff_options *diffopt,
 {
        int changed = ce_match_stat(ce, st, ce_option);
        if (S_ISGITLINK(ce->ce_mode)) {
-               unsigned orig_flags = diffopt->flags;
-               if (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG))
+               struct diff_flags orig_flags = diffopt->flags;
+               if (!diffopt->flags.override_submodule_config)
                        set_diffopt_flags_from_submodule_config(diffopt, ce->name);
-               if (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES))
+               if (diffopt->flags.ignore_submodules)
                        changed = 0;
-               else if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)
-                   && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES)))
-                       *dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));
+               else if (!diffopt->flags.ignore_dirty_submodules &&
+                        (!changed || diffopt->flags.dirty_submodules))
+                       *dirty_submodule = is_submodule_modified(ce->name,
+                                                                diffopt->flags.ignore_untracked_in_submodules);
                diffopt->flags = orig_flags;
        }
        return changed;
@@ -228,7 +229,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 
                if (!changed && !dirty_submodule) {
                        ce_mark_uptodate(ce);
-                       if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
+                       if (!revs->diffopt.flags.find_copies_harder)
                                continue;
                }
                oldmode = ce->ce_mode;
@@ -362,7 +363,7 @@ static int show_modified(struct rev_info *revs,
 
        oldmode = old->ce_mode;
        if (mode == oldmode && !oidcmp(oid, &old->oid) && !dirty_submodule &&
-           !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
+           !revs->diffopt.flags.find_copies_harder)
                return 0;
 
        diff_change(&revs->diffopt, oldmode, mode,
@@ -493,7 +494,7 @@ static int diff_cache(struct rev_info *revs,
        opts.head_idx = 1;
        opts.index_only = cached;
        opts.diff_index_cached = (cached &&
-                                 !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER));
+                                 !revs->diffopt.flags.find_copies_harder);
        opts.merge = 1;
        opts.fn = oneway_diff;
        opts.unpack_data = revs;
@@ -534,7 +535,7 @@ int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt)
        return 0;
 }
 
-int index_differs_from(const char *def, int diff_flags,
+int index_differs_from(const char *def, const struct diff_flags *flags,
                       int ita_invisible_in_index)
 {
        struct rev_info rev;
@@ -544,11 +545,12 @@ int index_differs_from(const char *def, int diff_flags,
        memset(&opt, 0, sizeof(opt));
        opt.def = def;
        setup_revisions(0, NULL, &rev, &opt);
-       DIFF_OPT_SET(&rev.diffopt, QUICK);
-       DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
-       rev.diffopt.flags |= diff_flags;
+       rev.diffopt.flags.quick = 1;
+       rev.diffopt.flags.exit_with_status = 1;
+       if (flags)
+               diff_flags_or(&rev.diffopt.flags, flags);
        rev.diffopt.ita_invisible_in_index = ita_invisible_in_index;
        run_diff_index(&rev, 1);
        object_array_clear(&rev.pending);
-       return (DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0);
+       return (rev.diffopt.flags.has_changes != 0);
 }
index 80ff17d460ed67fa4b38f8a8dfce7504b27bbb64..0ed5f0f496882cef9e04f9a93fe718a9f55a268a 100644 (file)
@@ -184,7 +184,7 @@ static int queue_diff(struct diff_options *o,
        } else {
                struct diff_filespec *d1, *d2;
 
-               if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+               if (o->flags.reverse_diff) {
                        SWAP(mode1, mode2);
                        SWAP(name1, name2);
                }
@@ -276,16 +276,16 @@ void diff_no_index(struct rev_info *revs,
        if (!revs->diffopt.output_format)
                revs->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-       DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
+       revs->diffopt.flags.no_index = 1;
 
-       DIFF_OPT_SET(&revs->diffopt, RELATIVE_NAME);
+       revs->diffopt.flags.relative_name = 1;
        revs->diffopt.prefix = prefix;
 
        revs->max_count = -2;
        diff_setup_done(&revs->diffopt);
 
        setup_diff_pager(&revs->diffopt);
-       DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
+       revs->diffopt.flags.exit_with_status = 1;
 
        if (queue_diff(&revs->diffopt, paths[0], paths[1]))
                exit(1);
diff --git a/diff.c b/diff.c
index e6814b9e9c6d6f49a48fb2d3234323e20dec5f56..0763e89263efac5fe75a57f0c068049fae610851 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -124,18 +124,18 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
        for (i = 0; i < params.nr; i++) {
                const char *p = params.items[i].string;
                if (!strcmp(p, "changes")) {
-                       DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
-                       DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
+                       options->flags.dirstat_by_line = 0;
+                       options->flags.dirstat_by_file = 0;
                } else if (!strcmp(p, "lines")) {
-                       DIFF_OPT_SET(options, DIRSTAT_BY_LINE);
-                       DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
+                       options->flags.dirstat_by_line = 1;
+                       options->flags.dirstat_by_file = 0;
                } else if (!strcmp(p, "files")) {
-                       DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
-                       DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
+                       options->flags.dirstat_by_line = 0;
+                       options->flags.dirstat_by_file = 1;
                } else if (!strcmp(p, "noncumulative")) {
-                       DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
+                       options->flags.dirstat_cumulative = 0;
                } else if (!strcmp(p, "cumulative")) {
-                       DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
+                       options->flags.dirstat_cumulative = 1;
                } else if (isdigit(*p)) {
                        char *end;
                        int permille = strtoul(p, &end, 10) * 10;
@@ -1412,7 +1412,7 @@ static void emit_rewrite_diff(const char *name_a,
        struct emit_callback ecbdata;
        struct strbuf out = STRBUF_INIT;
 
-       if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {
+       if (diff_mnemonic_prefix && o->flags.reverse_diff) {
                a_prefix = o->b_prefix;
                b_prefix = o->a_prefix;
        } else {
@@ -2660,7 +2660,7 @@ static void show_dirstat(struct diff_options *options)
        dir.alloc = 0;
        dir.nr = 0;
        dir.permille = options->dirstat_permille;
-       dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE);
+       dir.cumulative = options->flags.dirstat_cumulative;
 
        changed = 0;
        for (i = 0; i < q->nr; i++) {
@@ -2686,7 +2686,7 @@ static void show_dirstat(struct diff_options *options)
                        goto found_damage;
                }
 
-               if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE)) {
+               if (options->flags.dirstat_by_file) {
                        /*
                         * In --dirstat-by-file mode, we don't really need to
                         * look at the actual file contents at all.
@@ -2761,7 +2761,7 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o
        dir.alloc = 0;
        dir.nr = 0;
        dir.permille = options->dirstat_permille;
-       dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE);
+       dir.cumulative = options->flags.dirstat_cumulative;
 
        changed = 0;
        for (i = 0; i < data->nr; i++) {
@@ -3048,7 +3048,7 @@ static void builtin_diff(const char *name_a,
        const char *line_prefix = diff_line_prefix(o);
 
        diff_set_mnemonic_prefix(o, "a/", "b/");
-       if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+       if (o->flags.reverse_diff) {
                a_prefix = o->b_prefix;
                b_prefix = o->a_prefix;
        } else {
@@ -3072,7 +3072,7 @@ static void builtin_diff(const char *name_a,
                return;
        }
 
-       if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
+       if (o->flags.allow_textconv) {
                textconv_one = get_textconv(one);
                textconv_two = get_textconv(two);
        }
@@ -3132,13 +3132,13 @@ static void builtin_diff(const char *name_a,
                                 header.len, 0);
                strbuf_reset(&header);
                goto free_ab_and_return;
-       } else if (!DIFF_OPT_TST(o, TEXT) &&
+       } else if (!o->flags.text &&
            ( (!textconv_one && diff_filespec_is_binary(one)) ||
              (!textconv_two && diff_filespec_is_binary(two)) )) {
                struct strbuf sb = STRBUF_INIT;
                if (!one->data && !two->data &&
                    S_ISREG(one->mode) && S_ISREG(two->mode) &&
-                   !DIFF_OPT_TST(o, BINARY)) {
+                   !o->flags.binary) {
                        if (!oidcmp(&one->oid, &two->oid)) {
                                if (must_show_header)
                                        emit_diff_symbol(o, DIFF_SYMBOL_HEADER,
@@ -3167,7 +3167,7 @@ static void builtin_diff(const char *name_a,
                }
                emit_diff_symbol(o, DIFF_SYMBOL_HEADER, header.buf, header.len, 0);
                strbuf_reset(&header);
-               if (DIFF_OPT_TST(o, BINARY))
+               if (o->flags.binary)
                        emit_binary_diff(o, &mf1, &mf2);
                else {
                        strbuf_addf(&sb, "%sBinary files %s and %s differ\n",
@@ -3213,7 +3213,7 @@ static void builtin_diff(const char *name_a,
                xecfg.ctxlen = o->context;
                xecfg.interhunkctxlen = o->interhunkcontext;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
-               if (DIFF_OPT_TST(o, FUNCCONTEXT))
+               if (o->flags.funccontext)
                        xecfg.flags |= XDL_EMIT_FUNCCONTEXT;
                if (pe)
                        xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
@@ -3378,7 +3378,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
        diff_free_filespec_data(one);
        diff_free_filespec_data(two);
        if (data.status)
-               DIFF_OPT_SET(o, CHECK_FAILED);
+               o->flags.check_failed = 1;
 }
 
 struct diff_filespec *alloc_filespec(const char *path)
@@ -3545,14 +3545,12 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
                int fd;
 
                if (lstat(s->path, &st) < 0) {
-                       if (errno == ENOENT) {
-                       err_empty:
-                               err = -1;
-                       empty:
-                               s->data = (char *)"";
-                               s->size = 0;
-                               return err;
-                       }
+               err_empty:
+                       err = -1;
+               empty:
+                       s->data = (char *)"";
+                       s->size = 0;
+                       return err;
                }
                s->size = xsize_t(st.st_size);
                if (!s->size)
@@ -3872,9 +3870,9 @@ static void fill_metainfo(struct strbuf *msg,
                *must_show_header = 0;
        }
        if (one && two && oidcmp(&one->oid, &two->oid)) {
-               int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
+               int abbrev = o->flags.full_index ? 40 : DEFAULT_ABBREV;
 
-               if (DIFF_OPT_TST(o, BINARY)) {
+               if (o->flags.binary) {
                        mmfile_t mf;
                        if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
                            (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
@@ -3904,7 +3902,7 @@ static void run_diff_cmd(const char *pgm,
        int must_show_header = 0;
 
 
-       if (DIFF_OPT_TST(o, ALLOW_EXTERNAL)) {
+       if (o->flags.allow_external) {
                struct userdiff_driver *drv = userdiff_find_by_path(attr_path);
                if (drv && drv->external)
                        pgm = drv->external;
@@ -3984,7 +3982,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
        if (o->prefix_length)
                strip_prefix(o->prefix_length, &name, &other);
 
-       if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
+       if (!o->flags.allow_external)
                pgm = NULL;
 
        if (DIFF_PAIR_UNMERGED(p)) {
@@ -4083,7 +4081,7 @@ void diff_setup(struct diff_options *options)
        options->context = diff_context_default;
        options->interhunkcontext = diff_interhunk_context_default;
        options->ws_error_highlight = ws_error_highlight_default;
-       DIFF_OPT_SET(options, RENAME_EMPTY);
+       options->flags.rename_empty = 1;
 
        /* pathchange left =NULL by default */
        options->change = diff_change;
@@ -4134,14 +4132,14 @@ void diff_setup_done(struct diff_options *options)
        if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) ||
            DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) ||
            DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL))
-               DIFF_OPT_SET(options, DIFF_FROM_CONTENTS);
+               options->flags.diff_from_contents = 1;
        else
-               DIFF_OPT_CLR(options, DIFF_FROM_CONTENTS);
+               options->flags.diff_from_contents = 0;
 
-       if (DIFF_OPT_TST(options, FIND_COPIES_HARDER))
+       if (options->flags.find_copies_harder)
                options->detect_rename = DIFF_DETECT_COPY;
 
-       if (!DIFF_OPT_TST(options, RELATIVE_NAME))
+       if (!options->flags.relative_name)
                options->prefix = NULL;
        if (options->prefix)
                options->prefix_length = strlen(options->prefix);
@@ -4171,18 +4169,18 @@ void diff_setup_done(struct diff_options *options)
                                      DIFF_FORMAT_DIRSTAT |
                                      DIFF_FORMAT_SUMMARY |
                                      DIFF_FORMAT_CHECKDIFF))
-               DIFF_OPT_SET(options, RECURSIVE);
+               options->flags.recursive = 1;
        /*
         * Also pickaxe would not work very well if you do not say recursive
         */
        if (options->pickaxe)
-               DIFF_OPT_SET(options, RECURSIVE);
+               options->flags.recursive = 1;
        /*
         * When patches are generated, submodules diffed against the work tree
         * must be checked for dirtiness too so it can be shown in the output
         */
        if (options->output_format & DIFF_FORMAT_PATCH)
-               DIFF_OPT_SET(options, DIRTY_SUBMODULES);
+               options->flags.dirty_submodules = 1;
 
        if (options->detect_rename && options->rename_limit < 0)
                options->rename_limit = diff_rename_limit_default;
@@ -4204,14 +4202,14 @@ void diff_setup_done(struct diff_options *options)
         * to have found.  It does not make sense not to return with
         * exit code in such a case either.
         */
-       if (DIFF_OPT_TST(options, QUICK)) {
+       if (options->flags.quick) {
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
-               DIFF_OPT_SET(options, EXIT_WITH_STATUS);
+               options->flags.exit_with_status = 1;
        }
 
        options->diff_path_counter = 0;
 
-       if (DIFF_OPT_TST(options, FOLLOW_RENAMES) && options->pathspec.nr != 1)
+       if (options->flags.follow_renames && options->pathspec.nr != 1)
                die(_("--follow requires exactly one pathspec"));
 
        if (!options->use_color || external_diff())
@@ -4561,7 +4559,7 @@ int diff_opt_parse(struct diff_options *options,
        else if (starts_with(arg, "-C") || starts_with(arg, "--find-copies=") ||
                 !strcmp(arg, "--find-copies")) {
                if (options->detect_rename == DIFF_DETECT_COPY)
-                       DIFF_OPT_SET(options, FIND_COPIES_HARDER);
+                       options->flags.find_copies_harder = 1;
                if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
                        return error("invalid argument to -C: %s", arg+2);
                options->detect_rename = DIFF_DETECT_COPY;
@@ -4569,13 +4567,13 @@ int diff_opt_parse(struct diff_options *options,
        else if (!strcmp(arg, "--no-renames"))
                options->detect_rename = 0;
        else if (!strcmp(arg, "--rename-empty"))
-               DIFF_OPT_SET(options, RENAME_EMPTY);
+               options->flags.rename_empty = 1;
        else if (!strcmp(arg, "--no-rename-empty"))
-               DIFF_OPT_CLR(options, RENAME_EMPTY);
+               options->flags.rename_empty = 0;
        else if (!strcmp(arg, "--relative"))
-               DIFF_OPT_SET(options, RELATIVE_NAME);
+               options->flags.relative_name = 1;
        else if (skip_prefix(arg, "--relative=", &arg)) {
-               DIFF_OPT_SET(options, RELATIVE_NAME);
+               options->flags.relative_name = 1;
                options->prefix = arg;
        }
 
@@ -4615,21 +4613,21 @@ int diff_opt_parse(struct diff_options *options,
        /* flags options */
        else if (!strcmp(arg, "--binary")) {
                enable_patch_output(&options->output_format);
-               DIFF_OPT_SET(options, BINARY);
+               options->flags.binary = 1;
        }
        else if (!strcmp(arg, "--full-index"))
-               DIFF_OPT_SET(options, FULL_INDEX);
+               options->flags.full_index = 1;
        else if (!strcmp(arg, "-a") || !strcmp(arg, "--text"))
-               DIFF_OPT_SET(options, TEXT);
+               options->flags.text = 1;
        else if (!strcmp(arg, "-R"))
-               DIFF_OPT_SET(options, REVERSE_DIFF);
+               options->flags.reverse_diff = 1;
        else if (!strcmp(arg, "--find-copies-harder"))
-               DIFF_OPT_SET(options, FIND_COPIES_HARDER);
+               options->flags.find_copies_harder = 1;
        else if (!strcmp(arg, "--follow"))
-               DIFF_OPT_SET(options, FOLLOW_RENAMES);
+               options->flags.follow_renames = 1;
        else if (!strcmp(arg, "--no-follow")) {
-               DIFF_OPT_CLR(options, FOLLOW_RENAMES);
-               DIFF_OPT_CLR(options, DEFAULT_FOLLOW_RENAMES);
+               options->flags.follow_renames = 0;
+               options->flags.default_follow_renames = 0;
        } else if (!strcmp(arg, "--color"))
                options->use_color = 1;
        else if (skip_prefix(arg, "--color=", &arg)) {
@@ -4686,22 +4684,23 @@ int diff_opt_parse(struct diff_options *options,
                return argcount;
        }
        else if (!strcmp(arg, "--exit-code"))
-               DIFF_OPT_SET(options, EXIT_WITH_STATUS);
+               options->flags.exit_with_status = 1;
        else if (!strcmp(arg, "--quiet"))
-               DIFF_OPT_SET(options, QUICK);
+               options->flags.quick = 1;
        else if (!strcmp(arg, "--ext-diff"))
-               DIFF_OPT_SET(options, ALLOW_EXTERNAL);
+               options->flags.allow_external = 1;
        else if (!strcmp(arg, "--no-ext-diff"))
-               DIFF_OPT_CLR(options, ALLOW_EXTERNAL);
-       else if (!strcmp(arg, "--textconv"))
-               DIFF_OPT_SET(options, ALLOW_TEXTCONV);
-       else if (!strcmp(arg, "--no-textconv"))
-               DIFF_OPT_CLR(options, ALLOW_TEXTCONV);
+               options->flags.allow_external = 0;
+       else if (!strcmp(arg, "--textconv")) {
+               options->flags.allow_textconv = 1;
+               options->flags.textconv_set_via_cmdline = 1;
+       } else if (!strcmp(arg, "--no-textconv"))
+               options->flags.allow_textconv = 0;
        else if (!strcmp(arg, "--ignore-submodules")) {
-               DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
+               options->flags.override_submodule_config = 1;
                handle_ignore_submodules_arg(options, "all");
        } else if (skip_prefix(arg, "--ignore-submodules=", &arg)) {
-               DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
+               options->flags.override_submodule_config = 1;
                handle_ignore_submodules_arg(options, arg);
        } else if (!strcmp(arg, "--submodule"))
                options->submodule_format = DIFF_SUBMODULE_LOG;
@@ -4776,11 +4775,11 @@ int diff_opt_parse(struct diff_options *options,
                         &options->interhunkcontext))
                ;
        else if (!strcmp(arg, "-W"))
-               DIFF_OPT_SET(options, FUNCCONTEXT);
+               options->flags.funccontext = 1;
        else if (!strcmp(arg, "--function-context"))
-               DIFF_OPT_SET(options, FUNCCONTEXT);
+               options->flags.funccontext = 1;
        else if (!strcmp(arg, "--no-function-context"))
-               DIFF_OPT_CLR(options, FUNCCONTEXT);
+               options->flags.funccontext = 0;
        else if ((argcount = parse_long_opt("output", av, &optarg))) {
                char *path = prefix_filename(prefix, optarg);
                options->file = xfopen(path, "w");
@@ -5530,7 +5529,7 @@ void diff_flush(struct diff_options *options)
                separator++;
        }
 
-       if (output_format & DIFF_FORMAT_DIRSTAT && DIFF_OPT_TST(options, DIRSTAT_BY_LINE))
+       if (output_format & DIFF_FORMAT_DIRSTAT && options->flags.dirstat_by_line)
                dirstat_by_line = 1;
 
        if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT) ||
@@ -5565,8 +5564,8 @@ void diff_flush(struct diff_options *options)
        }
 
        if (output_format & DIFF_FORMAT_NO_OUTPUT &&
-           DIFF_OPT_TST(options, EXIT_WITH_STATUS) &&
-           DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
+           options->flags.exit_with_status &&
+           options->flags.diff_from_contents) {
                /*
                 * run diff_flush_patch for the exit status. setting
                 * options->file to /dev/null should be safe, because we
@@ -5614,11 +5613,11 @@ void diff_flush(struct diff_options *options)
         * diff_addremove/diff_change does not set the bit when
         * DIFF_FROM_CONTENTS is in effect (e.g. with -w).
         */
-       if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
+       if (options->flags.diff_from_contents) {
                if (options->found_changes)
-                       DIFF_OPT_SET(options, HAS_CHANGES);
+                       options->flags.has_changes = 1;
                else
-                       DIFF_OPT_CLR(options, HAS_CHANGES);
+                       options->flags.has_changes = 0;
        }
 }
 
@@ -5738,7 +5737,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
                         * to determine how many paths were dirty only
                         * due to stat info mismatch.
                         */
-                       if (!DIFF_OPT_TST(diffopt, NO_INDEX))
+                       if (!diffopt->flags.no_index)
                                diffopt->skip_stat_unmatch++;
                        diff_free_filepair(p);
                }
@@ -5787,10 +5786,10 @@ void diffcore_std(struct diff_options *options)
                diff_resolve_rename_copy();
        diffcore_apply_filter(options);
 
-       if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
-               DIFF_OPT_SET(options, HAS_CHANGES);
+       if (diff_queued_diff.nr && !options->flags.diff_from_contents)
+               options->flags.has_changes = 1;
        else
-               DIFF_OPT_CLR(options, HAS_CHANGES);
+               options->flags.has_changes = 0;
 
        options->found_follow = 0;
 }
@@ -5802,23 +5801,23 @@ int diff_result_code(struct diff_options *opt, int status)
        diff_warn_rename_limit("diff.renameLimit",
                               opt->needed_rename_limit,
                               opt->degraded_cc_to_c);
-       if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
+       if (!opt->flags.exit_with_status &&
            !(opt->output_format & DIFF_FORMAT_CHECKDIFF))
                return status;
-       if (DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
-           DIFF_OPT_TST(opt, HAS_CHANGES))
+       if (opt->flags.exit_with_status &&
+           opt->flags.has_changes)
                result |= 01;
        if ((opt->output_format & DIFF_FORMAT_CHECKDIFF) &&
-           DIFF_OPT_TST(opt, CHECK_FAILED))
+           opt->flags.check_failed)
                result |= 02;
        return result;
 }
 
 int diff_can_quit_early(struct diff_options *opt)
 {
-       return (DIFF_OPT_TST(opt, QUICK) &&
+       return (opt->flags.quick &&
                !opt->filter &&
-               DIFF_OPT_TST(opt, HAS_CHANGES));
+               opt->flags.has_changes);
 }
 
 /*
@@ -5830,10 +5829,10 @@ int diff_can_quit_early(struct diff_options *opt)
 static int is_submodule_ignored(const char *path, struct diff_options *options)
 {
        int ignored = 0;
-       unsigned orig_flags = options->flags;
-       if (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG))
+       struct diff_flags orig_flags = options->flags;
+       if (!options->flags.override_submodule_config)
                set_diffopt_flags_from_submodule_config(options, path);
-       if (DIFF_OPT_TST(options, IGNORE_SUBMODULES))
+       if (options->flags.ignore_submodules)
                ignored = 1;
        options->flags = orig_flags;
        return ignored;
@@ -5862,7 +5861,7 @@ void diff_addremove(struct diff_options *options,
         * Before the final output happens, they are pruned after
         * merged into rename/copy pairs as appropriate.
         */
-       if (DIFF_OPT_TST(options, REVERSE_DIFF))
+       if (options->flags.reverse_diff)
                addremove = (addremove == '+' ? '-' :
                             addremove == '-' ? '+' : addremove);
 
@@ -5881,8 +5880,8 @@ void diff_addremove(struct diff_options *options,
        }
 
        diff_queue(&diff_queued_diff, one, two);
-       if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
-               DIFF_OPT_SET(options, HAS_CHANGES);
+       if (!options->flags.diff_from_contents)
+               options->flags.has_changes = 1;
 }
 
 void diff_change(struct diff_options *options,
@@ -5900,7 +5899,7 @@ void diff_change(struct diff_options *options,
            is_submodule_ignored(concatpath, options))
                return;
 
-       if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
+       if (options->flags.reverse_diff) {
                SWAP(old_mode, new_mode);
                SWAP(old_oid, new_oid);
                SWAP(old_oid_valid, new_oid_valid);
@@ -5919,14 +5918,14 @@ void diff_change(struct diff_options *options,
        two->dirty_submodule = new_dirty_submodule;
        p = diff_queue(&diff_queued_diff, one, two);
 
-       if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
+       if (options->flags.diff_from_contents)
                return;
 
-       if (DIFF_OPT_TST(options, QUICK) && options->skip_stat_unmatch &&
+       if (options->flags.quick && options->skip_stat_unmatch &&
            !diff_filespec_check_stat_unmatch(p))
                return;
 
-       DIFF_OPT_SET(options, HAS_CHANGES);
+       options->flags.has_changes = 1;
 }
 
 struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)
@@ -6064,7 +6063,7 @@ void setup_diff_pager(struct diff_options *opt)
         * and because it is easy to find people oneline advising "git diff
         * --exit-code" in hooks and other scripts, we do not do so.
         */
-       if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
+       if (!opt->flags.exit_with_status &&
            check_pager_config("diff") != 0)
                setup_pager();
 }
diff --git a/diff.h b/diff.h
index 398b87b4cf0fe06010ed20320d55c1803dfc3331..0fb18dd735b5462e7b186c609efd048561381be4 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -60,42 +60,52 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
 
 #define DIFF_FORMAT_CALLBACK   0x1000
 
-#define DIFF_OPT_RECURSIVE           (1 <<  0)
-#define DIFF_OPT_TREE_IN_RECURSIVE   (1 <<  1)
-#define DIFF_OPT_BINARY              (1 <<  2)
-#define DIFF_OPT_TEXT                (1 <<  3)
-#define DIFF_OPT_FULL_INDEX          (1 <<  4)
-#define DIFF_OPT_SILENT_ON_REMOVE    (1 <<  5)
-#define DIFF_OPT_FIND_COPIES_HARDER  (1 <<  6)
-#define DIFF_OPT_FOLLOW_RENAMES      (1 <<  7)
-#define DIFF_OPT_RENAME_EMPTY        (1 <<  8)
-/* (1 <<  9) unused */
-#define DIFF_OPT_HAS_CHANGES         (1 << 10)
-#define DIFF_OPT_QUICK               (1 << 11)
-#define DIFF_OPT_NO_INDEX            (1 << 12)
-#define DIFF_OPT_ALLOW_EXTERNAL      (1 << 13)
-#define DIFF_OPT_EXIT_WITH_STATUS    (1 << 14)
-#define DIFF_OPT_REVERSE_DIFF        (1 << 15)
-#define DIFF_OPT_CHECK_FAILED        (1 << 16)
-#define DIFF_OPT_RELATIVE_NAME       (1 << 17)
-#define DIFF_OPT_IGNORE_SUBMODULES   (1 << 18)
-#define DIFF_OPT_DIRSTAT_CUMULATIVE  (1 << 19)
-#define DIFF_OPT_DIRSTAT_BY_FILE     (1 << 20)
-#define DIFF_OPT_ALLOW_TEXTCONV      (1 << 21)
-#define DIFF_OPT_DIFF_FROM_CONTENTS  (1 << 22)
-#define DIFF_OPT_DIRTY_SUBMODULES    (1 << 24)
-#define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25)
-#define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)
-#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)
-#define DIFF_OPT_DIRSTAT_BY_LINE     (1 << 28)
-#define DIFF_OPT_FUNCCONTEXT         (1 << 29)
-#define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
-#define DIFF_OPT_DEFAULT_FOLLOW_RENAMES (1U << 31)
-
-#define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
-#define DIFF_OPT_TOUCHED(opts, flag)    ((opts)->touched_flags & DIFF_OPT_##flag)
-#define DIFF_OPT_SET(opts, flag)    (((opts)->flags |= DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
-#define DIFF_OPT_CLR(opts, flag)    (((opts)->flags &= ~DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
+#define DIFF_FLAGS_INIT { 0 }
+struct diff_flags {
+       unsigned recursive:1;
+       unsigned tree_in_recursive:1;
+       unsigned binary:1;
+       unsigned text:1;
+       unsigned full_index:1;
+       unsigned silent_on_remove:1;
+       unsigned find_copies_harder:1;
+       unsigned follow_renames:1;
+       unsigned rename_empty:1;
+       unsigned has_changes:1;
+       unsigned quick:1;
+       unsigned no_index:1;
+       unsigned allow_external:1;
+       unsigned exit_with_status:1;
+       unsigned reverse_diff:1;
+       unsigned check_failed:1;
+       unsigned relative_name:1;
+       unsigned ignore_submodules:1;
+       unsigned dirstat_cumulative:1;
+       unsigned dirstat_by_file:1;
+       unsigned allow_textconv:1;
+       unsigned textconv_set_via_cmdline:1;
+       unsigned diff_from_contents:1;
+       unsigned dirty_submodules:1;
+       unsigned ignore_untracked_in_submodules:1;
+       unsigned ignore_dirty_submodules:1;
+       unsigned override_submodule_config:1;
+       unsigned dirstat_by_line:1;
+       unsigned funccontext:1;
+       unsigned pickaxe_ignore_case:1;
+       unsigned default_follow_renames:1;
+};
+
+static inline void diff_flags_or(struct diff_flags *a,
+                                const struct diff_flags *b)
+{
+       char *tmp_a = (char *)a;
+       const char *tmp_b = (const char *)b;
+       int i;
+
+       for (i = 0; i < sizeof(struct diff_flags); i++)
+               tmp_a[i] |= tmp_b[i];
+}
+
 #define DIFF_XDL_TST(opts, flag)    ((opts)->xdl_opts & XDF_##flag)
 #define DIFF_XDL_SET(opts, flag)    ((opts)->xdl_opts |= XDF_##flag)
 #define DIFF_XDL_CLR(opts, flag)    ((opts)->xdl_opts &= ~XDF_##flag)
@@ -122,8 +132,7 @@ struct diff_options {
        const char *a_prefix, *b_prefix;
        const char *line_prefix;
        size_t line_prefix_length;
-       unsigned flags;
-       unsigned touched_flags;
+       struct diff_flags flags;
 
        /* diff-filter bits */
        unsigned int filter;
@@ -389,7 +398,8 @@ extern int diff_result_code(struct diff_options *, int);
 
 extern void diff_no_index(struct rev_info *, int, const char **);
 
-extern int index_differs_from(const char *def, int diff_flags, int ita_invisible_in_index);
+extern int index_differs_from(const char *def, const struct diff_flags *flags,
+                             int ita_invisible_in_index);
 
 /*
  * Fill the contents of the filespec "df", respecting any textconv defined by
index 341529b5a865ae6460f50d8593d52497059f2408..9476bd21081f456be6ae6412ea591e11dde50686 100644 (file)
@@ -131,7 +131,7 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
        if (!DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two))
                return 0;
 
-       if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
+       if (o->flags.allow_textconv) {
                textconv_one = get_textconv(p->one);
                textconv_two = get_textconv(p->two);
        }
@@ -222,11 +222,11 @@ void diffcore_pickaxe(struct diff_options *o)
 
        if (opts & (DIFF_PICKAXE_REGEX | DIFF_PICKAXE_KIND_G)) {
                int cflags = REG_EXTENDED | REG_NEWLINE;
-               if (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE))
+               if (o->flags.pickaxe_ignore_case)
                        cflags |= REG_ICASE;
                regcomp_or_die(&regex, needle, cflags);
                regexp = &regex;
-       } else if (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE) &&
+       } else if (o->flags.pickaxe_ignore_case &&
                   has_non_ascii(needle)) {
                struct strbuf sb = STRBUF_INIT;
                int cflags = REG_NEWLINE | REG_ICASE;
@@ -236,7 +236,7 @@ void diffcore_pickaxe(struct diff_options *o)
                strbuf_release(&sb);
                regexp = &regex;
        } else {
-               kws = kwsalloc(DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE)
+               kws = kwsalloc(o->flags.pickaxe_ignore_case
                               ? tolower_trans_tbl : NULL);
                kwsincr(kws, needle, strlen(needle));
                kwsprep(kws);
index 0d8c3d2ee480d70718f1e6f0b43a1175a14e4584..12dc2a056f119124a0518bcb898b5526ea9c5ba5 100644 (file)
@@ -405,7 +405,7 @@ static int too_many_rename_candidates(int num_create,
                num_src > num_create ? num_src : num_create;
 
        /* Are we running under -C -C? */
-       if (!DIFF_OPT_TST(options, FIND_COPIES_HARDER))
+       if (!options->flags.find_copies_harder)
                return 1;
 
        /* Would we bust the limit if we were running under -C? */
@@ -463,7 +463,7 @@ void diffcore_rename(struct diff_options *options)
                        else if (options->single_follow &&
                                 strcmp(options->single_follow, p->two->path))
                                continue; /* not interested */
-                       else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
+                       else if (!options->flags.rename_empty &&
                                 is_empty_blob_oid(&p->two->oid))
                                continue;
                        else if (add_rename_dst(p->two) < 0) {
@@ -473,7 +473,7 @@ void diffcore_rename(struct diff_options *options)
                                goto cleanup;
                        }
                }
-               else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
+               else if (!options->flags.rename_empty &&
                         is_empty_blob_oid(&p->one->oid))
                        continue;
                else if (!DIFF_PAIR_UNMERGED(p) && !DIFF_FILE_VALID(p->two)) {
diff --git a/dir.c b/dir.c
index fc2bdc79fc8ff599c8fba922dd7407cacae0c730..047a950f55372babf61bfa9c8dbd979fc4b8bc26 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -1389,6 +1389,30 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
        case index_nonexistent:
                if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
                        break;
+               if (exclude &&
+                       (dir->flags & DIR_SHOW_IGNORED_TOO) &&
+                       (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) {
+
+                       /*
+                        * This is an excluded directory and we are
+                        * showing ignored paths that match an exclude
+                        * pattern.  (e.g. show directory as ignored
+                        * only if it matches an exclude pattern).
+                        * This path will either be 'path_excluded`
+                        * (if we are showing empty directories or if
+                        * the directory is not empty), or will be
+                        * 'path_none' (empty directory, and we are
+                        * not showing empty directories).
+                        */
+                       if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
+                               return path_excluded;
+
+                       if (read_directory_recursive(dir, istate, dirname, len,
+                                                    untracked, 1, 1, pathspec) == path_excluded)
+                               return path_excluded;
+
+                       return path_none;
+               }
                if (!(dir->flags & DIR_NO_GITLINKS)) {
                        struct object_id oid;
                        if (resolve_gitlink_ref(dirname, "HEAD", &oid) == 0)
@@ -1561,6 +1585,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
 {
        int exclude;
        int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case);
+       enum path_treatment path_treatment;
 
        if (dtype == DT_UNKNOWN)
                dtype = get_dtype(de, istate, path->buf, path->len);
@@ -1607,8 +1632,23 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
                return path_none;
        case DT_DIR:
                strbuf_addch(path, '/');
-               return treat_directory(dir, istate, untracked, path->buf, path->len,
-                                      baselen, exclude, pathspec);
+               path_treatment = treat_directory(dir, istate, untracked,
+                                                path->buf, path->len,
+                                                baselen, exclude, pathspec);
+               /*
+                * If 1) we only want to return directories that
+                * match an exclude pattern and 2) this directory does
+                * not match an exclude pattern but all of its
+                * contents are excluded, then indicate that we should
+                * recurse into this directory (instead of marking the
+                * directory itself as an ignored path).
+                */
+               if (!exclude &&
+                   path_treatment == path_excluded &&
+                   (dir->flags & DIR_SHOW_IGNORED_TOO) &&
+                   (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING))
+                       return path_recurse;
+               return path_treatment;
        case DT_REG:
        case DT_LNK:
                return exclude ? path_excluded : path_untracked;
diff --git a/dir.h b/dir.h
index e3717055d193366e6780b50d68f6a3c2360d32c4..57b0943dae807b6e7e9959c6e20f4fc9141c8af1 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -152,7 +152,8 @@ struct dir_struct {
                DIR_COLLECT_IGNORED = 1<<4,
                DIR_SHOW_IGNORED_TOO = 1<<5,
                DIR_COLLECT_KILLED_ONLY = 1<<6,
-               DIR_KEEP_UNTRACKED_CONTENTS = 1<<7
+               DIR_KEEP_UNTRACKED_CONTENTS = 1<<7,
+               DIR_SHOW_IGNORED_TOO_MODE_MATCHING = 1<<8
        } flags;
        struct dir_entry **entries;
        struct dir_entry **ignored;
diff --git a/git.rc b/git.rc
index 33aafb786cf7f73eb7d4a769e585cb958999e68a..49002e0d541f1ab080efd8b9b4732f52db89e984 100644 (file)
--- a/git.rc
+++ b/git.rc
@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION     MAJOR,MINOR,0,0
-PRODUCTVERSION  MAJOR,MINOR,0,0
+FILEVERSION     MAJOR,MINOR,MICRO,PATCHLEVEL
+PRODUCTVERSION  MAJOR,MINOR,MICRO,PATCHLEVEL
 BEGIN
   BLOCK "StringFileInfo"
   BEGIN
diff --git a/hex.c b/hex.c
index 28b44118cbf2c75b26d017a34ecfdf65dbf4c7eb..8df2d63728f0405a9b1dc70aa404954dd921b6bc 100644 (file)
--- a/hex.c
+++ b/hex.c
@@ -35,6 +35,18 @@ const signed char hexval_table[256] = {
         -1, -1, -1, -1, -1, -1, -1, -1,                /* f8-ff */
 };
 
+int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
+{
+       for (; len; len--, hex += 2) {
+               unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
+
+               if (val & ~0xff)
+                       return -1;
+               *binary++ = val;
+       }
+       return 0;
+}
+
 int get_sha1_hex(const char *hex, unsigned char *sha1)
 {
        int i;
index 493ee7d719d488f25cd6c45bb4c7ce1d5a75977b..14435ab65d1bbe3fc73be6a6d774b6ab6ffc8360 100644 (file)
@@ -1007,20 +1007,18 @@ static void remote_ls(const char *path, int flags,
                      void (*userFunc)(struct remote_ls_ctx *ls),
                      void *userData);
 
-/* extract hex from sharded "xx/x{40}" filename */
+/* extract hex from sharded "xx/x{38}" filename */
 static int get_oid_hex_from_objpath(const char *path, struct object_id *oid)
 {
-       char hex[GIT_MAX_HEXSZ];
-
        if (strlen(path) != GIT_SHA1_HEXSZ + 1)
                return -1;
 
-       memcpy(hex, path, 2);
+       if (hex_to_bytes(oid->hash, path, 1))
+               return -1;
        path += 2;
        path++; /* skip '/' */
-       memcpy(hex + 2, path, GIT_SHA1_HEXSZ - 2);
 
-       return get_oid_hex(hex, oid);
+       return hex_to_bytes(oid->hash + 1, path, GIT_SHA1_RAWSZ - 1);
 }
 
 static void process_ls_object(struct remote_ls_ctx *ls)
index 8c785f3ca20c52266d7f99ca0d306a324756ede8..12cc4ea4c8ef9de6acf3116f478ed22e18054a98 100644 (file)
@@ -684,7 +684,7 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
        struct imap *imap = ctx->imap;
        char *arg, *p;
 
-       if (*s != '[')
+       if (!s || *s != '[')
                return RESP_OK;         /* no response code */
        s++;
        if (!(p = strchr(s, ']'))) {
@@ -693,6 +693,10 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
        }
        *p++ = 0;
        arg = next_arg(&s);
+       if (!arg) {
+               fprintf(stderr, "IMAP error: empty response code\n");
+               return RESP_BAD;
+       }
        if (!strcmp("UIDVALIDITY", arg)) {
                if (!(arg = next_arg(&s)) || !(ctx->uidvalidity = atoi(arg))) {
                        fprintf(stderr, "IMAP error: malformed UIDVALIDITY status\n");
@@ -725,7 +729,8 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
 {
        struct imap *imap = ctx->imap;
        struct imap_cmd *cmdp, **pcmdp;
-       char *cmd, *arg, *arg1;
+       char *cmd;
+       const char *arg, *arg1;
        int n, resp, resp2, tag;
 
        for (;;) {
@@ -733,6 +738,10 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
                        return RESP_BAD;
 
                arg = next_arg(&cmd);
+               if (!arg) {
+                       fprintf(stderr, "IMAP error: empty response\n");
+                       return RESP_BAD;
+               }
                if (*arg == '*') {
                        arg = next_arg(&cmd);
                        if (!arg) {
@@ -807,6 +816,8 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
                        if (cmdp->cb.cont || cmdp->cb.data)
                                imap->literal_pending = 0;
                        arg = next_arg(&cmd);
+                       if (!arg)
+                               arg = "";
                        if (!strcmp("OK", arg))
                                resp = DRV_OK;
                        else {
index 580b3a98a03df8b1920b3f729c783b79ed781164..3b904f0375e233db974ab49b3b31dd2fc73e842d 100644 (file)
@@ -793,7 +793,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
        struct commit_list *parents;
        struct object_id *oid;
 
-       if (!opt->diff && !DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS))
+       if (!opt->diff && !opt->diffopt.flags.exit_with_status)
                return 0;
 
        parse_commit_or_die(commit);
index 24c5c26a6abdcc6aaeb1defa194d25b50e7ca6e5..b48b15a6fd88a89c03b259ebc3efed361c7f4d4a 100644 (file)
@@ -540,8 +540,8 @@ static struct string_list *get_renames(struct merge_options *o,
                return renames;
 
        diff_setup(&opts);
-       DIFF_OPT_SET(&opts, RECURSIVE);
-       DIFF_OPT_CLR(&opts, RENAME_EMPTY);
+       opts.flags.recursive = 1;
+       opts.flags.rename_empty = 0;
        opts.detect_rename = DIFF_DETECT_RENAME;
        opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
                            o->diff_rename_limit >= 0 ? o->diff_rename_limit :
@@ -2201,6 +2201,7 @@ static void merge_recursive_config(struct merge_options *o)
 
 void init_merge_options(struct merge_options *o)
 {
+       const char *merge_verbosity;
        memset(o, 0, sizeof(struct merge_options));
        o->verbosity = 2;
        o->buffer_output = 1;
@@ -2209,9 +2210,9 @@ void init_merge_options(struct merge_options *o)
        o->renormalize = 0;
        o->detect_rename = 1;
        merge_recursive_config(o);
-       if (getenv("GIT_MERGE_VERBOSITY"))
-               o->verbosity =
-                       strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);
+       merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
+       if (merge_verbosity)
+               o->verbosity = strtol(merge_verbosity, NULL, 10);
        if (o->verbosity >= 5)
                o->buffer_output = 0;
        strbuf_init(&o->obuf, 0);
index 30ec83ab043965a743918b4ee39c708a3fb3e717..4a83b0ebd5ce8b24da0b32820f5666571b099ecf 100644 (file)
@@ -125,7 +125,7 @@ static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
               oid_to_hex(base), oid_to_hex(remote));
 
        diff_setup(&opt);
-       DIFF_OPT_SET(&opt, RECURSIVE);
+       opt.flags.recursive = 1;
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_setup_done(&opt);
        diff_tree_oid(base, remote, "", &opt);
@@ -188,7 +188,7 @@ static void diff_tree_local(struct notes_merge_options *o,
               len, oid_to_hex(base), oid_to_hex(local));
 
        diff_setup(&opt);
-       DIFF_OPT_SET(&opt, RECURSIVE);
+       opt.flags.recursive = 1;
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_setup_done(&opt);
        diff_tree_oid(base, local, "", &opt);
diff --git a/notes.c b/notes.c
index d273822b2859b9877b1814a49d4f2dce9fad1d8b..c7f21fae441067f7250caf0b4186fcbcbc7630bb 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -334,23 +334,6 @@ static void note_tree_free(struct int_node *tree)
        }
 }
 
-/*
- * Read `len` pairs of hexadecimal digits from `hex` and write the
- * values to `binary` as `len` bytes. Return 0 on success, or -1 if
- * the input does not consist of hex digits).
- */
-static int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
-{
-       for (; len; len--, hex += 2) {
-               unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
-
-               if (val & ~0xff)
-                       return -1;
-               *binary++ = val;
-       }
-       return 0;
-}
-
 static int non_note_cmp(const struct non_note *a, const struct non_note *b)
 {
        return strcmp(a->path, b->path);
index 7a583b3011390c1a3cb1c0885e420e76b7751d26..8f7c25d5dbf5ccdcbf27db51fbe1970addebf9a7 100644 (file)
@@ -61,7 +61,7 @@ int init_patch_ids(struct patch_ids *ids)
        memset(ids, 0, sizeof(*ids));
        diff_setup(&ids->diffopts);
        ids->diffopts.detect_rename = 0;
-       DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
+       ids->diffopts.flags.recursive = 1;
        diff_setup_done(&ids->diffopts);
        hashmap_init(&ids->patches, patch_id_cmp, &ids->diffopts, 256);
        return 0;
diff --git a/perl/Git/Packet.pm b/perl/Git/Packet.pm
new file mode 100644 (file)
index 0000000..255b28c
--- /dev/null
@@ -0,0 +1,168 @@
+package Git::Packet;
+use 5.008;
+use strict;
+use warnings;
+BEGIN {
+       require Exporter;
+       if ($] < 5.008003) {
+               *import = \&Exporter::import;
+       } else {
+               # Exporter 5.57 which supports this invocation was
+               # released with perl 5.8.3
+               Exporter->import('import');
+       }
+}
+
+our @EXPORT = qw(
+                       packet_compare_lists
+                       packet_bin_read
+                       packet_txt_read
+                       packet_required_key_val_read
+                       packet_bin_write
+                       packet_txt_write
+                       packet_flush
+                       packet_initialize
+                       packet_read_capabilities
+                       packet_read_and_check_capabilities
+                       packet_check_and_write_capabilities
+               );
+our @EXPORT_OK = @EXPORT;
+
+sub packet_compare_lists {
+       my ($expect, @result) = @_;
+       my $ix;
+       if (scalar @$expect != scalar @result) {
+               return undef;
+       }
+       for ($ix = 0; $ix < $#result; $ix++) {
+               if ($expect->[$ix] ne $result[$ix]) {
+                       return undef;
+               }
+       }
+       return 1;
+}
+
+sub packet_bin_read {
+       my $buffer;
+       my $bytes_read = read STDIN, $buffer, 4;
+       if ( $bytes_read == 0 ) {
+               # EOF - Git stopped talking to us!
+               return ( -1, "" );
+       } elsif ( $bytes_read != 4 ) {
+               die "invalid packet: '$buffer'";
+       }
+       my $pkt_size = hex($buffer);
+       if ( $pkt_size == 0 ) {
+               return ( 1, "" );
+       } elsif ( $pkt_size > 4 ) {
+               my $content_size = $pkt_size - 4;
+               $bytes_read = read STDIN, $buffer, $content_size;
+               if ( $bytes_read != $content_size ) {
+                       die "invalid packet ($content_size bytes expected; $bytes_read bytes read)";
+               }
+               return ( 0, $buffer );
+       } else {
+               die "invalid packet size: $pkt_size";
+       }
+}
+
+sub remove_final_lf_or_die {
+       my $buf = shift;
+       unless ( $buf =~ s/\n$// ) {
+               die "A non-binary line MUST be terminated by an LF.\n"
+                   . "Received: '$buf'";
+       }
+       return $buf;
+}
+
+sub packet_txt_read {
+       my ( $res, $buf ) = packet_bin_read();
+       unless ( $res == -1 or $buf eq '' ) {
+               $buf = remove_final_lf_or_die($buf);
+       }
+       return ( $res, $buf );
+}
+
+sub packet_required_key_val_read {
+       my ( $key ) = @_;
+       my ( $res, $buf ) = packet_txt_read();
+       unless ( $res == -1 or ( $buf =~ s/^$key=// and $buf ne '' ) ) {
+               die "bad $key: '$buf'";
+       }
+       return ( $res, $buf );
+}
+
+sub packet_bin_write {
+       my $buf = shift;
+       print STDOUT sprintf( "%04x", length($buf) + 4 );
+       print STDOUT $buf;
+       STDOUT->flush();
+}
+
+sub packet_txt_write {
+       packet_bin_write( $_[0] . "\n" );
+}
+
+sub packet_flush {
+       print STDOUT sprintf( "%04x", 0 );
+       STDOUT->flush();
+}
+
+sub packet_initialize {
+       my ($name, $version) = @_;
+
+       packet_compare_lists([0, $name . "-client"], packet_txt_read()) ||
+               die "bad initialize";
+       packet_compare_lists([0, "version=" . $version], packet_txt_read()) ||
+               die "bad version";
+       packet_compare_lists([1, ""], packet_bin_read()) ||
+               die "bad version end";
+
+       packet_txt_write( $name . "-server" );
+       packet_txt_write( "version=" . $version );
+       packet_flush();
+}
+
+sub packet_read_capabilities {
+       my @cap;
+       while (1) {
+               my ( $res, $buf ) = packet_bin_read();
+               if ( $res == -1 ) {
+                       die "unexpected EOF when reading capabilities";
+               }
+               return ( $res, @cap ) if ( $res != 0 );
+               $buf = remove_final_lf_or_die($buf);
+               unless ( $buf =~ s/capability=// ) {
+                       die "bad capability buf: '$buf'";
+               }
+               push @cap, $buf;
+       }
+}
+
+# Read remote capabilities and check them against capabilities we require
+sub packet_read_and_check_capabilities {
+       my @required_caps = @_;
+       my ($res, @remote_caps) = packet_read_capabilities();
+       my %remote_caps = map { $_ => 1 } @remote_caps;
+       foreach (@required_caps) {
+               unless (exists($remote_caps{$_})) {
+                       die "required '$_' capability not available from remote" ;
+               }
+       }
+       return %remote_caps;
+}
+
+# Check our capabilities we want to advertise against the remote ones
+# and then advertise our capabilities
+sub packet_check_and_write_capabilities {
+       my ($remote_caps, @our_caps) = @_;
+       foreach (@our_caps) {
+               unless (exists($remote_caps->{$_})) {
+                       die "our capability '$_' is not available from remote"
+               }
+               packet_txt_write( "capability=" . $_ );
+       }
+       packet_flush();
+}
+
+1;
index 15d96fcc7a5a81ae0304bc51a603fe54bcbb95c6..f657de20e3983af8f990114c24bddd2775845d88 100644 (file)
@@ -30,6 +30,7 @@ instdir_SQ = $(subst ','\'',$(prefix)/lib)
 modules += Git
 modules += Git/I18N
 modules += Git/IndexInfo
+modules += Git/Packet
 modules += Git/SVN
 modules += Git/SVN/Memoize/YAML
 modules += Git/SVN/Fetcher
diff --git a/refs.c b/refs.c
index 62a7621025eba7ed39a6391caf1b1ecf511bd5ba..339d4318ee4500ffeb26426bdf9976979ecf739a 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -770,7 +770,7 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
                if (cb->cutoff_cnt)
                        *cb->cutoff_cnt = cb->reccnt - 1;
                /*
-                * we have not yet updated cb->[n|o]sha1 so they still
+                * we have not yet updated cb->[n|o]oid so they still
                 * hold the values for the previous record.
                 */
                if (!is_null_oid(&cb->ooid)) {
@@ -906,9 +906,6 @@ struct ref_update *ref_transaction_add_update(
        if (transaction->state != REF_TRANSACTION_OPEN)
                die("BUG: update called for transaction that is not open");
 
-       if ((flags & REF_ISPRUNING) && !(flags & REF_NODEREF))
-               die("BUG: REF_ISPRUNING set without REF_NODEREF");
-
        FLEX_ALLOC_STR(update, refname, refname);
        ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
        transaction->updates[transaction->nr++] = update;
@@ -940,7 +937,8 @@ int ref_transaction_update(struct ref_transaction *transaction,
                return -1;
        }
 
-       flags &= REF_TRANSACTION_UPDATE_ALLOWED_FLAGS;
+       if (flags & ~REF_TRANSACTION_UPDATE_ALLOWED_FLAGS)
+               BUG("illegal flags 0x%x passed to ref_transaction_update()", flags);
 
        flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0);
 
diff --git a/refs.h b/refs.h
index 15fd419c7d595f4c08650eb821a3d10e77688ade..18582a408c60b44ed0b74e6d6c762c7d4d93f0e9 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -126,7 +126,7 @@ int peel_ref(const char *refname, struct object_id *oid);
 /**
  * Resolve refname in the nested "gitlink" repository in the specified
  * submodule (which must be non-NULL). If the resolution is
- * successful, return 0 and set sha1 to the name of the object;
+ * successful, return 0 and set oid to the name of the object;
  * otherwise, return a non-zero value.
  */
 int resolve_gitlink_ref(const char *submodule, const char *refname,
@@ -260,7 +260,7 @@ struct ref_transaction;
 
 /*
  * The signature for the callback function for the for_each_*()
- * functions below.  The memory pointed to by the refname and sha1
+ * functions below.  The memory pointed to by the refname and oid
  * arguments is only guaranteed to be valid for the duration of a
  * single callback invocation.
  */
@@ -335,24 +335,6 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
  */
 int refs_pack_refs(struct ref_store *refs, unsigned int flags);
 
-/*
- * Flags controlling ref_transaction_update(), ref_transaction_create(), etc.
- * REF_NODEREF: act on the ref directly, instead of dereferencing
- *              symbolic references.
- *
- * Other flags are reserved for internal use.
- */
-#define REF_NODEREF    0x01
-#define REF_FORCE_CREATE_REFLOG 0x40
-
-/*
- * Flags that can be passed in to ref_transaction_update
- */
-#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \
-       REF_ISPRUNING |                      \
-       REF_FORCE_CREATE_REFLOG |            \
-       REF_NODEREF
-
 /*
  * Setup reflog before using. Fill in err and return -1 on failure.
  */
@@ -372,7 +354,7 @@ int reflog_exists(const char *refname);
 
 /*
  * Delete the specified reference. If old_oid is non-NULL, then
- * verify that the current value of the reference is old_sha1 before
+ * verify that the current value of the reference is old_oid before
  * deleting it. If old_oid is NULL, delete the reference if it
  * exists, regardless of its old value. It is an error for old_oid to
  * be null_oid. msg and flags are passed through to
@@ -480,22 +462,23 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
  *
  *     refname -- the name of the reference to be affected.
  *
- *     new_sha1 -- the SHA-1 that should be set to be the new value of
- *         the reference. Some functions allow this parameter to be
+ *     new_oid -- the object ID that should be set to be the new value
+ *         of the reference. Some functions allow this parameter to be
  *         NULL, meaning that the reference is not changed, or
- *         null_sha1, meaning that the reference should be deleted. A
+ *         null_oid, meaning that the reference should be deleted. A
  *         copy of this value is made in the transaction.
  *
- *     old_sha1 -- the SHA-1 value that the reference must have before
+ *     old_oid -- the object ID that the reference must have before
  *         the update. Some functions allow this parameter to be NULL,
  *         meaning that the old value of the reference is not checked,
- *         or null_sha1, meaning that the reference must not exist
+ *         or null_oid, meaning that the reference must not exist
  *         before the update. A copy of this value is made in the
  *         transaction.
  *
  *     flags -- flags affecting the update, passed to
- *         update_ref_lock(). Can be REF_NODEREF, which means that
- *         symbolic references should not be followed.
+ *         update_ref_lock(). Possible flags: REF_NO_DEREF,
+ *         REF_FORCE_CREATE_REFLOG. See those constants for more
+ *         information.
  *
  *     msg -- a message describing the change (for the reflog).
  *
@@ -511,11 +494,37 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
  */
 
 /*
- * Add a reference update to transaction. new_oid is the value that
- * the reference should have after the update, or null_oid if it
- * should be deleted. If new_oid is NULL, then the reference is not
- * changed at all. old_oid is the value that the reference must have
- * before the update, or null_oid if it must not have existed
+ * The following flags can be passed to ref_transaction_update() etc.
+ * Internally, they are stored in `ref_update::flags`, along with some
+ * internal flags.
+ */
+
+/*
+ * Act on the ref directly; i.e., without dereferencing symbolic refs.
+ * If this flag is not specified, then symbolic references are
+ * dereferenced and the update is applied to the referent.
+ */
+#define REF_NO_DEREF (1 << 0)
+
+/*
+ * Force the creation of a reflog for this reference, even if it
+ * didn't previously have a reflog.
+ */
+#define REF_FORCE_CREATE_REFLOG (1 << 1)
+
+/*
+ * Bitmask of all of the flags that are allowed to be passed in to
+ * ref_transaction_update() and friends:
+ */
+#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \
+       (REF_NO_DEREF | REF_FORCE_CREATE_REFLOG)
+
+/*
+ * Add a reference update to transaction. `new_oid` is the value that
+ * the reference should have after the update, or `null_oid` if it
+ * should be deleted. If `new_oid` is NULL, then the reference is not
+ * changed at all. `old_oid` is the value that the reference must have
+ * before the update, or `null_oid` if it must not have existed
  * beforehand. The old value is checked after the lock is taken to
  * prevent races. If the old value doesn't agree with old_oid, the
  * whole transaction fails. If old_oid is NULL, then the previous
@@ -624,7 +633,7 @@ int ref_transaction_abort(struct ref_transaction *transaction,
  * It is a bug to call this function when there might be other
  * processes accessing the repository or if there are existing
  * references that might conflict with the ones being created. All
- * old_sha1 values must either be absent or NULL_SHA1.
+ * old_oid values must either be absent or null_oid.
  */
 int initial_ref_transaction_commit(struct ref_transaction *transaction,
                                   struct strbuf *err);
index 2bd54e11aedf0e081072dbb58d327b969d0948bc..f75d960e1982a2db5dc8828c6f1b10ffe64fda48 100644 (file)
 #include "../object.h"
 #include "../dir.h"
 
+/*
+ * This backend uses the following flags in `ref_update::flags` for
+ * internal bookkeeping purposes. Their numerical values must not
+ * conflict with REF_NO_DEREF, REF_FORCE_CREATE_REFLOG, REF_HAVE_NEW,
+ * REF_HAVE_OLD, or REF_IS_PRUNING, which are also stored in
+ * `ref_update::flags`.
+ */
+
+/*
+ * Used as a flag in ref_update::flags when a loose ref is being
+ * pruned. This flag must only be used when REF_NO_DEREF is set.
+ */
+#define REF_IS_PRUNING (1 << 4)
+
+/*
+ * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken
+ * refs (i.e., because the reference is about to be deleted anyway).
+ */
+#define REF_DELETING (1 << 5)
+
+/*
+ * Used as a flag in ref_update::flags when the lockfile needs to be
+ * committed.
+ */
+#define REF_NEEDS_COMMIT (1 << 6)
+
+/*
+ * Used as a flag in ref_update::flags when we want to log a ref
+ * update but not actually perform it.  This is used when a symbolic
+ * ref update is split up.
+ */
+#define REF_LOG_ONLY (1 << 7)
+
+/*
+ * Used as a flag in ref_update::flags when the ref_update was via an
+ * update to HEAD.
+ */
+#define REF_UPDATE_VIA_HEAD (1 << 8)
+
+/*
+ * Used as a flag in ref_update::flags when the loose reference has
+ * been deleted.
+ */
+#define REF_DELETED_LOOSE (1 << 9)
+
 struct ref_lock {
        char *ref_name;
        struct lock_file lk;
@@ -195,7 +240,7 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
                        } else if (is_null_oid(&oid)) {
                                /*
                                 * It is so astronomically unlikely
-                                * that NULL_SHA1 is the SHA-1 of an
+                                * that null_oid is the OID of an
                                 * actual object that we consider its
                                 * appearance in a loose reference
                                 * file to be repo corruption
@@ -428,7 +473,7 @@ static void unlock_ref(struct ref_lock *lock)
  * are passed to refs_verify_refname_available() for this check.
  *
  * If mustexist is not set and the reference is not found or is
- * broken, lock the reference anyway but clear sha1.
+ * broken, lock the reference anyway but clear old_oid.
  *
  * Return 0 on success. On failure, write an error message to err and
  * return TRANSACTION_NAME_CONFLICT or TRANSACTION_GENERIC_ERROR.
@@ -989,22 +1034,29 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r)
 {
        struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
+       int ret = -1;
 
        if (check_refname_format(r->name, 0))
                return;
 
        transaction = ref_store_transaction_begin(&refs->base, &err);
-       if (!transaction ||
-           ref_transaction_delete(transaction, r->name, &r->oid,
-                                  REF_ISPRUNING | REF_NODEREF, NULL, &err) ||
-           ref_transaction_commit(transaction, &err)) {
-               ref_transaction_free(transaction);
+       if (!transaction)
+               goto cleanup;
+       ref_transaction_add_update(
+                       transaction, r->name,
+                       REF_NO_DEREF | REF_HAVE_NEW | REF_HAVE_OLD | REF_IS_PRUNING,
+                       &null_oid, &r->oid, NULL);
+       if (ref_transaction_commit(transaction, &err))
+               goto cleanup;
+
+       ret = 0;
+
+cleanup:
+       if (ret)
                error("%s", err.buf);
-               strbuf_release(&err);
-               return;
-       }
-       ref_transaction_free(transaction);
        strbuf_release(&err);
+       ref_transaction_free(transaction);
+       return;
 }
 
 /*
@@ -1081,7 +1133,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
                 */
                if (ref_transaction_update(transaction, iter->refname,
                                           iter->oid, NULL,
-                                          REF_NODEREF, NULL, &err))
+                                          REF_NO_DEREF, NULL, &err))
                        die("failure preparing to create packed reference %s: %s",
                            iter->refname, err.buf);
 
@@ -1284,7 +1336,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
        }
 
        if (!copy && refs_delete_ref(&refs->base, logmsg, oldrefname,
-                           &orig_oid, REF_NODEREF)) {
+                           &orig_oid, REF_NO_DEREF)) {
                error("unable to delete old %s", oldrefname);
                goto rollback;
        }
@@ -1300,7 +1352,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
                                RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
                                &oid, NULL) &&
            refs_delete_ref(&refs->base, NULL, newrefname,
-                           NULL, REF_NODEREF)) {
+                           NULL, REF_NO_DEREF)) {
                if (errno == EISDIR) {
                        struct strbuf path = STRBUF_INIT;
                        int result;
@@ -1325,7 +1377,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
        logmoved = log;
 
        lock = lock_ref_oid_basic(refs, newrefname, NULL, NULL, NULL,
-                                 REF_NODEREF, NULL, &err);
+                                 REF_NO_DEREF, NULL, &err);
        if (!lock) {
                if (copy)
                        error("unable to copy '%s' to '%s': %s", oldrefname, newrefname, err.buf);
@@ -1348,7 +1400,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
 
  rollback:
        lock = lock_ref_oid_basic(refs, oldrefname, NULL, NULL, NULL,
-                                 REF_NODEREF, NULL, &err);
+                                 REF_NO_DEREF, NULL, &err);
        if (!lock) {
                error("unable to lock %s for rollback: %s", oldrefname, err.buf);
                strbuf_release(&err);
@@ -1596,9 +1648,8 @@ static int files_log_ref_write(struct files_ref_store *refs,
 }
 
 /*
- * Write sha1 into the open lockfile, then close the lockfile. On
- * errors, rollback the lockfile, fill in *err and
- * return -1.
+ * Write oid into the open lockfile, then close the lockfile. On
+ * errors, rollback the lockfile, fill in *err and return -1.
  */
 static int write_ref_to_lockfile(struct ref_lock *lock,
                                 const struct object_id *oid, struct strbuf *err)
@@ -1764,7 +1815,7 @@ static int files_create_symref(struct ref_store *ref_store,
        int ret;
 
        lock = lock_ref_oid_basic(refs, refname, NULL,
-                                 NULL, NULL, REF_NODEREF, NULL,
+                                 NULL, NULL, REF_NO_DEREF, NULL,
                                  &err);
        if (!lock) {
                error("%s", err.buf);
@@ -2125,7 +2176,7 @@ static int split_head_update(struct ref_update *update,
        struct ref_update *new_update;
 
        if ((update->flags & REF_LOG_ONLY) ||
-           (update->flags & REF_ISPRUNING) ||
+           (update->flags & REF_IS_PRUNING) ||
            (update->flags & REF_UPDATE_VIA_HEAD))
                return 0;
 
@@ -2148,7 +2199,7 @@ static int split_head_update(struct ref_update *update,
 
        new_update = ref_transaction_add_update(
                        transaction, "HEAD",
-                       update->flags | REF_LOG_ONLY | REF_NODEREF,
+                       update->flags | REF_LOG_ONLY | REF_NO_DEREF,
                        &update->new_oid, &update->old_oid,
                        update->msg);
 
@@ -2167,8 +2218,8 @@ static int split_head_update(struct ref_update *update,
 
 /*
  * update is for a symref that points at referent and doesn't have
- * REF_NODEREF set. Split it into two updates:
- * - The original update, but with REF_LOG_ONLY and REF_NODEREF set
+ * REF_NO_DEREF set. Split it into two updates:
+ * - The original update, but with REF_LOG_ONLY and REF_NO_DEREF set
  * - A new, separate update for the referent reference
  * Note that the new update will itself be subject to splitting when
  * the iteration gets to it.
@@ -2220,10 +2271,10 @@ static int split_symref_update(struct files_ref_store *refs,
 
        /*
         * Change the symbolic ref update to log only. Also, it
-        * doesn't need to check its old SHA-1 value, as that will be
+        * doesn't need to check its old OID value, as that will be
         * done when new_update is processed.
         */
-       update->flags |= REF_LOG_ONLY | REF_NODEREF;
+       update->flags |= REF_LOG_ONLY | REF_NO_DEREF;
        update->flags &= ~REF_HAVE_OLD;
 
        /*
@@ -2289,10 +2340,10 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
  * Prepare for carrying out update:
  * - Lock the reference referred to by update.
  * - Read the reference under lock.
- * - Check that its old SHA-1 value (if specified) is correct, and in
+ * - Check that its old OID value (if specified) is correct, and in
  *   any case record it in update->lock->old_oid for later use when
  *   writing the reflog.
- * - If it is a symref update without REF_NODEREF, split it up into a
+ * - If it is a symref update without REF_NO_DEREF, split it up into a
  *   REF_LOG_ONLY update of the symref and add a separate update for
  *   the referent to transaction.
  * - If it is an update of head_ref, add a corresponding REF_LOG_ONLY
@@ -2340,11 +2391,11 @@ static int lock_ref_for_update(struct files_ref_store *refs,
        update->backend_data = lock;
 
        if (update->type & REF_ISSYMREF) {
-               if (update->flags & REF_NODEREF) {
+               if (update->flags & REF_NO_DEREF) {
                        /*
                         * We won't be reading the referent as part of
                         * the transaction, so we have to read it here
-                        * to record and possibly check old_sha1:
+                        * to record and possibly check old_oid:
                         */
                        if (refs_read_ref_full(&refs->base,
                                               referent.buf, 0,
@@ -2364,7 +2415,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
                        /*
                         * Create a new update for the reference this
                         * symref is pointing at. Also, we will record
-                        * and verify old_sha1 for this update as part
+                        * and verify old_oid for this update as part
                         * of processing the split-off update, so we
                         * don't have to do it here.
                         */
@@ -2384,7 +2435,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
 
                /*
                 * If this update is happening indirectly because of a
-                * symref update, record the old SHA-1 in the parent
+                * symref update, record the old OID in the parent
                 * update:
                 */
                for (parent_update = update->parent_update;
@@ -2511,13 +2562,18 @@ static int files_transaction_prepare(struct ref_store *ref_store,
         * transaction. (If we end up splitting up any updates using
         * split_symref_update() or split_head_update(), those
         * functions will check that the new updates don't have the
-        * same refname as any existing ones.)
+        * same refname as any existing ones.) Also fail if any of the
+        * updates use REF_IS_PRUNING without REF_NO_DEREF.
         */
        for (i = 0; i < transaction->nr; i++) {
                struct ref_update *update = transaction->updates[i];
                struct string_list_item *item =
                        string_list_append(&affected_refnames, update->refname);
 
+               if ((update->flags & REF_IS_PRUNING) &&
+                   !(update->flags & REF_NO_DEREF))
+                       BUG("REF_IS_PRUNING set without REF_NO_DEREF");
+
                /*
                 * We store a pointer to update in item->util, but at
                 * the moment we never use the value of this field
@@ -2575,7 +2631,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
 
                if (update->flags & REF_DELETING &&
                    !(update->flags & REF_LOG_ONLY) &&
-                   !(update->flags & REF_ISPRUNING)) {
+                   !(update->flags & REF_IS_PRUNING)) {
                        /*
                         * This reference has to be deleted from
                         * packed-refs if it exists there.
@@ -2594,8 +2650,8 @@ static int files_transaction_prepare(struct ref_store *ref_store,
 
                        ref_transaction_add_update(
                                        packed_transaction, update->refname,
-                                       update->flags & ~REF_HAVE_OLD,
-                                       &update->new_oid, &update->old_oid,
+                                       REF_HAVE_NEW | REF_NO_DEREF,
+                                       &update->new_oid, NULL,
                                        NULL);
                }
        }
@@ -2606,7 +2662,23 @@ static int files_transaction_prepare(struct ref_store *ref_store,
                        goto cleanup;
                }
                backend_data->packed_refs_locked = 1;
-               ret = ref_transaction_prepare(packed_transaction, err);
+
+               if (is_packed_transaction_needed(refs->packed_ref_store,
+                                                packed_transaction)) {
+                       ret = ref_transaction_prepare(packed_transaction, err);
+               } else {
+                       /*
+                        * We can skip rewriting the `packed-refs`
+                        * file. But we do need to leave it locked, so
+                        * that somebody else doesn't pack a reference
+                        * that we are trying to delete.
+                        */
+                       if (ref_transaction_abort(packed_transaction, err)) {
+                               ret = TRANSACTION_GENERIC_ERROR;
+                               goto cleanup;
+                       }
+                       backend_data->packed_transaction = NULL;
+               }
        }
 
 cleanup:
@@ -2692,7 +2764,7 @@ static int files_transaction_finish(struct ref_store *ref_store,
                struct ref_update *update = transaction->updates[i];
                if (update->flags & REF_DELETING &&
                    !(update->flags & REF_LOG_ONLY) &&
-                   !(update->flags & REF_ISPRUNING)) {
+                   !(update->flags & REF_IS_PRUNING)) {
                        strbuf_reset(&sb);
                        files_reflog_path(refs, &sb, update->refname);
                        if (!unlink_or_warn(sb.buf))
@@ -2938,7 +3010,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
         * reference if --updateref was specified:
         */
        lock = lock_ref_oid_basic(refs, refname, oid,
-                                 NULL, NULL, REF_NODEREF,
+                                 NULL, NULL, REF_NO_DEREF,
                                  &type, &err);
        if (!lock) {
                error("cannot lock ref '%s': %s", refname, err.buf);
index 74f1dea0f4f0bcb655e5e2ad02455925e1e3d040..023243fd5f1833f3c5f0b6fd3cd82b2e0c69644e 100644 (file)
@@ -744,7 +744,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store,
 /*
  * This value is set in `base.flags` if the peeled value of the
  * current reference is known. In that case, `peeled` contains the
- * correct peeled value for the reference, which might be `null_sha1`
+ * correct peeled value for the reference, which might be `null_oid`
  * if the reference is not a tag or if it is broken.
  */
 #define REF_KNOWS_PEELED 0x40
@@ -961,11 +961,11 @@ static struct ref_iterator *packed_ref_iterator_begin(
  * by the failing call to `fprintf()`.
  */
 static int write_packed_entry(FILE *fh, const char *refname,
-                             const unsigned char *sha1,
-                             const unsigned char *peeled)
+                             const struct object_id *oid,
+                             const struct object_id *peeled)
 {
-       if (fprintf(fh, "%s %s\n", sha1_to_hex(sha1), refname) < 0 ||
-           (peeled && fprintf(fh, "^%s\n", sha1_to_hex(peeled)) < 0))
+       if (fprintf(fh, "%s %s\n", oid_to_hex(oid), refname) < 0 ||
+           (peeled && fprintf(fh, "^%s\n", oid_to_hex(peeled)) < 0))
                return -1;
 
        return 0;
@@ -1203,8 +1203,8 @@ static int write_with_updates(struct packed_ref_store *refs,
                        int peel_error = ref_iterator_peel(iter, &peeled);
 
                        if (write_packed_entry(out, iter->refname,
-                                              iter->oid->hash,
-                                              peel_error ? NULL : peeled.hash))
+                                              iter->oid,
+                                              peel_error ? NULL : &peeled))
                                goto write_error;
 
                        if ((ok = ref_iterator_advance(iter)) != ITER_OK)
@@ -1224,8 +1224,8 @@ static int write_with_updates(struct packed_ref_store *refs,
                                                     &peeled);
 
                        if (write_packed_entry(out, update->refname,
-                                              update->new_oid.hash,
-                                              peel_error ? NULL : peeled.hash))
+                                              &update->new_oid,
+                                              peel_error ? NULL : &peeled))
                                goto write_error;
 
                        i++;
@@ -1261,6 +1261,100 @@ static int write_with_updates(struct packed_ref_store *refs,
        return -1;
 }
 
+int is_packed_transaction_needed(struct ref_store *ref_store,
+                                struct ref_transaction *transaction)
+{
+       struct packed_ref_store *refs = packed_downcast(
+                       ref_store,
+                       REF_STORE_READ,
+                       "is_packed_transaction_needed");
+       struct strbuf referent = STRBUF_INIT;
+       size_t i;
+       int ret;
+
+       if (!is_lock_file_locked(&refs->lock))
+               BUG("is_packed_transaction_needed() called while unlocked");
+
+       /*
+        * We're only going to bother returning false for the common,
+        * trivial case that references are only being deleted, their
+        * old values are not being checked, and the old `packed-refs`
+        * file doesn't contain any of those reference(s). This gives
+        * false positives for some other cases that could
+        * theoretically be optimized away:
+        *
+        * 1. It could be that the old value is being verified without
+        *    setting a new value. In this case, we could verify the
+        *    old value here and skip the update if it agrees. If it
+        *    disagrees, we could either let the update go through
+        *    (the actual commit would re-detect and report the
+        *    problem), or come up with a way of reporting such an
+        *    error to *our* caller.
+        *
+        * 2. It could be that a new value is being set, but that it
+        *    is identical to the current packed value of the
+        *    reference.
+        *
+        * Neither of these cases will come up in the current code,
+        * because the only caller of this function passes to it a
+        * transaction that only includes `delete` updates with no
+        * `old_id`. Even if that ever changes, false positives only
+        * cause an optimization to be missed; they do not affect
+        * correctness.
+        */
+
+       /*
+        * Start with the cheap checks that don't require old
+        * reference values to be read:
+        */
+       for (i = 0; i < transaction->nr; i++) {
+               struct ref_update *update = transaction->updates[i];
+
+               if (update->flags & REF_HAVE_OLD)
+                       /* Have to check the old value -> needed. */
+                       return 1;
+
+               if ((update->flags & REF_HAVE_NEW) && !is_null_oid(&update->new_oid))
+                       /* Have to set a new value -> needed. */
+                       return 1;
+       }
+
+       /*
+        * The transaction isn't checking any old values nor is it
+        * setting any nonzero new values, so it still might be able
+        * to be skipped. Now do the more expensive check: the update
+        * is needed if any of the updates is a delete, and the old
+        * `packed-refs` file contains a value for that reference.
+        */
+       ret = 0;
+       for (i = 0; i < transaction->nr; i++) {
+               struct ref_update *update = transaction->updates[i];
+               unsigned int type;
+               struct object_id oid;
+
+               if (!(update->flags & REF_HAVE_NEW))
+                       /*
+                        * This reference isn't being deleted -> not
+                        * needed.
+                        */
+                       continue;
+
+               if (!refs_read_raw_ref(ref_store, update->refname,
+                                      &oid, &referent, &type) ||
+                   errno != ENOENT) {
+                       /*
+                        * We have to actually delete that reference
+                        * -> this transaction is needed.
+                        */
+                       ret = 1;
+                       break;
+               }
+       }
+
+       strbuf_release(&referent);
+       return ret;
+}
+
 struct packed_transaction_backend_data {
        /* True iff the transaction owns the packed-refs lock. */
        int own_lock;
index 61687e408ad4b83d111531f9d5b10a058abcf673..640245d3b9f23a8ae7866dd477a5ed9bbfc71cde 100644 (file)
@@ -23,4 +23,13 @@ int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err)
 void packed_refs_unlock(struct ref_store *ref_store);
 int packed_refs_is_locked(struct ref_store *ref_store);
 
+/*
+ * Return true if `transaction` really needs to be carried out against
+ * the specified packed_ref_store, or false if it can be skipped
+ * (i.e., because it is an obvious NOOP). `ref_store` must be locked
+ * before calling this function.
+ */
+int is_packed_transaction_needed(struct ref_store *ref_store,
+                                struct ref_transaction *transaction);
+
 #endif /* REFS_PACKED_BACKEND_H */
index 043eb83748739d9d3d78586c69005bb866554e7e..82c1cf90a7ef61cc8174bff5a9800af2ec8d7053 100644 (file)
@@ -260,8 +260,8 @@ int add_ref_entry(struct ref_dir *dir, struct ref_entry *ref)
 
 /*
  * Emit a warning and return true iff ref1 and ref2 have the same name
- * and the same sha1.  Die if they have the same name but different
- * sha1s.
+ * and the same oid. Die if they have the same name but different
+ * oids.
  */
 static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2)
 {
index b0f3e300c7fc494160cb846d22756f13abe4f10a..dd834314bd8d5af0315dab19af50f3300a73ad90 100644 (file)
@@ -8,58 +8,22 @@
  */
 
 /*
- * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken
- * refs (i.e., because the reference is about to be deleted anyway).
+ * The following flags can appear in `ref_update::flags`. Their
+ * numerical values must not conflict with those of REF_NO_DEREF and
+ * REF_FORCE_CREATE_REFLOG, which are also stored in
+ * `ref_update::flags`.
  */
-#define REF_DELETING   0x02
 
 /*
- * Used as a flag in ref_update::flags when a loose ref is being
- * pruned. This flag must only be used when REF_NODEREF is set.
+ * The reference should be updated to new_oid.
  */
-#define REF_ISPRUNING  0x04
+#define REF_HAVE_NEW (1 << 2)
 
 /*
- * Used as a flag in ref_update::flags when the reference should be
- * updated to new_sha1.
+ * The current reference's value should be checked to make sure that
+ * it agrees with old_oid.
  */
-#define REF_HAVE_NEW   0x08
-
-/*
- * Used as a flag in ref_update::flags when old_sha1 should be
- * checked.
- */
-#define REF_HAVE_OLD   0x10
-
-/*
- * Used as a flag in ref_update::flags when the lockfile needs to be
- * committed.
- */
-#define REF_NEEDS_COMMIT 0x20
-
-/*
- * 0x40 is REF_FORCE_CREATE_REFLOG, so skip it if you're adding a
- * value to ref_update::flags
- */
-
-/*
- * Used as a flag in ref_update::flags when we want to log a ref
- * update but not actually perform it.  This is used when a symbolic
- * ref update is split up.
- */
-#define REF_LOG_ONLY 0x80
-
-/*
- * Internal flag, meaning that the containing ref_update was via an
- * update to HEAD.
- */
-#define REF_UPDATE_VIA_HEAD 0x100
-
-/*
- * Used as a flag in ref_update::flags when the loose reference has
- * been deleted.
- */
-#define REF_DELETED_LOOSE 0x200
+#define REF_HAVE_OLD (1 << 3)
 
 /*
  * Return the length of time to retry acquiring a loose reference lock
@@ -122,7 +86,7 @@ enum peel_status {
  * tag recursively until a non-tag is found.  If successful, store the
  * result to oid and return PEEL_PEELED.  If the object is not a tag
  * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,
- * and leave sha1 unchanged.
+ * and leave oid unchanged.
  */
 enum peel_status peel_object(const struct object_id *name, struct object_id *oid);
 
@@ -134,30 +98,29 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid
 int copy_reflog_msg(char *buf, const char *msg);
 
 /**
- * Information needed for a single ref update. Set new_sha1 to the new
- * value or to null_sha1 to delete the ref. To check the old value
- * while the ref is locked, set (flags & REF_HAVE_OLD) and set
- * old_sha1 to the old value, or to null_sha1 to ensure the ref does
- * not exist before update.
+ * Information needed for a single ref update. Set new_oid to the new
+ * value or to null_oid to delete the ref. To check the old value
+ * while the ref is locked, set (flags & REF_HAVE_OLD) and set old_oid
+ * to the old value, or to null_oid to ensure the ref does not exist
+ * before update.
  */
 struct ref_update {
-
        /*
-        * If (flags & REF_HAVE_NEW), set the reference to this value:
+        * If (flags & REF_HAVE_NEW), set the reference to this value
+        * (or delete it, if `new_oid` is `null_oid`).
         */
        struct object_id new_oid;
 
        /*
         * If (flags & REF_HAVE_OLD), check that the reference
-        * previously had this value:
+        * previously had this value (or didn't previously exist, if
+        * `old_oid` is `null_oid`).
         */
        struct object_id old_oid;
 
        /*
-        * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,
-        * REF_DELETING, REF_ISPRUNING, REF_LOG_ONLY,
-        * REF_UPDATE_VIA_HEAD, REF_NEEDS_COMMIT, and
-        * REF_DELETED_LOOSE:
+        * One or more of REF_NO_DEREF, REF_FORCE_CREATE_REFLOG,
+        * REF_HAVE_NEW, REF_HAVE_OLD, or backend-specific flags.
         */
        unsigned int flags;
 
@@ -195,7 +158,7 @@ int ref_update_reject_duplicates(struct string_list *refnames,
 /*
  * Add a ref_update with the specified properties to transaction, and
  * return a pointer to the new object. This function does not verify
- * that refname is well-formed. new_sha1 and old_sha1 are only
+ * that refname is well-formed. new_oid and old_oid are only
  * dereferenced if the REF_HAVE_NEW and REF_HAVE_OLD bits,
  * respectively, are set in flags.
  */
index 99c95c19b0093094878bdae02a22944fd2aeff37..e2e691dd5a48087da0b476cf4d6cded645f23d6e 100644 (file)
@@ -419,7 +419,7 @@ static void file_add_remove(struct diff_options *options,
 
        tree_difference |= diff;
        if (!revs->remove_empty_trees || tree_difference != REV_TREE_NEW)
-               DIFF_OPT_SET(options, HAS_CHANGES);
+               options->flags.has_changes = 1;
 }
 
 static void file_change(struct diff_options *options,
@@ -431,7 +431,7 @@ static void file_change(struct diff_options *options,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule)
 {
        tree_difference = REV_TREE_DIFFERENT;
-       DIFF_OPT_SET(options, HAS_CHANGES);
+       options->flags.has_changes = 1;
 }
 
 static int rev_compare_tree(struct rev_info *revs,
@@ -464,7 +464,7 @@ static int rev_compare_tree(struct rev_info *revs,
        }
 
        tree_difference = REV_TREE_SAME;
-       DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
+       revs->pruning.flags.has_changes = 0;
        if (diff_tree_oid(&t1->object.oid, &t2->object.oid, "",
                           &revs->pruning) < 0)
                return REV_TREE_DIFFERENT;
@@ -480,7 +480,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
                return 0;
 
        tree_difference = REV_TREE_SAME;
-       DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
+       revs->pruning.flags.has_changes = 0;
        retval = diff_tree_oid(NULL, &t1->object.oid, "", &revs->pruning);
 
        return retval >= 0 && (tree_difference == REV_TREE_SAME);
@@ -1412,8 +1412,8 @@ void init_revisions(struct rev_info *revs, const char *prefix)
        revs->abbrev = DEFAULT_ABBREV;
        revs->ignore_merges = 1;
        revs->simplify_history = 1;
-       DIFF_OPT_SET(&revs->pruning, RECURSIVE);
-       DIFF_OPT_SET(&revs->pruning, QUICK);
+       revs->pruning.flags.recursive = 1;
+       revs->pruning.flags.quick = 1;
        revs->pruning.add_remove = file_add_remove;
        revs->pruning.change = file_change;
        revs->pruning.change_fn_data = revs;
@@ -1927,11 +1927,11 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                die("--unpacked=<packfile> no longer supported.");
        } else if (!strcmp(arg, "-r")) {
                revs->diff = 1;
-               DIFF_OPT_SET(&revs->diffopt, RECURSIVE);
+               revs->diffopt.flags.recursive = 1;
        } else if (!strcmp(arg, "-t")) {
                revs->diff = 1;
-               DIFF_OPT_SET(&revs->diffopt, RECURSIVE);
-               DIFF_OPT_SET(&revs->diffopt, TREE_IN_RECURSIVE);
+               revs->diffopt.flags.recursive = 1;
+               revs->diffopt.flags.tree_in_recursive = 1;
        } else if (!strcmp(arg, "-m")) {
                revs->ignore_merges = 0;
        } else if (!strcmp(arg, "-c")) {
@@ -2076,7 +2076,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_ERE;
        } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) {
                revs->grep_filter.ignore_case = 1;
-               DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE);
+               revs->diffopt.flags.pickaxe_ignore_case = 1;
        } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) {
                revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_FIXED;
        } else if (!strcmp(arg, "--perl-regexp") || !strcmp(arg, "-P")) {
@@ -2409,7 +2409,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        /* Pickaxe, diff-filter and rename following need diffs */
        if (revs->diffopt.pickaxe ||
            revs->diffopt.filter ||
-           DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
+           revs->diffopt.flags.follow_renames)
                revs->diff = 1;
 
        if (revs->topo_order)
@@ -2418,7 +2418,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        if (revs->prune_data.nr) {
                copy_pathspec(&revs->pruning.pathspec, &revs->prune_data);
                /* Can't prune commits with rename following: the paths change.. */
-               if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
+               if (!revs->diffopt.flags.follow_renames)
                        revs->prune = 1;
                if (!revs->full_diff)
                        copy_pathspec(&revs->diffopt.pathspec,
index 1eb2c4669d529485a045de66d6711039d19a2442..19dd575ed9b3b280a3fdabc9121a2e193d6984db 100644 (file)
@@ -959,7 +959,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
                unborn = get_oid("HEAD", &head);
                if (unborn)
                        oidcpy(&head, &empty_tree_oid);
-               if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0, 0))
+               if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD",
+                                      NULL, 0))
                        return error_dirty_index(opts);
        }
        discard_cache();
@@ -1116,11 +1117,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
         */
        if (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&
            update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
-                      REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
+                      REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
                res = -1;
        if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
            update_ref(NULL, "REVERT_HEAD", &commit->object.oid, NULL,
-                      REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
+                      REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
                res = -1;
 
        if (res) {
@@ -2129,7 +2130,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                        msg = reflog_message(opts, "finish", "%s onto %s",
                                head_ref.buf, buf.buf);
                        if (update_ref(msg, head_ref.buf, &head, &orig,
-                                      REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) {
+                                      REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
                                res = error(_("could not update %s"),
                                        head_ref.buf);
                                goto cleanup_head_ref;
@@ -2283,7 +2284,7 @@ int sequencer_continue(struct replay_opts *opts)
                        if (res)
                                goto release_todo_list;
                }
-               if (index_differs_from("HEAD", 0, 0)) {
+               if (index_differs_from("HEAD", NULL, 0)) {
                        res = error_dirty_index(opts);
                        goto release_todo_list;
                }
@@ -2669,6 +2670,19 @@ int check_todo_list(void)
        return res;
 }
 
+static int rewrite_file(const char *path, const char *buf, size_t len)
+{
+       int rc = 0;
+       int fd = open(path, O_WRONLY | O_TRUNC);
+       if (fd < 0)
+               return error_errno(_("could not open '%s' for writing"), path);
+       if (write_in_full(fd, buf, len) < 0)
+               rc = error_errno(_("could not write to '%s'"), path);
+       if (close(fd) && !rc)
+               rc = error_errno(_("could not close '%s'"), path);
+       return rc;
+}
+
 /* skip picking commits whose parents are unchanged */
 int skip_unnecessary_picks(void)
 {
@@ -2741,29 +2755,11 @@ int skip_unnecessary_picks(void)
                }
                close(fd);
 
-               fd = open(rebase_path_todo(), O_WRONLY, 0666);
-               if (fd < 0) {
-                       error_errno(_("could not open '%s' for writing"),
-                                   rebase_path_todo());
-                       todo_list_release(&todo_list);
-                       return -1;
-               }
-               if (write_in_full(fd, todo_list.buf.buf + offset,
-                               todo_list.buf.len - offset) < 0) {
-                       error_errno(_("could not write to '%s'"),
-                                   rebase_path_todo());
-                       close(fd);
-                       todo_list_release(&todo_list);
-                       return -1;
-               }
-               if (ftruncate(fd, todo_list.buf.len - offset) < 0) {
-                       error_errno(_("could not truncate '%s'"),
-                                   rebase_path_todo());
+               if (rewrite_file(rebase_path_todo(), todo_list.buf.buf + offset,
+                                todo_list.buf.len - offset) < 0) {
                        todo_list_release(&todo_list);
-                       close(fd);
                        return -1;
                }
-               close(fd);
 
                todo_list.current = i;
                if (is_fixup(peek_command(&todo_list, 0)))
@@ -2948,15 +2944,7 @@ int rearrange_squash(void)
                        }
                }
 
-               fd = open(todo_file, O_WRONLY);
-               if (fd < 0)
-                       res = error_errno(_("could not open '%s'"), todo_file);
-               else if (write(fd, buf.buf, buf.len) < 0)
-                       res = error_errno(_("could not write to '%s'"), todo_file);
-               else if (ftruncate(fd, buf.len) < 0)
-                       res = error_errno(_("could not truncate '%s'"),
-                                          todo_file);
-               close(fd);
+               res = rewrite_file(todo_file, buf.buf, buf.len);
                strbuf_release(&buf);
        }
 
diff --git a/setup.c b/setup.c
index 03f51e056cd6e672ecd80ba94348173b9d496cc0..94768512b7913c4e46b90fc8226c183cbd7239d7 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -312,7 +312,9 @@ int is_git_directory(const char *suspect)
        size_t len;
 
        /* Check worktree-related signatures */
-       strbuf_addf(&path, "%s/HEAD", suspect);
+       strbuf_addstr(&path, suspect);
+       strbuf_complete(&path, '/');
+       strbuf_addstr(&path, "HEAD");
        if (validate_headref(path.buf))
                goto done;
 
index d7de8184edba767f0ffced8e3bd29db92b4e68af..d7089813762513254b8fe48199a57ecdeb8600f3 100644 (file)
@@ -1881,6 +1881,7 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
        DIR *dir;
        struct dirent *de;
        int r = 0;
+       struct object_id oid;
 
        if (subdir_nr > 0xff)
                BUG("invalid loose object subdirectory: %x", subdir_nr);
@@ -1898,6 +1899,8 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
                return r;
        }
 
+       oid.hash[0] = subdir_nr;
+
        while ((de = readdir(dir))) {
                if (is_dot_or_dotdot(de->d_name))
                        continue;
@@ -1905,20 +1908,15 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
                strbuf_setlen(path, baselen);
                strbuf_addf(path, "/%s", de->d_name);
 
-               if (strlen(de->d_name) == GIT_SHA1_HEXSZ - 2)  {
-                       char hex[GIT_MAX_HEXSZ+1];
-                       struct object_id oid;
-
-                       xsnprintf(hex, sizeof(hex), "%02x%s",
-                                 subdir_nr, de->d_name);
-                       if (!get_oid_hex(hex, &oid)) {
-                               if (obj_cb) {
-                                       r = obj_cb(&oid, path->buf, data);
-                                       if (r)
-                                               break;
-                               }
-                               continue;
+               if (strlen(de->d_name) == GIT_SHA1_HEXSZ - 2 &&
+                   !hex_to_bytes(oid.hash + 1, de->d_name,
+                                 GIT_SHA1_RAWSZ - 1)) {
+                       if (obj_cb) {
+                               r = obj_cb(&oid, path->buf, data);
+                               if (r)
+                                       break;
                        }
+                       continue;
                }
 
                if (cruft_cb) {
index 239d94d5394a318d1a36c3300981e34427928dd7..3ee4a0caa7e2db70ec1ba61a2fe152b989e9a186 100644 (file)
@@ -183,7 +183,7 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
                if (ignore)
                        handle_ignore_submodules_arg(diffopt, ignore);
                else if (is_gitmodules_unmerged(&the_index))
-                       DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
+                       diffopt->flags.ignore_submodules = 1;
        }
 }
 
@@ -402,16 +402,16 @@ const char *submodule_strategy_to_string(const struct submodule_update_strategy
 void handle_ignore_submodules_arg(struct diff_options *diffopt,
                                  const char *arg)
 {
-       DIFF_OPT_CLR(diffopt, IGNORE_SUBMODULES);
-       DIFF_OPT_CLR(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
-       DIFF_OPT_CLR(diffopt, IGNORE_DIRTY_SUBMODULES);
+       diffopt->flags.ignore_submodules = 0;
+       diffopt->flags.ignore_untracked_in_submodules = 0;
+       diffopt->flags.ignore_dirty_submodules = 0;
 
        if (!strcmp(arg, "all"))
-               DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
+               diffopt->flags.ignore_submodules = 1;
        else if (!strcmp(arg, "untracked"))
-               DIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
+               diffopt->flags.ignore_untracked_in_submodules = 1;
        else if (!strcmp(arg, "dirty"))
-               DIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES);
+               diffopt->flags.ignore_dirty_submodules = 1;
        else if (strcmp(arg, "none"))
                die("bad --ignore-submodules argument: %s", arg);
 }
@@ -616,7 +616,7 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
        argv_array_pushf(&cp.args, "--color=%s", want_color(o->use_color) ?
                         "always" : "never");
 
-       if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+       if (o->flags.reverse_diff) {
                argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
                                 o->b_prefix, path);
                argv_array_pushf(&cp.args, "--dst-prefix=%s%s/",
index d8e41f7ddd155b9f2861f55ab97943fed28968e7..937b831ea675230c1e0fbe8ba7ebb3004de71b3b 100755 (executable)
@@ -44,6 +44,7 @@ helper_test_clean() {
        reject $1 https example.com user2
        reject $1 http path.tld user
        reject $1 https timeout.tld user
+       reject $1 https sso.tld
 }
 
 reject() {
@@ -250,6 +251,24 @@ helper_test() {
                password=pass2
                EOF
        '
+
+       test_expect_success "helper ($HELPER) can store empty username" '
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=sso.tld
+               username=
+               password=
+               EOF
+               check fill $HELPER <<-\EOF
+               protocol=https
+               host=sso.tld
+               --
+               protocol=https
+               host=sso.tld
+               username=
+               password=
+               EOF
+       '
 }
 
 helper_test_timeout() {
index 86c1a51654fa6c1b049a313fe8d880c6a266ee62..c413bff9cf1f3a79ef494b39844c42d3a8c877f1 100755 (executable)
@@ -453,4 +453,16 @@ test_expect_success 're-init from a linked worktree' '
        )
 '
 
+test_expect_success MINGW 'redirect std handles' '
+       GIT_REDIRECT_STDOUT=output.txt git rev-parse --git-dir &&
+       test .git = "$(cat output.txt)" &&
+       test -z "$(GIT_REDIRECT_STDOUT=off git rev-parse --git-dir)" &&
+       test_must_fail env \
+               GIT_REDIRECT_STDOUT=output.txt \
+               GIT_REDIRECT_STDERR="2>&1" \
+               git rev-parse --git-dir --verify refs/invalid &&
+       printf ".git\nfatal: Needed a single revision\n" >expect &&
+       test_cmp expect output.txt
+'
+
 test_done
index ad685d92f8c7aa138cb29b0ef46e5d09e246f42c..6fd7fa476be2a091f683174d57100cbc7ba19fb8 100644 (file)
 #     to the "list_available_blobs" response.
 #
 
+use 5.008;
+use lib (split(/:/, $ENV{GITPERLLIB}));
 use strict;
 use warnings;
 use IO::File;
+use Git::Packet;
 
 my $MAX_PACKET_CONTENT_SIZE = 65516;
 my $log_file                = shift @ARGV;
@@ -55,89 +58,30 @@ sub rot13 {
        return $str;
 }
 
-sub packet_bin_read {
-       my $buffer;
-       my $bytes_read = read STDIN, $buffer, 4;
-       if ( $bytes_read == 0 ) {
-               # EOF - Git stopped talking to us!
-               print $debug "STOP\n";
-               exit();
-       }
-       elsif ( $bytes_read != 4 ) {
-               die "invalid packet: '$buffer'";
-       }
-       my $pkt_size = hex($buffer);
-       if ( $pkt_size == 0 ) {
-               return ( 1, "" );
-       }
-       elsif ( $pkt_size > 4 ) {
-               my $content_size = $pkt_size - 4;
-               $bytes_read = read STDIN, $buffer, $content_size;
-               if ( $bytes_read != $content_size ) {
-                       die "invalid packet ($content_size bytes expected; $bytes_read bytes read)";
-               }
-               return ( 0, $buffer );
-       }
-       else {
-               die "invalid packet size: $pkt_size";
-       }
-}
-
-sub packet_txt_read {
-       my ( $res, $buf ) = packet_bin_read();
-       unless ( $buf eq '' or $buf =~ s/\n$// ) {
-               die "A non-binary line MUST be terminated by an LF.";
-       }
-       return ( $res, $buf );
-}
-
-sub packet_bin_write {
-       my $buf = shift;
-       print STDOUT sprintf( "%04x", length($buf) + 4 );
-       print STDOUT $buf;
-       STDOUT->flush();
-}
-
-sub packet_txt_write {
-       packet_bin_write( $_[0] . "\n" );
-}
-
-sub packet_flush {
-       print STDOUT sprintf( "%04x", 0 );
-       STDOUT->flush();
-}
-
 print $debug "START\n";
 $debug->flush();
 
-( packet_txt_read() eq ( 0, "git-filter-client" ) ) || die "bad initialize";
-( packet_txt_read() eq ( 0, "version=2" ) )         || die "bad version";
-( packet_bin_read() eq ( 1, "" ) )                  || die "bad version end";
+packet_initialize("git-filter", 2);
 
-packet_txt_write("git-filter-server");
-packet_txt_write("version=2");
-packet_flush();
+my %remote_caps = packet_read_and_check_capabilities("clean", "smudge", "delay");
+packet_check_and_write_capabilities(\%remote_caps, @capabilities);
 
-( packet_txt_read() eq ( 0, "capability=clean" ) )  || die "bad capability";
-( packet_txt_read() eq ( 0, "capability=smudge" ) ) || die "bad capability";
-( packet_txt_read() eq ( 0, "capability=delay" ) )  || die "bad capability";
-( packet_bin_read() eq ( 1, "" ) )                  || die "bad capability end";
-
-foreach (@capabilities) {
-       packet_txt_write( "capability=" . $_ );
-}
-packet_flush();
 print $debug "init handshake complete\n";
 $debug->flush();
 
 while (1) {
-       my ( $command ) = packet_txt_read() =~ /^command=(.+)$/;
+       my ( $res, $command ) = packet_required_key_val_read("command");
+       if ( $res == -1 ) {
+               print $debug "STOP\n";
+               exit();
+       }
        print $debug "IN: $command";
        $debug->flush();
 
        if ( $command eq "list_available_blobs" ) {
                # Flush
-               packet_bin_read();
+               packet_compare_lists([1, ""], packet_bin_read()) ||
+                       die "bad list_available_blobs end";
 
                foreach my $pathname ( sort keys %DELAY ) {
                        if ( $DELAY{$pathname}{"requested"} >= 1 ) {
@@ -161,16 +105,14 @@ sub packet_flush {
                $debug->flush();
                packet_txt_write("status=success");
                packet_flush();
-       }
-       else {
-               my ( $pathname ) = packet_txt_read() =~ /^pathname=(.+)$/;
+       } else {
+               my ( $res, $pathname ) = packet_required_key_val_read("pathname");
+               if ( $res == -1 ) {
+                       die "unexpected EOF while expecting pathname";
+               }
                print $debug " $pathname";
                $debug->flush();
 
-               if ( $pathname eq "" ) {
-                       die "bad pathname '$pathname'";
-               }
-
                # Read until flush
                my ( $done, $buffer ) = packet_txt_read();
                while ( $buffer ne '' ) {
@@ -184,6 +126,9 @@ sub packet_flush {
 
                        ( $done, $buffer ) = packet_txt_read();
                }
+               if ( $done == -1 ) {
+                       die "unexpected EOF after pathname '$pathname'";
+               }
 
                my $input = "";
                {
@@ -194,6 +139,9 @@ sub packet_flush {
                                ( $done, $buffer ) = packet_bin_read();
                                $input .= $buffer;
                        }
+                       if ( $done == -1 ) {
+                               die "unexpected EOF while reading input for '$pathname'";
+                       }                       
                        print $debug " " . length($input) . " [OK] -- ";
                        $debug->flush();
                }
@@ -201,17 +149,13 @@ sub packet_flush {
                my $output;
                if ( exists $DELAY{$pathname} and exists $DELAY{$pathname}{"output"} ) {
                        $output = $DELAY{$pathname}{"output"}
-               }
-               elsif ( $pathname eq "error.r" or $pathname eq "abort.r" ) {
+               } elsif ( $pathname eq "error.r" or $pathname eq "abort.r" ) {
                        $output = "";
-               }
-               elsif ( $command eq "clean" and grep( /^clean$/, @capabilities ) ) {
+               } elsif ( $command eq "clean" and grep( /^clean$/, @capabilities ) ) {
                        $output = rot13($input);
-               }
-               elsif ( $command eq "smudge" and grep( /^smudge$/, @capabilities ) ) {
+               } elsif ( $command eq "smudge" and grep( /^smudge$/, @capabilities ) ) {
                        $output = rot13($input);
-               }
-               else {
+               } else {
                        die "bad command '$command'";
                }
 
@@ -220,25 +164,21 @@ sub packet_flush {
                        $debug->flush();
                        packet_txt_write("status=error");
                        packet_flush();
-               }
-               elsif ( $pathname eq "abort.r" ) {
+               } elsif ( $pathname eq "abort.r" ) {
                        print $debug "[ABORT]\n";
                        $debug->flush();
                        packet_txt_write("status=abort");
                        packet_flush();
-               }
-               elsif ( $command eq "smudge" and
+               } elsif ( $command eq "smudge" and
                        exists $DELAY{$pathname} and
-                       $DELAY{$pathname}{"requested"} == 1
-               ) {
+                       $DELAY{$pathname}{"requested"} == 1 ) {
                        print $debug "[DELAYED]\n";
                        $debug->flush();
                        packet_txt_write("status=delayed");
                        packet_flush();
                        $DELAY{$pathname}{"requested"} = 2;
                        $DELAY{$pathname}{"output"} = $output;
-               }
-               else {
+               } else {
                        packet_txt_write("status=success");
                        packet_flush();
 
@@ -258,8 +198,7 @@ sub packet_flush {
                                print $debug ".";
                                if ( length($output) > $MAX_PACKET_CONTENT_SIZE ) {
                                        $output = substr( $output, $MAX_PACKET_CONTENT_SIZE );
-                               }
-                               else {
+                               } else {
                                        $output = "";
                                }
                        }
diff --git a/t/t1409-avoid-packing-refs.sh b/t/t1409-avoid-packing-refs.sh
new file mode 100755 (executable)
index 0000000..e5cb8a2
--- /dev/null
@@ -0,0 +1,118 @@
+#!/bin/sh
+
+test_description='avoid rewriting packed-refs unnecessarily'
+
+. ./test-lib.sh
+
+# Add an identifying mark to the packed-refs file header line. This
+# shouldn't upset readers, and it should be omitted if the file is
+# ever rewritten.
+mark_packed_refs () {
+       sed -e "s/^\(#.*\)/\1 t1409 /" <.git/packed-refs >.git/packed-refs.new &&
+       mv .git/packed-refs.new .git/packed-refs
+}
+
+# Verify that the packed-refs file is still marked.
+check_packed_refs_marked () {
+       grep -q '^#.* t1409 ' .git/packed-refs
+}
+
+test_expect_success 'setup' '
+       git commit --allow-empty -m "Commit A" &&
+       A=$(git rev-parse HEAD) &&
+       git commit --allow-empty -m "Commit B" &&
+       B=$(git rev-parse HEAD) &&
+       git commit --allow-empty -m "Commit C" &&
+       C=$(git rev-parse HEAD)
+'
+
+test_expect_success 'do not create packed-refs file gratuitously' '
+       test_must_fail test -f .git/packed-refs &&
+       git update-ref refs/heads/foo $A &&
+       test_must_fail test -f .git/packed-refs &&
+       git update-ref refs/heads/foo $B &&
+       test_must_fail test -f .git/packed-refs &&
+       git update-ref refs/heads/foo $C $B &&
+       test_must_fail test -f .git/packed-refs &&
+       git update-ref -d refs/heads/foo &&
+       test_must_fail test -f .git/packed-refs
+'
+
+test_expect_success 'check that marking the packed-refs file works' '
+       git for-each-ref >expected &&
+       git pack-refs --all &&
+       mark_packed_refs &&
+       check_packed_refs_marked &&
+       git for-each-ref >actual &&
+       test_cmp expected actual &&
+       git pack-refs --all &&
+       test_must_fail check_packed_refs_marked &&
+       git for-each-ref >actual2 &&
+       test_cmp expected actual2
+'
+
+test_expect_success 'leave packed-refs untouched on update of packed' '
+       git update-ref refs/heads/packed-update $A &&
+       git pack-refs --all &&
+       mark_packed_refs &&
+       git update-ref refs/heads/packed-update $B &&
+       check_packed_refs_marked
+'
+
+test_expect_success 'leave packed-refs untouched on checked update of packed' '
+       git update-ref refs/heads/packed-checked-update $A &&
+       git pack-refs --all &&
+       mark_packed_refs &&
+       git update-ref refs/heads/packed-checked-update $B $A &&
+       check_packed_refs_marked
+'
+
+test_expect_success 'leave packed-refs untouched on verify of packed' '
+       git update-ref refs/heads/packed-verify $A &&
+       git pack-refs --all &&
+       mark_packed_refs &&
+       echo "verify refs/heads/packed-verify $A" | git update-ref --stdin &&
+       check_packed_refs_marked
+'
+
+test_expect_success 'touch packed-refs on delete of packed' '
+       git update-ref refs/heads/packed-delete $A &&
+       git pack-refs --all &&
+       mark_packed_refs &&
+       git update-ref -d refs/heads/packed-delete &&
+       test_must_fail check_packed_refs_marked
+'
+
+test_expect_success 'leave packed-refs untouched on update of loose' '
+       git pack-refs --all &&
+       git update-ref refs/heads/loose-update $A &&
+       mark_packed_refs &&
+       git update-ref refs/heads/loose-update $B &&
+       check_packed_refs_marked
+'
+
+test_expect_success 'leave packed-refs untouched on checked update of loose' '
+       git pack-refs --all &&
+       git update-ref refs/heads/loose-checked-update $A &&
+       mark_packed_refs &&
+       git update-ref refs/heads/loose-checked-update $B $A &&
+       check_packed_refs_marked
+'
+
+test_expect_success 'leave packed-refs untouched on verify of loose' '
+       git pack-refs --all &&
+       git update-ref refs/heads/loose-verify $A &&
+       mark_packed_refs &&
+       echo "verify refs/heads/loose-verify $A" | git update-ref --stdin &&
+       check_packed_refs_marked
+'
+
+test_expect_success 'leave packed-refs untouched on delete of loose' '
+       git pack-refs --all &&
+       git update-ref refs/heads/loose-delete $A &&
+       mark_packed_refs &&
+       git update-ref -d refs/heads/loose-delete &&
+       check_packed_refs_marked
+'
+
+test_done
index ebf4f5e4b2c1c1cc20a49888df14cedd14b49a8b..a2bba04ba96cb5e16dfbecf3f0d6180e150a7ec0 100755 (executable)
@@ -40,4 +40,21 @@ git_rebase_interactive () {
 
 test_submodule_switch "git_rebase_interactive"
 
+test_expect_success 'rebase interactive ignores modified submodules' '
+       test_when_finished "rm -rf super sub" &&
+       git init sub &&
+       git -C sub commit --allow-empty -m "Initial commit" &&
+       git init super &&
+       git -C super submodule add ../sub &&
+       git -C super config submodule.sub.ignore dirty &&
+       >super/foo &&
+       git -C super add foo &&
+       git -C super commit -m "Initial commit" &&
+       test_commit -C super a &&
+       test_commit -C super b &&
+       test_commit -C super/sub c &&
+       set_fake_editor &&
+       git -C super rebase -i HEAD^^
+'
+
 test_done
index 81c6059a2d9fe4d23e3fac11d765ecaf20aef756..46f15169f55c03742717f36f8d0e99241391b2ea 100755 (executable)
@@ -688,7 +688,7 @@ test_expect_success 'checking out a commit after submodule removal needs manual
        git submodule update &&
        git checkout -q HEAD^ &&
        git checkout -q master 2>actual &&
-       test_i18ngrep "^warning: unable to rmdir submod:" actual &&
+       test_i18ngrep "^warning: unable to rmdir '\''submod'\'':" actual &&
        git status -s submod >actual &&
        echo "?? submod/" >expected &&
        test_cmp expected actual &&
index b322c2f72202fbfda5c74f8d085744dd29c55fb3..ba548df4a918243ee1b2bcedab525e6ec7eff7d6 100755 (executable)
@@ -3,12 +3,18 @@
 test_description='various Windows-only path tests'
 . ./test-lib.sh
 
-if ! test_have_prereq MINGW; then
+if test_have_prereq CYGWIN
+then
+       alias winpwd='cygpath -aw .'
+elif test_have_prereq MINGW
+then
+       alias winpwd=pwd
+else
        skip_all='skipping Windows-only path tests'
        test_done
 fi
 
-UNCPATH="$(pwd)"
+UNCPATH="$(winpwd)"
 case "$UNCPATH" in
 [A-Z]:*)
        # Use administrative share e.g. \\localhost\C$\git-sdk-64\usr\src\git
@@ -45,8 +51,8 @@ test_expect_success push '
        test "$rev" = "$(git rev-parse --verify refs/heads/to-push)"
 '
 
-test_expect_success 'remote nick cannot contain backslashes' '
-       BACKSLASHED="$(pwd | tr / \\\\)" &&
+test_expect_success MINGW 'remote nick cannot contain backslashes' '
+       BACKSLASHED="$(winpwd | tr / \\\\)" &&
        git ls-remote "$BACKSLASHED" >out 2>err &&
        test_i18ngrep ! "unable to access" err
 '
index f5929c46f3ea7ed6317a77086d6263ac25a4f02b..6e5031f56fb4f211e0ba43911d4495b1bb0b5b62 100755 (executable)
@@ -452,7 +452,7 @@ test_expect_success 'checking out a commit before submodule moved needs manual u
        git mv sub sub2 &&
        git commit -m "moved sub to sub2" &&
        git checkout -q HEAD^ 2>actual &&
-       test_i18ngrep "^warning: unable to rmdir sub2:" actual &&
+       test_i18ngrep "^warning: unable to rmdir '\''sub2'\'':" actual &&
        git status -s sub2 >actual &&
        echo "?? sub2/" >expected &&
        test_cmp expected actual &&
diff --git a/t/t7521-ignored-mode.sh b/t/t7521-ignored-mode.sh
new file mode 100755 (executable)
index 0000000..9179094
--- /dev/null
@@ -0,0 +1,233 @@
+#!/bin/sh
+
+test_description='git status ignored modes'
+
+. ./test-lib.sh
+
+test_expect_success 'setup initial commit and ignore file' '
+       cat >.gitignore <<-\EOF &&
+       *.ign
+       ignored_dir/
+       !*.unignore
+       EOF
+       git add . &&
+       git commit -m "Initial commit"
+'
+
+test_expect_success 'Verify behavior of status on directories with ignored files' '
+       test_when_finished "git clean -fdx" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ! dir/ignored/ignored_1.ign
+       ! dir/ignored/ignored_2.ign
+       ! ignored/ignored_1.ign
+       ! ignored/ignored_2.ign
+       EOF
+
+       mkdir -p ignored dir/ignored &&
+       touch ignored/ignored_1.ign ignored/ignored_2.ign \
+               dir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&
+
+       git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify status behavior on directory with tracked & ignored files' '
+       test_when_finished "git clean -fdx && git reset HEAD~1 --hard" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ! dir/tracked_ignored/ignored_1.ign
+       ! dir/tracked_ignored/ignored_2.ign
+       ! tracked_ignored/ignored_1.ign
+       ! tracked_ignored/ignored_2.ign
+       EOF
+
+       mkdir -p tracked_ignored dir/tracked_ignored &&
+       touch tracked_ignored/tracked_1 tracked_ignored/tracked_2 \
+               tracked_ignored/ignored_1.ign tracked_ignored/ignored_2.ign \
+               dir/tracked_ignored/tracked_1 dir/tracked_ignored/tracked_2 \
+               dir/tracked_ignored/ignored_1.ign dir/tracked_ignored/ignored_2.ign &&
+
+       git add tracked_ignored/tracked_1 tracked_ignored/tracked_2 \
+               dir/tracked_ignored/tracked_1 dir/tracked_ignored/tracked_2 &&
+       git commit -m "commit tracked files" &&
+
+       git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify status behavior on directory with untracked and ignored files' '
+       test_when_finished "git clean -fdx" &&
+       cat >expect <<-\EOF &&
+       ? dir/untracked_ignored/untracked_1
+       ? dir/untracked_ignored/untracked_2
+       ? expect
+       ? output
+       ? untracked_ignored/untracked_1
+       ? untracked_ignored/untracked_2
+       ! dir/untracked_ignored/ignored_1.ign
+       ! dir/untracked_ignored/ignored_2.ign
+       ! untracked_ignored/ignored_1.ign
+       ! untracked_ignored/ignored_2.ign
+       EOF
+
+       mkdir -p untracked_ignored dir/untracked_ignored &&
+       touch untracked_ignored/untracked_1 untracked_ignored/untracked_2 \
+               untracked_ignored/ignored_1.ign untracked_ignored/ignored_2.ign \
+               dir/untracked_ignored/untracked_1 dir/untracked_ignored/untracked_2 \
+               dir/untracked_ignored/ignored_1.ign dir/untracked_ignored/ignored_2.ign &&
+
+       git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify status matching ignored files on ignored directory' '
+       test_when_finished "git clean -fdx" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ! ignored_dir/
+       EOF
+
+       mkdir ignored_dir &&
+       touch ignored_dir/ignored_1 ignored_dir/ignored_2 \
+               ignored_dir/ignored_1.ign ignored_dir/ignored_2.ign &&
+
+       git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify status behavior on ignored directory containing tracked file' '
+       test_when_finished "git clean -fdx && git reset HEAD~1 --hard" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ! ignored_dir/ignored_1
+       ! ignored_dir/ignored_1.ign
+       ! ignored_dir/ignored_2
+       ! ignored_dir/ignored_2.ign
+       EOF
+
+       mkdir ignored_dir &&
+       touch ignored_dir/ignored_1 ignored_dir/ignored_2 \
+               ignored_dir/ignored_1.ign ignored_dir/ignored_2.ign \
+               ignored_dir/tracked &&
+       git add -f ignored_dir/tracked &&
+       git commit -m "Force add file in ignored directory" &&
+       git status --porcelain=v2 --ignored=matching --untracked-files=all >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify matching ignored files with --untracked-files=normal' '
+       test_when_finished "git clean -fdx" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ? untracked_dir/
+       ! ignored_dir/
+       ! ignored_files/ignored_1.ign
+       ! ignored_files/ignored_2.ign
+       EOF
+
+       mkdir ignored_dir ignored_files untracked_dir &&
+       touch ignored_dir/ignored_1 ignored_dir/ignored_2 \
+               ignored_files/ignored_1.ign ignored_files/ignored_2.ign \
+               untracked_dir/untracked &&
+       git status --porcelain=v2 --ignored=matching --untracked-files=normal >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify matching ignored files with --untracked-files=normal' '
+       test_when_finished "git clean -fdx" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ? untracked_dir/
+       ! ignored_dir/
+       ! ignored_files/ignored_1.ign
+       ! ignored_files/ignored_2.ign
+       EOF
+
+       mkdir ignored_dir ignored_files untracked_dir &&
+       touch ignored_dir/ignored_1 ignored_dir/ignored_2 \
+               ignored_files/ignored_1.ign ignored_files/ignored_2.ign \
+               untracked_dir/untracked &&
+       git status --porcelain=v2 --ignored=matching --untracked-files=normal >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify status behavior on ignored directory containing tracked file' '
+       test_when_finished "git clean -fdx && git reset HEAD~1 --hard" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ! ignored_dir/ignored_1
+       ! ignored_dir/ignored_1.ign
+       ! ignored_dir/ignored_2
+       ! ignored_dir/ignored_2.ign
+       EOF
+
+       mkdir ignored_dir &&
+       touch ignored_dir/ignored_1 ignored_dir/ignored_2 \
+               ignored_dir/ignored_1.ign ignored_dir/ignored_2.ign \
+               ignored_dir/tracked &&
+       git add -f ignored_dir/tracked &&
+       git commit -m "Force add file in ignored directory" &&
+       git status --porcelain=v2 --ignored=matching --untracked-files=normal >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify behavior of status with --ignored=no' '
+       test_when_finished "git clean -fdx" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       EOF
+
+       mkdir -p ignored dir/ignored &&
+       touch ignored/ignored_1.ign ignored/ignored_2.ign \
+               dir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&
+
+       git status --porcelain=v2 --ignored=no --untracked-files=all >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify behavior of status with --ignored=traditional and --untracked-files=all' '
+       test_when_finished "git clean -fdx" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ! dir/ignored/ignored_1.ign
+       ! dir/ignored/ignored_2.ign
+       ! ignored/ignored_1.ign
+       ! ignored/ignored_2.ign
+       EOF
+
+       mkdir -p ignored dir/ignored &&
+       touch ignored/ignored_1.ign ignored/ignored_2.ign \
+               dir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&
+
+       git status --porcelain=v2 --ignored=traditional --untracked-files=all >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'Verify behavior of status with --ignored=traditional and --untracked-files=normal' '
+       test_when_finished "git clean -fdx" &&
+       cat >expect <<-\EOF &&
+       ? expect
+       ? output
+       ! dir/
+       ! ignored/
+       EOF
+
+       mkdir -p ignored dir/ignored &&
+       touch ignored/ignored_1.ign ignored/ignored_2.ign \
+               dir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&
+
+       git status --porcelain=v2 --ignored=traditional --untracked-files=normal >output &&
+       test_i18ncmp expect output
+'
+
+test_done
index 4bb93155bc6e0349156b21ad1287d573593a79d5..fe2e466ac1dcb164b214ce4856ed9d62884ddbd3 100644 (file)
@@ -212,9 +212,9 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
                mode = 0;
        }
 
-       if (DIFF_OPT_TST(opt, RECURSIVE) && isdir) {
+       if (opt->flags.recursive && isdir) {
                recurse = 1;
-               emitthis = DIFF_OPT_TST(opt, TREE_IN_RECURSIVE);
+               emitthis = opt->flags.tree_in_recursive;
        }
 
        if (emitthis) {
@@ -425,7 +425,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
        ttree = fill_tree_descriptor(&t, oid);
 
        /* Enable recursion indefinitely */
-       opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
+       opt->pathspec.recursive = opt->flags.recursive;
 
        for (;;) {
                int imin, cmp;
@@ -484,7 +484,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
                /* t = p[imin] */
                if (cmp == 0) {
                        /* are either pi > p[imin] or diff(t,pi) != ø ? */
-                       if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER)) {
+                       if (!opt->flags.find_copies_harder) {
                                for (i = 0; i < nparent; ++i) {
                                        /* p[i] > p[imin] */
                                        if (tp[i].entry.mode & S_IFXMIN_NEQ)
@@ -522,7 +522,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
                /* t > p[imin] */
                else {
                        /* ∀i pi=p[imin] -> D += "-p[imin]" */
-                       if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER)) {
+                       if (!opt->flags.find_copies_harder) {
                                for (i = 0; i < nparent; ++i)
                                        if (tp[i].entry.mode & S_IFXMIN_NEQ)
                                                goto skip_emit_tp;
@@ -608,8 +608,8 @@ static void try_to_follow_renames(const struct object_id *old_oid,
        q->nr = 0;
 
        diff_setup(&diff_opts);
-       DIFF_OPT_SET(&diff_opts, RECURSIVE);
-       DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
+       diff_opts.flags.recursive = 1;
+       diff_opts.flags.find_copies_harder = 1;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = opt->pathspec.items[0].match;
        diff_opts.break_opt = opt->break_opt;
@@ -706,7 +706,7 @@ int diff_tree_oid(const struct object_id *old_oid,
        strbuf_addstr(&base, base_str);
 
        retval = ll_diff_tree_oid(old_oid, new_oid, &base, opt);
-       if (!*base_str && DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename())
+       if (!*base_str && opt->flags.follow_renames && diff_might_be_rename())
                try_to_follow_renames(old_oid, new_oid, &base, opt);
 
        strbuf_release(&base);
index 61aba0b5c1bece4aad04bee649accae990a8ce18..d20356a776bc63d4a94e4b421582433fb915087a 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -569,7 +569,7 @@ static int warn_if_unremovable(const char *op, const char *file, int rc)
        if (!rc || errno == ENOENT)
                return 0;
        err = errno;
-       warning_errno("unable to %s %s", op, file);
+       warning_errno("unable to %s '%s'", op, file);
        errno = err;
        return rc;
 }
@@ -583,7 +583,7 @@ int unlink_or_msg(const char *file, struct strbuf *err)
        if (!rc || errno == ENOENT)
                return 0;
 
-       strbuf_addf(err, "unable to unlink %s: %s",
+       strbuf_addf(err, "unable to unlink '%s': %s",
                    file, strerror(errno));
        return -1;
 }
@@ -653,9 +653,9 @@ void write_file_buf(const char *path, const char *buf, size_t len)
 {
        int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (write_in_full(fd, buf, len) < 0)
-               die_errno(_("could not write to %s"), path);
+               die_errno(_("could not write to '%s'"), path);
        if (close(fd))
-               die_errno(_("could not close %s"), path);
+               die_errno(_("could not close '%s'"), path);
 }
 
 void write_file(const char *path, const char *fmt, ...)
index bedef256ce1aa3a51b0bb06de47ca7729a9ea3e3..ef26f0744632fdcca919e68ffc58bf414b29e597 100644 (file)
@@ -559,12 +559,12 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
        init_revisions(&rev, NULL);
        setup_revisions(0, NULL, &rev, NULL);
        rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
-       DIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES);
+       rev.diffopt.flags.dirty_submodules = 1;
        rev.diffopt.ita_invisible_in_index = 1;
        if (!s->show_untracked_files)
-               DIFF_OPT_SET(&rev.diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
+               rev.diffopt.flags.ignore_untracked_in_submodules = 1;
        if (s->ignore_submodule_arg) {
-               DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
+               rev.diffopt.flags.override_submodule_config = 1;
                handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);
        }
        rev.diffopt.format_callback = wt_status_collect_changed_cb;
@@ -583,7 +583,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)
        opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference;
        setup_revisions(0, NULL, &rev, &opt);
 
-       DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
+       rev.diffopt.flags.override_submodule_config = 1;
        rev.diffopt.ita_invisible_in_index = 1;
        if (s->ignore_submodule_arg) {
                handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);
@@ -658,10 +658,15 @@ static void wt_status_collect_untracked(struct wt_status *s)
        if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
                dir.flags |=
                        DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
-       if (s->show_ignored_files)
+       if (s->show_ignored_mode) {
                dir.flags |= DIR_SHOW_IGNORED_TOO;
-       else
+
+               if (s->show_ignored_mode == SHOW_MATCHING_IGNORED)
+                       dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
+       } else {
                dir.untracked = the_index.untracked;
+       }
+
        setup_standard_excludes(&dir);
 
        fill_directory(&dir, &the_index, &s->pathspec);
@@ -949,7 +954,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
        const char *c = color(WT_STATUS_HEADER, s);
 
        init_revisions(&rev, NULL);
-       DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
+       rev.diffopt.flags.allow_textconv = 1;
        rev.diffopt.ita_invisible_in_index = 1;
 
        memset(&opt, 0, sizeof(opt));
@@ -1619,7 +1624,7 @@ static void wt_longstatus_print(struct wt_status *s)
        }
        if (s->show_untracked_files) {
                wt_longstatus_print_other(s, &s->untracked, _("Untracked files"), "add");
-               if (s->show_ignored_files)
+               if (s->show_ignored_mode)
                        wt_longstatus_print_other(s, &s->ignored, _("Ignored files"), "add -f");
                if (advice_status_u_option && 2000 < s->untracked_in_ms) {
                        status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
@@ -2262,9 +2267,11 @@ int has_unstaged_changes(int ignore_submodules)
        int result;
 
        init_revisions(&rev_info, NULL);
-       if (ignore_submodules)
-               DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
-       DIFF_OPT_SET(&rev_info.diffopt, QUICK);
+       if (ignore_submodules) {
+               rev_info.diffopt.flags.ignore_submodules = 1;
+               rev_info.diffopt.flags.override_submodule_config = 1;
+       }
+       rev_info.diffopt.flags.quick = 1;
        diff_setup_done(&rev_info.diffopt);
        result = run_diff_files(&rev_info, 0);
        return diff_result_code(&rev_info.diffopt, result);
@@ -2283,8 +2290,8 @@ int has_uncommitted_changes(int ignore_submodules)
 
        init_revisions(&rev_info, NULL);
        if (ignore_submodules)
-               DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
-       DIFF_OPT_SET(&rev_info.diffopt, QUICK);
+               rev_info.diffopt.flags.ignore_submodules = 1;
+       rev_info.diffopt.flags.quick = 1;
        add_head_to_pending(&rev_info);
        diff_setup_done(&rev_info.diffopt);
        result = run_diff_index(&rev_info, 1);
index 64f4d33ea183c1a6e700f1f6667b83f0e904773e..fe27b465e220bb720dfd0b4d52ddeae74a942707 100644 (file)
@@ -27,6 +27,12 @@ enum untracked_status_type {
        SHOW_ALL_UNTRACKED_FILES
 };
 
+enum show_ignored_type {
+       SHOW_NO_IGNORED,
+       SHOW_TRADITIONAL_IGNORED,
+       SHOW_MATCHING_IGNORED,
+};
+
 /* from where does this commit originate */
 enum commit_whence {
        FROM_COMMIT,     /* normal */
@@ -70,7 +76,7 @@ struct wt_status {
        int display_comment_prefix;
        int relative_paths;
        int submodule_summary;
-       int show_ignored_files;
+       enum show_ignored_type show_ignored_mode;
        enum untracked_status_type show_untracked_files;
        const char *ignore_submodule_arg;
        char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];