Cách dễ dàng để kéo mới nhất của tất cả các mô đun con git


1846

Chúng tôi đang sử dụng các mô hình con git để quản lý một vài dự án lớn có sự phụ thuộc vào nhiều thư viện khác mà chúng tôi đã phát triển. Mỗi thư viện là một repo riêng được đưa vào dự án phụ thuộc dưới dạng mô hình con. Trong quá trình phát triển, chúng tôi thường muốn lấy phiên bản mới nhất của mọi mô hình con phụ thuộc.

Liệu git có một lệnh tích hợp để làm điều này? Nếu không, làm thế nào về một tệp bó Windows hoặc tương tự có thể làm điều đó?


git-deep sẽ giúp với điều này.
Mathew Kurian

9
@Brad bạn có muốn cập nhật các bản sao của mô hình con của bạn lên các vòng quay cam kết có tên trong dự án chính; hoặc bạn muốn kéo cam kết mới nhất từ ​​mỗi mô hình con? Hầu hết các câu trả lời ở đây đề cập đến trước đây; nhiều người muốn cái sau
chrisinmtown

Câu trả lời:


2464

Nếu đó là lần đầu tiên bạn kiểm tra một repo bạn cần sử dụng --inittrước:

git submodule update --init --recursive

Đối với git 1.8.2 trở lên, tùy chọn --remoteđã được thêm vào để hỗ trợ cập nhật các mẹo mới nhất của các chi nhánh từ xa:

git submodule update --recursive --remote

Điều này có thêm lợi ích của việc tôn trọng bất kỳ nhánh "không mặc định" nào được chỉ định trong tệp .gitmoduleshoặc .git/config(nếu bạn có bất kỳ, mặc định là origin / master, trong trường hợp một số câu trả lời khác ở đây cũng hoạt động tốt).

Đối với git 1.7.3 trở lên, bạn có thể sử dụng (nhưng các vấn đề dưới đây xung quanh những cập nhật nào vẫn được áp dụng):

git submodule update --recursive

hoặc là:

git pull --recurse-submodules

nếu bạn muốn kéo các mô hình con của mình đến các xác nhận mới nhất thay vì các cam kết hiện tại, các điểm repo tới.

Xem git-subodule (1) để biết chi tiết


299
Có lẽ bạn nên sử dụng git submodule update --recursivengày nay.
Jens Kohl

38
Cải thiện hiệu suất:git submodule foreach "(git checkout master; git pull)&"
Bogdan Gusiev

18
Cập nhật sẽ cập nhật từng mô hình con vào bản sửa đổi được chỉ định, không cập nhật nó vào bản mới nhất cho kho lưu trữ đó.
Peter DeWeese

21
Chỉ cần thêm, việc dán một cách mù quáng origin mastervào cuối lệnh này có thể có kết quả không mong muốn nếu một số mô hình con của bạn đang theo dõi một nhánh hoặc tên vị trí khác của mô hình con cụ thể đó. Rõ ràng với một số, nhưng có lẽ không phải tất cả mọi người.
Nathan Hornby

31
Chỉ để làm rõ cho mọi người. git submodule update --recursivenhìn để xem bản sửa đổi nào mà kho lưu trữ mẹ đã lưu trữ cho mỗi mô hình con, sau đó kiểm tra sửa đổi đó trong mỗi mô hình con. Nó KHÔNG kéo các cam kết mới nhất cho mỗi mô hình con. git submodule foreach git pull origin masterhoặc git pull origin master --recurse-submoduleslà những gì bạn muốn nếu bạn có ý định cập nhật từng mô hình con mới nhất từ ​​kho lưu trữ gốc của chúng. Chỉ sau đó, bạn mới nhận được các thay đổi đang chờ xử lý trong repo cha với các băm sửa đổi được cập nhật cho các mô hình con. Kiểm tra những người trong và bạn tốt.
Chev

636
git pull --recurse-submodules --jobs=10

một tính năng git đầu tiên được học trong 1.8.5.

Cho đến khi lỗi được sửa, lần đầu tiên bạn cần chạy

cập nhật mô hình con git --init --recursive


29
upvote, tôi sử dụng cái này: alias update_submodules = 'git pull --recurse-subodules && git subodule update'
Stephen C

3
Điều này hoạt động nếu các mô hình con đã được kéo ít nhất một lần nhưng đối với các mô hình con chưa bao giờ được kiểm tra, hãy xem câu trả lời của gahooa bên dưới.
Matt Browne

8
Điều này sẽ kéo lên đến phiên bản mà repo hàng đầu chỉ định; nó KHÔNG kéo đầu. Ví dụ: nếu TopRepo chỉ định phiên bản 2 phía sau CHÍNH cho SubRepo, thì điều này sẽ kéo SubRepo với phiên bản đó là 2 phía sau. Các câu trả lời khác ở đây kéo ĐẦU trong SubRepo.
Chris Moschini

11
Lưu ý rằng không phải git pull --recurse-submodulesvà cũng không git submodule update --recursivekhông không khởi tạo mới submodules nói thêm. Để khởi tạo chúng, bạn cần chạy git submodule update --recursive --init. Trích dẫn từ hướng dẫn sử dụng : Nếu mô hình con chưa được khởi tạo và bạn chỉ muốn sử dụng cài đặt như được lưu trữ trong .gitmodules, bạn có thể tự động khởi tạo mô hình con với tùy chọn --init.
patryk.beza

1
có thể thêm một gợi ý để git submodule update --recursive --remotecập nhật các mô hình con lên bản sửa đổi mới nhất từ ​​xa thay vì SHA-1 được lưu trữ.
Hanno S.

386

Trên init chạy lệnh sau:

git submodule update --init --recursive

từ trong thư mục git repo, hoạt động tốt nhất cho tôi.

Điều này sẽ kéo tất cả các mô hình con mới nhất.

Giải thích

git - the base command to perform any git command
    submodule - Inspects, updates and manages submodules.
        update - Update the registered submodules to match what the superproject
        expects by cloning missing submodules and updating the working tree of the
        submodules. The "updating" can be done in several ways depending on command
        line options and the value of submodule.<name>.update configuration variable.
            --init without the explicit init step if you do not intend to customize
            any submodule locations.
            --recursive is specified, this command will recurse into the registered
            submodules, and update any nested submodules within.

Sau này, bạn có thể chạy:

git submodule update --recursive

từ trong thư mục git repo, hoạt động tốt nhất cho tôi.

Điều này sẽ kéo tất cả các mô hình con mới nhất.


10
Có - câu trả lời được bình chọn cao nhất là cách tốt nhất để thực hiện trong '09, nhưng điều này chắc chắn đơn giản và trực quan hơn bây giờ.
Michael Scott Cuthbert

2
@MichaelScottCuthbert cảm ơn, tôi chắc chắn trong 3 năm nữa lệnh này cũng sẽ điên rồ
abc123

5
Tuy nhiên, điều này không kiểm tra bản sửa đổi mới nhất từ ​​mô hình con, chỉ có bản sửa đổi mới nhất mà phụ huynh đang theo dõi.
Nathan Osman

4
@NathanOsman đó là những gì bạn muốn ... bạn sẽ kết thúc với mã bị hỏng bằng cách không tuân theo theo dõi sửa đổi của cha mẹ. Nếu bạn là người duy trì của cha mẹ, bạn có thể tự cập nhật chúng và cam kết chúng.
abc123

2
Vâng, nhưng theo hiểu biết của tôi, đó không phải là điều OP muốn.
Nathan Osman

305

Lưu ý: Đây là từ năm 2009 và có thể đã tốt sau đó nhưng có những lựa chọn tốt hơn bây giờ.

Chúng tôi sử dụng này. Nó được gọi là git-pup:

#!/bin/bash
# Exists to fully update the git repo that you are sitting in...

git pull && git submodule init && git submodule update && git submodule status

Chỉ cần đặt nó trong một thư mục bin thích hợp (/ usr / local / bin). Nếu trên Windows, bạn có thể cần sửa đổi cú pháp để làm cho nó hoạt động :)

Cập nhật:

Đáp lại bình luận của tác giả ban đầu về việc kéo tất cả các Đầu của tất cả các mô hình con - đó là một câu hỏi hay.

Tôi khá chắc chắn rằng gitkhông có lệnh cho nội bộ này. Để làm như vậy, bạn sẽ cần xác định CHÍNH thực sự là gì cho một mô hình con. Điều đó có thể đơn giản như nói masterlà chi nhánh cập nhật nhất, v.v ...

Theo đó, tạo một tập lệnh đơn giản thực hiện như sau:

  1. kiểm tra git submodule statuskho "sửa đổi". Ký tự đầu tiên của các dòng đầu ra chỉ ra điều này. Nếu một repo phụ được sửa đổi, bạn có thể KHÔNG muốn tiếp tục.
  2. cho mỗi repo được liệt kê, cd vào thư mục của nó và chạy git checkout master && git pull. Kiểm tra lỗi.
  3. Cuối cùng, tôi khuyên bạn nên in một màn hình cho người dùng để chỉ ra trạng thái hiện tại của các mô hình con - có lẽ nhắc họ thêm tất cả và cam kết?

Tôi muốn đề cập rằng phong cách này không thực sự là những gì các mô hình con git được thiết kế cho. Thông thường, bạn muốn nói "LibraryX" ở phiên bản "2.32" và sẽ giữ nguyên như vậy cho đến khi tôi bảo nó "nâng cấp".

Đó là, theo một nghĩa nào đó, những gì bạn đang làm với kịch bản được mô tả, nhưng chỉ tự động hơn. Chăm sóc là cần thiết!

Cập nhật 2:

Nếu bạn đang ở trên một nền tảng windows, bạn có thể muốn xem xét việc sử dụng Python để triển khai tập lệnh vì nó rất có khả năng trong các lĩnh vực này. Nếu bạn đang sử dụng unix / linux, thì tôi khuyên bạn chỉ nên sử dụng tập lệnh bash.

Cần bất kỳ làm rõ? Chỉ cần đăng một bình luận.


Tôi không nghĩ đó là những gì tôi muốn. Sẽ không kéo phiên bản của các mô hình con mà siêu dự án đã cam kết cuối cùng. Tôi muốn kéo phiên bản đầu của tất cả các mô hình con.
Brad Robinson

3
Điều này hoạt động rất tốt và không chỉ hoạt động để cập nhật các mô hình con mà còn tìm nạp chúng lần đầu tiên nếu đó là những gì bạn cần.
Matt Browne

Tôi chỉ nhận được "Không có thông tin theo dõi cho chi nhánh hiện tại. Vui lòng chỉ định chi nhánh bạn muốn hợp nhất." Không có vấn đề gì tôi cố gắng: /
Nathan Hornby

9
Tại sao không tạo ra một bí danh cho nó? git config --global alias.pup '!git pull && git submodule init && git submodule update && git submodule status'và sau đó sử dụng nó như git pupkhông có bất kỳ kịch bản.
fracz

Cảm ơn bạn, vì một số lý do mặc dù tôi có git 1.9.1 tôi đã phải thực hiện git submodule initsau lần kéo đầu tiên có các mô hình con đi kèm, để mọi thứ sẽ bắt đầu hoạt động bình thường.
Ben Usman

164

Henrik đang đi đúng hướng. Lệnh 'foreach' có thể thực thi bất kỳ tập lệnh shell tùy ý nào. Hai tùy chọn để kéo mới nhất có thể là,

