diff --git a/_layouts/vi_reference.html b/_layouts/vi_reference.html new file mode 100644 index 0000000..8456233 --- /dev/null +++ b/_layouts/vi_reference.html @@ -0,0 +1,108 @@ + + +
+ +Tài liệu tham khảo Git được viết bởi đội ngũ GitHub.
+ ++ Làm việc với Git chủ yếu bao gồm tạo và so sánh các bản sao của dự án. + Phần này trình bày về những lệnh cần thiết để tạo và xác nhận các bản sao. +
+ + ++ Một khái niệm quan trọng của Git là 'chỉ mục'. Có thể được coi nó là một + vùng tạm thời trước khi tạo bản sao chính, nhờ nó bạn có thể tạo những bản + sao bao gồm một nhóm các chỉnh sửa được tổ chức tốt, thay vì phải xác nhận + chỉnh sửa của tất cả các tập tin cùng một lúc. +
+ +
+
+ Tóm tắt:, quá trình làm việc cơ bản với Git của bạn sẽ như
+ sau: sử dụng lệnh git add
để bắt đầu theo dõi tập tin mới và
+ cũng để chỉ mục các tập tin cũ đã chỉnh sửa. Sau đó dùng lệnh git
+ status
và git diff
để xem lại các chỉnh sửa đã được chỉ
+mục, và cuối cùng dùng lệnh git commit
để lưu lại bản sao của dự
+án.
+
+ Với git, bạn phải thêm tập tin vào vùng chỉ mục trước khi bạn có thể xác nhận.
+ Bạn có thể dùng lệnh git add
để thêm cả tập tin mới cũng như
+ những tập tin đã được theo dõi (ví dụ như tập tin từ những lần xác nhận
+ trước) vào vùng chỉ mục. Dưới đây là một vài ví dụ.
+
Ở ví dụ Hello World, sau khi khởi tạo dự án, ta sẽ bắt đầu thêm tập tin
+ vào bằng cách dùng git add
. Chúng ta có thể dùng git
+ status
để xem trạng thái hiện tại của dự án.
+
+ +
+$ git status -s +?? README +?? hello.rb ++ + + Hiện tại có hai tập tin chưa được theo dõi. Chúng ta có thể thêm chúng vào + dự án. + +
+$ git add README hello.rb ++ + + Bây giờ nếu chạy
git status
một lần nữa, chúng ta sẽ thấy
+ chúng đã được thêm.
+
++$ git status -s +A README +A hello.rb ++ + +
+ Git có thể thêm một cách đệ qui tất cả các tập tin trong một thư mục, do đó
+ để thêm tất cả các tập tin trong thư mục dự án, ta cũng thường dùng
+ git add .
. Việc dùng git add .
cũng có tác
+ dụng như khi bạn gõ lệnh git add README hello.rb
, và nếu như
+ trong thư mục hiện tại không có thêm thư mục con nào thì tác dụng của lệnh
+ git add .
và git add *
có thể nói là như
+ nhau.
+
Nếu bây giờ chúng ta sửa một tập tin và tiếp tục thực hiện lệnh
+ git status
, kết quả sẽ như thế này.
+$ vim README +$ git status -s +AM README +A hello.rb ++ + +
Trạng thái 'AM' có nghĩa là tập tin đã được chỉnh sửa sau khi ta thêm tập
+ tin đó vào (chữ 'A' chỉ 'Add', hay thêm vào, còn chữ 'M' chỉ 'Modified',
+ hay chỉnh sửa). Nếu bây giờ ta xác nhận, Git sẽ xác nhận tập tin này vào
+ thời điểm ta gõ lệnh git add
trước, không phải phiên bản ta
+ vừa lưu sửa đổi trên đĩa. Đó là vì Git không mặc định lưu mọi tập tin có
+ trong thư mục đang làm việc vào bản sao, mà bạn phải chỉ định cụ thể Git
+ thêm tập tin nào vào thông qua lệnh git add
.
+
+
+ Tóm tắt:, dùng git add
để thêm tập tin đã
+ chỉnh sửa vào phiên bản trước khi tiến hành xác nhận. Chỉ những chỉnh sửa nào
+ được thêm vào mới được xác nhận vào kho, nhờ vậy mà các phiên bản có thể
+ bao gồm chính xác những tập tin bạn muốn.
Có một ví dụ rất thú vị về cách áp dụng tính mềm dẻo này để chỉ mục chỉ
+ một phần của tập tin đã chỉnh sửa ở phần tùy chọn -p
của
+ git add
trong sách Pro Git.
+ Như đã thấy trong mục git add
, để xem trạng thái vùng chỉ mục so
+ với thư mục đang làm việc, ta dùng lệnh git status
. Để xem
+ kết quả ngắn gọn, ta thêm tùy chọn -s
. Nếu không có tùy
+ chọn nào, lệnh git status
sẽ cho thấy nhiều thông tin chi
+ tiết và gợi ý. Dưới đây là kết quả của cùng một trạng thái khi có và
+ không có -s
. Đầu tiên là kết quả ngắn gọn:
+
+$ git status -s +AM README +A hello.rb ++ + + Khi không dùng tham số
-s
, kết quả xuất ra chi tiết hơn:
+
++$ git status +# On branch master +# +# Initial commit +# +# Changes to be committed: +# (use "git rm --cached <file>..." to unstage) +# +# new file: README +# new file: hello.rb +# +# Changed but not updated: +# (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) +# +# modified: README +# ++ + +
Rất dễ để nhận ra sự khác biệt giữa hai kết quả trên. Dạng đầy đủ có + chứa gợi ý về lệnh mà ta sẽ dùng tiếp theo. +
+ + +Git cũng sẽ cho thấy những tập tin đã bị xóa và tập tin bị chỉnh sửa hay + đã được chỉ mục kể từ lần xác nhận trước. + +
+$ git status -s +M README + D hello.rb ++ + +
+Dạng ngắn của trạng thái bao gồm hai cột. Cột đầu tiên dành mô tả trạng thái
+các tập tin trong chỉ mục tạm, còn cột thứ hai là dành liệt kê các tập tin ở
+thư mục hiện hành. Nếu bạn đã sửa tập tin README sau khi chỉ mục nó vào vùng
+tạm mà không thực hiện lệnh git add
lần nữa, kết quả sẽ như thế
+này:
+
+$ git status -s +MM README + D hello.rb ++ +
+
+ Tóm tắt: dùng lệnh git status
khi cần xem
+ những chỉnh sửa và/hoặc đã đưa vào vùng chỉ mục để quyết định xem có nên xác
+ nhận lưu lại chúng hay không.
+
Lệnh git diff
có hai công dụng chính. Chúng ta sẽ nói đến
+ công dụng thể hiện những chỉnh sửa đã được chỉ mục hoặc chưa được chỉ mục.
+ Công dụng còn lại sẽ được đề cập đến trong trong phần "Kiểm tra và so sánh".
Mặc định git diff
sẽ hiển thị tổng hợp những sự chỉnh sửa
+ (một bản vá) mà bạn vừa tạo ra so với lần xác nhận trước mà chưa được ghi
+ nhận cho lần xác nhận kế tiếp.
+
+$ vim hello.rb +$ git status -s + M hello.rb +$ git diff +diff --git a/hello.rb b/hello.rb +index d62ac43..8d15d50 100644 +--- a/hello.rb ++++ b/hello.rb +@@ -1,7 +1,7 @@ + class HelloWorld + + def self.hello +- puts "hello world" ++ puts "hola mundo" + end + + end ++ + +
Trong khi lệnh git status
sẽ cho ta biết tập tin nào đã bị
+ chỉnh sửa hay đã được chỉ mục kể từ lần xác nhận trước, lệnh git
+ diff
sẽ chỉ ra những chỉnh sửa đó chính xác là như thế nào theo từng
+dòng. Lệnh này nên được dùng ngay sau git status
Lệnh git diff --cached
sẽ cho ta thấy những chỉnh sửa nào
+ đã được chỉ mục, có nghĩa là những chỉ mục sẽ được đưa vào bản sao tiếp
+ theo khi xác nhận. Ở ví dụ trên, nếu bạn đã chỉ mục các chỉnh sửa tập tin
+ hello.rb
, khi dùng lệnh git diff
sẽ không xuất
+ ra thông tin gì cho bạn vì lệnh này chỉ xuất thông tin những gì chưa
+ được chỉ mục.
+$ git status -s + M hello.rb +$ git add hello.rb +$ git status -s +M hello.rb +$ git diff +$ ++ + +
Để xem những chỉnh sửa đã được chỉ mục, bạn dùng lệnh
+ git diff --cached
+$ git status -s +M hello.rb +$ git diff +$ +$ git diff --cached +diff --git a/hello.rb b/hello.rb +index d62ac43..8d15d50 100644 +--- a/hello.rb ++++ b/hello.rb +@@ -1,7 +1,7 @@ + class HelloWorld + + def self.hello +- puts "hello world" ++ puts "hola mundo" + end + + end ++ +
Để xem tất cả những chỉnh sửa đã chỉ mục và chưa chỉ mục cùng một lúc,
+ bạn có thể dùng lệnh git diff HEAD
. Về cơ bản nghĩa là bạn
+ muốn xem những chỉnh sửa so với lần xác nhận trước. Nếu ta chỉnh sửa tập tin
+ hello.rb
, chỉ mục vài chỉnh sửa và không chỉ mục vài chỉnh sửa
+ khác. Chúng ta hãy xem kết quả khi dùng ba lệnh diff
này:
+$ vim hello.rb +$ git diff +diff --git a/hello.rb b/hello.rb +index 4f40006..2ae9ba4 100644 +--- a/hello.rb ++++ b/hello.rb +@@ -1,7 +1,7 @@ + class HelloWorld + ++ # says hello + def self.hello + puts "hola mundo" + end + + end +$ git diff --cached +diff --git a/hello.rb b/hello.rb +index 2aabb6e..4f40006 100644 +--- a/hello.rb ++++ b/hello.rb +@@ -1,7 +1,7 @@ + class HelloWorld + + def self.hello +- puts "hello world" ++ puts "hola mundo" + end + + end +$ git diff HEAD +diff --git a/hello.rb b/hello.rb +index 2aabb6e..2ae9ba4 100644 +--- a/hello.rb ++++ b/hello.rb +@@ -1,7 +1,8 @@ + class HelloWorld + ++ # says hello + def self.hello +- puts "hello world" ++ puts "hola mundo" + end + + end ++ +
Lệnh git diff --stat
cho kết quả chi tiết hơn so với lệnh
+ git status
, nhưng lại tóm lược hơn so với các lệnh diff trên.
+ Đây là ví dụ với tùy chọn --stat
.
+
+$ git status -s +MM hello.rb +$ git diff --stat + hello.rb | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) +$ git diff --cached --stat + hello.rb | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) +$ git diff HEAD --stat + hello.rb | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) ++ + +
+ Bạn cũng có thể thêm đường dẫn đến tập tin vào sau các tùy chọn này để giới
+ hạn kết quả của lệnh diff
cho một tập tin hay trong một thư
+ mục con.
+
+
+ Tóm tắt: lệnh git diff
dùng để xem chi tiết
+ hơn lệnh git status
- xem tập tin đã được chỉnh sửa hoặc ghi
+ nhận như thế nào theo từng dòng.
+
Sau khi những chỉnh sửa đã được chỉ mục bằng lệnh git add
,
+ bạn dùng lệnh git commit
để thực sự ghi những chỉnh sửa đó
+ thành một bản sao. Git ghi lại tên và email của bạn trong mỗi xác nhận bạn
+ tạo, vì vậy, bạn hãy thông tin về bạn cho Git biết.
+
+$ git config --global user.name 'Your Name' +$ git config --global user.email you@somedomain.com ++ + +
Bây giờ ta sẽ chỉ mục và xác nhận tất cả những chỉnh sửa của tập tin
+ hello.rb
. Trong ví dụ này, chúng ta sẽ dùng tùy chọn
+ -m
để nhập thông điệp xác nhận từ dòng lệnh.
+
+$ git add hello.rb
+$ git status -s
+M hello.rb
+$ git commit -m 'my hola mundo changes'
+[master 68aa034] my hola mundo changes
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+
+
+ Bản sao đã được ghi lại. Nếu bây giờ ta thực hiện lệnh git
+ status
, kết quả nhận được sẽ là ta có một "thư mục hiện hành
+ trống", có nghĩa là chúng ta chưa thực hiện chỉnh sửa nào kể từ lần xác nhận
+ gần nhất.
+$ git status +# On branch master +nothing to commit (working directory clean) ++ + +
Nếu không dùng tùy chọn -m
, Git sẽ mở một trình soạn thảo
+ văn bản để bạn viết thông điệp xác nhận. Theo mặc định trình soạn thảo văn
+ bản là vim
, và giao diện sẽ tương tự như thế này:
+
+ +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch master +# Changes to be committed: +# (use "git reset HEAD <file>..." to unstage) +# +# modified: hello.rb +# +~ +~ +".git/COMMIT_EDITMSG" 9L, 257C ++ + +
Lúc này bạn có thể thêm thông điệp xác nhận vào phần đầu văn bản. Những
+ dòng bắt đầu bằng '#' sẽ bị bỏ qua - Git sẽ hiển thị kết quả của lệnh
+ git status
ở đây để bạn nhớ bạn đã sửa và chỉ mục những
+ gì.
Thông thường, việc viết một thông điệp xác nhận tốt là rất quan trọng. + Đối với các dự án nguồn mở, có một quy tắc chung về việc viết thông điệp + xác nhận:
+ + ++Tóm lược ngắn (50 ký tự hoặc ít hơn) về những chỉnh sửa + +Thông tin chi tiết hơn nếu cần thiết. Giới hạn trong 72 ký tự trên một +dòng. Trong nhiều hoàn cảnh, dòng đầu tiên được coi như chủ đề và phần +còn lại là nội dung của một email. Dòng trống phân cách giữa tóm tắt và +phần thân rất quan trọng (trừ khi bỏ qua hoàn toàn phần thân); Một số +công cụ git có thể bị nhầm lẫn nếu bạn viết liền hai phần này với nhau. + +Các đoạn tiếp theo cũng được phân cách bằng những dòng trống. + + - Được phép sử dụng gạch đầu dòng + + - Dấu gạch ('-' - ND) hay dấu sao ('*' - ND) có thể được dùng như gạch + đầu dòng, bắt đầu bằng một khoảng trắng. Các gạch đầu dòng có thể + cách nhau bởi một dòng trống hoặc không, tùy theo quy định riêng + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch master +# Changes to be committed: +# (use "git reset HEAD+ + +..." to unstage) +# +# modified: hello.rb +# +~ +~ +~ +".git/COMMIT_EDITMSG" 25L, 884C written +
+ Thông điệp xác nhận rất quan trọng vì sức mạnh của Git phần lớn nằm ở + khả năng có thể tạo những xác nhận và sau đó chia sẻ chúng. Ba hay bốn xác + nhận được phân chia một cách hợp lý sẽ giúp việc theo dõi và xem lại dễ + dàng hơn. Bởi vì có sự phân chia giữa xác nhận và đẩy những chỉnh sửa này, + dành thời gian viết những thông điệp xác nhận tốt sẽ giúp đồng nghiệp + hiểu được bạn đang làm gì và vì sao dễ dàng hơn.
+ +Nếu bạn cho rằng giai đoạn git add
trong chu trình làm việc
+ là quá rườm rà, Git cho phép bỏ qua nó bằng tùy chọn -a
. Với
+ tùy chọn này, Git sẽ thực hiện git add
với tất cả những tập
+ tin đang được "tracked" (theo dõi) - tập tin đã được chỉnh sửa từ lần xác
+ nhận trước. Nhờ vậy bạn có thể thực hiện theo một chu trình làm việc theo
+ kiểu Subversion, chỉnh sửa tập tin và sau đó dùng lệnh git commit
+ -a
để ghi lại tất cả những chỉnh sửa. Bạn sẽ vẫn phải dùng lệnh
+git add
để bắt đầu theo dõi những tập tin mới, tương tự như với
+Subversion.
+
+$ vim hello.rb +$ git status -s + M hello.rb +$ git commit -m 'changes to hello file' +# On branch master +# Changed but not updated: +# (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) +# +# modified: hello.rb +# +no changes added to commit (use "git add" and/or "git commit -a") +$ git commit -am 'changes to hello file' +[master 78b2670] changes to hello file + 1 files changed, 2 insertions(+), 1 deletions(-) ++ + +
Chú ý rằng nếu bạn chưa chỉ mục chỉnh sửa nào mà thực hiện ngay lệnh
+ git commit
, Git sẽ xuất kết quả lệnh git status
,
+ nhắc nhở rằng chưa có chỉnh sửa nào được chỉ mục. Những phần quan trọng của
+ thông điệp này được đánh dấu, nêu rằng không có chỉnh sửa nào đã được thêm
+ vào để xác nhận. Nếu thêm tùy chọn -a
, tất cả chỉnh sửa sẽ được
+ chỉ mục và xác nhận đồng thời.
+
Đến đây ta đã hoàn thành một chu trình làm việc hoàn chỉnh - bạn thay
+ đổi các tập tin, sau đó dùng lệnh git add
để chỉ mục các thay
+ đổi, lệnh git status
và git diff
để bạn xem lại
+ những chỉnh sửa đó, và cuối cùng lệnh git commit
để thực sự ghi
+ lại bản sao.
+
+ Tóm tắt: dùng lệnh git commit
để ghi lại bản
+ sao gồm những chỉnh sửa đã được chỉ mục. Bản sao này sau đó có thể được so
+ sánh, chia sẻ hay hoàn lại nếu cần thiết.
+
Lệnh git reset
có lẽ là lệnh khó hiểu nhất được viết ra
+ nhưng nó rất hữu dụng một khi bạn bám vào nó. Có ba trường hợp được đưa ra
+ về lệnh này hoàn toàn hữu ích.
+
Trong trường hợp này, ta sẽ dùng nó để lấy lại những chỉnh sửa đã ghi
+ nhận. Giả sử bạn đã chỉnh sửa hai tập tin và muốn lưu lại trong hai lần xác
+ nhận riêng rẽ. Bạn nên chỉ mục và xác nhận lần lượt từng tập tin một. Nếu
+ chẳng may bạn đã chỉ mục cả hai tập tin này, thực hiện lệnh
+ git reset HEAD -- file
. --
dùng để thông báo
+ với Git rằng các tùy chọn đã được liệt kê hết, và sau đây sẽ là danh
+ sách đường dẫn, nhưng phân cách giữa các tùy chọn và đường dẫn là một
+ thói quen tốt.
+
Dưới đây ta sẽ chỉ mục chỉnh sửa ở hai tập tin và sau đó lần lượt lấy + lại những chỉnh sửa của từng tập tin.
+ ++$ git status -s + M README + M hello.rb +$ git add . +$ git status -s +M README +M hello.rb +$ git reset HEAD -- hello.rb +Unstaged changes after reset: +M hello.rb +$ git status -s +M README + M hello.rb ++ + +
Bây giờ nếu bạn thực hiện lệnh git commit
thì sẽ chỉ
+ ghi lại chỉnh sửa ở tập tin README
, chứ không bao gồm những
+ chỉnh sửa chưa được chỉ mục trong tập tin hello.rb
.
+
+ Khi bạn thực hiện lệnh này, thực tế là Git đã ghi đè checksum của một tập tin
+ trong chỉ mục bằng checksum của chính tập tin đó trong lần xác nhận trước. Vì
+ git add
tính checksum của một tập tin và ghi nó vào chỉ mục,
+ git reset HEAD
ghi lại nó bằng giá trị cũ, từ đó có thể bỏ
+ tập tin khỏi phạm vi chỉ mục.
+
+ Bạn có thể tạo một lệnh tắt git unstage
bằng cách chaỵ lệnh
+ git config --global alias.unstage "reset HEAD"
. Từ giờ bạn có
+ thể sử dụng lệnh git unstage [file]
để thực hiện thao tác này.
+
Nếu bạn không nhớ lệnh nào dùng để hủy chỉ mục chỉnh sửa, Git sẽ nhắc
+ cho bạn trong kết quả của lệnh git status
. Ví dụ khi bạn
+ dùng lệnh git status
mà không dùng tùy chọn -s
+ sẽ được kết quả như sau:
+$ git status +# On branch master +# Changes to be committed: +# (use "git reset HEAD <file>..." to unstage) +# +# modified: README +# modified: hello.rb +# ++ + +
Git mặc định dùng tùy chọn --mixed
khi bạn không thêm tùy
+ chọn nào vào lệnh git reset
. Các tùy chọn khác của lệnh này là
+ --soft
và --hard
.
+
+
+ Việc đầu tiên git reset
làm là hoàn tác xác nhận cuối
+ và đưa các tập tin trở về vùng chỉ mục. Nếu bạn thêm tuỳ chọn
+ --soft
. Ví dụ, nếu bạn chạy lệnh git reset --soft
+ HEAD~
(cha của HEAD), xác nhận cuối sẽ được hoàn tác và
+ các tập tin sẽ được đưa trở lại vùng chỉ mục.
+
+$ git status -s +M hello.rb +$ git commit -am 'hello with a flower' +[master 5857ac1] hello with a flower + 1 files changed, 3 insertions(+), 1 deletions(-) +$ git status +# On branch master +nothing to commit (working directory clean) +$ git reset --soft HEAD~ +$ git status -s +M hello.rb ++ + +
Lệnh này về cơ bản giống lệnh git commit --amend
, cho
+phép bạn thêm các chỉnh sửa vào xác nhận trước đó.
Tuỳ chọn thứ ba là dùng --hard
để huỷ chỉ mục, hoàn tác
+mọi chỉnh sửa bạn thêm vào từ lần xác nhận cuối. Đây là tuỳ chọn nguy
+hiểm nhất không an toàn cho thư mục làm việc của bạn. Bất kỳ chỉnh sửa
+chưa xác nhận sẽ mất.
+$ git status +# On branch 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: README +# +$ git reset --hard HEAD +HEAD is now at 5857ac1 hello with a flower +$ git status +# On branch master +nothing to commit (working directory clean) ++ + +
Ở ví dụ trên, ta có chỉnh sửa dự kiến xác nhận và chỉnh sửa chưa chỉ
+mục của tập tin README. Lệnh git reset --hard
đã xoá bỏ
+chúng và đặt lại toàn bộ về trạng thái giống lần xác nhận cuối.
Bạn có thể thay HEAD
với mã SHA-1 của lần xác nhận
+ bất ký để đặt lại về lần xác nhận đó.
+
+ Tóm tắt:,
+ lệnh git reset HEAD
dùng để hoàn tác lần xác nhận cuối,
+ huỷ chỉ mục các tập tin bạn không muốn đưa vào lần xác nhận bản sao
+ kế sau khi bạn đã dùng lệnh git add
thêm vào. (ND: bạn
+ có thể xem bài viết Reset
+ Demystified để hiểu rõ hơn về lệnh reset
của
+ Git)
Lệnh git rm
sẽ loại bỏ tập tin ra khỏi vùng chỉ mục. Điểm khác
+ biệt so với lệnh git reset HEAD
ở chỗ lệnh lệnh này chỉ hoàn trả
+ vùng chỉ mục lại trạng thái ban đầu, còn lệnh git rm
không chỉ
+ loại tập tin khỏi vùng chỉ mục mà còn xóa nó.
Theo mặc định, lệnh git rm file
sẽ loại bỏ hoàn toàn tập tin
+ đó khỏi vùng chỉ mục và đồng thời cũng xóa luôn tập tin trên đĩa cứng (thư mục
+ hiện hành). Để giữ tập tin trong thư mục hiện hành, bạn dùng lệnh git rm --cached
Khác với phần lớn các hệ thống quản lý mã nguồn khác, Git không theo dõi
+ các tập tin bị đổi tên. Thay vào đó nó chỉ theo dõi các bản sao để phát hiện những
+ tập tin đã bị xóa và thêm vào với nội dung giống nhau, khi đó Git sẽ hiểu đây là
+ trường hợp đổi tên. Mặc dù có lệnh git mv
, nhưng nó là thừa -
+ lệnh này chỉ đơn thuần git rm
, di chuyển tập tin trên đĩa cứng và
+ sau đó là git add
tập tin mới.
+ Tôi ít khi dùng lệnh này để xóa tập tin. Thay vào đó chỉ cần xóa tập tin trên đĩa
+ cứng và sau đó thực hiện lệnh git commit -a
cũng sẽ giúp loại
+ bỏ tập tin khỏi chỉ mục.
+
+ Tóm tắt:,
+ lệnh git rm
dùng để loại một tập tin nào đó khỏi sự theo dõi của
+ Git và đồng thời cũng xóa tập tin đó khỏi thư mục hiện hành.
Bạn đang chỉnh sửa dang dở thì một vấn đề phát sinh cần được thêm vào
+ngay, chẳng hạn một bản vá khẩn cấp, nhưng bạn lại không muốn xác nhận
+hoặc mất các chỉnh sửa hiện tại của bạn. Lệnh git stash
sẽ
+giải quyết vấn đề đó giúp bạn.
Cất giấu (stash) là đưa thư mục làm việc và vùng chỉ mục hiện tại + vào một ngăn xếp và đưa bạn trở về trạng thái của lần xác nhận + cuối.
+ + +Lệnh git stash
sẽ không kèm theo các tập tin chưa
+ theo dõi. Cũng như các bạn tạo xác nhận, bạn phải dùng lệnh
+ git add
để chỉ mục tập tin trước khi cất giấu hoặc với
+ các các phiên bản Git từ 1.7.7 về sau, bạn có thể dùng lệnh
+ git stash -u
để cất giấu các tập tin chưa đánh phiên
+ bản.
+$ git status -s
+M hello.rb
+$ git stash
+Saved working directory and index state WIP on master: 5857ac1 hello with a flower
+HEAD is now at 5857ac1 hello with a flower
+$ git status
+# On branch master
+nothing to commit (working directory clean)
+
+
+ Đôi khi, bạn cần biết bạn đã xếp gọn những gì vào ngăn cất giấu, lệnh
+ git stash list
sẽ hiển thị một hàng danh sách của các mục cất
+ giấu của bạn.
+
+$ git stash list +stash@{0}: WIP on master: 5857ac1 hello with a flower ++ + +
Mục cuối cùng thêm vào ngăn cất giấu được tham chiếu đến
+ stash@{0}
và tăng dần theo một.
+
+$ vim hello.rb +$ git commit -am 'it stops raining' +[master ee2d2c6] it stops raining +1 files changed, 1 insertions(+), 1 deletions(-) +$ vim hello.rb +$ git stash +Saved working directory and index state WIP on master: ee2d2c6 it stops raining +HEAD is now at ee2d2c6 it stops raining +$ git stash list +stash@{0}: WIP on master: ee2d2c6 it stops raining +stash@{1}: WIP on master: 5857ac1 hello with a flower ++ +
Khi bạn đã sẵn sàng tiếp tục công việc từ khi bạn đã cất giấu, lệnh
+ git stash apply
sẽ đem các thay đổi đã cất giấu trở lại thư
+ mục làm việc.
+
+$ git stash apply
+# On branch 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: hello.rb
+#
+no changes added to commit (use "git add" and/or "git commit -a")
+
+
+
+ Mặc định, lệnh trên sẽ tái ghép mục cuối cùng, tham chiếu đến
+ stash@{0}
, vào thư mục làm việc. Bạn có thể tái ghép mục cất giấu
+ khác bằng cách thêm vào tham chiếu trong danh sách đối số. Ví dụ, git
+ stash apply stash@{1}
sẽ tái ghép mục tham chiếu
+ stash@{1}
.
+
Nếu bạn muốn xóa mục khỏi ngăn cất giấu sau khi tái ghép, dùng lệnh
+ git stash pop
thay thế.
+
Lệnh git stash drop
sẽ xóa mục đã cất giấu. Mặc định, lệnh
+ sẽ xóa mục cuối cùng nếu bạn không kèm theo đối số để xóa một mục xác định.
+
Trong ví dụ sau, chúng ta có hai mục trong danh sách cất giấu nhưng
+ chúng ta muốn xóa mục đầu tiên được tham chiếu đến stash@{1}
.
+
+$ git stash drop stash@{1} +Dropped stash@{1} (0b1478540189f30fef9804684673907c65865d8f) ++ + +
Khi đã chắc chắn hoàn tất các công việc với danh sách cất giấu, bạn có
+ thể dùng lệnh git stash clear
để xóa tất cả các mục đã cất
+ giấu.
+
+
+ Tóm tắt: lệnh git stash
lưu tạm vài thay đổi
+ bạn chưa dự định xác nhận, và sẽ được tiếp tục khi bạn đã xong công việc
+ khác.
+
Rẽ nhánh là một trong các tính năng tôi thích của Git. + Khi làm việc với Git, bạn nên tạm quên đi khái niệm nhánh + mà bạn từng biết trong các hệ thống quản lý phiên bản khác, + vì thực tế, mỗi nhánh trong Git gần giống như một ngữ cảnh + (điều kiện hay hoàn cảnh làm việc). + Việc rẽ vào một nhánh tương tự việc chuyển qua ngữ cảnh làm việc mới, + và sau đó có thể nhanh chóng quay lại ngữ cảnh cũ. +
+ ++ ND: Việc rẽ nhánh giống như việc đang đi trên đường thì bạn muốn + rẽ sang ngã khác (ngã ba, ngã tư chẳng hạn), để thực hiện một số + việc như thăm người quen, tránh kẹt xe, rồi quay trở lại đường + chính sau. Một nhánh trong Git gần như một đoạn đường hoặc con đường. + Nếu các con đường ở Sài Gòn đã cố định, thì con đường trong Git + dễ chịu hơn mà bạn có thể tạo ra bất kỳ lúc nào :)
+ +
+
+ Tóm tắt: bạn tạo ra một nhánh mới bằng
+ git branch tên_nhánh
, sau đó rẽ vào nhánh đó bằng
+ git checkout tên_nhánh
; sau lưu lại các thay đổi trong
+ ngữ cảnh này, bạn có thể rẽ qua nhánh khác một cách dễ dàng.
+
+ Mỗi khi rẽ vào một nhánh, Git sẽ thay thư mục làm việc cho tương ứng
+ với nhánh đó; vì vậy, bạn không phải xử lý nhiều thư mục khác nhau
+ cho nhiều nhánh (có nghĩa là, chỉ dùng một thư mục cho nhiều nhánh. Điều
+ này rất khác với cách tiếp cận của Subversion -- ND). Cuối cùng, để
+ tích hợp hai nhánh với nhau, dùng git merge
. Có thể dễ dàng
+ tích hợp nhiều lần hai nhánh với nhau, hoặc có thể xóa một nhánh sau khi
+ nó đã được tích hợp.
+
Lệnh git branch
là để quản lý các nhánh; nó có thể
+ làm nhiều việc khác nhau, nên chúng ta chỉ để cập một số việc cơ bản
+ của lệnh này: liệt kê, tạo hoặc xóa nhánh. Ta cũng đề cập tới lệnh
+ git checkout
+ để rẽ vào một nhánh bất kỳ.
+
Khi không có tham số, git branch
sẽ liệt kê các nhánh
+ sẵn có, riêng nhánh bạn đang rẽ vào được đánh dấu sao * hoặc
+ tô màu xanh lá).
+
+$ git branch
+* master
+
+
+
+ Cho biết bạn đang rẽ vào nhánh 'master'. Đó là nhánh được tạo ra
+ tự động khi bạn khởi tạo kho bằng lệnh git init
. Cái tên
+ 'master' không phải là bắt buộc, nhưng nó được hầu hết dự án dùng do
+ sự lựa chọn mặc định của Git.
+
Bây gờ, ta thử tạo một nhánh mới rồi rẽ vào nhánh đó. + +
+$ git branch testing
+$ git branch
+* master
+ testing
+
+
+
+ Như bạn thấy, sau khi tạo ta sẽ thấy thêm nhánh mới khi liệt kê.
+ Nhánh mới tạo ra sẽ chứa những thay đổi cuối cùng đã xác nhận. Vì thế,
+ sau thời điểm nhánh 'testing' được tạo ra, bạn xác nhận các thay đổi
+ mới (sẽ diễn ra ở nhánh 'master'), rồi lại rẽ vào nhánh 'testing',
+ thì thư mục làm việc sẽ trở lại trạng thái ngay trước khi nhánh đó
+ đuợc tạo ra (nghĩa là nó sẽ không chứa các thay đổi bạn vừa xác nhận).
+ Như vậy, nhánh giống như các đánh dấu trên đường đi cho biết bạn đang
+ ở đâu. Ta hãy xem việc rẽ nhánh sẽ diễn ra thế nào, với lệnh
+ git checkout tên_nhánh
+
+$ ls +README hello.rb +$ echo 'test content' > test.txt +$ echo 'more content' > more.txt +$ git add *.txt +$ git commit -m 'added two files' +[master 8bd6d8b] added two files + 2 files changed, 2 insertions(+), 0 deletions(-) + create mode 100644 more.txt + create mode 100644 test.txt +$ ls +README hello.rb more.txt test.txt +$ git checkout testing +Switched to branch 'testing' +$ ls +README hello.rb ++ + +
Bây giờ, ta rẽ vào nhánh 'testing'. Bạn sẽ thấy các tập tin vừa tạo + ra ở trên sẽ bị xóa đi, nhưng chúng sẽ xuất hiện trở lại khi bạn quay + lại nhánh ban đầu 'master'.
+ ++$ ls +README hello.rb +$ git checkout master +Switched to branch 'master' +$ ls +README hello.rb more.txt test.txt ++ +
Nếu muốn xem xác nhận cuối của mỗi nhánh, bạn dùng lệnh git branch
+ -v
+$ git branch -v
+* master 54b417d fix javascript issue
+ development 74c111d modify component.json file
+ testing 62a557a update test scripts
+
+
+
+ Trong nhiều trường hợp bạn muốn rẽ vào một nhánh ngay sau khi nhánh
+ đó được tạo ra. Thay vì phải dùng cặp lệnh
+ git branch tên_nhán; git checkout tên_nhánh
,
+ bạn chỉ gõ tắt
+ git checkout -b tên_nhánh
.
+
+$ git branch +* master +$ ls +README hello.rb more.txt test.txt +$ git checkout -b removals +Switched to a new branch 'removals' +$ git rm more.txt +rm 'more.txt' +$ git rm test.txt +rm 'test.txt' +$ ls +README hello.rb +$ git commit -am 'removed useless files' +[removals 8f7c949] removed useless files + 2 files changed, 0 insertions(+), 2 deletions(-) + delete mode 100644 more.txt + delete mode 100644 test.txt +$ git checkout master +Switched to branch 'master' +$ ls +README hello.rb more.txt test.txt ++ + +
Như thấy ở trên, ta rẽ vào nhánh 'removals' ngay sau khi tạo ra nhánh + đó; trong nhánh này, ta thực hiện xóa bớt một số tập tin, xác nhận việc + xóa và rồi quay lại nhánh chính 'master', ở đó các tập tin vừa xóa sẽ + xuất hiện trở lại. Như vậy, việc rẽ nhánh hiểu và phân chia thư mục + làm việc theo đúng ngữ cảnh được chỉ định; việc chuyển đổi giữa các + nhánh không làm mất đi tập tin hoặc không gây ra nhầm lẫn.
+ + ++ Khi bắt đầu một dự án, bạn nên rẽ vào một nhánh riêng của dự án đó + (việc này cũng nhanh và dễ), và sau đó tích hợp nhánh của bạn với nhánh + chính của dự án; sau khi tích hợp thì có thể xóa nhánh riêng bạn tạo ra. + Bằng cách đó, bạn dễ dàng chuyển qua phiên bản (nhánh) ổn định của dự + án khi xảy ra vấn đề trên nhánh bạn phát triển; hơn nữa, bạn cũng có thể + dễ dàng tạm gác lại công việc của bạn trên nhánh riêng, để quay trở lại + các nhánh cũ do yêu cầu bắt buộc của dự án.
+ +Để xóa một nhánh, bạn chỉ việc dùng lệnh
+ git branch -d tên_nhánh
. Ví dụ, ta sẽ xóa nhánh
+ 'testing' đã tạo ra ở ví dụ ở trên.
+
+
+$ git branch +* master + testing +$ git branch -d testing +Deleted branch testing (was 78b2670). +$ git branch +* master ++ +
Khi nhánh đầu xa bạn làm việc đã được tích hợp vào nhánh chính đầu xa
+ master
hoặc bạn muốn xóa bỏ để dọn dẹp, bạn kèm theo vào sau lệnh
+ git push
một dấu hai chấm và tên nhánh cần xóa như ví dụ
+ sau:
+$ git push origin :tidy-cutlery +To git@github.com:octocat/Spoon-Knife.git + - [deleted] tidy-cutlery ++ + +
+ Ở ví dụ trên, chúng ta đã xóa nhánh "tidy-cutlery" khỏi kho đầu xa
+ "origin". Cách dễ nhớ nhất là bạn hãy nhớ lệnh dài ngoằng sau đây git
+ push remote-name local-branch:remote-branch
. Ý nghĩa của câu lệnh
+này là bạn muốn đẩy lên nhánh của kho trên máy tính của bạn trùng với kho đầu
+xa. Khi bạn xóa phần local-branch
, thì phần nhánh đầu xa cũng sẽ
+được xóa đi để trùng với nhánh trên máy tính.
+
Một cách khác, lệnh git push remote-name --delete
+ branchname
với cặp source:destination
cũng được
+ dùng xóa nhánh đầu xa.
+
+
+ Tóm tắt: bạn dùng git branch
để liệt kê các nhánh
+ hiện có, rẽ nhánh mới hoặc xóa đi các nhánh đã tích hợp hoặc không còn cần thiết.
+
Sau khi chia công việc riêng ra từng nhánh, có lúc bạn sẽ cần tích hợp
+ các nhánh với nhau, hoặc với nhánh chính. Để tích hợp, bạn dùng lệnh
+ git merge
.
+ Xét ví dụ ở trên với nhánh 'removals'. Ta nhớ lại rằng sau khi rẽ vào
+ nhánh 'removals', ta xóa đi một vài tập tin và xác nhận sự thay đổi.
+ Việc xóa tập tin này chỉ diễn ra ở nhánh 'removals', còn ở nhánh chính
+ 'master' không có tập tin nào được xóa. Bây giờ, để xác nhận rằng cả
+ các tập tin bị xóa trong 'removals' cũng bị xóa trong 'master', ta chỉ
+ việc tích hợp nhánh 'removals' với 'master'.
+
+$ git branch +* master + removals +$ ls +README hello.rb more.txt test.txt +$ git merge removals +Updating 8bd6d8b..8f7c949 +Fast-forward + more.txt | 1 - + test.txt | 1 - + 2 files changed, 0 insertions(+), 2 deletions(-) + delete mode 100644 more.txt + delete mode 100644 test.txt +$ ls +README hello.rb ++ +
Tất nhiên, quá trình phát triển của mã nguồn không chỉ đơn giản + là thêm và xóa tập tin. Git còn hỗ trợ thêm việc tích hợp các thay đổi + (hoặc sự khác biệt) giữa của tập tin ở hai nhánh khác nhau. + Lấy ví dụ, ta sẽ chỉnh nội dung tập tin ở một nhánh, trong khi ở nhánh + kia ta đổi tên tập tin, rồi rồi tích hợp hai tập tin đó với nhau. Nghe + có vẻ rối đây! Xem Git giải quyết thế nào nhé! +
+ ++$ git branch +* master +$ cat hello.rb +class HelloWorld + def self.hello + puts "Hello World" + end +end + +HelloWorld.hello ++ + +
Bây giờ ta đang ở nhánh 'master'. Ta sẽ tạo nhánh 'change_class' + và rẽ ngay vào nhánh đó: trong nhánh mới ta sẽ thực hiện đổi tên lớp + từ 'HelloWorld' dthành 'HiWorld'.
+ ++$ git checkout -b change_class +Switched to a new branch 'change_class' +$ vim hello.rb +$ head -1 hello.rb +class HiWorld +$ git commit -am 'changed the class name' +[change_class 3467b0a] changed the class name + 1 files changed, 2 insertions(+), 4 deletions(-) ++ + +
Việc đổi tên lớp được xác nhận sau lệnh git commit
.
+ Ta sẽ trở lại nhánh chính 'master' và sẽ thấy rằng trong tên lớp
+ vẫn là 'HelloWorld' (như cũ!). Ta sẽ đổi xem có sự khác biệt nào
+ với thay đổi đã thực hiện ở nhánh 'change_class', đồng thời đổi tên
+ tập tin từ hello.rb
thành ruby.rb
.
+
+$ git checkout master +Switched to branch 'master' +$ git mv hello.rb ruby.rb +$ vim ruby.rb +$ git diff +diff --git a/ruby.rb b/ruby.rb +index 2aabb6e..bf64b17 100644 +--- a/ruby.rb ++++ b/ruby.rb +@@ -1,7 +1,7 @@ + class HelloWorld + + def self.hello +- puts "Hello World" ++ puts "Hello World from Ruby" + end + + end +$ git commit -am 'added from ruby' +[master b7ae93b] added from ruby + 1 files changed, 1 insertions(+), 1 deletions(-) + rename hello.rb => ruby.rb (65%) ++ + +
Như ban thấy, sự thay đổi tên tập tin và nội dung cũng vừa được + xác nhận trong nhánh 'master'. Để ý rằng, tên lớp vẫn là 'HelloWorld'. + Nếu muốn thay đổi cả tên của lớp thành 'HiWorld', ta chỉ việc tích hợp + nội dung ở nhánh 'change_class' vào nhánh 'master'. Nhưng liệu Git + có tích hợp được không, vì tên tập tin đã đổi? Hãy xem:
+ ++$ git branch + change_class +* master +$ git merge change_class +Renaming hello.rb => ruby.rb +Auto-merging ruby.rb +Merge made by recursive. + ruby.rb | 6 ++---- + 1 files changed, 2 insertions(+), 4 deletions(-) +$ cat ruby.rb +class HiWorld + def self.hello + puts "Hello World from Ruby" + end +end + +HiWorld.hello ++ + +
Tốt quá, mọi chuyện diễn ra đúng như mong đợi. Như vậy trong quá + trình tích hợp ta đã không gặp xung đột nào, kể cả việc đổi tên tập tin + hoặc đổi tên lớp diễn ra ở nhánh khác
+ +Như vậy, Git thật là khéo léo, nhưng ta chưa hề đụng tới trường hợp + có xung đột. Không sao, khi xảy ra sự khác biệt về mã giữa hai nhánh + mà Git không thể hình dung được, sẽ tới phiên chúng ta giải quyết. + Trong ví dụ sau, ta sẽ thay đổi cùng một dòng của tập tin ở hai nhánh. +
+ +
+$ git branch +* master +$ git checkout -b fix_readme +Switched to a new branch 'fix_readme' +$ vim README +$ git commit -am 'fixed readme title' +[fix_readme 3ac015d] fixed readme title + 1 files changed, 1 insertions(+), 1 deletions(-) ++ + +
Sau khi rẽ vào nhánh 'fix_readme', ta thực hiện thay đổi một dòng + trong tập tin 'README'. Tiếp theo ta sẽ thay đổi cùng dòng đó, nhưng + ở tập tin của nhánh 'master'.
+ ++$ git checkout master +Switched to branch 'master' +$ vim README +$ git commit -am 'fixed readme title differently' +[master 3cbb6aa] fixed readme title differently + 1 files changed, 1 insertions(+), 1 deletions(-) ++ + +
Hãy xem có điều thú vị gì xảy ra khi tích hợp hai tập tin có xung đột + với nhau:
+ ++$ git merge fix_readme +Auto-merging README +CONFLICT (content): Merge conflict in README +Automatic merge failed; fix conflicts and then commit the result. +$ cat README +<<<<<<< HEAD +Many Hello World Examples +======= +Hello World Lang Examples +>>>>>>> fix_readme + +This project has examples of hello world in +nearly every programming language. ++ + +
Như bạn thấy, Git chèn vào các ký hiệu đánh dấu sự xung đột xảy + ra khi tích hợp. Git đã 'bó tay' khi dừng lại ở đó, và tới phiên bạn + quyết định. Để ý là, + một số công cụ đồ họa + như kdiff3, emerge, p4merge, ... sẽ giúp việc giải quyết xung đột + dễ dàng hơn. +
+ ++$ vim README # here I'm fixing the conflict +$ git diff +diff --cc README +index 9103e27,69cad1a..0000000 +--- a/README ++++ b/README +@@@ -1,4 -1,4 +1,4 @@@ +- Many Hello World Examples + -Hello World Lang Examples +++Many Hello World Lang Examples + + This project has examples of hello world in ++ + +
Một mẹo rất hay khi tích hợp các xung đột trong Git là nếu khi dùng
+ git diff
,
+ chương trình sẽ cho bạn thấy cả hai phần (cũ, mới) gây nên xung đột,
+ và cả cách giải quyết xung đột. Sau đó, bạn cần đánh dấu cho tập tin
+ rằng xung đột trên nó đã giải quyết xong: bạn sử dụng lệnh
+ git add
+ và cả git commit
để xác nhận.
+$ git status -s +UU README +$ git add README +$ git status -s +M README +$ git commit +[master 8d585ea] Merge branch 'fix_readme' ++ + +
Bây giờ thì xung đột được giải quyết trọn vẹn.
+ +
+
+ Tóm tắt: bạn dùng git merge
để tích hợp một nhánh với
+ nhánh bạn đang rẽ vào. Git sẽ tự động xác định phép tích hợp tốt nhất để
+ có được sản phẩm chung lai giữa hai nhánh.
+
Ta đã biết cách xác nhận các thay đổi, cách chuyển qua lại giữa
+ các nhánh. Nhưng chuyện gì xảy ra một khi ta quên mất ta đang ở nhánh
+ nào, ở vị trí nào trong một nhánh, hoặc lý do ta rẽ nhánh? Hoặc ta quên
+ mất sự khác biệt giữa các nhánh? Lường trước cách trả lời cho câu hỏi này,
+ Git cung cấp lệnh git log
để giúp bạn xem lại mô tả hoặc
+ lý do của tất cả các lần xác nhận.
Truớc khi hiểu về lệnh log
, bạn cần biết Git lưu những
+ gì mỗi khi bạn xác nhận sự thay đổi bằng lệnh git commit
.
+ Bên cạnh thông tin về các tập tin, người thay đổi, thông điệp, Git còn
+ lưu thông tin về xác nhận có liên quan trực tiếp tới xác nhận đang thực
+ hiện. Để hình dung, ta lấy ví dụ: khi bạn nhân bản một dự án, bạn cần
+ biết là thay đổi của bạn cho nhân bản đó dựa trên trạng thái nào của dự
+ án đã có. Thông tin về trạng thái cũ rất có ích, giúp bạn xác nhận ngữ
+ cảnh (nhánh) của bạn và giúp hình dung quá trình phát triển của toàn bộ
+ dự án. Bằng cách đặt tên 'cha' (parent) có ngữ cảnh gốc, Git tự động
+ biết được bạn làm gì cho ngữ cảnh của bạn (con).
+
Để xem danh sách các xác nhận 'cha' theo thời gian, bạn dùng lệnh
+ git log
khi đang ở một nhánh bất kỳ. Ví dụ, kết quả của lệnh
+ git log
trong dự án HelloWorld ở trên như sau đây.
+$ git log +commit 8d585ea6faf99facd39b55d6f6a3b3f481ad0d3d +Merge: 3cbb6aa 3ac015d +Author: Scott Chacon <schacon@gmail.com> +Date: Fri Jun 4 12:59:47 2010 +0200 + + Merge branch 'fix_readme' + + Conflicts: + README + +commit 3cbb6aae5c0cbd711c098e113ae436801371c95e +Author: Scott Chacon <schacon@gmail.com> +Date: Fri Jun 4 12:58:53 2010 +0200 + + fixed readme title differently + +commit 3ac015da8ade34d4c7ebeffa2053fcac33fb495b +Author: Scott Chacon <schacon@gmail.com> +Date: Fri Jun 4 12:58:36 2010 +0200 + + fixed readme title + +commit 558151a95567ba4181bab5746bc8f34bd87143d6 +Merge: b7ae93b 3467b0a +Author: Scott Chacon <schacon@gmail.com> +Date: Fri Jun 4 12:37:05 2010 +0200 + + Merge branch 'change_class' +... ++ + +
Để xem lược sử ngắn gọn trong một dòng, ta dùng tùy chọn
+ --oneline
.
+$ git log --oneline +8d585ea Merge branch 'fix_readme' +3cbb6aa fixed readme title differently +3ac015d fixed readme title +558151a Merge branch 'change_class' +b7ae93b added from ruby +3467b0a changed the class name +17f4acf first commit ++ + +
Qua thông tin thu được, ta hình dung được toàn bộ quá trình phát triển + của nhánh hiện tại (và của dự án). Nếu trong mỗi lần xác nhận, thông điệp + ta muốn Git lưu lại càng chi tiết thì ta dễ dàng nhớ lại, hình dùng + tốt về các thay đổi đã thực hiện cũng như ảnh hưởng của nó lên nhánh + hiện tại..
+ + +Ngoài ra, tùy chọn --graph
rất thú vị, khi nó vẽ ra
+ một cây phản ánh cấu trúc nhánh của dự án: Kết quả của tùy chọn này
+ giải thích tại sao ta dùng từ 'nhánh' để mô tả dự án
+$ git log --oneline --graph +* 8d585ea Merge branch 'fix_readme' +|\ +| * 3ac015d fixed readme title +* | 3cbb6aa fixed readme title differently +|/ +* 558151a Merge branch 'change_class' +|\ +| * 3467b0a changed the class name +* | b7ae93b added from ruby +|/ +* 17f4acf first commit ++ + +
Minh họa có vẻ đơn sơ trên thực tế giúp bạn hình dung rõ hơn về
+ dự án, lý do tạo nhánh và tích hợp các nhánh, và cũng giúp ích cho việc
+ quản lý các nhánh. Sau đây, ta sẽ thử tạo nhánh mới, rẽ vào đó để thực
+ hiện vài thay đổi rồi qua lại nhánh chính. Ta sẽ dùng lệnh log
+ để hình dung chung về tất cả các nhánh.
Trước hết, ta tạo và rẽ vào nhánh 'erlang' để có phiên bản của + chương trình HelloWorld trong ngôn ngữ Erlang. Rõ ràng, ta không nên + tạo ngay một phiên bản Erlang trong nhánh chính, nếu không thì sau một + hồi mọi thứ sẽ trở nên lộn xộn, thậm chí là không làm việc được.
+ ++$ git checkout -b erlang +Switched to a new branch 'erlang' +$ vim erlang_hw.erl +$ git add erlang_hw.erl +$ git commit -m 'added erlang' +[erlang ab5ab4c] added erlang + 1 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 erlang_hw.erl ++ + +
Trong nhánh 'erlang', ta cũng sẽ tạo ra một bản HelloWorl cũng bằng + ngôn ngữ hàm Haskell.
+ ++$ vim haskell.hs +$ git add haskell.hs +$ git commit -m 'added haskell' +[erlang 1834130] added haskell + 1 files changed, 4 insertions(+), 0 deletions(-) + create mode 100644 haskell.hs ++ + +
Các thay đổi được xác nhận. Bây giờ, ta quyết định quay ngược lại + phiên bản Ruby để thay đổi tên lớp. Phiên bản Ruby nằm trong nhánh chính, + vì thế ta cần rẽ vào nhánh đó trước.
+ ++$ git checkout master +Switched to branch 'master' +$ ls +README ruby.rb +$ vim ruby.rb +$ git commit -am 'reverted to old class name' +[master 594f90b] reverted to old class name + 1 files changed, 2 insertions(+), 2 deletions(-) ++ + +
Gỉa sử rằng mọi việc đã xong, bạn quay lại với các công việc khác
+ hơn là dự án HelloWorld buồn tẻ. Rồi một ngày khác, quay lại dự án này
+ ở nhánh 'master', bạn muốn biết những gì đã diễn ra trên nhánh 'erlang'
+ và vị trí trên nhánh chính 'master' mà bạn bắt đầu rẽ vào 'erlang'.
+ Nếu chỉ rẽ vào nhánh rồi xem nội dung các tập tin trong nhánh
+ đó, hiển nhiên là bạn sẽ không hình dung tại sao lại có phiên bản Haskell
+ trong nhánh 'erlang'. Bạn cần phải dùng git log
để tìm
+ hiểu các lý do; ngoài ra, việc chỉ định tên nhánh sẽ cho biết thông tin
+ về điểm rẽ nhánh.
+$ git log --oneline erlang
+1834130 added haskell
+ab5ab4c added erlang
+8d585ea Merge branch 'fix_readme'
+3cbb6aa fixed readme title differently
+3ac015d fixed readme title
+558151a Merge branch 'change_class'
+b7ae93b added from ruby
+3467b0a changed the class name
+17f4acf first commit
+
+
+
+ Từ kết quả trên, dễ thấy là phiên bản Haskell chỉ bắt đầu xuất hiện trong nhánh
+ 'erlang' (được tô màu ở trên). Nhưng git log
còn ghi ra
+ nhiều thông tin ở trước thời điểm nhánh 'erlang' được tạo ra.
+ Quá nhiều! Điều tuyệt vời là Git đã tính tới phàn nàn này: bạn có thể
+ chỉ định Git đưa các thông tin chỉ có ở nhánh này mà không xuất hiện
+ ở nhánh khác. Điều này rất có ích, chẳng hạn khi bạn muốn tích hợp nhánh
+ 'erlang' vào nhánh 'master', nhưng trước khi tích hợp, bạn cần biết
+ những gì sẽ diễn ra khi tích hợp.
+
+ Để không liệt kê các thông tin không cần thiết của một nhánh, bạn
+ dùng dấu mũ ^
trước tên nhánh. Ví dụ, nếu chỉ muốn xem
+ các thay đổi trong nhánh 'erlang', bỏ đi các thay đổi trong nhánh
+ 'master', chỉ việc dùng erlang ^master
:
+
+$ git log --oneline erlang ^master +1834130 added haskell +ab5ab4c added erlang +$ git log --oneline master ^erlang +594f90b reverted to old class name ++ + +
Sử dụng dấu mũ là một cách đơn giản, hiểu quả khi quản lý các nhánh, + cho phép bạn thấy được những cái chỉ có ở nhánh này mà không có ở + nhánh khác. Nhờ đó, bạn kiểm soát các thiếu sót hoặc hình dung + được những thay đổi khi tích hợp các nhánh. +
+ +
+
+ Tóm tắt: bạn dùng git log
để liệt kê thông tin về
+ các lần xác nhận sự thay đổi mã nguồn hoặc các lý do của việc rẽ nhánh,
+ nhờ đó giúp bạn hình dung quá trình phát triển và trạng thái hiện tại
+ của dự án.
+
+ Có một số thời điểm quan trọng trong quá trình phát triển dự án mà
+ bạn muốn ghi nhớ một cách dễ dàng và dài lâu. Chúng được đánh dấu
+ bằng lệnh git tag
: lệnh này đánh dấu ở một điểm trên nhánh
+ để bạn có thể dễ dàng so sánh với các xác nhận khác trong tương lai.
+ Thường thì bạn sẽ dùng 'tag' (thẻ) khi đưa ra một phiên bản của dự án.
+
Ví dụ, ta muốn công bố phiên bản "1.0" của chương trình HelloWorld.
+ Ta có đánh dấu sự thay đổi cuối cùng (HEAD
) là "v1.0" bằng
+ lệnh git tag -a v1.0
. Tùy chọn -a
cho phép
+ bạn thêm chú thích cho thẻ "v1.0". Mặc dù việc không dùng tùy chọn đó
+ cũng có tác dụng đánh dấu, nhưng kết quả là thông tin về thời điểm đánh
+ dấu, tác giả, các ghi chú bổ sung sẽ không được lưu lại. Vì vậy,
+ bạn luôn nên dùng tùy chọn -a
.
+$ git tag -a v1.0 ++ + +
Sau lệnh git tag -a
như trên, Git sẽ mở ra trình sọan thảo
+ để bạn bắt đầu ghi thông tin chi tiết về thẻ.
Sau đó, sử dụng lệnh git log --decorate
, ngoài các thông
+ tin về những lần xác nhận, bạn còn thấy thêm thông tin về các thẻ.
+$ git log --oneline --decorate --graph
+* 594f90b (HEAD, tag: v1.0, master) reverted to old class name
+* 8d585ea Merge branch 'fix_readme'
+|\
+| * 3ac015d (fix_readme) fixed readme title
+* | 3cbb6aa fixed readme title differently
+|/
+* 558151a Merge branch 'change_class'
+|\
+| * 3467b0a changed the class name
+* | b7ae93b added from ruby
+|/
+* 17f4acf first commit
+
+
+
+ Nếu sau khi đánh dấu, bạn xác nhận thêm các thay đổi, thẻ vẫn giữ + nguyên vị trí ở lần nó tạo ra lần đầu tiên. Như vậy, thẻ được đánh dấu + sẽ cố định và có thể dùng để so sánh với các trạng thái mới của dự án + trong tương lai.
+ +Việc đánh dấu cho các thay đổi hiển nhiên không phải là điều bắt buộc.
+ Có thể xảy ra việc bạn đã công bố một phiên bản của dự án mà không (quên)
+ đánh dấu. Khi đó, nếu muốn bổ sung đánh dấu, bạn cũng dùng lệnh git tag
,
+ nhưng đi kèm với chỉ số của xác nhận. Ví dụ, ta sẽ đánh dấu cho xác
+ nhận mang chỉ số 558151a
như sau đây:
+$ git tag -a v0.9 558151a
+$ git log --oneline --decorate --graph
+* 594f90b (HEAD, tag: v1.0, master) reverted to old class name
+* 8d585ea Merge branch 'fix_readme'
+|\
+| * 3ac015d (fix_readme) fixed readme title
+* | 3cbb6aa fixed readme title differently
+|/
+* 558151a (tag: v0.9) Merge branch 'change_class'
+|\
+| * 3467b0a changed the class name
+* | b7ae93b added from ruby
+|/
+* 17f4acf first commit
+
+
+
+ Các nhãn trỏ đến các đối tượng đã được theo dõi bởi phân nhánh sẽ được
+ tự động tải về khi bạn fetch
từ kho lưu trữ đàu xa. Tuy nhiên,
+ các nhãn không truy cập được bởi phân nhánh sẽ được bỏ qua. Bạn dùng tùy
+ chọn --tags
để chắc rằng tất cả các nhãn được kèm
+ theo khi tải về.
+$ git fetch origin --tags +remote: Counting objects: 1832, done. +remote: Compressing objects: 100% (726/726), done. +remote: Total 1519 (delta 1000), reused 1202 (delta 764) +Receiving objects: 100% (1519/1519), 1.30 MiB | 1.21 MiB/s, done. +Resolving deltas: 100% (1000/1000), completed with 182 local objects. +From git://github.com:example-user/example-repo + * [new tag] v1.0 -> v1.0 + * [new tag] v1.1 -> v1.1 ++ + +
Nếu bạn muốn dùng một nhãn đơn, dùng lệnh git fetch <remote>
+ tag <tag-name>
.
+
Mặc định, các nhãn không được kèm theo khi push
đến kho lưu
+ trữ đầu xa. Nếu bạn muốn kèm theo, bạn phải thêm vào tùy chọn
+ --tags
vào lệnh git push
.
+
+
+
+ Tóm tắt: bạn dùng lệnh git tag
để đánh dấu một xác nhận
+ hoặc điểm quan trọng trong kho lưu trữ. Việc đánh nhãn giúp bạn dễ nhớ các
+ xác nhận hơn mã SHA.
+
Để làm việc với Git, bạn phải có kho lưu trữ để Git cất giữ các bản sao + bạn lưu lại.
+ + ++ Có hai cách để có một kho: đơn giản nhất là bắt đầu từ một thư mục trên máy + tính của bạn, khi bạn muốn bắt đầu một dự án mới hoặc đã có với Git. Cách + thư hai là nhân bản từ một kho lưu trữ đã có; cách này + thường áp dụng khi bạn làm việc với một vài người khác trong dự án, và việc + nhân bản kho lưu trữ Git là để bắt đầu phần việc của riêng bạn cho dự án + đó. +
+ +Bắt đầu từ một thư mục làm việc bất kỳ, bạn dùng lệnh git
+ init
để tạo mới một kho lưu trữ Git cho thư mục đó. Ví dụ, ta có
+ thư mục 'konichiwa' với vài tập tin trong đó:
+$ cd konnichiwa +$ ls +README hello.rb ++ + +
Trong dự án này, chương trình "Hello World" được viết bằng các ngôn
+ ngữ khác nhau, và Ruby là ngôn ngữ đầu tiên. Để bắt đầu quản lý
+ phiên bản với Git, đơn giản ta chạy lệnh git init
để
+ tạo kho lưu trữ:
+$ git init +Initialized empty Git repository in /opt/konnichiwa/.git/ ++ + +
Bạn sẽ thấy xuất hiện thư mục .git
bên trong thư mục
+ 'konichiwa'. Thư mục này là kho lưu trữ Git, nơi mà Git lưu mọi thông
+ tin cần thiết để quản lý các phiên bản của dự án.
+$ ls -a +. .. .git README hello.rb ++ + +
Bây giờ bạn đã có thể bắt đầu ghi các bản sao dự án với khung kho lưu + trữ Git vừa tạo của bạn.
+ +
+
+ Tóm tắt:, bạn dùng git init
để tạo kho
+ lưu trữ Git cho một thư mục đã có. Việc tạo kho này có thể áp dụng
+ cho bất kỳ thư mục nào trên máy tính của bạn.
+ Khi làm việc với người khác, hoặc khi muốn có một bản sao để làm vài việc
+ riêng, bạn sẽ nhân bản kho Git của dự án. Lệnh sẽ dùng là git clone
+ [url]
, trong đó, [url] là địa chỉ của kho.
+
+$ git clone git://github.com/schacon/simplegit.git
+Initialized empty Git repository in /private/tmp/simplegit/.git/
+remote: Counting objects: 100, done.
+remote: Compressing objects: 100% (86/86), done.
+remote: Total 100 (delta 35), reused 0 (delta 0)
+Receiving objects: 100% (100/100), 9.51 KiB, done.
+Resolving deltas: 100% (35/35), done.
+$ cd simplegit/
+$ ls
+README Rakefile lib
+
+
+
+
+ Việc nhân bản một kho sẽ sao chép toàn bộ thông tin lược sử quá trình phát
+ triển dự án về thư mục (ở trên là 'simplegit') trên máy tính của bạn.
+ Trạng thái ban đầu của thư mục đó tương ứng với nhánh phát triển chính
+ (hay nhánh mặc định). Trong thư mục cũng có thư mục con .git
+ là kho lưu trữ Git địa phương (trong khi kho gốc được chỉ ra ở địa chỉ kho
+ trong lệnh nhân bản ở trên).
+
+$ ls -a +. .. .git README Rakefile lib +$ cd .git +$ ls +HEAD description info packed-refs +branches hooks logs refs +config index objects ++ + +
+ Khi nhân bản, Git mặc định tạo một thư mục cùng tên với kho Git trong phần địa + chỉ được cho khi nhân bản (phần tên này nằm sau dấu gạch chéo cuối cùng). + Tuy nhiên, nếu bạn muốn kết quả nhân bản nằm trong thư mục khác, bạn có thể + chỉ ra ở sau địa chỉ kho (cách với địa chỉ kho ít nhất một khoảng trắng.) +
+ +
+
+ Tóm tắt: bạn dùng git clone
để có một
+ bản sao của kho Git trên máy tính, để bạn có thể thực hiện các đóng
+ góp riêng cho dự án.
+ Trang web này để tham khảo về Git: một trang để tham khảo nhanh khi bạn học + hoặc sử dụng Git, chỉ chứa những lệnh quan trọng và hay dùng nhất của Git. + Các lệnh được nhóm lại thành từng mục theo tác vụ, và sẽ được trình bày với + những tùy chọn phổ biến nhất để hoàn thành tác vụ đó. +
+ + ++ Mỗi mục liên kết tới mục khác; mỗi trang cũng có tham khảo tới tài liệu + chuyên sâu hơn (ví dụ liên kết tới trang tài liệu chính thức hoặc các phần + trong tài liệu Sách Pro Git), để giúp các + bạn muốn nắm chắc hơn về Git. +
+Trước tiên ta sẽ tìm hiểu về nguyên lý cơ bản của Git.
+ ++ Điều đầu tiên hết sức quan trọng mà bạn phải biết, là Git rất khác + biệt so với Subversion, Perforce hoặc bất kỳ cách quản lý mã nguồn + nào bạn từng biết. Vì thế, để học Git được mau chóng, tốt nhất là + bạn hãy quên mọi thứ bạn biết về Subversion, CVS, ... để bắt đầu + suy nghĩ theo cách hoàn toàn khác với Git. +
+ + ++ Hãy bắt dầu từ số không. Giả sử bạn đang thiết kế một hệ thống để + quản lý mã nguồn mới. Câu hỏi đặt ra là: phương án đơn giản nhất trước + khi phải cần các công cụ mạnh như Subversion, Perforce,.. là gì? + Câu trả lời có thể là bạn chỉ việc chép thư mục qua một nơi mới, + nhưng cách hay làm để sao lưu dữ liệu. +
+ +$ cp -R project project.bak+ + +
+ Theo cách này, bạn dễ dàng phục hồi lại các tập tin bị thay đổi không + như ý, hoặc bạn có thể so sánh hai thư mục để có được tìm xem có + có sự thay đổi nào đã thực hiện. +
+ + ++ Nếu việc sao chép như trên diễn ra thường xuyên hơn, bạn có thể dùng + thêm các tên thư mục chứa thông tin về ngày tháng: +
+ +$ cp -R project project.2010-06-01.bak+ + +
+ Điều này dẫn tới kết quả là bạn sẽ có rất nhiều bản sao khác nhau của + dự án. Những bản sao này có thể dùng để chia sẻ với người khác, bằng + cách nén một trong các bản sao và đặt chúng lên một máy phục vụ web: + các lập trình viên khác có thể tải về bản sao, xem xét và thực hiện + các miếng vá thích hợp: +
+ ++ $ wget http://example.com/project.2010-06-01.zip + $ unzip project.2010-06-01.zip + $ cp -R project.2010-06-01 project-my-copy + $ cd project-my-copy + $ (change something) + $ diff project-my-copy project.2010-06-01 > change.patch + $ (email change.patch)+ + +
+ Khi nhận được miếng vá, lập trình viên chính của dự án sẽ xem xét và thực + hiện vá vào một bản sao nào đó của dự án. Thực tế, quá trình tạo bản sao, + chia sẻ và vá như trên là nguyên lý làm việc của nhiều hệ thống quản lý mã + nguồn, đặc biệt là của những dự án mã nguồn mở. +
+ + ++ Bây giờ, cũng theo nguyên lý khá hiệu quả đó, ta sẽ xây dựng một + công cụ nhanh hơn và đơn giản hơn: thay vì quản lý phiên bản của từng + tập tin trong dự án (như cách làm của Subversion), ta xây dựng công + cụ để tạo và quản lý các bản sao của toàn bộ dự án, mà ta không phải + tạo ra các bản sao mới của toàn bộ các tập tin (như cách sao chép + đã mô tả ở trên.) +
+ + +
+ Ý tưởng vừa nói mô tả bản chất hoạt động của Git. Bạn sẽ nhờ Git
+ để tạo bản sao của toàn bộ dự án, bằng lệnh git commit
+ (xác nhận), nhưng Git đủ thông minh để tạo ra một danh sách chỉ gồm
+ các tập tin có thay đổi vào lúc xác nhận và thực hiện tạo bản sao
+ chỉ với danh sách đó. Hầu hết các lệnh còn lại của Git sẽ làm việc
+ với các danh sách mà lệnh git commit
tạo ra (so sánh,
+ liệt kê), thay vì với toàn bộ các tập tin có trong thư mục.
+
+ Đơn giản hơn, bạn có thể nghĩ Git như một công cụ để so sánh và + trộn các bản sao của một dự án. Đừng nghĩ Git như công cụ để quản + lý phiên bản của từng tập tin như Subversion. +
+ ++ 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.
+
+ 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.
+
+
+ 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 ++ +
+ Các tùy chọn --since
và --before
hoặc
+ --until
và --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" ++ +
+ 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
và
+ --author
. Nếu bạn muốn dùng dạng thức AND (và) giữa
+ --grep
và --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
+
+
+
+ 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á.
+ +
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.
+ +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.
diff --git a/vi/remotes/index.html b/vi/remotes/index.html new file mode 100644 index 0000000..19315e8 --- /dev/null +++ b/vi/remotes/index.html @@ -0,0 +1,601 @@ +--- +layout: vi_reference +--- + ++ 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
.
+
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.
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.
+ +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. +
+ +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) ++ +
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.
+
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.
+
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.
+
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.
+