Tham Khảo Git

 

book Chia Sẻ và Cập Nhật Dự Án

Git không tập trung dữ liệu mở một máy phục vụ như Subversion. Mà tất cả thao tác sẽ cập nhật dữ liệu ngay trên máy tính của bạn. Để cộng tác với người khác, bạn phải đẩy dữ liệu lên một máy phục vụ chung mà họ có quyền truy cập, và nhờ đó đồng bộ kho lưu trên máy bạn với kho lưu trên máy phục vụ. Không có sự khác biệt giữa máy khách và máy phục vụ dành cho Git, bởi vì kho lưu trữ ở máy khách đã đồng bộ với kho lưu trữ trên máy phục vụ.

Môt khi đã có kho lưu trữ Git, hoặc là bạn sẽ thiết lập máy của bạn thành một máy phục vụ sử dụng kho đó để chia sẻ, hoặc bạn sẽ tiến hành đồng bộ hoặc khảo sát sự khác biệt giữa kho của bạn với kho Git khác bằng hai thao tác đẩy và kéo.

Thao tác đẩy và kéo được tiến hành bất kỳ khi nào bạn có kết nối mạng với kho Git khác, trong khi đó thao tác xác nhận (commit) được tiến hành hoàn tòan ở địa phương.

Tóm tắt: bạn lấy các thông tin mới từ kho Git khác về máy của bạn bằng lệnh git fetch (thao tác kéo), và chia sẻ những thay đổi do bạn thực hiện bằng lệnh git push (thao tác đẩy)). Địa chỉ các kho Git của dự án được quản lý nhờ git remote.

docs   book git remote quản lý địa chỉ các kho git

Vì Git không dùng một máy phục vụ chung để lưu dữ liệu như Subversion, các kho lưu trữ Git bình đẳng nhau, nằm trên các máy khác nhau và nhiệm vụ của bạn là đồng bộ những kho này với nhau. Từ đó, nảy sinh ra ý phải quản lý các kho cùng với kết nối tới chúng, kể cả phân quyền (đọc với kho này, được ghi vào kho kia,...).

Các kho ở máy phục vụ khác nhau không chỉ được phân biệt bằng địa chỉ URL đầy đủ, mà còn có thể bằng một tên ngắn gọn mà bạn gán cho địa chỉ đó. Như vậy, việc sử dụng các kho sẽ dễ nhớ, đơn giản hơn rất nhiều. Bạn sử dụng lệnh git remote để quản lý danh sách các kho.

git remote liệt kê tên các kho đầu xa

Khi dùng không có tham số, lệnh git remote liệt kê các tên của các địa chỉ kho xa đã biết. Mặc định, địa chỉ kho đầu tiên khi bạn vừa thực hiện lệnh nhân bản một kho sẽ có tên 'origin' (gốc). Khi có thêm tham số -v, ngoài tên của kho thì địa chỉ của kho cũng được in ra.

$ git remote
origin
$ git remote -v
origin	git@github.com:github/git-reference.git (fetch)
origin	git@github.com:github/git-reference.git (push)

Ở ví dụ trên, địa chỉ kho được liệt kê hai lần, bởi vì Git phân biệt địa chỉ kho để kéo và đẩy.

git remote add thêm một kho đầu xa vào dự án

Ta có thể thêm nhiều địa chỉ kho khác nhau cho dự án, bằng lệnh git remote add [tên] [địa chỉ]. Ở đây, '[tên]' là do bạn chọn để gợi nhớ, đại diện cho địa chỉ của kho (thường dài dòng khó nhớ).

Lấy ví dụ, bạn muốn chia sẻ chương trình Hello World với mọi người bằng cách đẩy nó lên GitHub (dịch vụ khác cũng tương tự), trước hết bạn tạo dự án ở GitHub, có tên là hw. Địa chỉ kho mà dịch vụ GitHub cung cấp cho dự án là "git@github.com:schacon/hw.git" (trong đó, @schacon@ được thay bởi tên của bạn ở GitHub). Ta sẽ thêm địa chỉ kho này cho dự án, với tên kho là 'github':

