Apakah mungkin untuk memindahkan / mengganti nama file di Git dan mempertahankan sejarahnya?

667

Saya ingin mengganti nama / memindahkan subtree proyek di Git untuk memindahkannya

/project/xyz

untuk

/components/xyz

Jika saya menggunakan dataran git mv project components, maka semua riwayat komit untuk xyz projecthilang. Apakah ada cara untuk memindahkan ini sedemikian rupa sehingga sejarah dipertahankan?

sgargan
sumber
2
Saya hanya ingin mencatat bahwa saya baru saja menguji memindahkan file melalui sistem file, dan setelah melakukan (melalui intellij) saya kemudian dapat melihat seluruh sejarah (termasuk sejarah ketika itu di lokasi yang berbeda) ketika melihat histori (lagi di intellij). Saya berasumsi intellij tidak melakukan sesuatu yang khusus untuk melakukannya, jadi senang mengetahui bahwa setidaknya sejarah dapat ditelusuri.
BT
Untuk aturan yang diikuti oleh Git ketika mendeteksi penggantian nama direktori, lihat jawaban saya di bawah ini
VonC
Saya menulis jawaban di sini. Saya harap ini berhasil. stackoverflow.com/questions/10828267/…
Mahmut EFE

Jawaban:

651

Git mendeteksi penggantian nama daripada mempertahankan operasi dengan komit, jadi apakah Anda menggunakan git mvatau mvtidak masalah.

The logperintah mengambil --followargumen yang terus sejarah sebelum operasi ganti nama, yaitu, mencari konten yang sama menggunakan heuristik:

http://git-scm.com/docs/git-log

Untuk mencari riwayat lengkap, gunakan perintah berikut:

git log --follow ./path/to/file
Troels Thomsen
sumber
63
Saya menduga ini adalah pertimbangan kinerja. Jika Anda tidak memerlukan riwayat lengkap, tentu butuh waktu lebih lama untuk memindai konten. Cara termudah adalah dengan mengatur alias git config alias.logf "log --follow"dan hanya menulis git logf ./path/to/file.
Troels Thomsen
13
@TroelsThomsen surel ini oleh Linus Torvalds, ditautkan dari jawaban ini , menunjukkan bahwa ini adalah pilihan desain Git yang disengaja karena diduga jauh lebih kuat daripada melacak nama baru, dll.
Emil Lundberg
127
Jawaban ini agak menyesatkan. Git memang "mendeteksi nama baru," tetapi sangat terlambat dalam game; pertanyaannya adalah menanyakan bagaimana Anda memastikan Git melacak penggantian nama, dan seseorang yang membaca ini dapat dengan mudah menyimpulkan bahwa Git mendeteksi mereka secara otomatis untuk Anda dan mencatatnya. Itu tidak. Git tidak memiliki penanganan nama pengganti yang sebenarnya, dan sebagai gantinya ada alat gabungan / log yang mencoba untuk mencari tahu apa yang terjadi - dan jarang melakukannya dengan benar. Linus memiliki argumen yang keliru tetapi keras mengapa git tidak boleh hanya melakukannya dengan cara yang benar dan melacak nama secara eksplisit. Jadi, kita terjebak di sini.
Chris Moschini
29
Penting: jika Anda mengganti nama direktori, misalnya saat mengganti nama paket Java, pastikan untuk mengeksekusi dua commit, pertama untuk perintah 'git mv {old} {new}', kedua untuk pembaruan semua file Java yang mereferensikan direktori paket berubah. Kalau tidak, git tidak dapat melacak file individual bahkan dengan parameter --follow.
nn4l
44
Meskipun Linus mungkin membuat kesalahan sangat sedikit, ini tampaknya salah. Cukup mengganti nama folder menyebabkan delta besar diunggah ke GitHub. Yang membuat saya berhati-hati tentang penggantian nama folder saya ... tapi itu jaket lurus yang cukup besar untuk seorang programmer. Kadang-kadang, saya HARUS mendefinisikan kembali makna sesuatu, atau mengubah cara hal-hal dikategorikan. Linus: "Dengan kata lain, saya benar. Saya selalu benar, tetapi kadang-kadang saya lebih benar daripada waktu lain. Dan sial, ketika saya mengatakan 'file tidak penting', saya benar-benar benar ( tm). " ... Saya ragu tentang itu.
Gabe Halsmer
94

