Sách “Pro Git v2” – Chương 2

Scott Chacon – Ben Straub – Dịch bởi http://elinux.vn

Chương 2: Vấn đề cơ bản về Git

Nếu bạn muốn đọc một chương duy nhất là có thể làm việc được với Git thì chính là chương này. Chương này trình bày những lệnh cơ bản nhất của Git cần để làm việc. Kết thúc chương, bạn có thể cấu hình và khởi tạo một kho chứa, bắt đầu và dừng quản lí phiên bản tệp tin, và stage and commit những thay đổi. Chúng tôi cũng sẽ trình bày cách làm thế nào để Git không quan tâm tới một tệp tin hoặc một nhóm các tệp, cách làm thế nào để loại bỏ lỗi nhanh và dễ dàng, cách làm thế nào để duyệt lịch sửa của một Dự án và nhìn những thay đổi giữa các lần commit, và cách làm thế nào để đẩy lên và kéo dữ liệu xuống từ các kho chứa trên mạng và internet.

Tạo Kho chứa Git

Có 02 cách để tạo kho chứa Git:

  1. Biến một thư mục chưa được kiểm soát phiên bản thành Kho chứa Git, hoặc
  2. Clone một kho chứa Git bất kì.

Tạo một Kho chứa từ thư mục

Nếu bạn có một thư mục Dự án mà chưa được kiểm soát phiên bản và bây giờ bạn muốn kiểm soát phiên bản bằng Git, đầu tiên bạn cần tới thư mục đó bằng cách chạy lệnh:

Với hệ điều hành Linux:

$ cd /home/user/my_project

Với hệ điều hành Mac:

$ cd /Users/user/my_project

Với hệ điều hành Windows:

$ cd /c/user/my_project

Sau đó, nhập lệnh:

$ git init

Lệnh này sẽ tạo ra một thư mục .git chứa tất cả các tệp tin cần thiết cho một Kho chứa. Lúc này, Dự án của bạn vẫn chưa được kiểm soát phiên bản.

(Xem ch10-git-internals.html để biết thêm thông tin về tệp nào chứa trong thư mục .git vừa mới được tạo ra)

Để bắt đầu kiểm soát phiên bản các tệp tin có sẵn trong thư mục sử dụng lệnh git add để kiểm soát và đưa nó vào trạng thái staged, tiếp theo là lệnh git commit để commit:

$ git add *.c
$ git add LICENSE
$ git commit -m 'initial project version'

Sau khi chạy các lệnh này, bạn đã có một Kho chứa Git với các tệp tin đã được kiểm soát phiên bản và một commit đầu tiên.

Clone một Kho chứa đã có sẵn

Nếu bạn muốn có một bản sao của một Kho chứa Git đã tồn tại — Ví dụ, một Dự án bạn muốn đóng góp cho nó — lệnh cần sử dụng là git clone. Nếu bạn đã quen thuộc với các VCS khác như Subversion, bạn sẽ thấy rằng lệnh là “clone” và không “checkout”. Đây là khác biệt quan trọng — thay cho việc lấy bản sao làm việc, Git sẽ nhận toàn bộ bản sao của tất cả các dữ liệu mà máy chủ có. Mọi phiên bản của các tệp tin trong Dự án sẽ được sao xuống máy tính của bạn khi chạy lệnh git clone. Trong trường hợp, nếu ổ đĩa của máy chủ của bạn bị lỗi, bạn có thể sử dụng gần như bất kì một bản sao nào ở một máy khách để khôi phục lại trạng thái của máy chủ ở thời điểm nó được sao chép (bạn có thể mất những thứ không được kiểm soát phiên bản, nhưng tất cả dữ liệu đã được kiểm soát phiên bản thì sẽ không bao giờ bị mất — xem ch04-git-on-the-server.html để biết chi tiết hơn).

Bạn clone một Kho chứa với lệnh git clone <url>. Ví dụ, bạn muốn clone một thư viện của Git tên nó là libgit2, bạn chạy lệnh:

$ git clone https://github.com/libgit2/libgit2

Lệnh này sẽ tạo một thư mục tên là libgit2, bên trong nó có một thư mục tên là .git, sao chép toàn bộ dữ liệu xuống máy tính của bạn và checkout phiên bản mới nhất cho bạn. Thư mục libgit2 vừa mới được tạo chứa các tệp tin của Dự án và cho phép sẵn sàng để làm việc với nó.

Nếu bạn muốn clone một Kho chứa vào một thư mục có tên tùy chọn mà không phải tên mặc định là libgit2 như trên, bạn chỉ rõ tên muốn đặt trong tham số (argument) của lệnh git clone như sau:

$ git clone https://github.com/libgit2/libgit2 mylibgit

Lệnh này tạo một thư mục có tên là mylibgit với nội dung giống hệt như với thư mục libgit2 ở trên.

Git có nhiều giao thức truyền dữ liệu khác nhau có thể sử dụng. Ví dụ trên sử dụng giao thức https://, nhưng bạn cũng có thể thấy git:// hoặc user@server:path/to/repo.git sử dụng giao thức SSH. Chương ch04-git-on-the-server.htmlsẽ giới thiệu toàn bộ các lựa chọn sẵn có mà máy chủ có thể dùng để truy cập Kho chứa Git của bạn và pros và cons.

Ghi những thay đổi tới Kho chứa

Bây giờ, bạn có một Kho chứa Git trên máy tính của mình và một bản checkout hoặc bản sao công việc phiên bản mới nhất của Dự án. Nhu cầu của bạn bây giờ là thay đổi các tệp tin và commit những thay đổi đó vào Kho chứa mỗi khi bạn nghĩ rằng cần lưu lại trạng thái ở thời điểm đó.

Nhớ rằng, mỗi tệp tin trong thư mục làm việc của bạn có thể ở một trong hai trạng thái tracked hoặc untracked. Các tệp tin ở trạng thái tracked là các tệp mà ở trong snapshot cuối cùng và chúng có thể đang unmodified, modified hoặc staged. Tóm lại, tệp tracked là các tệp mà Git biết về nó.

Tệp untracked là những thứ ngược lại — bất kì tệp tin nào trong thư mục làm việc không ở trong snapshot cuối cùng và không ở trong trạng thái stage. Khi bạn thực hiện clone một Kho chứa, tất cả các tệp tin trong Thư mục làm việc của bạn bây giờ sẽ ở trạng thái tracked và unmodified bởi vì Git vừa mới checkout chúng và bạn vẫn chưa thay đổi gì cả.

Khi bạn sửa tệp tin, chúng sẽ ở trạng thái modified. Bây giờ, bạn có thể stage chúng và sau đó commit tất cả những thay đổi đã được stage, chu trình cứ lặp lại như vậy.

Figure 1. Vòng đời trạng thái tệp tin trong Git.

Kiểm tra trạng thái các tệp tin của bạn

Công cụ để bạn xác định tệp tin nào đang ở trong trạng thái nào là lệnh git status. Nếu bạn chạy lệnh này ngay sau khi clone, bạn sẽ thấy như sau:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

Điều này nghĩa là bạn có một Thư mục làm việc trong sạch — hay nói cách khác là không có tệp tin tracked nào đã được thay đổi nội dung. Git cũng không thấy bất kì tệp untracked nào ở đây. Cuối cùng, lệnh này nói cho bạn biết bạn đang làm việc ở nhánh nào và nhắc cho bạn biết rằng nhánh đó tương ứng với nhánh nào trên máy chủ. Nhánh mặc định luôn là “master”, bây giờ bạn chưa cần tìm hiểu sâu về vấn đề này ở đây. Trong ch03-git-branching.html trình bày về nhánh sẽ giúp bạn hiểu rõ vấn đề này hơn. Ví dụ, thêm một tệp mới tên là README tới Dự án của bạn. Nếu tệp không có từ trước, và bạn chạy lệnh git status, bạn sẽ thấy nó ở trong phần untracked file như sau:

$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    README

nothing added to commit but untracked files present (use "git add" to track)

