Ja
- Sie konvertieren die Commit-Historie von Dateien in E-Mail-Patches mit
git log --pretty=email
- Sie ordnen diese Dateien in neuen Verzeichnissen an und benennen sie um
- Sie konvertieren diese Dateien (E-Mails) in Git-Commits zurück, um die Historie zu erhalten, indem Sie
git am
.
Begrenzung
- Tags und Äste werden nicht aufbewahrt
- Der Verlauf wird beim Umbenennen von Pfaddateien (Verzeichnisumbenennung) abgeschnitten
Schritt-für-Schritt-Erklärung mit Beispielen
1. Verlauf im E-Mail-Format extrahieren
Beispiel: Auszug Geschichte von file3
, file4
y file5
my_repo
dirA
file1
file2
dirB ^
subdir | To be moved
file3 | with history
file4 |
file5 v
dirC
file6
file7
Einstellen/Reinigen des Ziels
export historydir=/tmp/mail/dir # Absolute path
rm -rf "$historydir" # Caution when cleaning the folder
Extrahieren des Verlaufs 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
o --find-copies-harder
kann nicht kombiniert werden mit --reverse
. Aus diesem Grund wird der Verlauf beim Umbenennen einer Datei (oder eines übergeordneten Verzeichnisses) unterbrochen.
Vorläufiger Verlauf im E-Mail-Format:
/tmp/mail/dir
subdir
file3
file4
file5
Dan Bonachea schlägt vor, die Schleifen des Befehls zur Erstellung des Git-Protokolls in diesem ersten Schritt umzukehren: Anstatt git log einmal pro Datei auszuführen, führen Sie es genau einmal mit einer Liste von Dateien auf der Befehlszeile aus und erstellen Sie ein einziges, einheitliches Protokoll. Auf diese Weise bleiben Commits, die mehrere Dateien ändern, im Ergebnis ein einziger Commit, und alle neuen Commits behalten ihre ursprüngliche relative Reihenfolge bei. Beachten Sie, dass dies auch Änderungen im zweiten Schritt unten erfordert, wenn die Dateinamen im (nun vereinheitlichten) Protokoll umgeschrieben werden.
2. Dateibaum reorganisieren und Dateinamen aktualisieren
Angenommen, Sie möchten diese drei Dateien in ein anderes Projektarchiv verschieben (es kann dasselbe Projektarchiv 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
Reorganisieren Sie deshalb Ihre Dateien:
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 vorläufige Geschichte ist jetzt:
/tmp/mail/dir
dirB
dirB1
file33
file44
dirB2
file5
Ändern Sie auch Dateinamen in der Historie:
cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'
3. Neue Geschichte anwenden
Ihr anderes Repo ist:
my_other_repo
dirF
file55
file56
dirH
file77
Übernehmen Sie Commits aus temporären History-Dateien:
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 Commit-Zeitstempel bei ( Dan Bonachea Kommentar).
Ihr anderes Repo ist jetzt:
my_other_repo
dirF
file55
file56
dirB
dirB1
file33
file44
dirB2
file5
dirH
file77
Verwenden Sie git status
um die Anzahl der Commits zu sehen, die bereit sind, gepusht zu werden :-)
Extra-Trick: Überprüfen Sie umbenannte/verschobene Dateien innerhalb Ihres Repo
Zur Auflistung der umbenannten Dateien:
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
Weitere Anpassungen: Sie können den Befehl git log
Nutzung von Optionen --find-copies-harder
o --reverse
. Sie können auch die ersten beiden Spalten entfernen, indem Sie cut -f3-
und das Greifen vollständiger Muster '{.* => .*}'
.
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'
14 Stimmen
Über
git mv
: stackoverflow.com/questions/1094269/whats-the-purpose-of-git-mv5 Stimmen
Ich möchte nur anmerken, dass ich gerade das Verschieben von Dateien über das Dateisystem getestet habe, und nach dem Übertragen (über intellij) kann ich dann den gesamten Verlauf sehen (einschließlich des Verlaufs, wenn er sich an einem anderen Ort befand), wenn ich den Verlauf (wieder in intellij) ansehe. Ich gehe davon aus, dass intellij nichts Besonderes tut, um das zu tun, also ist es schön zu wissen, dass zumindest die Historie nachvollzogen werden kann.
0 Stimmen
Für die Regeln, denen Git bei der Erkennung einer Verzeichnisumbenennung folgt, siehe meine Antwort unten
0 Stimmen
Ich habe hier eine Antwort geschrieben. Ich hoffe, sie funktioniert. stackoverflow.com/questions/10828267/
0 Stimmen
Git-Unterbäume haben ohnehin "falsche" Historien. Wenn Sie ein Repository aufbrechen, indem Sie
git-subtree
gibt Git dem entstehenden Teilbaum eine erfundene Geschichte, die nicht mit der des Projekts übereinstimmt, von dem er sich abgespalten hat. Ich glaube, dass Git versucht, alle Commits zu ermitteln, die an einer der Dateien im Teilbaum beteiligt waren, und diese verwendet, um eine Geschichte zusammenzufügen. Außerdem werden diese Historien jedes Mal neu geschrieben, wenn Sie die Teilbäume neu kombinieren und neu aufteilen. Untermodule haben jedoch ihre eigene Historie, die vom übergeordneten Projekt getrennt ist.