Hal ini dimungkinkan untuk mengganti nama file dan menjaga sejarah utuh, meskipun hal itu menyebabkan file yang akan berganti nama di seluruh sejarah repositori. Ini mungkin hanya untuk pecinta git-log yang obsesif, dan memiliki beberapa implikasi serius, termasuk di antaranya:

  • Anda bisa menulis ulang riwayat bersama, yang merupakan JON paling penting saat menggunakan Git. Jika orang lain telah mengkloning repositori, Anda akan menghentikannya melakukan ini. Mereka harus mengkloning ulang untuk menghindari sakit kepala. Ini mungkin baik-baik saja jika penggantian nama cukup penting, tetapi Anda harus mempertimbangkan ini dengan saksama - Anda mungkin akan mengecewakan seluruh komunitas opensource!
  • Jika Anda telah mereferensikan file menggunakan nama lama itu sebelumnya dalam sejarah repositori, Anda secara efektif melanggar versi sebelumnya. Untuk mengatasinya, Anda harus melakukan sedikit lebih banyak hoop jumping. Bukan tidak mungkin, hanya membosankan dan mungkin tidak sepadan.

Sekarang, karena Anda masih bersama saya, Anda mungkin seorang pengembang solo yang mengganti nama file yang sepenuhnya terisolasi. Mari kita pindahkan file menggunakan filter-tree!

Asumsikan Anda akan memindahkan file oldke folder dirdan berikan namanew

Ini bisa dilakukan dengan git mv old dir/new && git add -u dir/new, tetapi itu menghancurkan sejarah.

Sebagai gantinya:

git filter-branch --tree-filter 'if [ -f old ]; then mkdir dir && mv old dir/new; fi' HEAD

akan mengulang setiap komit di cabang, mengeksekusi perintah dalam kutu untuk setiap iterasi. Banyak hal yang bisa salah ketika Anda melakukan ini. Saya biasanya menguji untuk melihat apakah file tersebut ada (jika tidak belum ada di sana untuk pindah) dan kemudian melakukan langkah-langkah yang diperlukan untuk menyemir pohon sesuai keinginan saya. Di sini Anda dapat menelusuri file untuk mengubah referensi ke file dan sebagainya. Hancurkan dirimu! :)

Setelah selesai, file dipindahkan dan lognya utuh. Anda merasa seperti bajak laut ninja.

Juga; Dir mkdir hanya diperlukan jika Anda memindahkan file ke folder baru, tentu saja. The jika akan menghindari penciptaan folder ini sebelumnya dalam sejarah dari file Anda ada.

Øystein Steimler
sumber
57
Sebagai kekasih git-log-obsesif, saya tidak akan pergi untuk ini. File-file itu tidak dinamai pada saat itu, maka sejarah mencerminkan situasi yang tidak pernah ada. Siapa yang tahu tes apa yang mungkin gagal di masa lalu! Risiko melanggar versi sebelumnya ada dalam hampir setiap kasus tidak sepadan.
Vincent
7
@Vincent Anda benar sekali, dan saya berusaha sejelas mungkin tentang ketidaksukaan dari solusi ini yang sesuai. Saya juga berpikir kita berbicara tentang dua arti kata "sejarah" dalam hal ini, saya menghargai keduanya.
Øystein Steimler
6
Saya menemukan ada situasi di mana orang mungkin membutuhkan ini. Katakanlah saya mengembangkan sesuatu di cabang pribadi saya, yang sekarang saya ingin gabungkan ke hulu. Tapi saya menemukan, nama file tidak tepat, jadi saya mengubahnya untuk seluruh cabang pribadi saya. Dengan cara itu saya bisa menjaga riwayat yang benar bersih dan memiliki nama yang benar dari awal.
user2291758
3
@ user2291758 itulah use case saya. Perintah-perintah git yang lebih kuat ini berbahaya tetapi itu tidak berarti mereka tidak memiliki kasus penggunaan yang sangat menarik jika Anda tahu apa yang Anda lakukan!
philix
1
jika mungkin, menggunakan --index-filterfor for renames akan jauh lebih cepat karena pohon tidak harus diperiksa dan dikembalikan pada setiap komit. --index-filterbertindak langsung pada setiap indeks komit.
Thomas Guyot-Sionnest
87