Bạn thấy rằng tệp README vừa mới tạo ở trạng thái untracked, bởi vì nó trong phần có tiêu đề là “Untracked files”. Untracked có nghĩa là Git thấy nó trong thư mục nhưng chưa có bất kì một snapshot (commit) nào của nó trong cơ sở dữ liệu; Git sẽ không chứa nó trong commit tiếp theo trừ khi bạn tracked nó bằng lệnh git add. Điều này rất có ý nghĩa trong trường hợp bạn không muốn chứa các tệp binary hoặc các tệp mà không muốn chứa trong snapshot. Nếu bạn muốn bắt đầu kiểm soát phiên bản nó, cùng tìm hiểu phần tiếp theo.

Kiểm soát phiên bản tệp mới

Để bắt đầu kiểm soát phiên bản tệp mới, sử dụng lệnh git add. Ví dụ, để kiểm soát tệp README, chạy lệnh sau:

$ git add README

Bây giờ, nếu bạn chạy lại lệnh git status, bạn sẽ thấy rằng nó đã được tracked và staged, sẵn sàng cho commit:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README

Có thể nói rằng nó đã ở trạng thái staged bởi vì nó ở dưới mục có tiêu đề là “Changes to be committed”. Nếu bây giờ bạn commit thì nội dung của tệp sẽ ở trong snapshot. Lệnh git add sử dụng đường dẫn của tệp hoặc thư mục; nếu nó là một thư muc, lệnh sẽ thêm toàn bộ các tệp trong thư mục đó.

Stage các tệp tin đã sửa

Bây giờ thay đổi một tệp đã được kiểm soát phiên bản. Nếu bạn thay đổi một tệp đã được kiểm soát phiên bản tên là CONTRIBUTING.md và sau đó chạy lệnh git status, bạn sẽ thấy kết quả như sau:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

CONTRIBUTING.md xuất hiện trong phần có tên là “Changes not staged for commit” — nó có nghĩa rằng một tệp đã được kiểm soát phiên bản và nội dung của nó đã thay đổi so với snapshot mới nhất, nhưng nó vẫn chưa được stage. Để stage nó, chạy lệnh git addgit add là lệnh có nhiều mục đích — nó có thể sử dụng để bắt đầu kiểm soát phiên bản một tệp mới, để stage tệp tin, và làm những việc khác như đánh dấu các tệp xung đột trong quá trình trộn đã được khắc phục. Sau khi đã stage nó, chạy lại lệnh git status, ta được như sau:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Cả hai tệp bây giờ đã được stage và sẵn sàng cho commit. Ở thời điểm bây giờ, giả sử bạn nhớ rằng bạn muốn sửa nội dung của CONTRIBUTING.md trước khi bạn commit nó. Bạn mở nó lại và sửa nó như ý muốn, và sửa xong giờ bạn đã sẵn sàng để commit nó. Bây giờ, ta chạy lại lệnh git status sẽ thấy như sau:

$ vim CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Chuyện gì xảy ra vậy? CONTRIBUTING.md có cả ở cả 2 trạng thái là unstaged và staged. Nếu bây giờ bạn commit thì nội dung tệp tin tại thời điểm chạy lệnh git add sẽ ở trong snapshot chứ không phải phiên bản bạn sửa cuối cùng. Nếu bạn sửa một tệp sau khi bạn chạy lệnh git add thì bạn phải chạy lại lệnh git add để stage phiên bản cuối cùng của file.

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Trạng thái ngắn gọn

Kết quả của chạy lệnh git status chi tiết, nhưng nó cũng quá dài dòng. Git cho phép hiển thị status ngắn gọn hơn bằng lệnh git status -s hoặc git status --short như sau:

$ git status -s
 M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt

Các tệp không được kiểm soát phiên bản có dấu ?? ở trước, các tệp mới mà đã được stage thì phía trước có dấu A, các tệp đã sửa có dấu M và vân vân. Có hai cột được sử dụng: cột bên trái cùng là trạng thái của vùng staging và cột bên phải là trạng thái của thư mục làm việc. Ví dụ, trong trạng thái ngắn gọn ở trên, README được sửa trong thư mục làm việc nhưng vẫn chưa được stage, trong khi lib/simplegit.rb đã được sửa và được stage. Rakefile đã được sửa, được stage và sửa lại.

Bỏ qua các tệp không kiểm soát phiên bản

Thông thường, bạn sẽ có một lớp các tệp bạn không muốn Git tự động thêm hoặc thậm chí là hiển thị trạng thái untracked. Thường thì đây là các tệp tự động được tạo ra như log file hoặc các tệp được tạo ra trong quá trình build. Trong các trường hợp như thế, bạn có thể tạo một tệp chứa pattern có tên là .gitignore. Đây là một ví dụ về .gitignore:

$ cat .gitignore
*.[oa]
*~

Dòng đầu tiên nói với Git bỏ qua bất kì tệp nào kết thúc với “.o” hoặc “.a” — đây là các object file và archive file được tạo ra trong quá trình build. Dòng thứ hai nói với Git bỏ qua tất cả các tệp mà tên của nó kết thúc với dấu ~, đây là kí tự được sử dụng bởi các Bộ soạn thảo như Emacs để chỉ thị đó là tệp tạm thời. Việc sử dụng .gitignore cho Kho chứa mới trước khi bạn bắt đầu làm việc là một ý tưởng hay để bạn không commit những tệp bạn không muốn nó có trong Kho chứa Git.

Luật cho pattern của .gitignore như sau:

  • Các dòng trống hoặc các dòng bắt đầu bằng kí tự # sẽ bị bỏ qua.
  • Các pattern theo chuẩn glob được sử dụng
  • Có thể bắt đầu pattern với một kí tự / có nghĩa là chỉ tác dụng với thư mục hiện tại chứ không tác dụng với thư mục con.
  • Có thể đặt dấu forward slash (/) ở cuối của pattern để chỉ rõ đó là một thư mục.
  • Bắt đầu pattern bằng dấu chấm than (!) có ý nghĩa ngược lại với pattern gốc.

Glob pattern giống với regular expression của shell. Một kí tự * có nghĩa là không hoặc có bất kì kí tự nào; [abc]' có nghĩa là bất kì kí tự nào bên trong ngặc vuông (trong trường hợp này là a,b, hoặc c); một dấu hỏi `? có nghĩa là một kí tự bất kì nào đó; và dấu ngoặc vuông mà nội dung bên trong nó cách nhau bởi dấu gạch giữa thì có nghĩa là bất kì kí tự nào giữa chúng, ví dụ [0-9] có nghĩa là bất kì kí tự nào từ 0 tới 9. Bạn cũng có thể sử dụng hai dấu sao để chỉ thư muc lồng nhau, ví dụ a/**/z có thể là a/za/b/za/b/c/z, và vân vân.

Đây là một ví dụ khác về .gitignore:

# bỏ qua tất cả các tệp kết thúc với .a
*.a

# kiểm soát phiên bản lib.a kể cả khi đã bỏ qua tất cả các tệp kết thúc là .a ở trên
!lib.a

# bỏ qua tệp TODO trong thư mục hiện tại, các tệp TODO trong thư mục con vẫn track bình thường
/TODO

# bỏ qua tất cả các tệp trong thư mục có tên là build
build/

# bỏ qua doc/notes.txt, những doc/server/arch.txt thì không
doc/*.txt

# bỏ qua tất cả các tệp .pdf trong thư mục doc/ và trong các thư mục con của nó
doc/**/*.pdf
Github có rất nhiều các tệp .gitignore cho nhiều loại Dự án và ngôn ngữ tại https://github.com/github/gitignore , có thể dùng tham khảo cho Dự án của bạn.
Trong trường hợp đơn giản, một Kho chứa có thể chỉ có một tệp .gitignore trong thư mục chính, tepẹ này sẽ được áp dụng tới toàn bộ kho chứa. Mặc dù vậy, cũng có thể có các tệp .gitignore ở trong các thư mục con. Các tệp .gitignore này chỉ được áp dụng với các tệp trong thư mục nó được đặt. (Mã nguồn của Linux kernel có tới 206 file .gitignore)Phạm vi cuốn sách này không đi chi tiết về sử dụng nhiều tệp .gitignore; để tìm hiểu chi tiết hơn sử dụng lệnh man gitignore.

