Tham Khảo Git

 

book Kiểm Tra và So Sánh

Bạn đã có vài nhánh tách theo từng chủ đề, chức năng riêng biệt trong toàn dự án. Vậy làm sao bạn theo dõi chúng? Git có nhiều công cụ giúp bạn kiểm tra phần nào được chỉnh sửa, sự khác biệt giữa các nhánh,...

Tóm tắt: bạn dùng lệnh git log để xác định các xác nhận trong lược sử dự án theo tác giả, ngày tháng, nội dung hoặc lược sử. Và lệnh git diff để so sánh các điểm khác nhau như là xem sự khác biệt giữa hai nhánh hoặc một phiên bản nào đó khác phiên bản khác thế nào.

docs   book git log lọc lược sử các xác nhận

Chúng ta đã dùng lệnh git log để so sánh các nhánh theo cách xem các xác nhận của một nhánh với một nhánh khác. (Gợi ý nếu bạn quên, đó là lệnh: git log branchA ^branchB). Tuy nhiên, lệnh git log có rất nhiều tùy chọn để chúng ta tìm kiếm các xác nhận. Bạn có thể xem toàn bộ các tùy chọn này trong tài liệu chính thức vì ở đây, chúng ta chỉ khám phá các tùy chọn thường dùng nhất trong quá trình quản lý kho lưu trữ Git của bạn.

git log --author xem các xác nhận theo tác giả

Tùy chọn --author sẽ lọc lược sử xác nhận theo tác giả cho bạn. Để tìm các xác nhận được viết bởi Linus trong bộ mã nguồn Git, chúng ta dùng git log --author=Linus. Git phân biệt chữ hoa thường và cũng sẽ tìm trong địa chỉ email. Chúng ta dùng -[số] để giới hạn kết quả theo [số] xác nhận cuối trong ví dụ sau:

$ git log --author=Linus --oneline -5
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory
3bb7256 make "index-pack" a built-in
377d027 make "git pack-redundant" a built-in
b532581 make "git unpack-file" a built-in
112dd51 make "mktag" a built-in

git log --since --before xem xác nhận theo ngày tháng

Các tùy chọn --since--before hoặc --until--after sẽ lọc lược sử xác nhận theo ngày tháng. Trong mã nguồn Git, chúng ta sẽ xem được các xác nhận cách đây ba tuần nhưng chỉ sau ngày 18 tháng Tư với ví dụ sau (dùng tùy chọn --no-merges để loại bỏ các xác nhận được tích hợp trong quá trình tìm kiếm):

$ git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges
5469e2d Git 1.7.1-rc2
d43427d Documentation/remote-helpers: Fix typos and improve language
272a36b Fixup: Second argument may be any arbitrary string
b6c8d2d Documentation/remote-helpers: Add invocation section
5ce4f4e Documentation/urls: Rewrite to accomodate transport::address
00b84e9 Documentation/remote-helpers: Rewrite description
03aa87e Documentation: Describe other situations where -z affects git diff
77bc694 rebase-interactive: silence warning when no commits rewritten
636db2c t3301: add tests to use --format="%N"

git log --grep lọc xác nhận theo thông điệp

Bạn có thể tìm một cụm từ nhất định trong thông điệp xác nhận với tùy chọn --grep. Chúng ta sẽ tìm trong mã nguồn Git một xác nhận có chứa biến môi trường P4EDITOR để xem đã thay đổi những gì với tùy chọn --grep.

$ git log --grep=P4EDITOR --no-merges
commit 82cea9ffb1c4677155e3e2996d76542502611370
Author: Shawn Bohrer
Date:   Wed Mar 12 19:03:24 2008 -0500

    git-p4: Use P4EDITOR environment variable when set

    Perforce allows you to set the P4EDITOR environment variable to your
    preferred editor for use in perforce.  Since we are displaying a
    perforce changelog to the user we should use it when it is defined.

    Signed-off-by: Shawn Bohrer <shawn.bohrer@gmail.com>
    Signed-off-by: Simon Hausmann <simon@lst.de>

Git sẽ tìm kiếm theo dạng OR (hay/hoặc) các đối số --grep--author. Nếu bạn muốn dùng dạng thức AND (và) giữa --grep--author để xem các xác nhận của tác giả nào đó AND (và) có nội dung thông điệp cụ thể, bạn phải thêm tùy chọn --all-match. Trong các ví dụ sau, chúng ta sẽ dùng tùy chọn --format để xem tác giả của mỗi xác nhận.

Chúng ta có ba xác nhận với thông điệp có chứa cụm từ 'p4 depo':

$ git log --grep="p4 depo" --format="%h %an %s"
ee4fd1a Junio C Hamano Merge branch 'master' of git://repo.or.cz/git/fastimport
da4a660 Benjamin Sergeant git-p4 fails when cloning a p4 depo.
1cd5738 Simon Hausmann Make incremental imports easier to use by storing the p4 d

Nếu theo ví dụ trên, chúng ta thêm vào đối số --author=Hausmann để lọc ra một xác nhận của Simon, nhưng lúc này, Git sẽ hiểu rằng chúng ta đang tìm các xác nhận của Simon OR (hay/hoặc) các xác nhận có thông điệp "p4 depo":

$ git log --grep="p4 depo" --format="%h %an %s" --author="Hausmann"
cdc7e38 Simon Hausmann Make it possible to abort the submission of a change to Pe
f5f7e4a Simon Hausmann Clean up the git-p4 documentation
30b5940 Simon Hausmann git-p4: Fix import of changesets with file deletions
4c750c0 Simon Hausmann git-p4: git-p4 submit cleanups.
0e36f2d Simon Hausmann git-p4: Removed git-p4 submit --direct.
edae1e2 Simon Hausmann git-p4: Clean up git-p4 submit's log message handling.
4b61b5c Simon Hausmann git-p4: Remove --log-substitutions feature.
36ee4ee Simon Hausmann git-p4: Ensure the working directory and the index are cle
e96e400 Simon Hausmann git-p4: Fix submit user-interface.
38f9f5e Simon Hausmann git-p4: Fix direct import from perforce after fetching cha
2094714 Simon Hausmann git-p4: When skipping a patch as part of "git-p4 submit" m
1ca3d71 Simon Hausmann git-p4: Added support for automatically importing newly ap
...

Bạn muốn tìm một thông điệp xác nhận thực sự khó hiểu, hoặc bạn muốn tìm một chức năng được giới thiệu khi nào hay các biến này được đưa vào từ đoạn mã nào? Git sẽ giúp bạn tìm chuỗi kí tự bạn cần thông qua các thay đổi của mỗi xác nhận. Ví dụ, chúng ta cần tìm các xác nhận có tên chức năng 'userformat_find_requirements' trong các thay đổi: (chú ý là không có '=' giữa '-S' và chuỗi cần tìm)

$ git log -Suserformat_find_requirements
commit 5b16360330822527eac1fa84131d185ff784c9fb
Author: Johannes Gilger
Date:   Tue Apr 13 22:31:12 2010 +0200

    pretty: Initialize notes if %N is used

    When using git log --pretty='%N' without an explicit --show-notes, git
    would segfault. This patches fixes this behaviour by loading the needed
    notes datastructures if --pretty is used and the format contains %N.
    When --pretty='%N' is used together with --no-notes, %N won't be
    expanded.

    This is an extension to a proposed patch by Jeff King.

    Signed-off-by: Johannes Gilger
    Signed-off-by: Junio C Hamano

git log -p xem bản vá của mỗi xác nhận

Each commit is a snapshot of the project, but since each commit records the snapshot it was based off of, Git can always calculate the difference and show it to you as a patch. That means for any commit you can get the patch that commit introduced to the project. You can either do this by running git show [SHA] with a specific commit SHA, or you can run git log -p, which tells Git to put the patch after each commit. It is a great way to summarize what has happened on a branch or between commits.

$ git log -p --no-merges -2
commit 594f90bdee4faf063ad07a4a6f503fdead3ef606
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jun 4 15:46:55 2010 +0200

    reverted to old class name

diff --git a/ruby.rb b/ruby.rb
index bb86f00..192151c 100644
--- a/ruby.rb
+++ b/ruby.rb
@@ -1,7 +1,7 @@
-class HiWorld
+class HelloWorld
   def self.hello
     puts "Hello World from Ruby"
   end
 end

-HiWorld.hello
+HelloWorld.hello

commit 3cbb6aae5c0cbd711c098e113ae436801371c95e
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jun 4 12:58:53 2010 +0200

    fixed readme title differently

diff --git a/README b/README
index d053cc8..9103e27 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Hello World Examples
+Many Hello World Examples
 ======================

 This project has examples of hello world in

Đây là một cách tuyệt vời để tổng hợp các thay đổi hoặc xem lại một nhóm các xác nhận trước khi tích hợp vào nhánh chính hay phát hành bản vá.

git log --stat hiển thị thống kê thay đổi theo từng xác nhận

Nếu tùy chọn -p quá dài dòng, bạn có thể tóm tắt các thay đổi với --stat. Đây là kết quả của --stat thay cho -p ở ví dụ trên.

$ git log --stat --no-merges -2
commit 594f90bdee4faf063ad07a4a6f503fdead3ef606
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jun 4 15:46:55 2010 +0200

    reverted to old class name

 ruby.rb |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

commit 3cbb6aae5c0cbd711c098e113ae436801371c95e
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jun 4 12:58:53 2010 +0200

    fixed readme title differently

 README |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Cùng thông tin cơ bản nhưng gọn gàng, cô đọng hơn - bạn vẫn xem được các thay đổi liên quan và các tập tin nào đã được chỉnh sửa.

docs   book git diff

Finally, to see the absolute changes between any two commit snapshots, you can use the git diff command. This is largely used in two main situations - seeing how two branches differ from one another and seeing what has changed since a release or some other older point in history. Let's look at both of these situations.

To see what has changed since the last release, you can simply run git diff [version] (or whatever you tagged the release). For example, if we want to see what has changed in our project since the v0.9 release, we can run git diff v0.9.

$ git diff v0.9
diff --git a/README b/README
index d053cc8..d4173d5 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Hello World Examples
+Many Hello World Lang Examples
 ======================

 This project has examples of hello world in
diff --git a/ruby.rb b/ruby.rb
index bb86f00..192151c 100644
--- a/ruby.rb
+++ b/ruby.rb
@@ -1,7 +1,7 @@
-class HiWorld
+class HelloWorld
   def self.hello
     puts "Hello World from Ruby"
   end
 end

-HiWorld.hello
+HelloWorld.hello

Bạn có thể thêm tùy chọn --stat giống như đã dùng với lệnh git log.

$ git diff v0.9 --stat
 README  |    2 +-
 ruby.rb |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

Để so sánh hai nhánh khác nhau, tuy nhiên, bạn có thể chạy một cái gì đó như git diff branchA branchB nhưng vấn đề là nó sẽ làm chính xác những gì bạn đang yêu cầu - về cơ bản nó sẽ cung cấp cho bạn một tập tin vá lỗi mà có thể biến ảnh chụp ở mũi của branchA vào ảnh chụp ở mũi của branchB. Điều này có nghĩa nếu hai ngành đã tách ra - đi theo các hướng khác nhau - nó sẽ loại bỏ tất cả các công việc đã được giới thiệu vào branchA và sau đó thêm tất cả mọi thứ đã được giới thiệu vào branchB. Điều này có lẽ không phải những gì bạn muốn - bạn muốn thay đổi thêm vào branchB mà không phải là trong branchA, vì vậy bạn thực sự muốn sự khác biệt giữa nơi hai nhánh tách ra và chóp branchB. Vì vậy, nếu lịch sử của chúng tôi trông như thế này:

