Re: [PATCH v2 2/2] mv: check for missing destination directory before renaming

Lucas Zamboni Orioli <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <CAH01Q-_k1QEcTLTMygBceUWjGNFLNewixf80bYOD2_s20jajrQ@mail.gmail.com>
Em dom., 26 de jul. de 2026 às 11:59, Junio C Hamano
<[email protected]> escreveu:
> Think carefully about cases where 'a' is a directory and 'a/b' is a
> symlink, or where 'a' and 'a/b' are directories and 'a/b/c' is a
> symlink, and so on.  We do not want to craft an arbitrary rule that
> says we allow or refuse to operate depending on the link target.

Thanks for pushing on this, chasing the symlink case down turned up
more than a bad message. With a tracked symlink in the leading path,
"git mv" leaves the index inconsistent with the worktree:

    mkdir repo && cd repo
    git init
    echo content >a
    mkdir real-dir
    echo content >real-dir/b
    ln -s . c
    git add .
    git commit -m "initial"
    git mv a c/real-dir/a
    git status

'c' is a tracked symlink to '.'. The move follows it, so on disk the
file lands at the resolved path 'real-dir/a', but the index records
the literal 'c/real-dir/a'. "git status" then reports a staged rename
to 'c/real-dir/a', an unstaged deletion of that same path (nothing is
there on disk), and the real file untracked at 'real-dir/a', with the
symlink 'c' also shown untracked. A later "git add" did reconcile it
by finding the file at its real location, but "git mv" on its own has
already produced an index that describes a worktree that doesn't
exist, it got there precisely by traversing a tracked symlink.

So this is the "not careful enough" case you suspected, and the fix is
the behavior you described: refuse to operate when any component of the
destination's leading path is a symlink, independent of where it
points. I'm thinking of using has_symlink_leading_path() (symlinks.c) for
that check, which is what "git apply" already uses to avoid following in-tree
symlinks, so the behavior stays consistent with the rest of the tree.

For v3 I'll fold this into the series: the leading-directory check will
reject a missing directory or a non-directory/symlink component up
front, which covers both the original misleading-error case and this
symlink traversal. Tests will cover a symlink as the final component
and as an intermediate one ('a/b/c' with 'a' a symlink), plus the
existing missing-directory and dry-run cases.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.