Tidak.

Jawaban singkatnya adalah TIDAK . Tidak mungkin untuk mengganti nama file di Git dan mengingat sejarahnya. Dan itu menyebalkan.

Rumor mengatakan bahwa itu git log --follow--find-copies-harderakan berfungsi, tetapi itu tidak bekerja untuk saya, bahkan jika tidak ada perubahan pada isi file, dan langkah telah dilakukan git mv.

(Awalnya saya menggunakan Eclipse untuk mengganti nama dan memperbarui paket dalam satu operasi, yang mungkin membingungkan Git. Tetapi itu adalah hal yang sangat umum untuk dilakukan. --followTampaknya berfungsi jika hanya mvdilakukan dan kemudian a commitdan mvtidak terlalu jauh.)

Linus mengatakan bahwa Anda seharusnya memahami seluruh isi proyek perangkat lunak secara holistik, tidak perlu melacak file individual. Sayangnya, otak kecil saya tidak bisa melakukan itu.

Benar- benar menjengkelkan karena begitu banyak orang dengan tanpa sadar mengulangi pernyataan bahwa Git secara otomatis melacak gerakan. Mereka telah menyia-nyiakan waktu saya. Git tidak melakukan hal seperti itu. Sesuai desain (!) Git tidak melacak pergerakan sama sekali.

Solusi saya adalah mengganti nama file kembali ke lokasi aslinya. Ubah perangkat lunak agar sesuai dengan kontrol sumber. Dengan Git Anda sepertinya perlu "git" dengan benar untuk pertama kali.

Sayangnya, itu memecah Eclipse, yang tampaknya digunakan --follow. git log --followterkadang tidak menunjukkan riwayat lengkap file dengan riwayat ganti nama yang rumit meskipun git logdemikian. (Saya tidak tahu kenapa.)

(Ada beberapa peretasan yang terlalu cerdik yang kembali dan mengaktifkan kembali karya lama, tetapi agak menakutkan. Lihat GitHub-Gist: emiller / git-mv-with-history .)

Tuntable
sumber
2
Saya percaya Anda benar. Saya hanya mencoba menggunakan php-cs-fixer untuk memformat ulang sumber untuk proyek Laravel 5 saya tetapi bersikeras mengubah kapitalisasi klausa namespace agar sesuai dengan nilai huruf kecil dari folder aplikasi. Tetapi ruang nama (atau komposer autoload) hanya berfungsi dengan CamelCase. Saya perlu mengubah kapitalisasi folder ke Aplikasi tetapi ini menyebabkan perubahan saya hilang. Ini adalah contoh yang paling sepele, tetapi menunjukkan bagaimana heuristik git tidak dapat mengikuti perubahan nama yang paling sederhana (- ikuti dan - cari-salinan-lebih keras seharusnya menjadi aturan, bukan pengecualian).
Zack Morris
6
git -1, subversi +1
Cosmin
Apakah ini masih benar? Itu lebih banyak alasan bagi saya untuk tetap dengan tfs untuk saat ini, menjaga riwayat file yang dipindahkan / diganti adalah suatu keharusan dalam proyek besar.
Cesar
@Cesar Jika dengan "mengingat sejarah", yang ia maksudkan adalah "ikuti perubahan nama saat melihat log" (yang merupakan satu-satunya hal berguna yang harus kita pedulikan), maka ini tidak pernah benar! Git tidak "merekam" nama, tetapi alat dapat dengan mudah mendeteksi mereka dan memberi kami nama dan gerakan. Jika "itu tidak berhasil" untuk seseorang, dia harus mengubah alat yang dia gunakan. Ada banyak GUI Git hebat yang memiliki kemampuan ini.
Mohammad Dehghan
Jawaban singkatnya adalah Ya. Versi git saat ini mendukung "log git - ikuti" juga. dan saya setuju dengan @MohammadDehghan
insung
43
git log --follow [file]

akan menampilkan sejarah melalui penggantian nama.

