]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'js/diff-cached-fsmonitor-fix'
authorJunio C Hamano <gitster@pobox.com>
Wed, 20 Sep 2023 17:44:57 +0000 (10:44 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 20 Sep 2023 17:44:57 +0000 (10:44 -0700)
"git diff --cached" codepath did not fill the necessary stat
information for a file when fsmonitor knows it is clean and ended
up behaving as if it is not clean, which has been corrected.

* js/diff-cached-fsmonitor-fix:
  diff-lib: fix check_removed when fsmonitor is on

1  2 
diff-lib.c
t/t7527-builtin-fsmonitor.sh

diff --combined diff-lib.c
index d8aa777a7378de1a9f4f8842f29431e84a3f4f5e,083e18dc9d071a3ab26b1a4a3ad67bb6d7438dcb..5848e4f9ca294052b0e06c7e4d038ebd462ade92
@@@ -1,24 -1,16 +1,24 @@@
  /*
   * Copyright (C) 2005 Junio C Hamano
   */
 -#include "cache.h"
 +#include "git-compat-util.h"
  #include "quote.h"
  #include "commit.h"
  #include "diff.h"
  #include "diffcore.h"
 +#include "gettext.h"
 +#include "hash.h"
 +#include "hex.h"
 +#include "object-name.h"
 +#include "read-cache.h"
  #include "revision.h"
  #include "cache-tree.h"
  #include "unpack-trees.h"
  #include "refs.h"
 +#include "repository.h"
  #include "submodule.h"
 +#include "symlinks.h"
 +#include "trace.h"
  #include "dir.h"
  #include "fsmonitor.h"
  #include "commit-reach.h"
   * exists for ce that is a submodule -- it is a submodule that is not
   * checked out).  Return negative for an error.
   */
