git submodule và việc đồng bộ thư viện ở nhiều dự án con

Lời nói đầu

Bài viết này dành cho lập trình viên Android, sử dụng Android Studio IDE, có kiến thức cơ bản về git.

Tình huống

Bạn tự tay viết library cá nhân cho mình. Thư viện này sẽ được import vào các project của bạn dưới dạng module.
Theo thông thường, toàn bộ source code của library sẽ được copy vào thư mục project của bạn luôn => có NHIỀU bản copy của library nằm rải rác trong các dự án của bạn.
Với cách làm trên, sẽ nảy sinh các vấn đề:
1. Mỗi khi bạn cập nhật library, bạn sẽ phải thực hiện việc cập nhật (import) cho TẤT CẢ các project có sử dụng library này.
2. project của bạn sẽ phình ra thêm một khoản => tốn băng thông khi clone, push, pull
3. Nếu bạn đưa library của mình lên git server (chắc chắn rồi), thì khi push projectimport library, library source code nó sẽ không lên theo khi bạn push, và khi clone về, library module sẽ trống trơn. Nhìn trên github bạn sẽ thấy thư mục đó sẽ có dạng như này: submodulelibrary @ 3f569e3, hay trên bitbucket: submodulelibrary [515a0baf5b3c]

Để giải quyết những vấn đề này, git cung cấp mô hình submodule.

git submodule

git submodule là mô hình cho phép bạn sử dụng một git project khác làm submodule cho project của mình, tuy nhiên, bạn không hề phải bận tâm về chuyện source code của submodule kia. Bạn có thể hiểu nôm na giống như là bạn compile một thư viện trong file build.gradle vậy. Hai cái tương tự nhau nhưng có những điểm rất khác biệt, mình sẽ làm rõ vấn đề này ở một bài viết khác.
Với git submodule, bạn có thể thoả mái chọn có cập nhật code mới nhất hay không. Rồi bạn có thể chọn lấy codeversion nào, commit nào (vì thằng sub nó cũng được git quản lý mà :P).
Với từng này thông tin, là ta đã có đủ dữ liệu để giải quyết vấn đề ở đầu bài viết rồi:
– Đầu tiên đưa library lên git server
– Sau đó import cái library module này theo dạng git submodule là xong.
– Khi cập nhật library, ta chỉ việc push lên và sang bên project rồi pull xuống là xong.
– Nếu chia sẻ project cho các thành viên khác trong team, họ cũng làm tương tự: clone project về, sau đó pull library.

Để hiểu rõ hơn, cứ code demo là thấy ngay thôi 😛

Code code code

Chuẩn bị môi trường

  • Đầu tiên tạo một Android Studio project tên là SubModuleLibrary.
  • Trong SubModuleLibrary, tạo một Android library module tên là submodulelibrary.
    Screen Shot 2015-08-23 at 4.43.09 PM
    Vì đây là library project nên ta có thể remove app module trong project và cả trong ổ đĩa.
  • Tiếp đến ta tạo một Android Studio project khác tên là DemoSubModule.
    Và thằng app module của DemoSubModule project sẽ dử dụng thư viện submodulelibrary bên kia.

Bên trong submodulelibrary

Để đơn giản hết mức có thể, library này chỉ chứa một lớp Foo và phương thức tĩnh ping sẽ trả về một String:

DemoSubModule project import submodulelibrary

Lại là để đơn giản hết mức có thể, project này đơn giản chỉ là gọi Foo.ping() rồi hiển thị kết quả lên một cái TextView thôi:

Layout: main_activity.xml:

Triển khai

submodulelibrary

Đưa submodulelibrary lên git server như bao dự án bình thường khác:

Q&A:
– Trong lệnh git remote add gh, tại sao lại là gh mà không phải origin như bình thường tôi vẫn làm?
-> Đây là thói quen của mình thôi, để hiểu rõ vấn đề này, mời bạn đọc bài viết Git remote và việc push source code lên nhiều nơi cùng lúc.

Xong phần library, giờ tới DemoSubModule project.

DemoSubModule project

  1. Cấu hình git
  1. Cấu hình liên kết tới thư viện trên git server
    Cú pháp: git submodule add [URL] [PATH_TO_SUBMODULE]:

Mở file .git/config, xem nội dung thay đổi:

Tiếp đến là import submodulelibraryvào.

  1. Trong Android Studio, chuột phải vào app chọn Open Module Setting.
  2. Cửa sổ Project Structure hiện ra, click vào nút dấu cộng (+) ở góc trên bên trái, chọn Import Gradle Project
    Screen Shot 2015-08-23 at 5.39.15 PM
  3. Ở màn hình Create New Module, tại mục Source directory, click vào nút có dấu ba chấm ..., trỏ đến thư mục submodulelibrary của DemoSubModule project rồi bấm Choose.
  4. Tại đây nó sẽ sinh ra lỗi: Project already contains module with this name. Nguyên nhân là do submodulelibrary module đã được clone về từ lúc nãy, nếu thêm vào nữa thì sẽ bị xung đột (mà Android Studio thì khôn có cơ chế tự động load module), để giải quyết lỗi này, ta có hai phương án:

– Đổi tên trong ô Module Name thành submodulelibrary2
– Move thư mục submodulelibrary ra chỗ khác (Desktop chẳng hạn), rồi tiến hành import lại bình thường.
Ở đây mình chọn phương án 1:
Screen Shot 2015-08-23 at 10.36.59 PM
5. Link submodulelibrary2 vào app module của mình bằng cách:
– Ở màn hình Project Structure, chọn app, sau đó chọn thẻ Dependencies.
– Bấm dấu cộng (+) ở góc dưới bên trái để thêm Dependency, chọn Module Dependency-> chọn submodulelibrary2 -> OK
Screen Shot 2015-08-23 at 10.43.07 PM

Dòng code trên lớp MainActivity lúc này sẽ hết báo lỗi, bạn có thể chạy thử chương trình để đảm bảo rằng mọi thứ OK.
Đến đây là xong việc cấu hình, ta có thể đưa code lên git server:

Mẹo Bạn có thể kiểm tra trạng thái của các submodule bằng lệnh:

Q&A
1. Vậy bây giờ tôi sửa thư viện submodulelibrary, thì lại phải sang DemoSubModule project để import à?
-> Không. Mình đang cấu hình để khỏi phải làm công việc thủ công này mà. Sau khi push lên git server, mình chỉ việc sang DemoSubModule projectpull code về thôi. Ngoài ra, bạn có thể chỉnh sửa submodulelibrary ở ngay trong DemoSubModule projectpush lên tương tự làm ở “bản gốc”, vì bên này nó cũng có cấu hình git mà.
2. Thế sao không import thẳng từ bên SubModuleLibrary projectmà phải mất công lấy trên git server về vậy?
-> Nếu import thẳng thì bạn chỉ import mình cái submodulelibrary module thôi, không hề có thông tin git đi kèm, do đó, cơ chế git submodule sẽ không làm việc. Bạn có thể thử để hiểu rõ hơn 🙂
3. Bây giờ tôi muốn chia sẻ SubModuleLibrary project cho người khác để họ cũng có thể dùng thư viện của tôi?
-> Thì bạn cũng chỉ việc đưa cho người ta cái link git của thư viện của bạn, và họ cũng tiến hành add như bạn mới làm trên kìa thôi (git submodule add git@github.com:BinhCQ/SubModuleLibrary.git submodulelibrary/)
4. Còn tôi muốn chia sẻ DemoSubModule project cho người khác, họ cũng phải add như vậy à, thế có phiền quá không?
-> Bạn đã add rồi, và chỉ cần add một lần duy nhất, bên kia chỉ việc cập nhật thôi. Để hiểu rõ hơn, chúng ta sẽ code tiếp.

Chia sẻ

Để mô phỏng việc chia sẻ dự án cho người khác, hay đơn giản là bạn sang máy khác và muốn lấy code về để tiếp tục phát triển dự án, ta sẽ clone dự án vào một thư mục khác, sau đó thử mở lên và chạy.
Ra terminal, cd đến Desktop và thực hiện clone:

Lúc này, thư mục submodulelibrary đang rỗng, bởi vì bạn chưa cập nhật submodule:

Đến đây bạn có thể mở SubModuleLibrary project bằng Android Studio để kiểm tra kết quả.
Mẹo Bạn có thể chạy lệnh git submodule update --init để chạy một lần hai lệnh ở trên luôn 😛
Giải quyết xong ba vấn đề ở đầu bài. Vậy là từ nay, bạn có thể thoả mái import library của mình vào nhiều project, đồng thời, bạn có thể thực hiện việc sửa code library ở bất kỳ project con nào, sau đó push lên và các project con kia chỉ việc cd vào thư mục librarypull về là được.

Thêm chút nữa

Có một lưu ý nhỏ là: khi ở các project con, library sẽ không ở master branch mà sẽ bị đẩy sang một temporary branch:

Do đó, nếu muốn sửa code thì trước hết ta phải checkout về master (git checkout master), sau đó mới tiến hành sửa code.

Source code

Toàn bộ source code mình để trên github:
SubModuleLibrary project
DemoSubModule project

Lập trình và hơn thế nữa

Spread the love
  •  
  •  
  •  
  •  
  •  

Leave a Reply

4 Comments on "git submodule và việc đồng bộ thư viện ở nhiều dự án con"

avatar
  Subscribe  
newest oldest most voted
Notify of
Nguyễn Hải Long
Guest

Hi bạn,
Cho mình hỏi sự khác nhau giữa submodule và subtree trong git.
Và nên sử dụng cái nào trong quản lý dự án?
Cám ơn bạn!

Nguyễn Hải Long
Guest

Cám ơn bạn nhé!
Mình hỏi thêm 1 vấn đề nữa, mình có 1 submodule, xong mình gửi cho 1 bạn khác cái submodule đó, rồi bạn đó clone về project của bạn đó.
Thì bạn đó có quyền chỉnh sửa cái submodule đó rồi push lên git không? Hay chỉ mình mới có quyền modify submodule đó?