Erik Hesselink
sumber
29
Tampaknya ini mengharuskan Anda untuk melakukan penggantian nama saja sebelum Anda mulai memodifikasi file. Jika Anda memindahkan file (di shell) dan kemudian mengubahnya, semua taruhan dimatikan.
yoyo
22
@ yoyo: itu karena git tidak melacak nama, itu mendeteksi mereka. A git mvpada dasarnya melakukan a git rm && git add. Ada opsi seperti -M90/ --find-renames=90untuk mempertimbangkan nama file yang akan diganti namanya saat 90% identik.
vdboor
22

Saya lakukan:

git mv {old} {new}
git add -u {new}
James M. Greene
sumber
3
-U tampaknya tidak melakukan apa-apa untukku, apakah itu seharusnya memperbarui sejarah?
jeremy
1
Mungkin Anda ingin berperilaku -Asebagai gantinya? Sekali lagi, lihat di sini: git-scm.com/docs/git-add
James M. Greene
1
Itu memang menambah file, namun itu tidak memperbarui sejarah sehingga 'git log file name' menunjukkan sejarah lengkap. Ini hanya menampilkan riwayat lengkap jika Anda masih menggunakan opsi --follow.
jeremy
3
Saya melakukan refactor rumit yang memindahkan direktori include (menggunakan mv, bukan git mv) dan kemudian mengubah banyak jalur #include dalam file yang diganti namanya. git tidak dapat menemukan cukup banyak kesamaan untuk melacak sejarah. Tapi git add -u adalah hal yang saya butuhkan. status git sekarang menunjukkan "berganti nama" di mana sebelumnya menunjukkan "dihapus" dan "file baru".
AndyJost
1
Ada banyak pertanyaan di SO yang membahas tujuan git add -u. Dokumen Git cenderung tidak membantu, dan merupakan tempat terakhir yang ingin saya lihat. Berikut ini satu pos yang ditampilkan git add -udalam aksi: stackoverflow.com/a/2117202 .
Nobar
17

Saya ingin mengganti nama / memindahkan subtree proyek di Git untuk memindahkannya

/project/xyz

untuk

/ komponen / xyz

Jika saya menggunakan dataran git mv project components, maka semua riwayat komit untuk xyzproyek hilang.

Tidak (8 tahun kemudian, Git 2.19, Q3 2018), karena Git akan mendeteksi penggantian nama direktori , dan sekarang ini lebih baik didokumentasikan.

Lihat komit b00bf1c , komit 1634688 , komit 0661e49 , komit 4d34dff , komit 983f464 , komit c840e1a , komit 9929430 (27 Jun 2018), dan komit d4e8062 , komit 5dacd4a (25 Jun 2018) oleh Elijah Newren ( newren) .
(Digabung oleh Junio ​​C Hamano - gitster- dalam komit 0ce5a69 , 24 Jul 2018)

Itu sekarang dijelaskan dalam Documentation/technical/directory-rename-detection.txt:

Contoh:

Ketika semua x/a, x/bdan x/ctelah pindah ke z/a, z/bdan z/c, kemungkinan x/dditambahkan sementara itu juga ingin pindah ke z/ddengan mengambil petunjuk bahwa seluruh direktori ' x' pindah ke ' z'.

Tetapi ada banyak kasus lain, seperti:

satu sisi histori x -> zmengubah nama , dan yang lain mengganti nama beberapa file x/e, menyebabkan perlunya penggabungan untuk melakukan penggantian nama transitif.

Untuk menyederhanakan deteksi penggantian nama direktori, aturan tersebut diberlakukan oleh Git:

beberapa aturan dasar batas ketika deteksi ganti nama direktori berlaku:

  1. Jika direktori tertentu masih ada di kedua sisi gabungan, kami tidak menganggapnya telah diubah namanya.
  2. Jika subset dari file yang akan diubah namanya memiliki file atau direktori di jalan (atau akan di jalan satu sama lain), "matikan" direktori ganti nama untuk sub-path tertentu dan laporkan konflik kepada pengguna .
  3. Jika sisi lain dari sejarah melakukan perubahan nama direktori ke jalur yang sisi sejarah Anda berganti nama, maka abaikan nama tertentu itu dari sisi lain sejarah untuk setiap nama direktori implisit (tapi peringatkan pengguna).