git submodule foreach git pull origin master

và,

git submodule foreach /path/to/some/cool/script.sh

Điều đó sẽ lặp qua tất cả các mô hình con khởi tạo và chạy các lệnh đã cho.


144

Sau đây làm việc cho tôi trên Windows.

git submodule init
git submodule update

6
Đây rõ ràng không phải là những gì OP yêu cầu. Nó sẽ chỉ cập nhật vào cam kết mô hình con liên quan và không phải là mới nhất.
Patrick

52
Tuy nhiên, đây là điều duy nhất trên trang này có git để kéo các mô đun con vào lần đầu tiên tôi kiểm tra một repo
theheadofabroom

2
Cũng có thể sử dụng: cập nhật mô hình con git --init --recursive (đặc biệt nếu mô hình con được đề cập là RestKit từ một bản sao mới)
HCdev

33

Chỉnh sửa :

Trong các ý kiến ​​đã được chỉ ra (bởi philfreo ) rằng phiên bản mới nhất là bắt buộc. Nếu có bất kỳ mô hình con lồng nhau nào cần có trong phiên bản mới nhất của chúng:

git submodule foreach --recursive git pull

----- Bình luận lỗi thời bên dưới -----

Đây không phải là cách chính thức để làm điều đó sao?

git submodule update --init

Tôi sử dụng nó mọi lúc. Không có vấn đề cho đến nay.

Biên tập:

Tôi chỉ thấy rằng bạn có thể sử dụng:

git submodule foreach --recursive git submodule update --init 

Mà cũng sẽ đệ quy kéo tất cả các mô hình con, tức là phụ thuộc.


5
Câu trả lời của bạn không trả lời câu hỏi của OP, nhưng để làm những gì bạn đã đề xuất, bạn chỉ có thể nóigit submodule update --init --recursive
philfreo

2
Tôi thấy, phiên bản mới nhất là cần thiết. Chà, điều này có thể hữu ích nếu có các mô hình con lồng nhau: git submodule foreach --recursive git pull
chống độc

1
Tôi không thể thực hiện bất kỳ thứ nào trong số này thực sự tải xuống bất cứ thứ gì - "cập nhật mô hình con git --init --recursive" làm việc cho tôi.
BrainSlugs83

33

Vì có thể xảy ra rằng nhánh mặc định của các mô hình con của bạn không phải master , đây là cách tôi tự động hóa các nâng cấp mô hình con Git đầy đủ:

git submodule init
git submodule update
git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx'

Trong số rất nhiều câu trả lời cho nhiều câu hỏi, câu hỏi này có hiệu quả với tôi (2019, lỗi github với id băm cụ thể)
philshem

30

Lần đầu tiên

Bản sao và mô hình ban đầu

git clone git@github.com:speedovation/kiwi-resources.git resources
git submodule init

Nghỉ ngơi

Trong quá trình phát triển, chỉ cần kéo và cập nhật mô hình con

git pull --recurse-submodules  && git submodule update --recursive

Cập nhật mô hình con Git để cam kết mới nhất về nguồn gốc

git submodule foreach git pull origin master

Cách ưa thích nên dưới đây

git submodule update --remote --merge

lưu ý: hai lệnh cuối có hành vi giống nhau


Tôi đã thực hiện một bản sao git không có mô đun con do nhầm lẫn và tất cả các tùy chọn khác không hoạt động, không ai thực hiện mô hình con nhân bản. Sử dụng của bạn, git submodule updateđã lừa Bây giờ tôi đang tải xuống dữ liệu mô đun con bị thiếu từ bước đầu tiên. Cảm ơn bạn. Tôi không giỏi về git: C
m3nda

