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.