Git development
 help / color / mirror / Atom feed
* fsmonitor (Linux): edits in subdirectories of a renamed directory are missed
@ 2026-10-13 13:39 Erik Cervin-Edin
  0 siblings, 0 replies; only message in thread
From: Erik Cervin-Edin @ 2026-10-13 13:39 UTC (permalink / raw)
  To: git; +Cc: Paul Tarjan, Patrick Steinhardt

What did you do before the bug happened? (Steps to reproduce your issue)

With the built-in fsmonitor daemon on Linux, I renamed a directory that
has a subdirectory, then edited a file in each:

    git init repro && cd repro
    git config core.fsmonitor true
    mkdir -p old/pkg/sub new
    echo a >old/pkg/top.txt
    echo a >old/pkg/sub/f.txt
    git add . && git commit -qm init
    git status --short          # starts the daemon
    git mv old/pkg new/pkg
    git commit -qm move
    echo b >>new/pkg/top.txt
    echo b >>new/pkg/sub/f.txt
    GIT_TRACE_FSMONITOR=1 git status --short

What did you expect to happen? (Expected behavior)

Both edited files listed as modified:

     M new/pkg/sub/f.txt
     M new/pkg/top.txt

What happened instead? (Actual behavior)

Only the file directly in the renamed directory is listed. The daemon
reports the edit in the subdirectory under its path from before the
rename:

    fsmonitor_refresh_callback 'new/pkg/top.txt' (pos 1)
    fsmonitor_refresh_callback INV: 'new/pkg/top.txt'
    fsmonitor_refresh_callback CNT: 1
    fsmonitor_refresh_callback 'old/pkg/sub/f.txt' (pos -3)
     M new/pkg/top.txt

`git -c core.fsmonitor=false status --short` lists both files.

What's different between what you expected and what actually happened?

Changes anywhere below a subdirectory of a renamed directory are
missing from status and diff, with no warning. It is not a
race: later edits in that subdirectory, made well after the rename, are
missed too. It persists until something invalidates the fsmonitor
state. I hit it moving a source package: 19 of 56 edited files were
missing from `git status`, all in subdirectories of the moved
directory, and a commit made from that status would have left them
out.

Anything else you want to add:

I believe the cause is in add_watch() in
compat/fsmonitor/fsm-listen-linux.c. An inotify watch follows the
directory's inode, so the subdirectories of a renamed directory are
still watched. When the rename is processed, they are registered again
under their new paths with IN_MASK_CREATE, inotify_add_watch() fails
with EEXIST, and add_watch() returns early without updating the
descriptor-to-path map. Only the renamed directory's own entry gets its
new path.

Patrick Steinhardt asked about exactly this in review of v5 of the
Linux listener:

  https://lore.kernel.org/git/aZ1bRQv9Cjke298f@pks.im/

  > In case the watch already exists, can't it be the case that we
  > have raced e.g. during a rename? [...] If we then see EEXIST we
  > wouldn't update the hash map and thus keep the old path intact.

As far as I can see that question was not answered on the list, and
v15 of the series still returns early on EEXIST. It turns out to be
deterministic rather than a race.


[System Info]
git version:
git version 2.56.0.rc2.275.gfcaf1f5383
cpu: x86_64
built from commit: fcaf1f5383f52c5ebd5e2df3ea023601e2084b10
sizeof-long: 8
sizeof-size_t: 8
shell-path: /bin/sh
rust: enabled
feature: fsmonitor--daemon
gettext: enabled
libcurl: 8.18.0
OpenSSL: OpenSSL 3.5.8 25 Aug 2026
zlib-ng: 2.3.3
SHA-1: SHA1_DC
SHA-256: SHA256_BLK
default-ref-storage-format: files
default-hash: sha1
uname: Linux 7.2.9-200.fc44.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Oct  3 19:59:55 UTC 2026 x86_64
compiler info: gnuc: 16.2
libc info: glibc: 2.43
$SHELL (typically, interactive shell): /bin/bash


[Enabled Hooks]
not run from a git repository - no hooks to show

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-13 13:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-13 13:39 fsmonitor (Linux): edits in subdirectories of a renamed directory are missed Erik Cervin-Edin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox