Vì lợi ích của người đọc, điều này ở đây cố gắng tóm tắt và đưa ra hướng dẫn từng bước về cách thực hiện nếu mọi thứ không hoạt động như mong đợi. Sau đây là cách được thử nghiệm và an toàn cho git
phiên bản 2.17
trở lên để thoát khỏi mô hình con :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- Nếu điều này không làm việc cho bạn, xem bên dưới.
- Không có lựa chọn. Không có gì nguy hiểm. Và thậm chí không xem xét làm nhiều hơn nữa!
- Đã thử nghiệm với Debian Buster
2.20.1
và Ubuntu 18.04 2.17.1
.
"$submodule"
chỉ để nhấn mạnh nơi đặt tên, và bạn phải cẩn thận với không gian và những thứ tương tự
- Nếu trên Windows bỏ qua dòng đầu tiên và thay thế
"$submodule"
bằng cách Windows của một đường dẫn được chỉ định đúng đến mô hình con. (Tôi không phải Windows)
Cảnh báo!
Không bao giờ chạm vào bên trong của .git
thư mục chính mình! Chỉnh sửa bên trong .git
bước vào mặt tối. Tránh xa bằng mọi giá!
Và vâng, bạn có thể đổ lỗi git
cho điều này, vì nhiều thứ tiện dụng đã bị thiếu trong git
quá khứ. Giống như một cách thích hợp để loại bỏ các mô đun con một lần nữa.
Tôi nghĩ rằng có một phần rất nguy hiểm trong tài liệu của git submodule
. Nó khuyên bạn nên loại bỏ $GIT_DIR/modules/<name>/
chính mình.
Theo hiểu biết của tôi, điều này không chỉ sai, nó còn cực kỳ nguy hiểm và gây ra những cơn đau đầu lớn trong tương lai! Xem bên dưới.
Lưu ý rằng
git module deinit
là nghịch đảo trực tiếp với
git module init
nhưng
git submodule deinit -- module
git rm -- module
cũng khá nghịch đảo
git submodule add -- URL module
git submodule update --init --recursive -- module
bởi vì một số lệnh về cơ bản cần phải làm nhiều hơn là một điều duy nhất:
git submodule deinit -- module
git rm
- (2) loại bỏ các tập tin của mô-đun
- (3) do đó loại bỏ đệ quy các mô hình con của mô hình con
- (4) cập nhật
.gitmodules
git submodule add
- kéo dữ liệu đến
.git/modules/NAME/
- (1) có
git submodule init
, vì vậy cập nhật.git/config
- (2)
git submodule update
, do đó, kiểm tra mô-đun một cách không hồi quy
- (4) cập nhật
.gitmodules
git submodule update --init --recursive -- module
- kéo thêm dữ liệu nếu cần
- (3) kiểm tra các mô hình con của mô hình con đệ quy
Điều này không thể đối xứng hoàn toàn, vì việc giữ nó đối xứng nghiêm ngặt không có nhiều ý nghĩa. Đơn giản là không cần nhiều hơn hai lệnh. Ngoài ra, "lấy dữ liệu" là ẩn, vì bạn cần nó, nhưng việc xóa thông tin được lưu trong bộ nhớ cache không được thực hiện, vì điều này hoàn toàn không cần thiết và có thể xóa sạch dữ liệu quý giá.
Điều này thực sự gây hoang mang cho người mới, nhưng về cơ bản là một điều tốt: git
chỉ cần làm điều rõ ràng và làm điều đó đúng, và thậm chí không cố gắng làm nhiều hơn nữa. git
là một công cụ, phải thực hiện một công việc đáng tin cậy, thay vì chỉ là một "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" dịch cho tôi thành "phiên bản xấu xa của con dao quân đội Thụy Sĩ").
Vì vậy, tôi hiểu những lời phàn nàn của mọi người, nói rằng "Tại sao tôi không làm điều git
hiển nhiên cho tôi". Điều này là do "rõ ràng" ở đây phụ thuộc vào quan điểm. Độ tin cậy trong mỗi tình huống là quan trọng hơn nhiều. Do đó những gì rõ ràng đối với bạn thường không phải là điều đúng đắn trong tất cả các tình huống kỹ thuật có thể. Xin nhớ rằng: AFAICS git
đi theo con đường kỹ thuật, không phải xã hội. (Do đó tên thông minh: git)
Nếu thất bại
Các lệnh trên có thể thất bại do sau:
- Bạn
git
quá già Sau đó sử dụng một cái mới hơn git
. (Xem bên dưới cách.)
- Bạn có dữ liệu không được cam kết và có thể mất dữ liệu. Sau đó, tốt hơn cam kết chúng đầu tiên.
- Subodule của bạn không sạch sẽ trong một
git clean
ý nghĩa. Sau đó, đầu tiên làm sạch mô hình con của bạn bằng cách sử dụng lệnh đó. (Xem bên dưới.)
- Bạn đã làm một cái gì đó trong quá khứ không được hỗ trợ bởi
git
. Sau đó, bạn đang ở trong bóng tối và mọi thứ trở nên xấu xí và phức tạp. (Có lẽ sử dụng máy khác để sửa nó.)
- Có lẽ có nhiều cách để thất bại mà tôi không biết (tôi chỉ là một số
git
người sử dụng năng lượng.)
Sửa lỗi có thể làm theo.
Sử dụng cái mới hơn git
Nếu máy tính của bạn quá cũ không có submodule deinit
trong bạn git
. Nếu bạn không muốn (hoặc có thể) cập nhật git
, thì chỉ cần sử dụng máy khác với máy mới hơn git
! git
có nghĩa là được phân phối đầy đủ, vì vậy bạn có thể sử dụng cái khác git
để hoàn thành công việc:
workhorse:~/path/to/worktree$ git status --porcelain
không được xuất bất cứ thứ gì! Nếu có, hãy dọn dẹp mọi thứ trước!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- Bây giờ làm các công cụ con
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
. Nếu điều này không làm việc, sử dụnggit reset --soft FETCH_HEAD
- Bây giờ dọn dẹp mọi thứ, cho đến khi
git status
sạch sẽ trở lại. Bạn có thể làm như vậy, bởi vì bạn đã có nó sạch sẽ, nhờ bước đầu tiên.
Đây othermachine
có thể là một số VM hoặc một số Ubuntu WSL trong Windows, bất cứ điều gì. Ngay cả một chroot
(nhưng tôi cho rằng bạn không phải là root, bởi vì nếu bạn là root
nó sẽ dễ dàng hơn để cập nhật lên bản mới hơn git
).
Lưu ý rằng nếu bạn không thể ssh
vào, có rất nhiều cách để vận chuyển git
kho. Bạn có thể sao chép worktree của mình trên một số thanh USB (bao gồm cả .git
thư mục) và sao chép từ thanh này. Sao chép bản sao, chỉ để có được mọi thứ một cách sạch sẽ một lần nữa. Đây có thể là PITA, trong trường hợp các mô đun con của bạn không thể truy cập trực tiếp từ othermachine. Nhưng cũng có một giải pháp cho việc này:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
Bạn có thể sử dụng bội số này, và điều này được lưu vào $HOME/.gitconfig
. Cái gì đó như
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
viết lại các URL như
https://github.com/XXX/YYY.git
vào
/mnt/usb/repo/XXX/YYY.git
Thật dễ dàng nếu bạn bắt đầu làm quen với git
các tính năng mạnh mẽ như thế này.
Dọn dẹp đồ đạc trước
Làm sạch bằng tay là tốt, bởi vì cách này có lẽ bạn phát hiện ra một số điều bạn quên mất.
- Nếu git phàn nàn về những thứ chưa được lưu, hãy cam kết và đẩy nó vào nơi an toàn.
- Nếu git phàn nàn về một số thức ăn thừa,
git status
và git clean -ixfd
là bạn của bạn
- Cố gắng kiêng những lựa chọn
rm
và deinit
miễn là bạn có thể. Tùy chọn (như -f
) git
là tốt nếu bạn là Pro. Nhưng khi bạn đến đây, có lẽ bạn không có nhiều kinh nghiệm trong submodule
khu vực. Vì vậy, tốt hơn là an toàn hơn xin lỗi.
Thí dụ:
$ 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'
Bạn thấy, không -f
cần thiết trên submodule deinit
. Nếu mọi thứ sạch sẽ, theo một git clean
nghĩa nào đó. Cũng lưu ý rằng git clean -x
không cần thiết. Điều này có nghĩa là git submodule deinit
loại bỏ vô điều kiện các tập tin không bị theo dõi bị bỏ qua. Đây thường là những gì bạn muốn, nhưng đừng quên nó. Đôi khi các tệp bị bỏ qua có thể là quý giá, như dữ liệu được lưu trong bộ nhớ cache mất hàng giờ đến hàng ngày để được tính lại.
Tại sao không bao giờ loại bỏ $GIT_DIR/modules/<name>/
?
Có lẽ mọi người muốn loại bỏ kho lưu trữ được lưu trữ, bởi vì họ sợ gặp phải một vấn đề sau này. Điều này là đúng, nhưng chạy vào "vấn đề" đó là cách chính xác để giải quyết nó! Bởi vì việc khắc phục rất dễ dàng và được thực hiện ngay bạn sẽ có thể sống hạnh phúc mãi mãi. Điều này tránh được rắc rối rườm rà hơn so với khi bạn tự xóa dữ liệu.
Thí dụ:
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
Dòng cuối cùng xuất ra lỗi sau:
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.
Tại sao lỗi này? Bởi vì .git/modules/two/
trước đây đã được điền từ https://github.com/hilbix/empty.git và bây giờ sẽ được nhập lại từ một thứ khác, cụ thể là https://github.com/hilbix/src.git . Bạn sẽ không thấy điều này nếu bạn nhập lại từ https://github.com/hilbix/empty.git
Làm gì bây giờ? Vâng, chỉ cần làm chính xác như đã nói! Sử dụng--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules
sau đó trông giống như
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/
cho
someunusedname/
two/
Bằng cách này trong tương lai, bạn có thể chuyển nhánh / cam kết tiến và lùi và sẽ không bao giờ gặp rắc rối nữa , do two/
có hai kho lưu trữ ngược dòng khác nhau (và có thể không tương thích). Và tốt nhất là: Bạn cũng giữ cả hai bộ nhớ cache cục bộ.
- Điều này không chỉ đúng với bạn. Nó cũng đúng cho tất cả những người khác sử dụng kho lưu trữ của bạn.
- Và bạn không mất lịch sử. Trong trường hợp bạn quên đẩy phiên bản mới nhất của mô hình con cũ, bạn có thể nhập bản sao cục bộ và thực hiện sau đó. Lưu ý rằng điều khá phổ biến là ai đó quên đẩy một số mô hình con (vì đây là Pita cho người mới, cho đến khi họ quen với việc này
git
).
Tuy nhiên, nếu bạn xóa thư mục được lưu trong bộ nhớ cache, cả hai thanh toán khác nhau sẽ vấp ngã nhau, vì bạn sẽ không sử dụng các --name
tùy chọn, phải không? Vì vậy, mỗi lần bạn thực hiện kiểm tra, có lẽ bạn phải xóa .git/modules/<module>/
thư mục nhiều lần. Điều này là vô cùng cồng kềnh và làm cho nó khó sử dụng một cái gì đó như git bisect
.
Vì vậy, có một lý do rất kỹ thuật để giữ thư mục mô-đun này là một giữ chỗ. Những người khuyên nên xóa một cái gì đó bên dưới .git/modules/
hoặc không biết rõ hơn hoặc quên nói với bạn rằng điều này làm cho các tính năng mạnh mẽ git bisect
gần như không thể sử dụng nếu điều này vượt qua sự không tương thích của mô hình con như vậy.
Một lý do nữa được hiển thị ở trên. Nhìn vào ls
. Bạn thấy gì ở đó?
Vâng, biến thể thứ 2 của mô-đun two/
không nằm dưới .git/modules/two/
, nó nằm dưới .git/modules/someunusedname/
! Vì vậy, những điều như git rm $module; rm -f .git/module/$module
là hoàn toàn sai! Bạn phải tham khảo ý kiến module/.git
hoặc .gitmodules
tìm ra thứ phù hợp để loại bỏ!
Vì vậy, không chỉ hầu hết các câu trả lời khác rơi vào cái bẫy nguy hiểm này, ngay cả các git
tiện ích mở rộng rất phổ biến cũng có lỗi này ( hiện đã được sửa ở đó )! Vì vậy, tốt hơn hãy giữ tay của .git/
thư mục nếu bạn không chính xác, những gì bạn đang làm!
Và từ quan điểm triết học, xóa sổ lịch sử luôn là sai!
Ngoại trừ cơ học lượng tử , như thường lệ, nhưng đây là một thứ hoàn toàn khác.
FYI bạn có thể đoán nó: hilbix là tài khoản GitHub của tôi.
git rm modulename
vàrm -rf .git/modules/modulename