Untuk kepentingan pembaca, ini di sini mencoba untuk meringkas dan memberikan panduan langkah demi langkah tentang bagaimana melakukannya jika hal-hal tidak berfungsi seperti yang diharapkan. Berikut ini adalah cara yang aman dan teruji untuk git
versi 2.17
dan di atasnya untuk menyingkirkan submodule :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- Jika ini tidak berhasil untuk Anda, lihat di bawah.
- Tidak ada opsi. Tidak ada yang berbahaya. Dan bahkan tidak mempertimbangkan untuk berbuat lebih banyak!
- Diuji dengan Debian Buster
2.20.1
dan Ubuntu 18.042.17.1
.
"$submodule"
hanya untuk menekankan di mana harus meletakkan nama, dan bahwa Anda harus berhati-hati dengan spasi dan sejenisnya
- Jika pada Windows abaikan baris pertama dan gantikan
"$submodule"
dengan cara Windows jalur yang ditentukan dengan benar ke submodule. (Saya bukan Windows)
Peringatan!
Jangan pernah menyentuh bagian dalam .git
direktori sendiri! Mengedit di dalam.git
memasuki sisi gelap. Jauhi semua biaya!
Dan ya, Anda bisa disalahkan git
untuk ini, karena banyak hal berguna yang hilanggit
di masa lalu. Seperti cara yang tepat untuk menghapus submodula lagi.
Saya pikir ada bagian yang sangat berbahaya dalam dokumentasi git submodule
. Disarankan untuk menghapus $GIT_DIR/modules/<name>/
diri sendiri.
Dalam pemahaman saya ini bukan hanya salah, itu sangat berbahaya dan memprovokasi sakit kepala besar di masa depan! Lihat di bawah.
Catat itu
git module deinit
adalah kebalikan langsung ke
git module init
tapi
git submodule deinit -- module
git rm -- module
juga cukup terbalik
git submodule add -- URL module
git submodule update --init --recursive -- module
karena beberapa perintah pada dasarnya perlu melakukan lebih dari satu hal:
git submodule deinit -- module
- (1) pembaruan
.git/config
git rm
- (2) menghapus file-file modul
- (3) dengan demikian secara rekursif menghilangkan submodul submodul
- (4) pembaruan
.gitmodules
git submodule add
- menarik data ke
.git/modules/NAME/
- (1) tidak
git submodule init
, jadi pembaruan.git/config
- (2) tidak
git submodule update
, jadi, memeriksa modul secara tidak rekursif
- (4) pembaruan
.gitmodules
git submodule update --init --recursive -- module
- menarik data lebih lanjut jika diperlukan
- (3) memeriksa submodul submodul secara rekursif
Ini tidak dapat sepenuhnya simetris, karena menjaganya tetap simetris tidak masuk akal. Tidak perlu ada lebih dari dua perintah. Juga "menarik data" adalah implisit, karena Anda membutuhkannya, tetapi menghapus informasi yang di-cache tidak dilakukan, karena ini tidak diperlukan sama sekali dan mungkin menghapus data berharga.
Ini benar-benar membingungkan bagi pendatang baru, tetapi pada dasarnya adalah hal yang baik: git
lakukan saja hal yang jelas dan lakukan itu dengan benar, dan bahkan tidak mencoba untuk berbuat lebih banyak. git
adalah alat, yang harus melakukan pekerjaan yang dapat diandalkan, alih-alih menjadi sekadar "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" menerjemahkan bagi saya menjadi "versi jahat pisau tentara Swiss").
Jadi saya mengerti keluhan orang, mengatakan "Mengapa tidak melakukan git
hal yang jelas bagi saya". Ini karena "jelas" di sini tergantung dari sudut pandang. Keandalan dalam setiap situasi jauh lebih penting. Oleh karena itu apa yang jelas bagi Anda sering bukan hal yang benar dalam semua situasi teknis yang memungkinkan. Harap diingat bahwa: AFAICS git
mengikuti jalur teknis, bukan jalur sosial. (Oleh karena itu nama pintar: git)
Jika ini gagal
Perintah di atas mungkin gagal karena hal berikut:
- Kamu
git
terlalu tua. Kemudian gunakan yang lebih baru git
. (Lihat di bawah bagaimana caranya.)
- Anda memiliki data yang tidak berkomitmen dan mungkin kehilangan data. Maka lebih baik komit dulu.
- Submodule Anda tidak bersih dalam
git clean
arti tertentu. Kemudian pertama-tama bersihkan submodule Anda menggunakan perintah itu. (Lihat di bawah.)
- Anda telah melakukan sesuatu di masa lalu yang tidak didukung oleh
git
. Kemudian Anda berada di sisi gelap dan segalanya menjadi jelek dan rumit. (Mungkin menggunakan mesin lain untuk memperbaikinya.)
- Mungkin ada lebih banyak cara untuk gagal yang tidak saya sadari (saya hanya
git
pengguna-daya).
Kemungkinan perbaikan mengikuti.
Gunakan yang lebih baru git
Jika mesin Anda terlalu tua, tidak ada submodule deinit
di komputer Anda git
. Jika Anda tidak ingin (atau dapat) memperbarui git
, gunakan saja komputer lain dengan yang lebih baru git
! git
dimaksudkan untuk didistribusikan sepenuhnya, sehingga Anda dapat menggunakan yang lain git
untuk menyelesaikan pekerjaan:
workhorse:~/path/to/worktree$ git status --porcelain
tidak boleh mengeluarkan apapun! Jika ya, bersihkan dulu!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- Sekarang lakukan hal-hal submodule
othermachine:~/TMPWORK$ git commit . -m . && exit
workhorse:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git
workhorse:~/path/to/worktree$ git merge --ff-only FETCH_HEAD
. Jika ini tidak berhasil, gunakangit reset --soft FETCH_HEAD
- Sekarang
git status
bersihkan , sampai bersih kembali. Anda dapat melakukannya, karena Anda telah membersihkannya sebelumnya, berkat langkah pertama.
Ini othermachine
bisa berupa VM, atau Ubuntu WSL di Windows, apa pun. Bahkan a chroot
(tapi saya berasumsi bahwa Anda non-root, karena jika Anda root
harus lebih mudah untuk memperbarui ke yang lebih baru git
).
Perhatikan bahwa jika Anda tidak bisa ssh
masuk, ada banyak cara untuk mengangkut git
repositori. Anda dapat menyalin worktree Anda pada beberapa stik USB (termasuk .git
direktori), dan mengkloning dari stik. Mengkloning salinan, hanya untuk mendapatkan hal-hal dengan cara yang bersih lagi. Ini mungkin PITA, jika submodul Anda tidak dapat diakses dari mesin lain secara langsung. Tetapi ada solusi untuk ini juga:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
Anda dapat menggunakan multiply ini, dan ini disimpan ke dalam $HOME/.gitconfig
. Sesuatu seperti
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
suka menulis ulang URL
https://github.com/XXX/YYY.git
ke
/mnt/usb/repo/XXX/YYY.git
Sangat mudah jika Anda mulai terbiasa dengan git
fitur canggih seperti ini.
Bersihkan dulu
Membersihkan secara manual baik, karena dengan cara ini Anda mungkin mendeteksi beberapa hal yang Anda lupa.
- Jika git mengeluh tentang hal-hal yang belum disimpan, komit dan dorong ke tempat yang aman.
- Jika git mengeluh tentang beberapa sisa makanan,
git status
dan itu git clean -ixfd
adalah temanmu
- Cobalah untuk menjauhkan diri dari opsi ke
rm
dan deinit
selama Anda bisa. Pilihan (seperti -f
) untuk git
yang baik jika Anda seorang Pro. Tetapi ketika Anda datang ke sini, Anda mungkin tidak begitu berpengalaman di submodule
daerah tersebut. Jadi lebih baik aman daripada menyesal.
Contoh:
$ git status --porcelain
M two
$ git submodule deinit two
error: the following file has local modifications:
two
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'two' contains local modifications; use '-f' to discard them
$ cd two
$ git submodule deinit --all
error: the following file has local modifications:
md5chk
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'md5chk' contains local modifications; use '-f' to discard them
$ cd md5chk
$ git submodule deinit --all
error: the following file has local modifications:
tino
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'tino' contains local modifications; use '-f' to discard them
$ cd tino
$ git status --porcelain
?? NEW
$ git clean -i -f -d
Would remove the following item:
NEW
*** Commands ***
1: clean 2: filter by pattern 3: select by numbers 4: ask each
5: quit 6: help
What now> 1
Removing NEW
$ cd ../../..
$ git status --porcelain
$ git submodule deinit two
Cleared directory 'two'
Submodule 'someunusedname' (https://github.com/hilbix/src.git) unregistered for path 'two'
Anda lihat, tidak -f
perlu submodule deinit
. Jika semuanya bersih, dalam git clean
arti tertentu. Perhatikan juga bahwa git clean -x
tidak diperlukan. Ini berarti git submodule deinit
menghapus tanpa syarat file yang tidak terpantau yang diabaikan. Ini biasanya yang Anda inginkan, tetapi jangan lupakan itu. Terkadang file yang diabaikan mungkin berharga, seperti data cache yang membutuhkan waktu berjam-jam untuk dihitung kembali.
Kenapa tidak pernah dihapus $GIT_DIR/modules/<name>/
?
Mungkin orang ingin menghapus repositori dalam cache, karena mereka takut mengalami masalah nanti. Ini benar, tetapi mengalami "masalah" itu adalah cara yang benar untuk menyelesaikannya! Karena perbaikannya mudah, dan dilakukan dengan benar, Anda akan dapat hidup bahagia selamanya. Ini menghindari lebih banyak masalah rumit daripada saat Anda menghapus data sendiri.
Contoh:
mkdir tmptest &&
cd tmptest &&
git init &&
git submodule add https://github.com/hilbix/empty.git two &&
git commit -m . &&
git submodule deinit two &&
git rm two &&
git commit -m . &&
git submodule add https://github.com/hilbix/src.git two
Baris terakhir menampilkan kesalahan berikut:
A git directory for 'two' is found locally with remote(s):
origin https://github.com/hilbix/empty.git
If you want to reuse this local git directory instead of cloning again from
https://github.com/hilbix/src.git
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.
Kenapa kesalahan ini? Karena .git/modules/two/
sebelumnya telah diisi dari https://github.com/hilbix/empty.git dan sekarang akan diisi ulang dari sesuatu yang lain, yaitu https://github.com/hilbix/src.git . Anda tidak akan melihat ini jika Anda mengisi ulang dari https://github.com/hilbix/empty.git
Apa yang harus dilakukan sekarang? Nah, lakukan persis seperti yang diperintahkan! Menggunakan--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules
maka terlihat seperti
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/
memberi
someunusedname/
two/
Dengan cara ini di masa depan Anda dapat beralih cabang / komit maju dan mundur dan tidak akan pernah mendapat masalah lagi , karena two/
memiliki dua repositori hulu yang berbeda (dan mungkin tidak kompatibel). Dan yang terbaik adalah: Anda menyimpan keduanya dalam cache secara lokal juga.
- Ini tidak hanya berlaku untuk Anda. Itu juga berlaku untuk semua orang lain yang menggunakan repositori Anda.
- Dan Anda tidak kehilangan sejarah. Jika Anda lupa untuk mendorong versi terbaru dari submodule lama, Anda dapat memasukkan salinan lokal dan melakukannya nanti. Perhatikan bahwa sangat umum bahwa seseorang lupa untuk mendorong beberapa submodul (karena ini adalah PITA untuk pendatang baru, sampai mereka terbiasa
git
).
Namun jika Anda menghapus direktori yang di-cache, kedua pemeriksaan yang berbeda akan saling bertabrakan, karena Anda tidak akan menggunakan --name
opsi, bukan? Jadi setiap kali Anda melakukan checkout Anda mungkin harus menghapus .git/modules/<module>/
direktori lagi dan lagi. Ini sangat rumit dan membuatnya sulit untuk menggunakan sesuatu seperti git bisect
.
Jadi ada alasan yang sangat teknis untuk menjaga direktori modul ini sebagai pengganti. Orang-orang yang merekomendasikan untuk menghapus sesuatu di bawah .git/modules/
ini tidak tahu yang lebih baik atau lupa untuk memberi tahu Anda bahwa ini membuat fitur-fitur canggih seperti git bisect
hampir tidak mungkin digunakan jika ini melintasi ketidakcocokan submodule.
Alasan lebih lanjut ditunjukkan di atas. Lihatlah ls
. Apa yang kamu lihat di sana?
Nah, varian modul ke-2 two/
tidak di bawah .git/modules/two/
, itu di bawah .git/modules/someunusedname/
! Jadi hal-hal seperti git rm $module; rm -f .git/module/$module
itu sama sekali salah! Anda harus berkonsultasi module/.git
atau .gitmodules
menemukan hal yang benar untuk dihapus!
Jadi tidak hanya sebagian besar jawaban lain masuk ke dalam jebakan berbahaya ini, bahkan git
ekstensi yang sangat populer pun memiliki bug ini ( sekarang sudah diperbaiki di sana )! Jadi, lebih baik tetap tangani .git/
direktori Anda jika Anda tidak tepat, apa yang Anda lakukan!
Dan dari sudut pandang filosofis, menghapus sejarah selalu salah!
Kecuali untuk mekanika kuantum , seperti biasa, tetapi ini adalah sesuatu yang sangat berbeda.
FYI Anda mungkin dapat menebaknya: hilbix adalah akun GitHub saya.
git rm modulename
danrm -rf .git/modules/modulename