Xem nhưng thay đổi Staged và Unstaged

Nếu lệnh git status cung cấp thông tin quá mơ hồ cho bạn — bạn muốn biết chính xác bạn đã thay đổi cái gì chứ không phải chỉ là tệp đã thay đổi nội dụng — để làm điều này sử dụng lệnh git diff. Chúng tôi sẽ trình bày chi tiết về lệnh git diff sau, nhưng bạn sẽ sử dụng nó thường xuyên để trả lời hai câu hỏi: một là, cái bạn đã thay đổi nhưng chưa stage là gì? hai là, cái bạn đã stage nhưng chưa commit? Lệnh git status đã trả lời câu hỏi này nhưng chỉ chung chung bằng cách nêu tên tệp, nhưng lệnh git diff sẽ cho bạn biết chính xác dòng nào được thêm và dòng nào đã bị xóa.

Tiếp tục sử dụng hai tệp README và CONTRIBUTING.md làm ví dụ. Sửa và stage README và sau đó sửa CONTRIBUTING.mdmà không stage. Nếu bạn chạy lệnh git status, bạn sẽ có kết quả như sau:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Để xem cái gì bạn đã thay đổi mà chưa stage, chạy lệnh git diff với không tham số như sau:

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's

Lệnh này so sánh nội dung ở trong Thư mục làm việc với nội dung trong vùng staging area. Kết quả cho bạn biết rằng những thay đổi bạn thực hiện vẫn chưa được stage.

Nếu bạn muốn xem cái bạn đã stage nhưng chưa commit, bạn sử dụng lệnh git diff --staged. Lệnh này sẽ so sánh nội dung trong vùng stagging với commit mới nhất:

$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project

Ta thấy rằng, lệnh git diff tự nó không hiện ra toàn bộ những thay đổi được thực hiện kể từ lần commit cuối cùng — chỉ có những thay đổi vẫn chưa được stage. Nếu bạn đã stage tất cả những thay đổi, thì lệnh git diff sẽ không hiện ra nội dung gì.

Ví dụ khác, nếu bạn stage tệp CONTRIBUTING.md và sau đó sửa nó, bạn có thể sử dụng lệnh git diff để xem những thay đổi mà đã được stage và cả những thay đổi chưa được stage. Ví dụ, bây giờ thư mục làm việc của bạn như sau:

$ git add CONTRIBUTING.md
$ echo '# test line' >> CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   CONTRIBUTING.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Bây giờ bạn có thể sử dụng lệnh git diff để xem cái gì vẫn chưa được stage.

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 643e24f..87f08c8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -119,3 +119,4 @@ at the
 ## Starter Projects

 See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
+# test line

và lệnh git dif --cached để xem cái bạn đã stage (hai option --staged và --cached giống nhau)

$ git diff --cached
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's
Git Diff trong các công cụ ngoàiChúng ta sẽ tiếp tục sử dụng lệnh git diff theo các cách khác nhau trong phần còn lại của cuốn sách này. Có thể xem những thay đổi bằng các công cụ đồ họa hoặc các phần mềm khác. Thay cho việc chạy lệnh git diff bạn chạy lệnh git difftool, thì những thay đổi khi này có thể đọc bằng các phần mềm khác như emerge, vimdiff,…​(kể cả các phần mềm thương mại). Chạy lệnh git difftool --tool-help để xem thêm cách sử dụng.

Commit những thay đổi của bạn

Bây giờ, vùng staging area đã như bạn mong muốn, bạn có thể commit. Nhớ rằng bất kì cái gì vẫn chưa được stage (tức là chưa ở trong vùng staging) — bất kì tệp bạn tạo hoặc sửa mà chưa chạy lệnh git add thì sẽ không được commit. Chúng sẽ vẫn chỉ ở trạng thái modified trên ổ đĩa của bạn mà thôi. Trong trường hợp này, trước khi commit, bạn nên chạy lại lệnh git status để xem lại để sẵn sàng cho commit. Cách đơn giản nhất để commit là dùng lệnh git commit:

$ git commit

Lệnh này sẽ khởi động Trình soạn thảo mặc định trên máy tính của bạn (Trình soạn thảo mặc định được thiết lập bằng biến EDITOR — thường là vim hoặc emacs, bạn có thể cấu hình bất kì Trình soạn thảo nào mà mình muốn sử dụng lệnh git config --global core.editor giống như trong ch01-getting-started.html).

Trong Trình soạn thảo sẽ hiển thị đoạn nội dung như sau (ví dụ này đang dùng Trình soạn thảo là Vim):

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	new file:   README
#	modified:   CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C

Bạn có thể thấy rằng nội dung Thông điệp mặc định chứa đầu ra của lệnh git status đã bị comment và trên cùng có một dòng trống. Bạn có thể xóa các comment có sẵn này và nhập thông điệp của mình, hoặc bạn có thể cứ để đó để sau này giúp bạn nhớ cái mà bạn đang commit. (Nếu bạn muốn thay phần nội dung là đầu ra của lệnh git status bằng đầu ra của lệnh git diff thì sử dụng option -v như sau git commit -v.

Bạn cũng có thể nhập luôn thông điệp mà không cần nhập qua Trình soạn thảo như trên bằng sử dụng cờ -m, như sau:

$ git commit -m "Story 182: Fix benchmarks for speed"
[master 463dc4f] Story 182: Fix benchmarks for speed
 2 files changed, 2 insertions(+)
 create mode 100644 README

Bây giờ bạn đã tạo commit đầu tiên! Bạn có thể thấy rằng kết quả của lệnh commit sẽ cho bạn biết các thông tin: Nhánh nào bạn lưu commit (master), giá trị SHA-1 checksum của commit đó (trường hợp này là 463dc4f), bao nhiêu tệp đã thay đổi, và thống kê số dòng được thêm và bị xóa.

Nhớ rằng, commit chỉ sử dụng những nội dung trong vùng staging (tức là đã được staged). Bất kì cái gì mà chưa được stage thì vẫn ở trong trạng thái modified. Mỗi một lần commit tức là bạn đã lưu trạng thái của Dự án ở thời điểm đó, bất kì thời điểm sau này bạn có thể khôi phục lại trạng thái commit đó hoặc dùng nó để so sánh với các commit khác.

Bỏ qua bước stage

Mặc dù, dữ liệu bạn muốn commit phải chuyển sang vùng staging area, nhưng đôi khi điều đó gây phiền phức. Nếu bạn muốn bỏ qua việc phải đưa dữ liệu vào vùng staging are, mà commit luôn những thay đổi, git cung cấp cách làm việc đó bằng sử dụng cờ -a trong lệnh git commit như sau:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'added new benchmarks'
[master 83e38c7] added new benchmarks
 1 file changed, 5 insertions(+), 0 deletions(-)

Ta thấy răng không cần phải chạy lệnh git add trước khi commit. Bởi vì cờ -a có nghĩa là chứa toàn bộ các tệp thay đổi. Chức năng này thuận tiện, nhưng cần thận vì đôi khi nó làm cho chứa những thay đổi không mong muốn mà lại có trong commit.

Xóa bỏ các tệp

Để xóa một tệp tin từ Git, bạn phải xóa nó khỏi tracked files (nói chính xác hơn là xóa nó khỏi vùng staging area) và sau đó commit. Lệnh git rm thực hiện công việc đó, và lệnh này cũng xóa tệp khỏi Thư mục làm việc, bởi vậy bạn sẽ không nhìn thấy nó trong mục untracked file nữa.

Nếu bạn chỉ xóa tệp khỏi Thư mục làm việc như với tệp thông thường (tệp không được kiểm soát phiên bản bởi Git), khi chạy lệnh git status nó sẽ hiển thị trong mục “Changes not staged for commit”:

$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    PROJECTS.md

no changes added to commit (use "git add" and/or "git commit -a")

Sau đó, nếu bạn chạy lệnh git rm thì tệp đã xóa sẽ được cập nhật vào trong vùng staging area.

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    PROJECTS.md

Lần commit tiếp theo, tệp này sẽ biến mất và không được kiểm soát phiên bản nữa.

Trường hợp bạn sửa tệp và đã chuyển nó vào vùng staging area, thì bạn phải xóa nó bằng cờ -f. Đây là cách an toàn của Git để ngăn chặn xóa nhầm dữ liệu vẫn chưa được commit, bởi vì xóa dữ liệu chưa commit thì không thể khôi phục được.

Trường hợp nữa là, bạn muốn giữ tệp trong Thư mục làm việc nhưng xóa nó khỏi staging area. Hay nói cách khác, bạn muốn tệp đang được kiểm soát phiên bản trở thành không được kiểm soát. Chức năng này hữu ích trong trường hợp bạn không muốn kiểm soát phiên bản một tệp nào đó nhưng lại quên thêm nó vào .gitignore. Để thực hiện chức năng này thêm --cached vào lệnh git rm như ví dụ sau:

$ git rm --cached README

Bạn có thể dùng tên tệp, tên thư mục hoặc glob pattern đối với lệnh git rm. Giống như ví dụ sau:

$ git rm log/\*.log

Chú ý, dấu backslash (\) ở phía trước dấu *. Điều này là rất cần thiết vì Git thực hiện khai triển tên tệp theo cách của riêng nó ngoài thực hiện khai triển tên tệp theo shell. Lệnh này xóa toàn bộ các tệp có phần mở rộng là .log trong thư mục log/. Hoặc, bạn có thể làm gì đó giống như sau:

$ git rm \*~

Lệnh này xóa bỏ toàn bộ các tệp mà tên của nó kết thúc với kí tự ~.

Di chuyển các tệp tin

Không giống như các VCS khác, Git không kiểm soát phiên bản sự di chuyển của tệp tin. Nếu bạn đổi tên một tệp tin trong Git, sẽ không có dự liệu nào được lưu trong Git nói rằng bạn đã đổi tên tệp. Mặc dù vậy, Git khá thông minh trong việc nhận ra điều đó.

Nếu bạn muốn đổi tên một tệp trong Git, bạn có thể làm như sau:

$ git mv file_from file_to

Với lệnh trên thì Git coi nó như là đổi tên tệp:

$ git mv README.md README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Lệnh trên tương đương với:

$ mv README.md README
$ git rm README.md
$ git add README

Git ngấm ngầm hiểu rằng đây chính là đổi tên tệp, vậy không quan trọng là bạn đổi tên tệp theo cách nào. Chỉ có sự khác biệt là thay vì một lệnh thì phải chạy tới 3 lệnh để thực hiện — đây là chức năng thuận tiện.

Xem lịch sử commit

Sau khi bạn đã tạo vài commits, hoặc bạn clone một kho chứa có sẵn nhiều commit, bạn sẽ muốn nhìn lại xem những gì đã được thực hiện trước đó. Công cụ đơn giản và mạnh nhất đó là lệnh git log.

Ví dụ dưới sử dụng một Dự án rất đơn giản tên là “simplefit”. Để lấy Dự án về máy, chạy lệnh:

$ git clone https://github.com/schacon/simplegit-progit

Khi bạn chạy lệnh git log trong Dự án này, bạn sẽ có được kết quả như sau:

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

Mặc định, lệnh với không tham số, git log sẽ liệt kê ra các commit được thực hiện theo thứ tự mới nhất được liệt kê trên cùng. Ta thấy rằng, lệnh này liệt kê mỗi commit có một giá trị SHA-1, tên và địa chỉ email của tác giả, dữ liệu và thông điệp khi commit.

Lệnh git log có nhiều cờ cho phép bạn tìm kiếm thông tin dễ dàng hơn. Sau đây là một vài cờ phổ biến.

Một trong những cờ hữu dụng hơn cả là -p hoặc --patch, hiển thị sự khác nhau giữa các commit. Ta cũng có thể giới hạn số lượng nội dung được hiển thị, ví dụ sử dụng -2 chỉ hiển thị 2 commit mới nhất:

$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
 spec = Gem::Specification.new do |s|
     s.platform  =   Gem::Platform::RUBY
     s.name      =   "simplegit"
-    s.version   =   "0.1.0"
+    s.version   =   "0.1.1"
     s.author    =   "Scott Chacon"
     s.email     =   "schacon@gee-mail.com"
     s.summary   =   "A simple gem for using Git in Ruby code."

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
     end

 end
-
-if $0 == __FILE__
-  git = SimpleGit.new
-  puts git.show
-end

Cờ này hữu ích trong xem những người hợp tác với mình trên Dự án đó sửa (thêm, bớt) cái gì. Ta cũng có thể sử dụng các cờ thống kê tổng hợp với lệnh git log. Ví dụ, nếu bạn muốn xem thống kê tổng hợp cho một commit nào đó, sử dụng --stat:

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

 Rakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

 lib/simplegit.rb | 5 -----
 1 file changed, 5 deletions(-)

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

 README           |  6 ++++++
 Rakefile         | 23 +++++++++++++++++++++++
 lib/simplegit.rb | 25 +++++++++++++++++++++++++
 3 files changed, 54 insertions(+)

Bạn có thể thấy rằng, --stat sẽ cho thông tin về danh sách các tệp đã bị sửa, bao nhiêu tệp đã thay đổi, bao nhiêu dòng trong tệp đó được thêm vào và bị xóa bỏ đi. Cuối cùng là thông tin tổng hợp về commit đó.

Cờ khác cũng rất hữu ích là --pretty. Nó dùng để thay đổi cách hiển thị đầu ra của lệnh git log khác với định dạng mặc định như trên. Giá trị oneline của --pretty giúp in thông tin mỗi commit chỉ trong một dòng, nó hữu ích đối với trường hợp hiển thị nhiều commit một lúc. Ngoài ra, shortfull và fuller hiển thị đầu ra với định dạng tương đối giống nhau nhưng chỉ khác là thông tin chúng mang lại khác nhau theo đúng nghĩa của từ đó.

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

Cờ thú vị nhất là format cho phép bạn chỉ rõ định dạng hiển thị thông tin theo ý mình. Nó đặc biệt hữu ích khi khi bạn tạo nội dung cho machine parsing — bởi vì bạn là người chỉ rõ định dạng, nên bạn sẽ biết được nó không bị thay đổi cùng với các cập nhật sau này của Git:

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit

Bảng Những lựa chọn hữu ích cho git log --pretty=format bên dưới liệt kê một vài lựa chọn mà lệnh git log --pretty=format:"" sử dụng.

Lựa chọnChức năng
%HMã hash của commit
%hMã hash ngắn gọn của commit
%TMã hash dạng cây
%tMã hash ngắn gọn dạng cây
%PMã hash gốc
%pMã hash gốc ngắn gọn
%anTên tác giả
%aeĐịa chỉ thư điện tử (email) của tác giả
%adNgày tác giả (định dạng tương tự như –date=option)
%arNgày tác giả, tương đối
%cnTên của Committer
%ceĐịa chỉ email của Committer
%cdNgày Committer
%crNgày Committer, tương đối
%sChủ đề

Bạn có thể đang băn khoăn về sự khác nhau giữa tác giả và committer. Tác giả là người khởi tạo công việc, còn committer thì là người cuối cùng áp dụng công việc đó. Cụ thể, nếu bạn gửi một patch (bản vá) tới một Dự án và một trong các thành viên chính của dự án sử dụng patch đó, thì cả hai cùng có công — bạn là tác giả, còn thành viên chính kia chính là commiter. Chúng tôi sẽ trình bày kỹ hơn sự khác biệt này trong ch05-distributed-git.html.

Ngoài hai cờ oneline và format còn có lưa chọn rất hữu ích dành cho nó là --graph. Lựa chọn này hiển thị thêm một biểu đồ về nhánh và lịch sử trộn:

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*  11d191e Merge branch 'defunkt' into local

Thông tin kiểu như thế này rất thú vị đối với chương sau khi nói về nhánh và trộn.

Đây chỉ là các lựa chọn định dạng đầu ra đơn giản cho lệnh git log — còn rất nhiều định dạng khác. Các lựa chọn chung dành cho git log liệt kê các lựa chọn chúng tôi đã trình bày.

Lựa chọnChức năng
-pHiển thị bản vá cho mỗi commit.
--statHiển thị thống kê các tệp đã sửa cho mỗi commit.
--shortstatChỉ hiển thị dòng đã thay đổi/thêm/xóa với –stat.
--name-onlyHiển thị danh sách các tệp đã sửa sau thông tin commit.
--name-statusHiển thị danh sách các tệp với thông tin thêm/sửa/xóa.
--abbrev-commitChỉ hiển thị vài kí tự đầu tiên của SHA-1 checksum.
--relative-dateHiển thị ngày theo định dạng tương đối (ví dụ, “2 tuần trước”).
--graphHiển thị thêm biểu đồ ASCII về nhánh và lịch sử trộn.
--prettyHiển thị commit theo nhiều định dạng khác nhau. Gồm oneline, short, full, fuller, and format (Cho phép hiển thị đầu ra theo cách riêng của mình).
--onelineCùng chức năng với --pretty=oneline --abbrev-commit.

Giới hạn thông tin đầu ra của Log

Ngoài các lựa chọn cho điều chỉnh định dạng thông tin đầu ra, git log có các lựa chọn cho giới hạn thông tin đầu ra — nghĩa là, các lựa chọn cho phép chỉ hiển thị một phần thông tin. Bạn đã thực sự thấy một lựa chọn kiểu như vậy — lựa chọn -2 chỉ hiện thị 2 commit mới nhất. Thực tế, lựa chọn cho phép hiển thị số commit bất kì -<n>, trong đó n là số nguyên hiển thị n commit mới nhất. Trong thực tế, thường không sử dụng lựa chọn này, vì Git mặt định đã hiển thị thông tin theo trang, bạn chỉ thấy một trang tại một thời điểm.

Mặc dù vậy, những lựa chọn giới hạn về mặt thời gian như --since và --until lại rất hữu ích. Ví dụ, lệnh sau hiển thị các commit được thực hiện 2 tuần gần nhất:

$ git log --since=2.weeks

Lệnh này làm việc với nhiều định dạng — bạn có thể chỉ rõ ngày cụ thể như "2008-01-15", hoặc ngày tương đối như "2 years 1 day 3 minutes ago".

Bạn cũng có thể lọc theo thông tin mà bạn quan tâm. Như --author cho phép bạn lọc theo tên tác giả, và --grep cho phép bạn tìm kiếm theo từ khóa (keyword) trong thông điệp commit (commit messages).

Bạn có thể dùng nhiều lần --author và --grep, các lựa chọn này sẽ làm cho đầu ra chỉ hiển thị các commit phù hợp với bất kì --author nào và bất kì --grep patterns; Mặc dầu vậy, nếu sử dụng thêm --all-match thì đầu ra sẽ chỉ hiển thị các commit mà phù hợp với tất cả các --grep patterns.

Bộ lọc hữu ích khác là -S, lựa chọn này dùng một string và chỉ hiển thị các commit thay đổi số lần xuất hiện của string đó. Ví dụ, nếu bạn muốn tìm commit cuối cùng mà commit đó thêm hoặc xóa tham chiếu với một hàm, bạn có thể sử dụng:

$ git log -S tên_hàm

Lựa chọn hữu ích cuối cùng là truyền cho git log một bộ lọc là một đường dẫn. Nếu bạn chỉ rõ một thư mục hoặc tên tệp, lựa chọn này cho phép chỉ hiển thị các commit mà có thay đổi tới những tệp này. Đây luôn là lựa chọn dùng sau cùng và thường được đặt trước dấu double dash (--) để chia đường dẫn với các lựa chọn khác.

Trong Những lựa chọn để lọc thông tin đầu ra của lệnh git log chúng tôi liệt kê những lựa chọn vừa trình bày trên và một vài lựa chọn cho bạn tham chiếu khi cần.

Lựa chọnMô tả
-<n>Chỉ hiển thị n commit cuối cùng
--since--afterChỉ hiển thị các commit sau ngày này
--until--beforechỉ hiển thị các commit trước ngày này.
--authorChỉ hiển thị các commit có tác giả phù hợp với pattern.
--committerchỉ hiển thị các commit mà có committer phù hợp với pattern.
--grepChỉ hiển thị các commit mà thông điệp commit của nó chứa string.
-Schỉ hiển thị các commit mà thêm hoặc xóa code phù hợp với string.

Ví dụ, nếu bạn muốn xem commit nào sửa test files trong lịch sử mã nguồn Git mà được commit bởi Junio Hamano trong tháng 10 năm 2008 và nó không phải là commit trộn (merge commit), bạn chạy lệnh sau:

$ git log --pretty="%h - %s" --author='Junio C Hamano' --since="2008-10-01" \
   --before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch

Trong số gần 40,000 commits trong lịch sử của mã nguồn Git, lệnh này cho đầu ra là 6 commit phù hợp với yêu cầu.

Ngăn chặn hiển thị các commit trộn (merge commit)Phụ thuộc vào Quy trình làm việc (workflow) được sử dụng trong kho chứa của bạn, có thể có các commit trong lịch sử của bạn chỉ là commit trộn, thông thường chúng không có thông tin. Để ngăn chặn hiển thị các commit trộn thì sử dụng cờ --no-merges.

Undoing việc gì đó

Bây giờ, bạn muốn undo một công việc nào đó. Phần này, sẽ trình bày một vài công cụ giúp bạn undo. Nhưng không phải lúc nào cũng có thể undo được những thay đổi bạn đã làm. Đây là một trong số những lĩnh vực mà Git sẽ làm mất công việc của bạn nếu bạn làm sai.

Một trong những undo phổ biến là khi bạn commit quá sớm và có thể quên thêm các tệp, hoặc muốn ghi lại thông điệp cho commit. Nếu bạn muốn làm lại commit đó, thực hiện các công việc bạn đã quên, stage chúng và commit lại sử dụng lựa chọn --amend:

$ git commit --amend

Lệnh này sẽ lấy vùng staging area và sử dụng nó cho commit. Nếu bạn không thay đổi gì so với commit cuối cùng (ví dụ, bạn chạy ngay lệnh này sau khi bạn vừa mới commit), thì snapshot sẽ giống nhau và bạn chỉ thay đổi mỗi thông điệp.

Khi bạn chạy lệnh trên, cửa sổ cho phép bạn nhập thông điệp hiện ra, nội dung ban đầu của nó chính là thông điệp của commit ngay trước đó bạn vừa thực hiện, bạn nhập thông điệp mới, và thông điệp này sẽ ghi đè thông điệp trước đó.

Nếu bạn commit và sau đó nhận ra là mình quên thực hiện thay đổi trong một tệp mà bạn muốn thêm vào commit này, bạn làm như sau:

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

Thì commit sau sẽ thay thế cho commit ngay trước đó. Kết quả là, 03 lệnh trên chỉ có duy nhất một commit với nội dung là có cả forgotten_file, nhưng thông điệp vẫn là “initial commit“.

Quan trọng bạn phải hiểu rằng khi bạn sửa commit vừa mới thực hiện, bạn sẽ không thực hiện quá nhiều thay đổi như là thay thế toàn bộ bằng một commit mới mà commit cũ không liên quan gì. Khi thực hiện điều này thì commit mà bị sửa sẽ được Git coi như chưa bao giờ xảy ra và nó sẽ không tồn tại trong lịch sử.Giá trị hiển nhiên của việc sửa commit là làm cho commit của bạn chuyên nghiệp hơn, tránh trường hợp có các commit với thông điệp 'Ô, quên thêm một tệp' hoặc commit mà chỉ sửa những lỗi nhỏ (như dấu chấm phảy, lỗi đánh máy,…​)

Unstaging tệp đã Staged

Tiếp theo, tìm hiểu cách làm thế nào làm việc với vùng staging area và Thư mục làm việc khi chúng thay đổi. Tiện lợi là ở chỗ, thông tin đầu ra của lệnh git status có phần nhắc nhở bạn làm thế nào để undo những thay đổi. Ví dụ, xét khi bạn đã thay đổi 02 tệp và muốn commit chúng riêng, như bạn nhỡ chạy lệnh git add * và stage cả hai. Giờ làm thế nào để unstage một trong số chúng.

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

Ngay bên dưới dòng 'Changes to be committed', Nó nói rằng sử dụng git reset HEAD <file>... để unstage. Vậy, sử dụng lời khuyên đó, ta thử unstage tệp CONTRIBUTING.md:

$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M	CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Lệnh này hơi lạ, nhưng nó làm việc tốt. Ta thấy, tệp CONTRIBUTING.md đã sửa những lại thấy rằng nó đang unstaged.

Đúng là lệnh git reset là một lệnh nguy hiểm, đặc biệt nếu bạn sử dụng nó với cờ --hard.

Để biết thêm về lệnh git reset và muốn làm chủ nó. Vui lòng xem tại ch07-git-tools.html.

Đưa các tệp ở trạng thái modified về trạng thái unmodified

Bây giờ, bạn nhận ra rằng bạn lại không muốn giữ những thay đổi đã thực hiện ở tệp CONTRIBUTING.md. Có thể dễ dàng unmodify (tức là, đưa nó về trạng thái mà trước khi tiến hành thay đổi nó, trạng thái mà nó ở commit gần nhất). May mắn là, lệnh git status cũng cho ta biết phải làm thế nào. Trong ví dụ vừa làm trên, thông tin ra cho vùng unstaged area như sau:

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Ta thấy rằng, nó chỉ cho ta cách làm thế nào để loại bỏ những thay đổi đã thực hiện. Thử làm theo:

$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Ta thấy rằng, những thay đổi đã bị loại bỏ.

Lệnh git checkout -- <file> là một lệnh nguy hiển. Bất kì thay đổi bạn đã làm với tệp đó là không lấy lại được. Đừng sử dụng lệnh này trừ trường hộp bạn biết chắc rằng bạn không cần tệp nữa.

Nếu bạn muốn giữ những thay đổi đã làm nhưng lại không muốn sử dụng nó ngay bây giờ, stashing và phân nhánh là lĩnh vực cần tìm hiểu tại ch03-git-branching.html.

Nhớ rằng, mọi thứ đã được commit trong Git hầu như luôn luôn có thể khôi phục. Thậm chí các commit ở trên các nhánh đã bị xóa hoặc các commit đã bị ghi đè bằng cờ --amend. Để hiểu sâu hơn tìm hiểu về phần khôi phục dữ liệu tại ch10-git-internals.html. Mặc dù vậy, bất cứ cái gì bạn mất mà chưa được commit thì nhiều khả năng không bao giờ lấy lại được.

Làm việc với Remote

Để có thể hợp tác với ai đó trên bất kì Dự án nào mà sử dụng Git để quản lí phiên bản, bạn cần biết làm thế nào để quản lí kho chứa ở xa của mình. Kho chứa ở xa là dự án được lưu ở trên Internet hoặc nơi nào đó trên Mạng. Bạn có thể có nhiều kho chứa ở xa, ở đó bạn có quyền chỉ đọc (read-only) hoặc có quyền đọc/ghi (read/write). Hợp tác với người khác là quá trình quản lí, quá trình đẩy lên và kéo xuống dữ liệu từ kho chứa ở xa khi bạn cần chia sẻ công việc. Quản lí kho chứa ở xa là biết cách thêm, xóa nó khi không cần nữa, quản lí nhiều nhánh trên remote và định nghĩa chúng được bám (track) hay không,…​ Trong phần này, sẽ trình bày một vài kỹ năng cho việc quản lí remote.

Kho chứa ở xa có thể ở trên chính máy tính của bạn.Hoàn toàn bạn có thể đang làm việc với kho chứa ở xa mà thực tế nó đang ở trên máy tính của bạn. Từ remote không nhất thiết phải là một nơi nào đó trên Mạng hoặc Internet, đơn giản, nó chỉ là một kho chứa ở một nơi khác với kho chứa bạn đang làm việc. Làm việc với kho chứa ở xa như vậy không khác gì với kho chứa ở xa ở trên Mạng hoặc Internet.

Hiển thị thông tin remote bạn đang dùng

Để xem remote nào bạn đã cấu hình, bạn có thể dùng lệnh git remote. Lệnh này liệt kê tên ngắn (shortname) của mỗi remote mà bạn đã thiết lập. Nếu bạn clone một kho chứa nào đó, thì ít nhất bạn sẽ nhìn thấy origin — đó là tên mặc định Git sử dụng cho remote mà bạn clone từ nó:

$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Reusing existing pack: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (772/772), done.
Checking connectivity... done.
$ cd ticgit
$ git remote
origin

Bạn cũng có thể sử dụng -v khi muốn hiển thị cả tên ngắn và URL của remote:

$ git remote -v
origin	https://github.com/schacon/ticgit (fetch)
origin	https://github.com/schacon/ticgit (push)

Nếu bạn có hơn một remote, lệnh sẽ liệt kê tất cả chúng. Ví dụ, một kho chứa với nhiều remote cho hợp tác công việc với nhiều người trong như sau:

$ cd grit
$ git remote -v
bakkdoor  https://github.com/bakkdoor/grit (fetch)
bakkdoor  https://github.com/bakkdoor/grit (push)
cho45     https://github.com/cho45/grit (fetch)
cho45     https://github.com/cho45/grit (push)
defunkt   https://github.com/defunkt/grit (fetch)
defunkt   https://github.com/defunkt/grit (push)
koke      git://github.com/koke/grit.git (fetch)
koke      git://github.com/koke/grit.git (push)
origin    git@github.com:mojombo/grit.git (fetch)
origin    git@github.com:mojombo/grit.git (push)

Điều đó có nghĩa rằng ta có thể kéo những công việc của bất kì user nào khá dễ. Ngoài ra, chúng ta có thể có quyền đẩy dữ liệu lên một hoặc nhiều remote (kiến thức này không đề cập ở đây).

Lưu ý rằng các remote sử dụng nhiều loại giao thức khác nhau; kiến thức này được trình bày rõ hơn trong ch04-git-on-the-server.html.

Thêm Remote tới kho chứa của bạn

Như trên ta đã thấy lệnh git clone mặc định chức năng của nó là thêm origin remote. Bây giờ, làm thế nào để thêm một remote mới và gán cho nó một tên ngắn để dễ dàng cho sử dụng sau này, sử dụng lệnh git remote add <shortname> <url>:

$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin	https://github.com/schacon/ticgit (fetch)
origin	https://github.com/schacon/ticgit (push)
pb	https://github.com/paulboone/ticgit (fetch)
pb	https://github.com/paulboone/ticgit (push)

Bây giờ bạn có thể sử dụng pb để thay thế cho đường dẫn tới remote vừa mới thêm. Ví dụ, bạn muốn tải toàn bộ thông tin mà Paul có nhưng bạn vẫn chưa có trong kho chứa của mình, bạn chạy lệnh git fetch pb:

$ git fetch pb
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 43 (delta 10), reused 31 (delta 5)
Unpacking objects: 100% (43/43), done.
From https://github.com/paulboone/ticgit
 * [new branch]      master     -> pb/master
 * [new branch]      ticgit     -> pb/ticgit

Nhánh master của Paul bây giờ có thể truy cập từ máy tính của bạn pb/master — bạn cũng có thể trộn nó với một trong các nhánh của bạn, hoặc bạn có thể checkout một nhánh mới tại thời điểm đó. (Nội dung về nhánh trên Git và làm thế nào sử dụng chúng chi tiết hơn trong ch03-git-branching.html.)

Fetching và pulling dữ liệu từ remote

Như bạn đã thấy, để lấy dữ liệu từ remote, bạn chạy lệnh:

$ git fetch <remote>

Lệnh này sẽ kéo xuống toàn bộ dữ liệu từ remote mà bạn chưa có. Sau đó, bạn có tham chiếu tới tất cả các nhánh từ remote đó, từ đó bạn có thể trộn hoặc kiểm tra ở bất kì thời điểm nào.

Nếu bạn clone một kho chứa, lệnh sẽ tự động thêm remote đó với tên origin. Vậy nên lệnh git fetch origin sẽ lấy toàn bộ công việc mới đã được đẩy lên máy chủ tính từ khi bạn clone nó. Chú ý rằng, lệnh git fetch chỉ tải xuống dữ liệu xuống kho chứa nội bộ của bạn — nó không tự động trộn nó với bất kì công việc nào khác hoặc sửa cái bạn đang làm việc. Bạn phải trộn nó bằng tay với công việc của bạn khi bạn thấy điều đó cần thiết.

Nếu nhánh hiện tại của bạn được thiết lập để bám một nhánh trên máy chủ (xem phần tiếp theo và ch03-git-branching.html để thêm thông tin), bạn có thể sử dụng lệnh git pull để tự động lấy dữ liệu và trộn nhánh trên máy chủ với nhánh hiện tại của bạn. Mặc định, lệnh git clone tự động thiết lập nhánh master nội bộ để bám nhánh master trên máy chủ mà bạn clone từ nó. Nói chung, chạy lệnh git pull lấy dữ liệu từ máy chủ bạn clone từ nó và tự động thử trộn nó vào công việc mà bạn hiện đang làm việc.

Đẩy dữ liệu lên Remote của bạn

Tại một thời điểm, khi bạn muốn chia sẻ công việc của mình, bạn phải đẩy nó lên remote. Lệnh cho thực hiện công việc này là : git push <remote> <branch>. Nếu bạn muốn đẩy nhánh master địa phương lên origin remote, thì bạn có thể chạy lệnh sau để đẩy các commits bạn đã thực hiện lên máy chủ:

$ git push origin master

Lệnh này chỉ làm việc khi bạn clone từ một máy chủ mà bạn có quyền ghi và không có ai đẩy dữ liệu trong thời gian từ khi bạn clone tới khi bạn đẩy dữ liệu lên. Nghĩa là, nếu bạn và một ai khác clone tại cùng một thời điểm và họ đẩy lên công việc của họ và sau đó bạn đẩy lên, thì lệnh của bạn sẽ không được thực hiện. Đầu tiên, bạn sẽ phải lấy công việc của họ xuống và tích hợp nó vào trong công việc của bạn trước khi bạn được phép đẩy công việc của mình lên. Xem ch03-git-branching.html để học thêm về cách đẩy dữ liệu lên remote.

Hiển thị thông tin về Remote

Nếu bạn muốn xem thông tin về một remote cụ thể nào đó, bạn có thể sử dụng lệnh git remote show <remote>. Nếu bạn chạy lệnh với tên ngắn, như là origin, bạn có thể có được thông tin như sau:

$ git remote show origin
* remote origin
  Fetch URL: https://github.com/schacon/ticgit
  Push  URL: https://github.com/schacon/ticgit
  HEAD branch: master
  Remote branches:
    master                               tracked
    dev-branch                           tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)

Nó liệt kê URL cho remote, cũng như thông tin về nhánh của remote đó. Lệnh nói với bạn rằng lệnh git pull, sau khi lấy toàn bộ dữ liệu từ remote xuống, nó sẽ thực hiện trộn nhánh master trên remote với nhánh master nội bộ của bạn. Ngoài ra, nó cũng có danh sách tất cả các tham chiếu tới nhánh ở remote mà nó kéo xuống.

Đây là ví dụ đơn giản, nhiều khả năng bạn sẽ gặp phải. Khi bạn sử dụng Git sâu hơn, bạn có thể tìm hiểu thêm thông tin từ lệnh git remote show:

$ git remote show origin
* remote origin
  URL: https://github.com/my-org/complex-project
  Fetch URL: https://github.com/my-org/complex-project
  Push  URL: https://github.com/my-org/complex-project
  HEAD branch: master
  Remote branches:
    master                           tracked
    dev-branch                       tracked
    markdown-strip                   tracked
    issue-43                         new (next fetch will store in remotes/origin)
    issue-45                         new (next fetch will store in remotes/origin)
    refs/remotes/origin/issue-11     stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
    dev-branch merges with remote dev-branch
    master     merges with remote master
  Local refs configured for 'git push':
    dev-branch                     pushes to dev-branch                     (up to date)
    markdown-strip                 pushes to markdown-strip                 (up to date)
    master                         pushes to master                         (up to date)