Anser này thực sự là một câu trả lời rất hay để đặt một câu hỏi ở trên đầu: tại sao tôi phải ".. - recursive-subodules .." và sau đó thêm "... cập nhật ..." thậm chí ".. .foreach ... "sau này để có được cam kết mới nhất? Tất cả điều này trông không giống GIT chút nào! "Cập nhật" đang làm gì và tại sao tôi phải tự đi đến từng mô-đun để kéo? Không phải đó là những gì "... --recurse-subodules .." đang làm sao? Có gợi ý nào không?
Peter Branforn

20

Tôi không biết phiên bản git này đang hoạt động, nhưng đó là những gì bạn đang tìm kiếm:

git submodule update --recursive

Tôi cũng sử dụng nó git pullđể cập nhật kho lưu trữ gốc:

git pull && git submodule update --recursive

10

Các câu trả lời ở trên là tốt, tuy nhiên chúng tôi đã sử dụng git-hook để làm cho việc này dễ dàng hơn nhưng hóa ra trong git 2.14 , bạn có thể đặt git config submodule.recursethành true để bật các mô hình con thành cập nhật khi bạn kéo vào kho git của mình.

Tuy nhiên, điều này sẽ có tác dụng phụ trong việc đẩy tất cả các mô đun con thay đổi nếu chúng ở trên các nhánh, nhưng nếu bạn cần hành vi đó thì điều này có thể thực hiện công việc.

Có thể được thực hiện bằng cách sử dụng:

git config submodule.recurse true

Phải yêu thích tùy chọn này, thật không may vẫn cần phải sử dụng git submodule inittrước khi sử dụng nếu mô hình con của bạn chưa được khởi tạo.
Pellet

5

Git cho windows 2.6.3 :

git submodule update --rebase --remote


Đó là người duy nhất làm việc cho tôi. Tôi thậm chí còn không thể khởi tạo hoặc cập nhật khi con trỏ mô hình con trỏ đang chỉ vào một phiên bản không còn ở xa nữa
Pavel P

4

Từ cấp cao nhất trong repo:

git submodule foreach git checkout develop
git submodule foreach git pull

Điều này sẽ chuyển tất cả các chi nhánh để phát triển và kéo mới nhất


2
Không hoạt động với tôi, với git 2.7.
Bruno Haible

Bạn có một cái gì đó giống như một tập tin sln có thêm tất cả các tham chiếu dự án trong cây không? Ngoài ra bạn thấy lỗi gì? Bạn có thể kiểm tra tập tin gitignore của mình không
Srayan Guhathakurta 21/03/19

1
git submodule foreach git pull origin masterPhải nối chi nhánh tôi muốn lấy. ngoài ra, làm việc hoàn hảo.
Torxed

3

Tôi đã làm điều này bằng cách điều chỉnh câu trả lời của gahooa ở trên :

Tích hợp nó với một [alias]...

Nếu dự án mẹ của bạn có một cái gì đó như thế này trong .gitmodules:

[submodule "opt/submodules/solarized"]
    path = opt/submodules/solarized
    url = git@github.com:altercation/solarized.git
[submodule "opt/submodules/intellij-colors-solarized"]
    path = opt/submodules/intellij-colors-solarized
    url = git@github.com:jkaving/intellij-colors-solarized.git

Thêm một cái gì đó như thế này trong .gitconfig của bạn

[alias]
    updatesubs = "!sh -c \"git submodule init && git submodule update && git submodule status\" "

Sau đó, để cập nhật các mô hình con của bạn, chạy:

git updatesubs

Tôi có một ví dụ về nó trong repo thiết lập môi trường của tôi .


3

Tất cả bạn cần làm bây giờ là một đơn giản git checkout

Chỉ cần đảm bảo kích hoạt nó thông qua cấu hình toàn cầu này: git config --global submodule.recurse true


2

Đây là dòng lệnh để lấy từ tất cả các kho git của bạn cho dù chúng có hay không là mô đun con:

ROOT=$(git rev-parse --show-toplevel 2> /dev/null)
find "$ROOT" -name .git -type d -execdir git pull -v ';'