$ git remote
$ git remote add github git@github.com:schacon/hw.git
$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)

Ở tên tên của kho được chọn là 'github', có lẽ là một tên gợi nhớ; thực tế thì cũng như các nhánh, bạn có thể chọn tên bất kỳ nào cho địa chỉ của kho.

git remote rm xóa một địa chỉ kho đầu xa

Lệnh git remote rm [tên kho] sẽ bỏ đi một kho không còn phù hợp với dự án (nếu bạn muốn giữ nguyên địa chỉ kho và đổi tên kho thì hãy dùng git remote rename

$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
$ git remote add origin git://github.com/pjhyett/hw.git
$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
origin	git://github.com/pjhyett/hw.git (fetch)
origin	git://github.com/pjhyett/hw.git (push)
$ git remote rm origin
$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)

git remote rename [tên-cũ] [tên-mới] đổi tên kho đầu xa

Nếu bạn muốn đổi tên hiện tại của một kho đầu xa mà không phải xóa và thêm vào lần nữa, bạn dùng lệnh git remote rename [tên-cũ] [tên-mới]

$ git remote add github git@github.com:schacon/hw.git
$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
$ git remote rename github origin
$ git remote -v
origin	git@github.com:schacon/hw.git (fetch)
origin	git@github.com:schacon/hw.git (push)

Tóm tắt: với git remote bạn xem được danh sách tên các kho xa cùng địa của kho. Lệnh git remote add dùng để thêm kho mới, còn git remote rm dùng để xóa đi.

git remote set-url cập nhật địa chỉ URL kho đầu xa

Lệnh git remote set-url dùng để cập nhật địa chỉ đầu xa

$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
origin	git://github.com/pjhyett/hw.git (fetch)
origin	git://github.com/pjhyett/hw.git (push)
$ git remote set-url origin git://github.com/github/git-reference.git
$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
origin	git://github.com/github/git-reference.git (fetch)
origin	git://github.com/github/git-reference.git (push)

Với trường hợp dưới đây, bạn có thể thêm địa chỉ đẩy khác khi kèm theo cờ --push để tách biệt hai kho đẩy và tải về.

$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
origin	git://github.com/github/git-reference.git (fetch)
origin	git://github.com/github/git-reference.git (push)
$ git remote set-url --push origin git://github.com/pjhyett/hw.git
$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
origin	git://github.com/github/git-reference.git (fetch)
origin	git://github.com/pjhyett/hw.git (push)

Thực chất, lệnh git remote set-url thực thi lệnh git config remote nhưng trả về kết quả nếu xảy ra lỗi còn lệnh git config remote không trả về kết quả nếu bạn gõ nhầm hoặc lệnh không thực hiện.

Chúng ta sẽ cập nhật kho đầu xa github nhưng ta dùng guhflub trong cả hai trường hợp.

$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
origin	git://github.com/github/git-reference.git (fetch)
origin	git://github.com/github/git-reference.git (push)
$ git config remote.guhflub git://github.com/mojombo/hw.git
$ git remote -v
github	git@github.com:schacon/hw.git (fetch)
github	git@github.com:schacon/hw.git (push)
origin	git://github.com/github/git-reference.git (fetch)
origin	git://github.com/github/git-reference.git (push)
$ git remote set-url guhflub git://github.com/mojombo/hw.git
fatal: No such remote 'guhflub'

Tóm tắt: bạn có thể cập nhật đường dẫn kho đầu xa với lệnh git remote set-url. Bạn cũng có thể tách riêng biệt địa chỉ tải về và địa chỉ đẩy.

docs   book git fetch tải về nhánh và dữ liệu mới từ kho đầu xa


docs   book git pull kéo về dữ liệu từ kho đầu xa và tích hợp vào nhánh hiện tại