Lệnh này cho biết nhánh nào tự động được đẩy khi bạn chạy lệnh git push khi đang ở một nhánh nào đó. Nó cũng chỉ cho bạn biết rằng nhánh nào trên remote bạn chưa có, nhánh nào bạn đã xóa, và nhiều nhánh có thể tự động được trộn khi sử dụng lệnh git pull.

Đổi tên và xóa remote

Bạn có thể chạy lệnh git remote rename để thay đổi tên ngắn của remote. Ví dụ, nếu bạn muốn đổi tên pb thành paul, làm như sau:

$ git remote rename pb paul
$ git remote
origin
paul

Bây giờ, tất cả tham chiếu tới các nhánh trên remote cũng thay đổi theo. Ví dụ, trước đây là pb/master thì bây giờ là paul/master.

Nếu bạn muốn xóa bỏ một remote vì một lí do nào đó (di chuyển máy chủ, không hợp tác với người khác qua remote này nữa,…​), giờ bạn muốn xóa remote đó đi, sử dụng một trong hai lệnh git remote remove hoặc git remote rm:

$ git remote remove paul
$ git remote
origin

Khi bạn xóa tham chiếu tới remote như trên thì tất cả các nhánh và các cài đặt liên quan tới remote đó cũng bị xóa theo.