Anda dapat melihat banyak tes t/t6043-merge-rename-directories.sh, yang juga menunjukkan bahwa:

  • a) Jika mengubah nama memecah direktori menjadi dua atau lebih yang lain, direktori dengan paling banyak mengubah nama, "menang".
  • b) Hindari deteksi direktori-ganti nama untuk lintasan, jika lintasan itu adalah sumber nama ganti rugi di kedua sisi penggabungan.
  • c) Hanya menerapkan nama direktori implisit ke direktori jika sisi lain dari sejarah adalah orang yang melakukan penggantian nama.
VONC
sumber
15

Objektif

  • Gunakan (terinspirasi dari Smar , dipinjam dari Exherbo )git am
  • Tambahkan riwayat komit dari file yang disalin / dipindahkan
  • Dari satu direktori ke direktori lainnya
  • Atau dari satu repositori ke yang lain

Batasan

  • Tag dan cabang tidak disimpan
  • Histori terpotong pada nama file path (nama direktori)

Ringkasan

  1. Ekstrak riwayat dalam format email menggunakan
    git log --pretty=email -p --reverse --full-index --binary
  2. Atur ulang pohon file dan perbarui nama file
  3. Tambahkan riwayat baru menggunakan
    cat extracted-history | git am --committer-date-is-author-date

1. Ekstrak histori dalam format email

Contoh: Ekstrak riwayat file3, file4danfile5

my_repo
├── dirA
│   ├── file1
│   └── file2
├── dirB            ^
│   ├── subdir      | To be moved
│   │   ├── file3   | with history
│   │   └── file4   | 
│   └── file5       v
└── dirC
    ├── file6
    └── file7

Atur / bersihkan tujuan

export historydir=/tmp/mail/dir       # Absolute path
rm -rf "$historydir"    # Caution when cleaning the folder

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 --followatau --find-copies-hardertidak dapat digabungkan dengan --reverse. Inilah sebabnya mengapa sejarah dipotong ketika file diganti namanya (atau ketika direktori induk diubah namanya).

Riwayat sementara dalam format email:

/tmp/mail/dir
    ├── subdir
    │   ├── file3
    │   └── file4
    └── file5

Dan Bonachea menyarankan untuk membalikkan loop dari perintah pembuatan git log pada langkah pertama ini: daripada menjalankan git log sekali per file, jalankan persis sekali dengan daftar file pada baris perintah dan buat satu log tunggal. Dengan cara ini komit yang memodifikasi banyak file tetap menjadi komit tunggal dalam hasil, dan semua komit baru mempertahankan urutan relatif aslinya. Catatan ini juga membutuhkan perubahan pada langkah kedua di bawah ini ketika menulis ulang nama file di log (sekarang disatukan).


2. Atur kembali pohon file dan perbarui nama file

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         # from subdir
│   │   ├── file33    # from file3
│   │   └── file44    # from file4
│   └── dirB2         # new dir
│        └── file5    # from file5
└── dirH
    └── file77

Karena itu atur ulang file Anda:

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

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"' {} ';'

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 --committer-date-is-author-date

--committer-date-is-author-datemempertahankan stempel waktu komit asli ( komentar Dan Bonachea ).

Repo Anda yang lain sekarang:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB
│   ├── dirB1
│   │   ├── file33
│   │   └── file44
│   └── dirB2
│        └── file5
└── dirH
    └── file77

Gunakan git statusuntuk melihat jumlah komit yang siap didorong :-)