- static int check_removed(const struct index_state *istate, const struct cache_entry *ce, struct stat *st)
+ static int check_removed(const struct cache_entry *ce, struct stat *st)
  {
-       assert(is_fsmonitor_refreshed(istate));
-       if (!(ce->ce_flags & CE_FSMONITOR_VALID) && lstat(ce->name, st) < 0) {
+       if (lstat(ce->name, st) < 0) {
                if (!is_missing_file_error(errno))
                        return -1;
                return 1;
        }
        if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
                return 1;
        if (S_ISDIR(st->st_mode)) {
@@@ -96,7 -88,7 +96,7 @@@ static int match_stat_with_submodule(st
        return changed;
  }
  
 -int run_diff_files(struct rev_info *revs, unsigned int option)
 +void run_diff_files(struct rev_info *revs, unsigned int option)
  {
        int entries, i;
        int diff_unmerged_stage = revs->max_count;
                        memset(&(dpath->parent[0]), 0,
                               sizeof(struct combine_diff_parent)*5);
  
-                       changed = check_removed(istate, ce, &st);
+                       changed = check_removed(ce, &st);
                        if (!changed)
                                wt_mode = ce_mode_from_stat(ce, st.st_mode);
                        else {
                } else {
                        struct stat st;
  
-                       changed = check_removed(istate, ce, &st);
+                       changed = check_removed(ce, &st);
                        if (changed) {
                                if (changed < 0) {
                                        perror(ce->name);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        trace_performance_since(start, "diff-files");
 -      return 0;
  }
  
  /*
@@@ -303,7 -296,7 +303,7 @@@ static int get_stat_data(const struct i
        if (!cached && !ce_uptodate(ce)) {
                int changed;
                struct stat st;
-               changed = check_removed(istate, ce, &st);
+               changed = check_removed(ce, &st);
                if (changed < 0)
                        return -1;
                else if (changed) {
@@@ -588,7 -581,7 +588,7 @@@ void diff_get_merge_base(const struct r
        if (revs->pending.nr == 1) {
                struct object_id oid;
  
 -              if (get_oid("HEAD", &oid))
 +              if (repo_get_oid(the_repository, "HEAD", &oid))
                        die(_("unable to get HEAD"));
  
                mb_child[1] = lookup_commit_reference(the_repository, &oid);
        free_commit_list(merge_bases);
  }
  
 -int run_diff_index(struct rev_info *revs, unsigned int option)
 +void run_diff_index(struct rev_info *revs, unsigned int option)
  {
        struct object_array_entry *ent;
        int cached = !!(option & DIFF_INDEX_CACHED);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        trace_performance_leave("diff-index");
 -      return 0;
  }
  
  int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt)
@@@ -670,23 -664,16 +670,23 @@@ int index_differs_from(struct repositor
        setup_revisions(0, NULL, &rev, &opt);
        rev.diffopt.flags.quick = 1;
        rev.diffopt.flags.exit_with_status = 1;
 -      if (flags)
 +      if (flags) {
                diff_flags_or(&rev.diffopt.flags, flags);
 +              /*
 +               * Now that flags are merged, honor override_submodule_config
 +               * and ignore_submodules from passed flags.
 +               */
 +              if (flags->override_submodule_config)
 +                      rev.diffopt.flags.ignore_submodules = flags->ignore_submodules;
 +      }
        rev.diffopt.ita_invisible_in_index = ita_invisible_in_index;
 -      run_diff_index(&rev, 1);
 +      run_diff_index(&rev, DIFF_INDEX_CACHED);
        has_changes = rev.diffopt.flags.has_changes;
        release_revisions(&rev);
        return (has_changes != 0);
  }
  
 -static struct strbuf *idiff_prefix_cb(struct diff_options *opt, void *data)
 +static struct strbuf *idiff_prefix_cb(struct diff_options *opt UNUSED, void *data)
  {
        return data;
  }
index 0c241d6c148d7b5ebc9a9b3aaf44723fb1028e8b,1d4c0cbab8afa5bdd16a60ad6cd5357210a31279..78503158fd699d2df75e8fbbbaf164a129f2578b
@@@ -809,6 -809,11 +809,11 @@@ my_match_and_clean () 
                status --porcelain=v2 >actual.without &&
        test_cmp actual.with actual.without &&
  
+       git -C super --no-optional-locks diff-index --name-status HEAD >actual.with &&
+       git -C super --no-optional-locks -c core.fsmonitor=false \
+               diff-index --name-status HEAD >actual.without &&
+       test_cmp actual.with actual.without &&
        git -C super/dir_1/dir_2/sub reset --hard &&
        git -C super/dir_1/dir_2/sub clean -d -f
  }
@@@ -866,9 -871,27 +871,9 @@@ test_expect_success 'submodule always v
  # the submodule, and someone does a `git submodule absorbgitdirs`
  # in the super, Git will recursively invoke `git submodule--helper`
  # to do the work and this may try to read the index.  This will
 -# try to start the daemon in the submodule *and* pass (either
 -# directly or via inheritance) the `--super-prefix` arg to the
 -# `git fsmonitor--daemon start` command inside the submodule.
 -# This causes a warning because fsmonitor--daemon does take that
 -# global arg (see the table in git.c)
 -#
 -# This causes a warning when trying to start the daemon that is
 -# somewhat confusing.  It does not seem to hurt anything because
 -# the fsmonitor code maps the query failure into a trivial response
 -# and does the work anyway.
 -#
 -# It would be nice to silence the warning, however.
 +# try to start the daemon in the submodule.
  
 -have_t2_error_event () {
 -      log=$1
 -      msg="fsmonitor--daemon doesnQt support --super-prefix" &&
 -
 -      tr '\047' Q <$1 | grep -e "$msg"
 -}
 -
 -test_expect_success "stray submodule super-prefix warning" '
 +test_expect_success "submodule absorbgitdirs implicitly starts daemon" '
        test_when_finished "rm -rf super; \
                            rm -rf sub;   \
                            rm super-sub.trace" &&
  
        test_path_is_dir super/dir_1/dir_2/sub/.git &&
  
 +      cwd="$(cd super && pwd)" &&
 +      cat >expect <<-EOF &&
 +      Migrating git directory of '\''dir_1/dir_2/sub'\'' from
 +      '\''$cwd/dir_1/dir_2/sub/.git'\'' to
 +      '\''$cwd/.git/modules/dir_1/dir_2/sub'\''
 +      EOF
        GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
 -              git -C super submodule absorbgitdirs &&
 +              git -C super submodule absorbgitdirs >out 2>actual &&
 +      test_cmp expect actual &&
 +      test_must_be_empty out &&
  
 -      ! have_t2_error_event super-sub.trace
 +      # Confirm that the trace2 log contains a record of the
 +      # daemon starting.
 +      test_subcommand git fsmonitor--daemon start <super-sub.trace
  '
  
  # On a case-insensitive file system, confirm that the daemon
  # notices when the .git directory is moved/renamed/deleted
 -# regardless of how it is spelled in the the FS event.
 +# regardless of how it is spelled in the FS event.
  # That is, does the FS event receive the spelling of the
  # operation or does it receive the spelling preserved with
  # the file/directory.
  #
  test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' '
 -#     test_when_finished "stop_daemon_delete_repo test_insensitive" &&
 +      test_when_finished "stop_daemon_delete_repo test_insensitive" &&
  
        git init test_insensitive &&
  
        test_path_is_dir test_insensitive/.git &&
        test_path_is_dir test_insensitive/.GIT &&
  
 -      # Rename .git using an alternate spelling to verify that that
 -      # daemon detects it and automatically shuts down.
 +      # Rename .git using an alternate spelling to verify that
 +      # the daemon detects it and automatically shuts down.
        mv test_insensitive/.GIT test_insensitive/.FOO &&
  
        # See [1] above.
        # directories and files that we touched.  We may or may not get a
        # trailing slash on modified directories.
        #
 -      egrep "^event: abc/?$"       ./insensitive.trace &&
 -      egrep "^event: abc/def/?$"   ./insensitive.trace &&
 -      egrep "^event: abc/def/xyz$" ./insensitive.trace
 +      grep -E "^event: abc/?$"       ./insensitive.trace &&
 +      grep -E "^event: abc/def/?$"   ./insensitive.trace &&
 +      grep -E "^event: abc/def/xyz$" ./insensitive.trace
  '
  
  # The variable "unicode_debug" is defined in the following library
@@@ -979,57 -992,20 +984,57 @@@ test_expect_success !UNICODE_COMPOSITIO
        then
                # We should have seen NFC event from OS.
                # We should not have synthesized an NFD event.
 -              egrep    "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace &&
 -              egrep -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace
 +              grep -E    "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace &&
 +              grep -E -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace
        else
                # We should have seen NFD event from OS.
                # We should have synthesized an NFC event.
 -              egrep "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace &&
 -              egrep "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace
 +              grep -E "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace &&
 +              grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace
        fi &&
  
        # We assume UNICODE_NFD_PRESERVED.
        # We should have seen explicit NFD from OS.
        # We should have synthesized an NFC event.
 -      egrep "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace &&
 -      egrep "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace
 +      grep -E "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace &&
 +      grep -E "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace
 +'
 +
 +test_expect_success 'split-index and FSMonitor work well together' '
 +      git init split-index &&
 +      test_when_finished "git -C \"$PWD/split-index\" \
 +              fsmonitor--daemon stop" &&
 +      (
 +              cd split-index &&
 +              git config core.splitIndex true &&
 +              # force split-index in most cases
 +              git config splitIndex.maxPercentChange 99 &&
 +              git config core.fsmonitor true &&
 +
 +              # Create the following commit topology:
 +              #
 +              # *   merge three
 +              # |\
 +              # | * three
 +              # * | merge two
 +              # |\|
 +              # | * two
 +              # * | one
 +              # |/
 +              # * 5a5efd7 initial
 +
 +              test_commit initial &&
 +              test_commit two &&
 +              test_commit three &&
 +              git reset --hard initial &&
 +              test_commit one &&
 +              test_tick &&
 +              git merge two &&
 +              test_tick &&
 +              git merge three &&
 +
 +              git rebase --force-rebase -r one
 +      )
  '
  
  test_done