The 'can not move directory into itself' error occurs when using git mv with wildcards that include the destination directory. Use the -k flag to skip problematic moves, or exclude the destination from the pattern.
The "fatal: can not move directory into itself" error occurs when you use `git mv` with a wildcard pattern (like `*`) that expands to include the destination directory itself. For example, when you run `git mv * subdirectory/`, the shell expands `*` to include ALL items in the current directory, including the destination `subdirectory`. Git then attempts to move `subdirectory` into itself, which is logically impossible and would create an infinite loop, so Git aborts the entire operation with this error. This is a common user error when trying to reorganize project structure, such as moving all files into a new subdirectory. The fix is straightforward: either use the `-k` flag to skip problematic moves, exclude the destination from your pattern, or move files in a different way.
The -k flag tells Git to skip any move operations that would cause errors, while still processing the valid ones:
# Skip moves that would fail (including moving directory into itself)
git mv -k * destination_folder/This is the simplest solution. Git will move all files and subdirectories except the destination folder itself.
Note: The -k flag may not work on all systems (some report issues on macOS Sierra and Ubuntu). If it doesn't work for you, try the alternative methods below.
In Bash, you can use extended globbing to exclude specific directories from the pattern:
# Enable extended globbing
shopt -s extglob
# Move everything except the destination folder
git mv !(destination_folder) destination_folder/
# Disable extended globbing when done (optional)
shopt -u extglobThe !(pattern) syntax matches everything that doesn't match the pattern.
Use a loop to move each item separately, excluding the destination:
# Move all items except 'destination_folder'
for file in $(ls | grep -v 'destination_folder'); do
git mv "$file" destination_folder/
doneOr more robustly with find:
# Move files and directories, excluding the destination
find . -maxdepth 1 -not -name 'destination_folder' -not -name '.' | while read item; do
git mv "$item" destination_folder/
doneIf the destination doesn't exist yet, create it and then move items:
# Create the destination directory
mkdir -p new_folder
# Move specific files/folders explicitly
git mv file1.txt file2.txt subfolder/ new_folder/
# Or use the -k flag now that the directory exists
git mv -k * new_folder/Being explicit about what you're moving avoids wildcard issues entirely.
To move only Git-tracked files (ignoring untracked files and directories):
# Move all tracked files to a subdirectory
for f in $(git ls-files); do
mkdir -p "destination_folder/$(dirname $f)"
git mv "$f" "destination_folder/$f"
doneThis approach is particularly useful when you want to preserve the directory structure within the destination.
If git mv is giving you trouble, you can use the regular mv command and let Git detect the changes:
# Create destination if needed
mkdir -p destination_folder
# Move files with regular mv (which handles this case fine)
mv file1.txt file2.txt other_folder/ destination_folder/
# Stage the changes
git add -A
# Verify Git detected the moves
git statusGit is smart enough to detect that files were moved (not deleted and re-added) when the content is identical.
After moving files, verify everything is correct:
# Check git status
git status
# Verify the renamed/moved files show correctly
git diff --staged --name-status
# Commit the changes
git commit -m "Move files to destination_folder"The status should show files as "renamed" (R) rather than deleted and added, indicating Git tracked the move correctly.
### Understanding Shell Glob Expansion
When you type git mv * destination/, your shell expands * BEFORE passing arguments to Git. So Git receives something like:
git mv file1.txt file2.txt destination/ destination/Git then tries to move each item, including destination/ into destination/, which is impossible.
### The -k Flag Behavior
The -k (skip) flag tells Git to silently skip any move operations that would fail, rather than aborting the entire command. This includes:
- Moving a directory into itself
- Source files that don't exist
- Destination already exists (without -f)
### Case-Sensitive Renames
On case-insensitive filesystems (default macOS, Windows), renaming a directory to change only case requires a two-step approach:
# Won't work directly on case-insensitive systems:
git mv Folder folder # fatal: renaming 'Folder' failed: Invalid argument
# Instead, use a temporary name:
git mv Folder temp_folder
git mv temp_folder folder### Preserving History with Moves
Git tracks content, not files, so moves are automatically detected. However, for cleaner history:
# Use git log --follow to track file history across renames
git log --follow -- destination_folder/file.txt### PowerShell Users
In PowerShell on Windows, use this syntax instead:
git mv -k (Get-ChildItem *) destination_folder/### Dry Run Before Moving
Always preview what will happen before executing:
# Dry run - shows what would be moved without actually doing it
git mv -n * destination_folder/This helps you identify potential issues before they occur.
warning: BOM detected in file, this may cause issues
UTF-8 Byte Order Mark (BOM) detected in file
fatal: Server does not support --shallow-exclude
Server does not support --shallow-exclude
warning: filtering out blobs larger than limit
Git partial clone filtering large blobs warning
fatal: Server does not support --shallow-since
Server does not support --shallow-since in Git
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server