Nếu bạn chạy nó trong kho git hàng đầu của bạn, bạn có thể thay thế "$ROOT"vào ..


1

Tôi nghĩ bạn sẽ phải viết một kịch bản để làm điều này. Thành thật mà nói, tôi có thể cài đặt python để làm điều đó để bạn có thể sử dụng os.walkđể cdcho mỗi thư mục và ban hành các lệnh thích hợp. Sử dụng python hoặc một số ngôn ngữ kịch bản lệnh khác, ngoài lô, sẽ cho phép bạn dễ dàng thêm / xóa các dự án con mà không phải sửa đổi tập lệnh.


1

Lưu ý: cách không quá dễ dàng, nhưng hoàn toàn khả thi và nó có ưu điểm độc đáo của riêng nó.

Nếu một người muốn sao chép chỉ HEADsửa đổi một kho lưu trữ và chỉ HEADs của tất cả các mô hình con của nó (tức là để kiểm tra "thân cây"), thì người ta có thể sử dụng theo tập lệnh Lua . Đôi khi lệnh đơn giản git submodule update --init --recursive --remote --no-fetch --depth=1có thể dẫn đến một gitlỗi không thể phục hồi . Trong trường hợp này, người ta cần dọn sạch thư mục con của thư mục .git/modulesvà sao chép mô hình con thủ công bằng cách sử dụng git clone --separate-git-dirlệnh. Sự phức tạp duy nhất là tìm ra URL , đường dẫn của .gitthư mục của mô hình con và đường dẫn của mô hình con trong cây siêu dự án.

Ghi chú: tập lệnh chỉ được kiểm tra đối với https://github.com/boostorg/boost.gitkho lưu trữ. Đặc thù của nó: tất cả các mô hình con được lưu trữ trên cùng một máy chủ và .gitmoduleschỉ chứa các URL tương đối .

-- mkdir boost ; cd boost ; lua ../git-submodules-clone-HEAD.lua https://github.com/boostorg/boost.git .
local module_url = arg[1] or 'https://github.com/boostorg/boost.git'
local module = arg[2] or module_url:match('.+/([_%d%a]+)%.git')
local branch = arg[3] or 'master'
function execute(command)
    print('# ' .. command)
    return os.execute(command)
end
-- execute('rm -rf ' .. module)
if not execute('git clone --single-branch --branch master --depth=1 ' .. module_url .. ' ' .. module) then
    io.stderr:write('can\'t clone repository from ' .. module_url .. ' to ' .. module .. '\n')
    return 1
end
-- cd $module ; git submodule update --init --recursive --remote --no-fetch --depth=1
execute('mkdir -p ' .. module .. '/.git/modules')
assert(io.input(module .. '/.gitmodules'))
local lines = {}
for line in io.lines() do
    table.insert(lines, line)
end
local submodule
local path
local submodule_url
for _, line in ipairs(lines) do
    local submodule_ = line:match('^%[submodule %"([_%d%a]-)%"%]$')
    if submodule_ then
        submodule = submodule_
        path = nil
        submodule_url = nil
    else
        local path_ = line:match('^%s*path = (.+)$')
        if path_ then
            path = path_
        else
            submodule_url = line:match('^%s*url = (.+)$')
        end
        if submodule and path and submodule_url then
            -- execute('rm -rf ' .. path)
            local git_dir = module .. '/.git/modules/' .. path:match('^.-/(.+)$')
            -- execute('rm -rf ' .. git_dir)
            execute('mkdir -p $(dirname "' .. git_dir .. '")')
            if not execute('git clone --depth=1 --single-branch --branch=' .. branch .. ' --separate-git-dir ' .. git_dir .. ' ' .. module_url .. '/' .. submodule_url .. ' ' .. module .. '/' .. path) then
                io.stderr:write('can\'t clone submodule ' .. submodule .. '\n')
                return 1
            end
            path = nil
            submodule_url = nil
        end
    end
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.