Git: Restore file permissions

Git complains that files are changed, even if only the permissions are changed

Published on

Having a Git repository where some of the files have permissions changes, a git checkout may not be the solution if other changes have been made.

#!/bin/bash

# The script should run from the root of the Git repository
cd "$(git rev-parse --show-toplevel)" || exit 1

git diff --name-only --diff-filter=M -z |
while IFS= read -r -d '' file; do
    oldmode=$(git ls-tree HEAD -- "$file" | awk '{print $1}')
    
    # Safety check: skip the file if it is NOT in HEAD, or the output is empty
    if [ -z "$oldmode" ]; then
        continue
    fi
    
    # Process only regular files (those starting with 100)
    if [[ "$oldmode" =~ ^100 ]]; then
        # Extract the last 3 octal digits (the actual permissions, e.g., 644)
        clean_mode="${oldmode:3}"
        chmod "$clean_mode" "$file"
    else
        # display skipped file (symlinks, submodules, etc.)
        echo "Skipped (not a regular file): $file (Mode: $oldmode)"
    fi
done

maybe not the best (it calls git ls-tree HEAD for every file) but it handles spaces, tabs, backslashes and any valid Git filename. Also, this version does not parse human-readable output.

Built by me and ChatGPT. Improved by me with shellcheck and Gemini.