Sau khi thêm kho xa, thì tự nhiên dẫn tới nhu cầu cập nhật dữ liệu ở nhánh xa về máy tính của bạn. Git có hai lệnh cho nhu cầu này: Lệnh git fetch sẽ giúp thông tin trên máy của bạn cập nhật so với nhánh xa, bằng cách tải thông tin từ kho xa về (chỉ tải những thông tin chưa có trên máy bạn) và đánh dấu để bạn biết bạn đã đồng bộ dữ liệu với nhánh nào trên kho xa. Cách này còn gọi là "nhánh xa", bởi vì sau khi cập nhật về, Git để nguyên đó mà không lấy ra và thay thế các nội dung đang có trong thư mục làm việc. Việc dùng git fetch giúp bạn kiểm tra các thay đổi, so sánh và thậm chí trộn các thay đổi xa với thư mục làm việc của bạn.

Lệnh thứ hai để đồng bộ là git pull. Thực ra, lệnh này là một cách gộp: đầu tiên, Git thi hành git fetch để cập nhật thông tin từ xa xuống máy, rồi ngay sau đó tiến hành trộn nhờ lệnh git merge (việc trộn này chỉ diễn ra với nhánh mà bạn đang làm việc). Một cách cá nhân, tác giả không thích lệnh này, bởi nó không thật sự an toàn, bởi tốt nhất là chỉ nên trộn sau khi đã kiểm tra, so sánh kỹ. Tuy nhiên, việc dùng git pull cũng có cái hay mà bạn có thể tìm hiểu thêm ở tài liệu chính thức.

Bây giờ, đi vào chi tiết. Giả sử các kho xa đã được thiết lập và bạn muốn kéo thông tin từ xa về máy: bạn sẽ dùng lệnh git fetch [tên kho]. Sau đó, bạn có thể trộn bằng git merge [tên kho]/[tên nhánh]. Chẳng hạn, khi đang thực hiện dự án Hello World, thấy có ai đó đã sửa đổi cho dự án này, và bạn muốn kéo các thay đổi của họ về máy, thì các lệnh sẽ dùng như sau:

$ git fetch github
remote: Counting objects: 4006, done.
remote: Compressing objects: 100% (1322/1322), done.
remote: Total 2783 (delta 1526), reused 2587 (delta 1387)
Receiving objects: 100% (2783/2783), 1.23 MiB | 10 KiB/s, done.
Resolving deltas: 100% (1526/1526), completed with 387 local objects.
From github.com:schacon/hw
   8e29b09..c7c5a10  master     -> github/master
   0709fdc..d4ccf73  c-langs    -> github/c-langs
   6684f82..ae06d2b  java       -> github/java
 * [new branch]      ada        -> github/ada
 * [new branch]      lisp       -> github/lisp

Thông tin ở trên cho biết, kể từ lần đồng bộ cuối cùng, đã có 5 nhánh được thêm hoặc cập nhật vào kho xa: hai nhánh 'ada' v 'lisp' là hoàn tòan mới, các nhánh còn lại 'master', 'c-langs' và 'java' được cập nhật.

Trong kết quả ở trên bạn thấy cách Git ánh xạ các nhánh với nhau. Ví dụ, nhánh xa 'remote' tương ứng với nhánh 'github/master' trên máy của bạn. Nhờ thế, để trộn nhánh xa 'master' với thư mục hiện tại, bạn chỉ việc dùng lệnh git merge github/master. Bạn cũng có thể xem những thay đổi diễn ra ở nhánh xa nhưng chưa được trộn vào nhánh 'master' của bạn bằng lệnh git log github/master ^master. Để ý là, nếu bạn dùng tên 'origin' cho nhánh xa thì thay vì 'github/master' như trong các ví dụ vừa rồi, bạn phải dùng origin/master instead. Ngoài ra, hầu hết các lệnh các tác dụng với nhánh địa phương cũng có thể dùng với nhánh xa.