Trik tambahan: Periksa 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 logmenggunakan opsi --find-copies-harderatau --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 '{.* => .*}'
olibre
sumber
4
WASPADALAH: Teknik ini membagi komit yang mengubah 2 atau lebih file menjadi komit terfragmentasi terpisah, dan selanjutnya mengacak pesanan mereka dengan menyortir nama file (sehingga fragmen dari satu komit asli tidak tampak berdekatan dalam sejarah linier). Karenanya, riwayat yang dihasilkan hanya "benar" berdasarkan file-demi-file. Jika Anda memindahkan lebih dari satu file, maka NONE dari commit baru dalam histori yang dihasilkan menunjukkan snapshot konsisten dari file yang dipindahkan yang pernah ada dalam sejarah repo asli.
Dan Bonachea
2
Hai @DanBonachea. Terima kasih atas tanggapan Anda yang menarik. Saya telah berhasil melakukan migrasi beberapa repo yang berisi beberapa file menggunakan teknik ini (bahkan dengan mengganti nama file dan file melintasi direktori). Apa yang Anda sarankan untuk berubah dalam jawaban ini. Apakah Anda pikir kami harus menambahkan spanduk PERINGATAN di bagian atas jawaban ini yang menjelaskan batasan teknik ini? Cheers
olibre
2
Saya mengadaptasi teknik ini untuk menghindari masalah dengan membalik loop dari perintah pembuatan git log pada langkah 1. Yaitu. daripada menjalankan git log sekali per file, jalankan itu tepat sekali dengan daftar file pada baris perintah dan menghasilkan satu log tunggal. Dengan begini komit yang memodifikasi 2 atau lebih file tetap komit tunggal dalam hasilnya, dan semua komit baru mempertahankan urutan relatif aslinya. Catatan ini juga membutuhkan perubahan pada langkah 2 saat menulis ulang nama file di log (sekarang disatukan). Saya juga menggunakan git am --committer-date-is-author-date untuk menjaga stempel waktu komit asli.
Dan Bonachea
1
Terima kasih atas percobaan dan berbagi Anda. Saya telah memperbarui sedikit jawaban untuk pembaca lain. Namun saya telah mengambil waktu untuk menguji pemrosesan Anda. Silakan mengedit jawaban ini jika Anda ingin memberikan contoh baris perintah. Cheers;)
olibre
4

Saya mengikuti proses multi-langkah ini untuk memindahkan kode ke direktori induk dan menyimpan riwayat.

Langkah 0: Membuat 'sejarah' cabang dari 'master' untuk diamankan

Langkah 1: Menggunakan alat git-filter-repo untuk menulis ulang sejarah. Perintah ini di bawah ini memindahkan folder 'FolderwithContentOfInterest' ke satu tingkat dan memodifikasi riwayat komit yang relevan

git filter-repo --path-rename ParentFolder/FolderwithContentOfInterest/:FolderwithContentOfInterest/ --force

Langkah 2: Pada saat ini repositori GitHub kehilangan jalur repositori jarak jauhnya. Referensi jarak jauh ditambahkan

git remote add origin [email protected]:MyCompany/MyRepo.git

Langkah 3: Tarik informasi tentang repositori

git pull

Langkah 4: Hubungkan cabang lokal yang hilang dengan cabang asal

git branch --set-upstream-to=origin/history history

Langkah 5: Alamat merge konflik untuk struktur folder jika diminta

Langkah 6: Dorong !!

git push

Catatan: Riwayat yang diubah dan folder yang dipindahkan tampaknya sudah dikomit. enter code here

Selesai Pindah kode ke direktori induk / yang dikehendaki menjaga riwayat tetap utuh!

Parag Bangad
sumber
2

Sementara inti dari Git, pipa Git tidak melacak nama, sejarah yang Anda tampilkan dengan log "porselen" Git dapat mendeteksi mereka jika Anda mau.

Untuk yang diberikan git loggunakan opsi -M:

git log -p -M

Dengan versi Git saat ini.

Ini berfungsi untuk perintah lain git diffjuga.

Ada beberapa opsi untuk membuat perbandingan lebih atau kurang ketat. Jika Anda mengganti nama file tanpa membuat perubahan signifikan pada file pada saat yang sama, itu membuat Git log dan teman-teman lebih mudah mendeteksi nama tersebut. Karena alasan ini beberapa orang mengganti nama file di satu komit dan mengubahnya di yang lain.

Ada biaya dalam penggunaan CPU setiap kali Anda meminta Git untuk menemukan di mana file telah diubah namanya, jadi apakah Anda menggunakannya atau tidak, dan kapan, terserah Anda.

Jika Anda ingin selalu memiliki riwayat Anda dilaporkan dengan deteksi nama dalam repositori tertentu, Anda dapat menggunakan:

git config diff.renames 1

Memindahkan file dari satu direktori ke yang lain adalah terdeteksi. Ini sebuah contoh:

commit c3ee8dfb01e357eba1ab18003be1490a46325992
Author: John S. Gruber <[email protected]>
Date:   Wed Feb 22 22:20:19 2017 -0500

    test rename again

diff --git a/yyy/power.py b/zzz/power.py
similarity index 100%
rename from yyy/power.py
rename to zzz/power.py