Gắn thẻ (Tagging)

Giống như hầu hết các VCS, Git có khả năng gắn thẻ tại một thời điểm nào đó trong lịch sử. Thông thường mọi người sử dụng chức năng này để đánh dấu các thời điểm phát hành (phiên bản v1.0,…​). Trong phần này, bạn sẽ học cách làm thế nào để liệt kê các thẻ đã có, làm thế nào để gắn thẻ mới và các loại thẻ khác nhau.

Liệt kê các thẻ của bạn

Liệt kê các thẻ đã có trong Git là dễ dàng. Chỉ cần nhập git tag (với cờ -l hoặc --list):

$ git tag
v0.1
v1.3

Lệnh này liệt kê các thẻ theo thứ tự bảng chữ cái; thứ tự xuất hiện của chúng là không quan trọng.

Bạn cũng có thể tìm các thẻ mà phù hợp với pattern. Ví dụ, Kho chứa mã nguồn Git có tới hơn 500 thẻ. Nếu bạn chỉ quan tâm tới nhìn các thẻ 1.8.5, sử dụng lệnh:

$ git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5
Sử dụng wildcards bắt buộc phải có cờ -l hoặc --listNếu bạn muốn hiển thị toàn bộ danh sách các thẻ trong kho chứa dùng lệnh git tag có cờ -l hoặc --list hay không tùy ở bạn.Nhưng nếu bạn dùng wildcard pattern để giới hạn các thẻ được hiển thị theo ý mình thì bắt buộc phải dùng cờ này.

Tạo Thẻ

Git hỗ trợ hai loại thẻ: lightweight và annotated.

Thẻ Lightweight chỉ là một con trỏ tới một commit nào đó.

Nhưng, Thẻ Annotated được lưu như là một đối tượng đầy đủ trong cơ sở dữ liệu của Git. Chúng được checksum, chứa tên thẻ, địa chỉ emai và ngày tạo thẻ, có thông điệp khi tạo thẻ và có thể được kí và xác mình bằng GNU Privacy Guard (GPG). Nói chung là khuyên bạn sử dụng Thẻ Annotated để bạn có thể có tất cả thông tin; nhưng nếu bạn chỉ muốn một thẻ tạm thời hoặc vì một vài lí do nào đó không muốn giữ thông tin khác thì nên dùng thẻ loại lightweight.

Thẻ Annotated

Tạo một thẻ annotated trong Git rất đơn giản. Cách dễ dàng nhất là dùng cờ -a khi bạn chạy lệnh tag:

