Jawaban ini memberikan perintah menarik berdasarkan git am
dan disajikan menggunakan contoh, langkah demi langkah.
Objektif
- Anda ingin memindahkan beberapa atau semua file dari satu repositori ke yang lain.
- Anda ingin menyimpan sejarah mereka.
- Tetapi Anda tidak peduli tentang menyimpan tag dan cabang.
- Anda menerima riwayat terbatas untuk file berganti nama (dan file dalam direktori berganti nama).
Prosedur
- Ekstrak riwayat dalam format email menggunakan
git log --pretty=email -p --reverse --full-index --binary
- Atur ulang pohon file dan perbarui perubahan nama file dalam riwayat [opsional]
- Terapkan riwayat baru menggunakan
git am
1. Ekstrak histori dalam format email
Contoh: Ekstrak riwayat file3
, file4
danfile5
my_repo
├── dirA
│ ├── file1
│ └── file2
├── dirB ^
│ ├── subdir | To be moved
│ │ ├── file3 | with history
│ │ └── file4 |
│ └── file5 v
└── dirC
├── file6
└── file7
Bersihkan tujuan direktori sementara
export historydir=/tmp/mail/dir # Absolute path
rm -rf "$historydir" # Caution when cleaning
Bersihkan sumber repo Anda
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
Ekstrak riwayat setiap file dalam format email
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"' {} ';'
Sayangnya opsi --follow
atau --find-copies-harder
tidak dapat digabungkan dengan --reverse
. Inilah sebabnya mengapa sejarah dipotong ketika file diganti namanya (atau ketika direktori induk diubah namanya).
Setelah: Riwayat sementara dalam format email
/tmp/mail/dir
├── subdir
│ ├── file3
│ └── file4
└── file5
2. Atur ulang susunan file dan perbarui perubahan nama file dalam riwayat [opsional]
Misalkan Anda ingin memindahkan ketiga file ini di repo lain ini (bisa menjadi repo yang sama).
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
Karena itu atur ulang file Anda:
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
Riwayat sementara Anda sekarang:
/tmp/mail/dir
└── dirB
├── dirB1
│ ├── file33
│ └── file44
└── dirB2
└── file5
Ubah juga nama file dalam riwayat:
cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'
Catatan: Ini menulis ulang sejarah untuk mencerminkan perubahan path dan nama file.
(yaitu perubahan lokasi / nama baru dalam repo baru)
3. Terapkan sejarah baru
Repo Anda yang lain adalah:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
└── dirH
└── file77
Terapkan komit dari file riwayat sementara:
cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am
Repo Anda yang lain sekarang:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB ^
│ ├── dirB1 | New files
│ │ ├── file33 | with
│ │ └── file44 | history
│ └── dirB2 | kept
│ └── file5 v
└── dirH
└── file77
Gunakan git status
untuk melihat jumlah komit yang siap didorong :-)
Catatan: Karena riwayat telah ditulis ulang untuk mencerminkan jalur dan perubahan nama file:
(yaitu dibandingkan dengan lokasi / nama dalam repo sebelumnya)
- Tidak perlu
git mv
mengubah lokasi / nama file.
- Tidak perlu
git log --follow
mengakses riwayat lengkap.
Trik tambahan: Mendeteksi file yang diubah namanya / dipindahkan dalam repo Anda
Untuk membuat daftar file yang telah diubah namanya:
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
Kustomisasi lainnya: Anda dapat menyelesaikan perintah git log
menggunakan opsi --find-copies-harder
atau --reverse
. Anda juga dapat menghapus dua kolom pertama menggunakan cut -f3-
dan menangkap pola lengkap '{. * =>. *}'.
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'