Search code examples
c++gitclang-format

git clang-format removes unstaged changes


I am writing a pre-commit hook for a repo where if some of the staged files are not formatted the hook will format the files and gives a message. Here is the content of the hook

#!/bin/bash

PYTHON=""
ROOT_DIR=$(git rev-parse --show-toplevel)
SCRIPT_DIR="${ROOT_DIR}/tools/source-formatter"
CLANG_BINARY=""
OS_TYPE=$(uname -s)
CLANG_FORMAT_SCRIPT="${SCRIPT_DIR}/git-clang-format"

function handle_exit() {
    exit_code=$?
    if [[ $exit_code -ne 0 ]] && [[ $exit_code -ne 10 ]]
    then
        echo ""
        echo "** Commit failed **"
        echo ""
        if [[ $MSG == *"changed files"* ]]
        then
            echo "File structure are updated to comply with clang-format."
            echo ""
            echo "${MSG}"
            echo ""
            echo "Please review the changed, add to index and commit again."
            echo "** If you need to commit without the formatting please use the --no-verify option for commit **"
        else
            echo "Staged changes needs to be formatted but clang-format refused to do so. Cause:"
            echo "$MSG"
        fi
    fi
}

trap 'handle_exit' EXIT

if [ "$OS_TYPE" = "Linux" ]; then
    CLANG_BINARY="clang-format.linux"
elif [ "$OS_TYPE" = "Darwin" ]; then
    CLANG_BINARY="clang-format"
elif [ "$OS_TYPE" = "MINGW" ] || [ "$os_type" = "Windows_NT" ]; then
    CLANG_BINARY="clang-format.exe"
else
    echo "Unknown platform $OS_TYPE"
    exit 10
fi

set -e
MSG=$(${CLANG_FORMAT_SCRIPT} --staged --extensions "h,cpp" --binary="${SCRIPT_DIR}/${CLANG_BINARY}" 2>&1)

Some clarification on the script:

  1. I have a copy of git-clang-format and clang-format in the repo directory.
  2. The version of the clang-format and the script is 16
  3. I am running this on MacOs

Now here is the steps to produce my problem:

  1. Have staged changes in file A which require reformatting
  2. Have staged changes in file B which don’t require reformatting
  3. Have unstaged changes in file B which are actual changes (let’s say new function)
  4. Try to commit staged changes, the hook doesn’t allow it because of file A.

The effect:

  • The result of code formater is unstaged changed in A.
  • The problem is that the new changes in file B are gone.

Can someone please tell me why this happens and how to stop it from happening? I should also mention that if the changes that need formatting are staged in B and anything else is not staged in B then the git-clang-format refuses to format and prints a message saying that there are unstaged changes.


Solution

  • Apparently this is a known bug and will be solved with the next release git-clang-format script.

    Here is the relevant PR.