Diese Antwort enthält interessante Befehle, die auf git am
Beispielen basieren und anhand von Beispielen Schritt für Schritt dargestellt werden.
Zielsetzung
- Sie möchten einige oder alle Dateien von einem Repository in ein anderes verschieben.
- Sie wollen ihre Geschichte behalten.
- Es ist Ihnen jedoch egal, ob Sie Tags und Zweige behalten.
- Sie akzeptieren einen begrenzten Verlauf für umbenannte Dateien (und Dateien in umbenannten Verzeichnissen).
Verfahren
- Extrahieren Sie den Verlauf im E-Mail-Format mit
git log --pretty=email -p --reverse --full-index --binary
- Dateibaum neu organisieren und Dateinamenänderung im Verlauf aktualisieren [optional]
- Wenden Sie einen neuen Verlauf mit an
git am
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
Reinigen Sie das temporäre Verzeichnis Ziel
export historydir=/tmp/mail/dir # Absolute path
rm -rf "$historydir" # Caution when cleaning
Reinigen Sie die Repo- Quelle
git commit ... # Commit your working files
rm .gitignore # Disable gitignore
git clean -n # Simulate removal
git clean -f # Remove untracked file
git checkout .gitignore # Restore gitignore
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.
Nachher: Temporärer Verlauf im E-Mail-Format
/tmp/mail/dir
├── subdir
│ ├── file3
│ └── file4
└── file5
2. Reorganisieren Sie den Dateibaum und aktualisieren Sie die Änderung des Dateinamens im Verlauf [optional]
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 # was subdir
│ │ ├── file33 # was file3
│ │ └── file44 # was file4
│ └── dirB2 # new dir
│ └── file5 # = file5
└── dirH
└── file77
Organisieren Sie daher Ihre Dateien neu:
cd /tmp/mail/dir
mkdir dirB
mv subdir dirB/dirB1
mv dirB/dirB1/file3 dirB/dirB1/file33
mv dirB/dirB1/file4 dirB/dirB1/file44
mkdir 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"' {} ';'
Hinweis: Dadurch wird der Verlauf neu geschrieben, um die Änderung von Pfad und Dateiname widerzuspiegeln.
(dh die Änderung des neuen Ortes / Namens innerhalb des neuen Repos)
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
Dein anderes Repo ist jetzt:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB ^
│ ├── dirB1 | New files
│ │ ├── file33 | with
│ │ └── file44 | history
│ └── dirB2 | kept
│ └── file5 v
└── dirH
└── file77
Verwenden Sie git status
diese Option, um die Anzahl der Commits anzuzeigen, die zum Pushing bereit sind :-)
Hinweis: Da der Verlauf neu geschrieben wurde, um die Änderung von Pfad und Dateiname widerzuspiegeln:
(dh verglichen mit dem Ort / Namen im vorherigen Repo)
- Sie müssen
git mv
den Speicherort / Dateinamen nicht ändern.
- Sie müssen nicht auf
git log --follow
den vollständigen Verlauf zugreifen.
Zusätzlicher Trick: Erkennen 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 '{.* => .*}'