commit ae181377154eca800832087500c258a20c95d1c3
Author: John S. Gruber <[email protected]>
Date:   Wed Feb 22 22:19:17 2017 -0500

    rename test

diff --git a/power.py b/yyy/power.py
similarity index 100%
rename from power.py
rename to yyy/power.py

Harap dicatat bahwa ini berfungsi setiap kali Anda menggunakan diff, bukan hanya dengan git log. Sebagai contoh:

$ git diff HEAD c3ee8df
diff --git a/power.py b/zzz/power.py
similarity index 100%
rename from power.py
rename to zzz/power.py

Sebagai percobaan saya membuat perubahan kecil dalam satu file di cabang fitur dan melakukan itu dan kemudian di cabang master saya mengubah nama file, melakukan, dan kemudian membuat perubahan kecil di bagian lain file dan melakukan itu. Ketika saya pergi ke fitur cabang dan bergabung dari master, gabungan tersebut mengganti nama file dan menggabungkan perubahan. Inilah output dari penggabungan:

 $ git merge -v master
 Auto-merging single
 Merge made by the 'recursive' strategy.
  one => single | 4 ++++
  1 file changed, 4 insertions(+)
  rename one => single (67%)

Hasilnya adalah direktori yang berfungsi dengan nama file diubah dan kedua perubahan teks dibuat. Jadi mungkin bagi Git untuk melakukan hal yang benar meskipun faktanya itu tidak secara eksplisit melacak nama.

Ini adalah jawaban yang terlambat untuk pertanyaan lama sehingga jawaban yang lain mungkin benar untuk versi Git pada saat itu.

John S Gruber
sumber
1

Pertama buat komit mandiri hanya dengan mengganti nama.

Kemudian setiap perubahan pada konten file dimasukkan ke dalam komit terpisah.

Jakub Pawlowski
sumber
1

Untuk mengganti nama direktori atau file (saya tidak tahu banyak tentang kasus yang kompleks, jadi mungkin ada beberapa peringatan):

git filter-repo --path-rename OLD_NAME:NEW_NAME

Untuk mengganti nama direktori dalam file yang menyebutkannya (dimungkinkan untuk menggunakan panggilan balik, tapi saya tidak tahu caranya):

git filter-repo --replace-text expressions.txt

expressions.txtadalah file yang diisi dengan garis-garis seperti literal:OLD_NAME==>NEW_NAME(dimungkinkan untuk menggunakan RE Python dengan regex:atau glob dengan glob:).

Untuk mengganti nama direktori dalam pesan commit:

git-filter-repo --message-callback 'return message.replace(b"OLD_NAME", b"NEW_NAME")'

Ekspresi reguler Python juga didukung, tetapi harus ditulis dalam Python, secara manual.

Jika repositori asli, tanpa remote, Anda harus menambahkan --forceuntuk memaksa penulisan ulang. (Anda mungkin ingin membuat cadangan repositori Anda sebelum melakukan ini.)

Jika Anda tidak ingin menyimpan referensi (akan ditampilkan dalam riwayat cabang Git GUI), Anda harus menambahkan --replace-refs delete-no-add.

Pugsley
sumber
0

Cukup pindahkan file dan panggungnya dengan:

git add .

Sebelum komit, Anda dapat memeriksa status:

git status

Itu akan menunjukkan:

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    old-folder/file.txt -> new-folder/file.txt

Saya diuji dengan Git versi 2.26.1.

Diambil dari Halaman Bantuan GitHub .

Muda
sumber
-3

Saya membuat memindahkan file dan kemudian melakukannya

git add -A

yang menempatkan di area sataging semua file yang dihapus / baru. Di sini git menyadari bahwa file tersebut dipindahkan.

git commit -m "my message"
git push

Saya tidak tahu mengapa tetapi ini berhasil untuk saya.

Xelian
sumber
Kuncinya di sini adalah Anda tidak perlu mengubah satu huruf pun, bahkan jika Anda mengubah sesuatu dan menekan Ctrl + Z, riwayatnya akan rusak. JADI dalam hal ini jika Anda menulis sesuatu, kembalikan file tersebut, dan pindahkan lagi dan buat satu add-> commit untuknya.
Xelian