$ git log --graph --oneline --decorate --all
* 594f90b (HEAD, tag: v1.0, master) reverted to old class name
| * 1834130 (erlang) added haskell
| * ab5ab4c added erlang
|/
*   8d585ea Merge branch 'fix_readme'
...

Và chúng ta muốn xem những gì trên nhánh "erlang" so với nhánh "master", chạy git diff master erlang sẽ cung cấp cho chúng ta điều sai trái.

$ git diff --stat master erlang
 erlang_hw.erl |    5 +++++
 haskell.hs    |    4 ++++
 ruby.rb       |    4 ++--
 3 files changed, 11 insertions(+), 2 deletions(-)

Bạn thấy rằng nó thêm các tập tin của erlang và haskell, đó là những gì chúng tôi đã làm trong chi nhánh đó, nhưng sau đó sản lượng cũng trở lại trạng các thay đổi đối với ruby tập tin mà chúng tôi đã làm trong ngành chủ. Những gì chúng ta thực sự muốn nhìn thấy chỉ là những thay đổi đã xảy ra trong "Erlang" chi nhánh (thêm hai tập tin). Chúng ta có thể có được kết quả mong muốn bằng cách làm khác từ phổ biến cam kết họ tách ra từ:

$ git diff --stat 8d585ea erlang
 erlang_hw.erl |    5 +++++
 haskell.hs    |    4 ++++
 2 files changed, 9 insertions(+), 0 deletions(-)

Đó là những gì chúng tôi đang tìm kiếm, nhưng chúng tôi không muốn phải tìm ra những gì cam kết hai nhánh tách ra từ mỗi lần. May mắn thay, có một Git phím tắt này. Nếu bạn chạy git diff master...erlang (với ba dấu chấm ở giữa tên chi nhánh), Git sẽ tự động tìm ra những gì phổ biến cam kết (hay còn gọi là "hợp nhất cơ sở") của hai cam kết được và làm khác ra điều đó.

$ git diff --stat master erlang
 erlang_hw.erl |    5 +++++
 haskell.hs    |    4 ++++
 ruby.rb       |    4 ++--
 3 files changed, 11 insertions(+), 2 deletions(-)
$ git diff --stat master...erlang
 erlang_hw.erl |    5 +++++
 haskell.hs    |    4 ++++
 2 files changed, 9 insertions(+), 0 deletions(-)

Gần như tất cả thời gian bạn muốn so sánh hai nhánh, bạn sẽ muốn sử dụng cú pháp ba dấu chấm, bởi vì nó sẽ hầu như luôn luôn cung cấp cho bạn những gì bạn muốn.

Như một chút của một sang một bên, bạn cũng có thể có Git tay tính toán những gì hợp nhất cơ sở (tổ tiên đầu tiên phổ biến cam kết) của hai cam kết sẽ với các git merge-base lệnh:

$ git merge-base master erlang
8d585ea6faf99facd39b55d6f6a3b3f481ad0d3d

Lệnh git diff master...erlang có thể được thực hiện bằng lệnh tương đương sau:

$ git diff --stat $(git merge-base master erlang) erlang
 erlang_hw.erl |    5 +++++
 haskell.hs    |    4 ++++
 2 files changed, 9 insertions(+), 0 deletions(-)

Bạn có thể tùy ý dùng câu lệnh dễ nhớ.

Tóm tắt: lệnh git diff cho bạn biết dự án thay đổi thế nào từ lần cuối bạn xem hoặc các công việc độc đáo của một nhánh từ lúc tách ra. Luôn dùng lệnh git diff branchA...branchB để kiểm tra nhánhB liên quan nhánhB thế nào.

Bạn hãy đọc Pro Git book để hiểu hơn về Git.