// Personal website of Chris Smith

Snippets » Git » Rewrite history after enabling transcrypt

After applying Transcrypt to a repo, you may want to retroactively apply the encryption.

This script will take all the current crypt rules from .gitattributes and propagate them back. Other rules (e.g. LFS config) will be retained.

#!/bin/bash
set -e

if ! git rev-parse --git-dir > /dev/null 2>&1; then
    echo "Error: Not in a git repository"
    exit 1
fi

if [ ! -f .gitattributes ]; then
    echo "Error: .gitattributes not found in current directory"
    exit 1
fi

CRYPT_RULES=$(grep 'filter=crypt' .gitattributes || true)

if [ -z "$CRYPT_RULES" ]; then
    echo "Error: No crypt rules found in .gitattributes"
    exit 1
fi

TEMP_RULES=$(mktemp)
echo "$CRYPT_RULES" > "$TEMP_RULES"

export FILTER_BRANCH_SQUELCH_WARNING=1
git filter-branch --tree-filter '
    RULES_FILE="'"$TEMP_RULES"'"

    echo ""  # Makes filter-branch print its status
    touch .gitattributes

    while IFS= read -r rule; do
        [ -z "$rule" ] && continue

        pattern=$(echo "$rule" | sed -E "s/^([^[:space:]]+).*/\1/")

        if ! grep -qF "$rule" .gitattributes; then
            echo "$rule" >> .gitattributes

            # Re-add matching files to apply the filter
            for file in $(git ls-files | grep -E "^${pattern//\*/.*}$" || true); do
                if [ -f "$file" ]; then
                    git rm --cached --quiet -- "$file" 2>/dev/null || true
                    git add -- "$file" 2>/dev/null || true
                fi
            done
        fi
    done < "$RULES_FILE"
' --tag-name-filter cat -- --all 2>&1 | sed -e '/deprecated key derivation/d' -e '/Using -iter or -pbkdf2/d'

rm "$TEMP_RULES"
echo "Done"