git_cleaner.py: Rekursiv git gc auf allen Repositories ausführen

Das Skript git_cleaner.py durchsucht ein angegebenes Verzeichnis (oder standardmäßig das aktuelle Verzeichnis) rekursiv nach Git-Repositorys und führt auf jedem git gc aus. Es erfasst Größe und Dateianzahl des .git-Verzeichnisses vor und nach dem git gc, sodass deutlich wird, wie viel Platz zurückgewonnen und wie viele Dateien entfernt wurden. Am Ende gibt das Skript eine Zusammenfassung aller verarbeiteten Repositorys aus.

git_cleaner.py
#!/usr/bin/env python3
import os
import subprocess
import argparse
import sys

def get_dir_stats(path):
    """Gibt ein Tupel (total_size_bytes, total_file_count) zurück."""
    total_size = 0
    file_count = 0
    for dirpath, _, filenames in os.walk(path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            if not os.path.islink(fp):
                total_size += os.path.getsize(fp)
                file_count += 1
    return total_size, file_count

def format_size(bytes_size):
    """Wandelt Bytes in eine lesbare Zeichenkette um."""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if abs(bytes_size) < 1024:
            return f"{bytes_size:.2f} {unit}"
        bytes_size /= 1024
    return f"{bytes_size:.2f} TB"

def main():
    parser = argparse.ArgumentParser(
        description="Rekursiv 'git gc' ausführen und eingesparten Platz sowie Dateien melden."
    )
    parser.add_argument(
        "target_dir",
        nargs="?",
        default=".",
        help="Zu durchsuchendes Verzeichnis (Standard: '.')"
    )

    args, unknown_args = parser.parse_known_args()
    target_path = os.path.abspath(args.target_dir)

    if not os.path.isdir(target_path):
        print(f"Error: {target_path} is not a directory.")
        sys.exit(1)

    total_saved_bytes = 0
    total_files_removed = 0
    repos_processed = 0

    print(f"--- Scanning: {target_path} ---")

    for root, dirs, _ in os.walk(target_path):
        if ".git" in dirs:
            repos_processed += 1
            git_dir = os.path.join(root, ".git")

            # 1. Statistik vorher erfassen
            size_before, files_before = get_dir_stats(git_dir)

            print(f"\n[{repos_processed}] Optimiere: {root}")

            try:
                # 2. git gc ausführen
                # Hinweis: -C führt git im angegebenen Verzeichnis aus
                cmd = ["git", "-C", root, "gc"] + unknown_args
                subprocess.run(cmd, check=True, capture_output=True)

                # 3. Statistik nachher erfassen
                size_after, files_after = get_dir_stats(git_dir)

                saved_size = size_before - size_after
                removed_files = files_before - files_after

                total_saved_bytes += max(0, saved_size)
                total_files_removed += max(0, removed_files)

                print(f"    Dateien: {files_before} -> {files_after} ({removed_files} entfernt)")
                print(f"    Größe:  {format_size(size_before)} -> {format_size(size_after)} ({format_size(saved_size)} eingespart)")

            except subprocess.CalledProcessError as e:
                print(f"    [!] Fehler: {e.stderr.decode().strip()}")

            # Effizienz: nicht in das gerade verarbeitete .git-Verzeichnis hineinlaufen
            dirs.remove(".git")

    # Abschluss-Tabelle
    print("\n" + "="*45)
    print(f"{'ZUSAMMENFASSUNG':^45}")
    print("-" * 45)
    print(f" Verarbeitete Repositorys : {repos_processed}")
    print(f" Platz gesamt eingespart  : {format_size(total_saved_bytes)}")
    print(f" Dateien gesamt entfernt  : {total_files_removed}")
    print("="*45)

if __name__ == "__main__":
    main()

Beispielausgabe

git_cleaner_output.txt
[...]

[433] Optimizing: /home/uli/dev/FlareDNS
    Files: 73 -> 33 (40 removed)
    Size:  70.14 KB -> 47.03 KB (23.10 KB saved)

=============================================
                FINAL SUMMARY
---------------------------------------------
 Repositories Processed : 433
 Total Space Reclaimed  : 238.14 MB
 Total Files Removed    : 21612
=============================================

Ähnliche Beiträge nach Kategorie: Git, Python