Zielsetzung
- Verwendung (inspiriert von Smar , entlehnt von Exherbo )
git am
- Fügen Sie den Commit-Verlauf kopierter / verschobener Dateien hinzu
- Von einem Verzeichnis zum anderen
- Oder von einem Repository zum anderen
Verjährung
- Tags und Zweige werden nicht beibehalten
- Der Verlauf wird beim Umbenennen der Pfaddatei abgeschnitten (Verzeichnis umbenennen).
Zusammenfassung
- Extrahieren Sie den Verlauf im E-Mail-Format mit
git log --pretty=email -p --reverse --full-index --binary
- Ordnen Sie den Dateibaum neu an und aktualisieren Sie die Dateinamen
- Fügen Sie einen neuen Verlauf mit hinzu
cat extracted-history | git am --committer-date-is-author-date
1. Extrahieren Sie den Verlauf im E-Mail-Format
Beispiel: Extrahieren Sie den Verlauf von file3
, file4
undfile5
my_repo
├── dirA
│ ├── file1
│ └── file2
├── dirB ^
│ ├── subdir | To be moved
│ │ ├── file3 | with history
│ │ └── file4 |
│ └── file5 v
└── dirC
├── file6
└── file7
Ziel festlegen / reinigen
export historydir=/tmp/mail/dir # Absolute path
rm -rf "$historydir" # Caution when cleaning the folder
Extrahieren Sie den Verlauf jeder Datei im E-Mail-Format
cd my_repo/dirB
find -name .git -prune -o -type d -o -exec bash -c 'mkdir -p "$historydir/${0%/*}" && git log --pretty=email -p --stat --reverse --full-index --binary -- "$0" > "$historydir/$0"' {} ';'
Leider Option --follow
oder --find-copies-harder
kann nicht mit kombiniert werden --reverse
. Aus diesem Grund wird der Verlauf beim Umbenennen der Datei (oder beim Umbenennen eines übergeordneten Verzeichnisses) abgeschnitten.
Temporärer Verlauf im E-Mail-Format:
/tmp/mail/dir
├── subdir
│ ├── file3
│ └── file4
└── file5
Dan Bonachea schlägt vor, die Schleifen des Befehls zur Generierung des Git-Protokolls in diesem ersten Schritt umzukehren : Anstatt das Git-Protokoll einmal pro Datei auszuführen, führen Sie es genau einmal mit einer Liste von Dateien in der Befehlszeile aus und generieren Sie ein einzelnes einheitliches Protokoll. Auf diese Weise bleiben Commits, die mehrere Dateien ändern, ein einziges Commit im Ergebnis, und alle neuen Commits behalten ihre ursprüngliche relative Reihenfolge bei. Beachten Sie, dass dies auch Änderungen im zweiten Schritt unten erfordert, wenn Dateinamen im (jetzt einheitlichen) Protokoll neu geschrieben werden.
2. Ordnen Sie den Dateibaum neu an und aktualisieren Sie die Dateinamen
Angenommen, Sie möchten diese drei Dateien in diesem anderen Repo verschieben (kann dasselbe Repo sein).
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB # New tree
│ ├── dirB1 # from subdir
│ │ ├── file33 # from file3
│ │ └── file44 # from file4
│ └── dirB2 # new dir
│ └── file5 # from file5
└── dirH
└── file77
Organisieren Sie daher Ihre Dateien neu:
cd /tmp/mail/dir
mkdir -p dirB/dirB1
mv subdir/file3 dirB/dirB1/file33
mv subdir/file4 dirB/dirB1/file44
mkdir -p dirB/dirB2
mv file5 dirB/dirB2
Ihre vorübergehende Geschichte ist jetzt:
/tmp/mail/dir
└── dirB
├── dirB1
│ ├── file33
│ └── file44
└── dirB2
└── file5
Ändern Sie auch Dateinamen innerhalb des Verlaufs:
cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'
3. Wenden Sie einen neuen Verlauf an
Dein anderes Repo ist:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
└── dirH
└── file77
Übernehmen Sie Commits aus temporären Verlaufsdateien:
cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am --committer-date-is-author-date
--committer-date-is-author-date
behält die ursprünglichen Festschreibungszeitstempel bei (Kommentar von Dan Bonachea ).
Dein anderes Repo ist jetzt:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB
│ ├── dirB1
│ │ ├── file33
│ │ └── file44
│ └── dirB2
│ └── file5
└── dirH
└── file77
Verwenden Sie git status
diese Option, um die Anzahl der Commits anzuzeigen, die zum Pushing bereit sind :-)
Zusätzlicher Trick: Überprüfen Sie umbenannte / verschobene Dateien in Ihrem Repo
So listen Sie die umbenannten Dateien auf:
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
Weitere Anpassungen: Sie können den Befehl git log
mit den Optionen --find-copies-harder
oder ausführen --reverse
. Sie können die ersten beiden Spalten auch mit cut -f3-
dem vollständigen Muster '{. * =>. *}' Entfernen und erfassen.
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'
git mv
: stackoverflow.com/questions/1094269/whats-the-purpose-of-git-mv