Trường hợp có nhiều nhánh xa, ngoài việc chỉ định lấy thông tin từ một nhánh cụ thể bằng lệnh git fetch [tên kho] bạn có thể chỉ định Git cập nhật từ tất cả các nhánh bằng lệnh git fetch --all.

Tóm tắt: Dùng git fetch [tên kho] để đồng bộ dữ liệu từ kho ở xa đến kho của bạn, để lấy về những dữ liệu có ở xa mà chưa có trong thư mục làm việc, và sau đó bạn có thể so sánh, khảo sát và trộn các kết quả khi cần thiết.

docs   book git push đẩy dữ liệu mới lên kho đầu xa

Sau khi thực hiện một số thay đổi cho dự án, xác nhận thay đổi bằng lệnh git commit, bạn có thể chia sẻ thay đổi này với mọi người bằng cách đẩy cách kết quả lênh nhánh ở xa. Thao tác này ngược với việc kéo đã mô tả ở trên. Lệnh để thực hiện đẩy là git push [tên kho] [tên nhánh], sẽ chép nội dung nhánh hiện tại thành nhánh ở kho xa. Ví dụ, ta sẽ đẩy nhánh 'master' lên kho xa:

$ git push github master
Counting objects: 25, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (25/25), done.
Writing objects: 100% (25/25), 2.43 KiB, done.
Total 25 (delta 4), reused 0 (delta 0)
To git@github.com:schacon/hw.git
 * [new branch]      master -> master

Thật dễ dàng :) Sau khi đẩy như trên, một lập trình viên khác dễ dàng kéo mọi thay đổi mà bạn thực hiện về máy tính của họ.

Trong ví dụ tiếp sau, ta tiếp tục đẩy nhánh 'erlang', thay vì 'master' như trên.

$ git push github erlang
Counting objects: 7, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 652 bytes, done.
Total 6 (delta 1), reused 0 (delta 0)
To git@github.com:schacon/hw.git
 * [new branch]      erlang -> erlang

Sau lệnh trên, khi người khác nhân bản kho ở Github, hoặc kéo thông tin từ kho đó, họ sẽ thấy nhánh 'erlang' để khảo sát hoặc trộn. Ví dụ cho thấy, bạn có thể tạo ra nhánh bất kỳ và đẩy lên kho xa mà bạn có quyền ghi. Nếu nhánh chưa có trên kho, nhánh mới sẽ được tạo ra, còn không thì nhánh cũ sẽ được cập nhật.

Vấn đề lớn nhất mà bạn có thể gặp khi đẩy dữ liệu lên kho xa, là việc bạn và một người khác 'đồng thời' đẩy lên một nhánh của cùng một kho. Nếu bạn là người thực hiện sau một chút, thì Git không cho phép bạn ghi đè lên kết quả của người kia. Git sẽ dùng lệnh git log ở phía máy phục vụ để kiểm tra xem kho địa phương của bạn có quá hạn chưa; nếu đúng là quá hạn, Git từ chối và bạn phải kéo cập nhật từ kho xa về, trộn trước khi đẩy lên kho. Dưới đây là minh họa cho ý này:

$ git push github master
To git@github.com:schacon/hw.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:schacon/hw.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

Vì Git từ chối thay đổi mà bạn đẩy lên, bạn phải dùng git fetch github; git merge github/master rồi mới đẩy lên lần nữa.

Tóm tắt: Dùng git push [tên kho] [tên nhánh] để đẩy các thay đổi mà bạn thực hiện ở máy lên kho xa. Git sẽ xem xét trạng thái của nhánh ở kho xa và thực hiện chuyển dữ liệu nếu có thể. Trường hợp nhánh của bạn đã quá hạn (hay quá cũ) so với thông tin được xác nhận trên kho xa, Git từ chối và bạn phải thực hiện kéo các thông tin từ trên kho về máy để tiếp tục.

Kiểm Tra và So Sánh »