$ git tag -a v1.4 -m "my version 1.4"
$ git tag
v0.1
v1.3
v1.4

Cờ -m chỉ đó là thông điệp của thẻ đó, nó được lưu cùng với thẻ. Nếu bạn không dùng cờ này thì Git khởi chạy một Trình soạn thảo cho phép bạn nhập thông điệp (giống với khi thực hiện một commit).

Bạn có thể nhìn thấy thông tin về Thẻ cùng với commit được gắn thẻ đó bằng lệnh git show:

$ git show v1.4
tag v1.4
Tagger: Ben Straub <ben@straub.cc>
Date:   Sat May 3 20:19:12 2014 -0700

my version 1.4

commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

Thông tin về Thẻ (ngày tạo thẻ, và thông điệp thẻ,…​) được hiển thị trước khi hiển thị thông tin về commit được gắn thẻ đó.

Thẻ Lightweight

Cách khác để gắn thẻ một commit là sử dụng loại thẻ lightweight. Như đã nói ở trên, thẻ này chỉ là một tham chiếu tới commit đó, nó hoàn toàn không có thông tin gì thêm. Để tạo một thẻ loại này, không sử dụng bất kì cờ nào cho lệnh git tag. như sau:

$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5

Giờ thử chạy lệnh git show để xem thông tin về thẻ, bạn sẽ thấy rằng không có thông tin nào của thẻ. Lệnh này hiển thị thông tin về commit mà được gắn thẻ tương ứng:

$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

Gắn thẻ sau

Bạn cũng có thể gắn thẻ cho commit khi đã di chuyển qua nó. Giả sử, lịch sử commit của bạn như sau:

$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme

Bây giờ, giả sử bạn quên gắn thẻ v1.2.cho Dự án tại commit có thông điệp là “updated rakefile”. Để gắn thẻ cho commit đó, bạn dùng giá trị checksum của commit đó (hoặc một phần của nó) ở sau cùng của lệnh, như sau:

$ git tag -a v1.2 9fceb02

Bạn có thể thấy rằng bạn đã gắn thẻ cho commti đó:

$ git tag
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5

$ git show v1.2
tag v1.2
Tagger: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Feb 9 15:32:16 2009 -0800

version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <mchacon@gee-mail.com>
Date:   Sun Apr 27 20:43:35 2008 -0700

    updated rakefile
...

Chia sẻ các Thẻ

Mặc định, lệnh git push không đẩy các thẻ lên remote. Bạn sẽ phải chỉ rõ đẩy các thẻ lên máy chủ sau khi bạn đã tạo chúng. Quá trình này giống hệt việc bạn chia sẻ các nhánh — bạn có thể chạy lệnh git push origin <tagname>.

$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag]         v1.5 -> v1.5

Nếu bạn có nhiều thẻ và muốn đẩy chúng một lần, bạn có thể sử dụng cờ --tags cho lệnh git push. Lệnh này sẽ đẩy tất cả các thẻ mà trên máy chủ chưa có lên.

$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag]         v1.4 -> v1.4
 * [new tag]         v1.4-lw -> v1.4-lw

Bây giờ, khi một ai khác clone hoặc pull dữ liệu từ kho chứa của bạn, họ sẽ có được tất cả các thẻ.

Checkout tại vị trí gắn thẻ

Nếu bạn muốn xem phiên bản của các tệp tin ở vị trí được gắn thẻ nào đó, bạn có thể thực hiện checkout tại vị trí thẻ đó, mặc dù, lệnh này sẽ đặt kho chứa của bạn ở trạng thái “detached HEAD” — trạng thái này sẽ có một vài nhược điểm:

$ git checkout 2.0.0
Note: checking out '2.0.0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch>

HEAD is now at 99ada87... Merge pull request #89 from schacon/appendix-final

$ git checkout 2.0-beta-0.1
Previous HEAD position was 99ada87... Merge pull request #89 from schacon/appendix-final
HEAD is now at df3f601... add atlas.json and cover image

Ở trạng thái “detached HEAD”, nếu bạn thực hiện những thay đổi và sau đó làm một commit, Thẻ sẽ vẫn ở vị trí cũ, nhưng commit mới sẽ không thuộc về bất kì một nhánh nào và nó sẽ không thể chạm vào nó được, ngoại trừ sử dụng giá trị băm (hash) của commit đó. Bởi vậy, nếu bạn cần thực hiện các thay đổi — ví dụ như sửa lỗi phiên bản cũ — thường thì bạn sẽ muốn tạo một nhánh như sau:

$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'

Nếu bạn làm như trên và làm một commit, nhánh version2 sẽ khác một chút so với thẻ v2.0.0 vì nó sẽ di chuyển theo những commit mới.

Bí danh ( Alias) với Git

Trước khi kết thúc chương này, có một mẹo nhỏ có thể giúp bạn trải nghiệm Git đơn giản hơn, dễ dàng hơn và quen thuộc hơn là: Bí danh (alias). Chúng ta sẽ không nhắc tới chúng hoặc cho rằng bạn đã sử dụng chúng ở phần sau trong sách này, nhưng có lẽ bạn nên biết làm thế nào để sử dụng chúng.

Git không tự động suy luận ra lệnh khi bạn chỉ nhập một phần của lệnh. Nếu bạn không muốn nhập đầy đủ lệnh, thì bạn thiết lập các Bí danh cho mỗi lệnh sử dụng lệnh git config. Đây là hai ví dụ bạn có thể sử dụng Bí danh:

$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status

Khi thiết lập Bí danh cho lệnh git commit như trên, giờ bạn chỉ cần nhập git ci là Git sẽ hiểu là bạn dùng lệnh git commit. Trong quá trình sử dụng Git, nếu bạn sử dụng lệnh nào thường xuyên thì sử dụng Bí danh cho lệnh đó sẽ rất hữu ích.

Kỹ thuật này cũng rất hữu ích trong việc tạo các lệnh mà bạn nghĩ rằng nên có (nhưng mà Git lại chưa có sẵn). Ví dụ, để chỉnh sửa lại vấn đề không ổn định bạn gặp phải với unstaging một tệp, bạn có thể thêm bí danh cho lệnh unstage của riêng bạn:

$ git config --global alias.unstage 'reset HEAD --'

Lệnh trên làm cho hai lệnh dưới đây là tương đương nhau:

$ git unstage fileA
$ git reset HEAD -- fileA

Cái này dường như sáng sủa hơn. Nó cũng phổ biến khi thêm một lệnh last, giống như sau:

$ git config --global alias.last 'log -1 HEAD'

Cách này, bạn có thể nhìn thấy commit cuối cùng dễ dàng:

$ git last
commit 66938dae3329c7aebe598c2246a8e6af90d04646
Author: Josh Goebel <dreamer3@example.com>
Date:   Tue Aug 26 19:48:51 2008 +0800

    test for current head

    Signed-off-by: Scott Chacon <schacon@example.com>

Bạn có thể nói rằng, Git đơn giản thay lệnh mới bằng bất kì lệnh nào mà nó thay thế cho. Mặc dù vậy, có thể bạn muốn chạy một lệnh bên ngoài, chứ không phải là lệnh sẵn có của Git. Trong trường hợp đó, bạn bắt đầu lệnh với kí tự !. Nó rất hữu ích nếu bạn viết công cụ riêng cho mình để làm việc với Kho chứa Git. Chúng ta có thể minh họa bằng cách làm cho lệnh git visual thành lệnh để chạy lệnh gitk như sau:

$ git config --global alias.visual '!gitk'

Tóm tắt chương 2

Kết thúc chương này, bạn có thể có kiến thức cơ bản về: tạo hoặc clone một kho chứa, quản lí phiên bản tệp tin, stage và commit những thay đổi và xem lịch sửa của Dự án. Chương tiếp theo, là đặc trưng khiến Git khác biệt nhất so với các VCS khác, đó là nhánh (branching).

Tải xuống

Đọc online: http://elinux.vn/Books/kythuat/progit_chap2.html

Hãy bình luận đầu tiên

Để lại một phản hồi

Thư điện tử của bạn sẽ không được hiện thị công khai.


*