drawback.txt rechecked
[gitmagic.git] / vi / secrets.txt
blobd146d1833e2f2b7afc90e8e02f950a3d779bdb5f
1 == Bí Quyết của Git ==
3 Chúng ta mổ xẻ để hiểu được làm thế nào mà Git có thể thi hành kỳ diệu như vậy. Tôi sẽ không thể nói quá chi tiết được. Nếu bạn muốn có được sự mô tả chỉ tiết thì hãy đọc http://schacon.github.com/git/user-manual.html[sổ tay hướng dẫn sử dụng Git].
5 === Tính Ẩn ===
7 Git làm việc có vẻ kín đáo? Chỉ cần nói riêng về việc sử dụng lệnh *commit* và *merge*, bạn có thể làm việc mà không cần biết đến sự tồn tại của hệ thống quản lý mã nguồn. Cho đến khi bạn cần nó, và cho đến khi bạn vui sướng vì Git đã trông coi mã nguồn cho bạn trong suốt thời gian qua.
9 Các hệ thống quản lý mã nguồn khác ép buộc bạn luôn luôn phải tranh đấu với thói quan liêu. Quyền truy cập của các tệp tin có thể là chỉ cho phép đọc trừ phi bạn nói rõ với máy chủ trung tâm là các tệp tin nào bạn muốn chỉnh sửa. Tốc độ làm việc của phần lớn các lệnh sẽ tỷ lệ nghịch với số lượng người sử dụng. Mọi công việc sẽ đình trệ khi mạng máy tính hay máy chủ ngừng hoạt động.
11 Đối lập với hạn chế trên, Git đơn giản giữ lịch sử của dự án của bạn tại thư mục `.git` trong thư mục làm việc của bạn. Đây là bản sao lịch sử của riêng bạn, do vậy bạn có thể làm việc không cần mạng cho đến khi cần truyền thông với những người khác. Bạn có toàn quyền quyết định với các tệp tin của mình bởi vì Git có thể tạo lại trạng thái đã ghi lại từ `.git` bất kỳ lúc nào một cách dễ dàng.
13 === Toàn Vẹn Dữ Liệu ===
15 Phần lớn mọi người sử dụng phương pháp mã hóa để giữ cho thông tin của mình không bị nhòm ngó, nhưng có thứ quan trọng không kém đó là giữ cho thông tin của mình được toàn vẹn. Chính việc sử dụng hàm băm mã hóa đã làm ngăn ngừa sự sai hỏng dữ liệu do rủi ro hay ác ý.
17 Giá trị SHA1 có thể coi như là một số định danh 160-bit không trùng lắp cho mỗi chuỗi ký tự bạn dùng trong đời sống của mình. Trên thực tế nó còn làm được nhiều hơn thế: nó có thể thực hiện điều trên với mọi chuỗi ký tự mà mọi người có thể sử dụng trong suốt cuộc đời của mình.
19 Bản thân giá trị SHA1 cũng là một chuỗi ký tự, chúng ta có thể băm chuỗi có chứa giá trị băm khác. Khả năng quan sát đơn giản này cực kỳ hữu dụng: tra cứu 'hash chains' (tra cứu theo các chuỗi móc xích với nhau bằng giá trị băm). Sau này chúng ta sẽ thấy làm cách nào Git sử dụng nó để mà đảm bảo tính toàn vẹn của dữ liệu.
21 Tóm lại, Git lưu giữ dữ liệu của bạn trong thư mục con `.git/objects`, thay vì sử dụng tên tệp tin như thông thường, bạn sẽ chỉ nhìn thấy ID của chúng. Bằng cách sử dụng ID để làm tên tệp tin, cũng tốt như là cách sử dụng kỹ thuật lockfiles (khóa tệp tin) và timestamp (theo dõi thời gian của tệp tin), Git biến hệ thống tệp tin thông thường bất kỳ nào trở thành một cơ sở dữ liệu hiệu quả và mạnh mẽ.
23 === Thông Minh ===
25 Làm thể nào mà Git biết bạn đã đổi tên một tệp tin, dù là bạn chẳng bao giờ đề cập đến điều này một cách rõ ràng? Chắc chắn rồi, bạn có lẽ đã chạy lệnh *git mv*, nhưng nó chính xác giống hệt như việc chạy lệnh *git rm* sau đó là lệnh *git add*.
27 Git khám phá ra cách truy tìm các tệp tin đã được đổi tên hay sao chép giữa các phiên bản liên tiếp. Trên thực tế, nó có thể tìm ra từng đoạn mã nguồn đã bị di chuyển hay sao chép giữa các tệp tin! Dẫu cho nó không thể xử lý được mọi trường hợp, nó làm khá tốt, và đặc tính này luôn luôn được phát triển. Nếu nó không làm việc với bạn, hãy thử bật các tùy chọn dành cho việc phát hiện sự sao chép, và nên cất nhắc đến việc cập nhật.
29 === Mục Lục ===
31 Với mọi tệp tin được theo dõi, Git ghi lại các thông tin như là kích thước, thời gian tạo và lần cuối sửa đổi trong một tệp tin được biết đến là một mục lục 'index'. Để xác định rõ một tệp tin có bị thay đổi hay không, Git so sánh nó ở thời điểm hiện tại với phần lưu giữ trong bộ nhớ. Nếu chúng giống nhau, thế thì Git có thể bỏ qua việc đọc tệp tin đó lại lần nữa.
33 Bởi vì gọi lệnh ``stat'' nhanh hơn đáng kể so với đọc tệp tin, nếu bạn chỉ chỉnh sửa
34 vài tệp tin, Git có thể cập nhật trạng thái của nó cực kỳ nhanh chóng.
36 Chúng ta đã nói trước rằng mục lục (index) là vùng làm việc của trạng thái. Tại sao lại là một chùm tệp tin
37 stat vùng stage? Bởi vì lệnh add đặt các tệp tin vào trong cơ sở dữ liệu của Git
38 và cập nhật những stat này, trong lúc lệnh commit được thực hiện, mà không có tùy chọn, tạo ra một
39 commit trên cơ sở chỉ trên các stat và các tệp tin đã sẵn có trong cơ sở dữ liệu.
41 === Nguồn Gốc của Git ===
43 http://lkml.org/lkml/2005/4/6/121[Linux Kernel Mailing List post] này miêu tả các sự kiện nối tiếp nhau về Git. Toàn bộ tuyến này chỉ dành cho các sử gia đam mê Git.
45 === Đối tượng Cơ Sở Dữ Liệu ===
47 Mỗi một phiên bản của dữ liệu của bạn được giữ trong 'đối tượng cơ sở dữ liệu' (object database), mà nó nằm trong
48 thư mục con `.git/objects`; cái khác nằm trong thư mục `.git/` lưu giữ ít dữ liệu hơn:
49 mục lục, tên các nhánh, các thẻ tag, các tùy chọn cấu hình, nhật ký, vị trí
50 hiện tại của head của lần commit, và những thứ tương tự như thế. Đối tượng cơ sở dữ liệu cho đến bây giờ vẫn là phần tử cơ bản xuất sắc nhất,
51 và là cội nguồn sức mạnh của Git.
53 Mỗi tệp tin trong `.git/objects` là một 'đối tượng'. Ở đây có 3 loại đối tượng
54 liên quan đến chúng ta: đối tượng nội dung tập tin 'blob', đối tượng cây 'tree', và đối tượng lần chuyển giao 'commit'.
56 === Đối Tượng Blob ===
58 Đầu tiên, hãy tạo một tệp tin bất kỳ. Đặt cho nó một cái tên, tên gì cũng được. Trong một thư mục rỗng:
60  $ echo sweet > YOUR_FILENAME
61  $ git init
62  $ git add .
63  $ find .git/objects -type f
65 Bạn sẽ thấy +.git/objects/aa/823728ea7d592acc69b36875a482cdf3fd5c8d+.
67 Làm sao mà tôi biết được tệp tin khi không thấy tên của nó? Đó là bởi vì đó là giá trị
68 băm SHA1 của:
70  "blob" SP "6" NUL "sweet" LF
72 là aa823728ea7d592acc69b36875a482cdf3fd5c8d,
73 với SP là khoảng trắng, NUL là byte có giá trị bằng 0 và LF ký tự xuống dòng. Bạn có thể xác minh lại
74 bằng lệnh sau:
76   $ printf "blob 6\000sweet\n" | sha1sum
78 Git sử dụng cách 'lấy nội dung để làm tên cho tệp tin': tệp tin không được lưu trữ như theo tên của chúng,
79 mà bằng giá trị băm dữ liệu mà chúng chứa, trong tệp tin chúng ta gọi là một 'đối tượng
80 blob'. Chúng ta có thể nghĩ giá trị băm như là một định danh duy nhất cho nội dung của tệp tin, do vậy
81 ta có tên tệp tin được định danh bởi nội dung của nó. Phần khởi đầu `blob 6` đơn thuần
82 chỉ là phần đầu để thể hiện kiểu của đối tượng và độ dài của nó tính bằng byte; việc làm này
83 làm đơn giản hóa việc vận hành bên trong Git.
85 Đến đây tôi có thể dễ dàng đoán được bạn nghĩ gì. Tên của tệp tin là không thích hợp:
86 chỉ khi có dữ liệu bên trong được sử dụng để xây dựng nên đối tượng blob.
88 Bạn có lẽ sẽ kinh ngạc với những gì xảy ra với các tệp tin có cùng nội dung. Hãy thử thêm một bản sao
89 một tệp tin nào đó của bạn, với bất kỳ một cái tên nào cũng được. Nội dung của +.git/objects+ ở tại
90 cùng một chỗ cho dù bạn thêm vào bao nhiêu lần đi chăng nữa. Git chỉ lưu giữ dữ liệu một lần duy nhất.
92 Nhưng dẫu sao, các tệp tin nằm trong +.git/objects+ đã bị nén lại theo chuẩn zlib do vậy bạn
93 không thể xem chúng một cách trực tiếp được. Đọc chúng thông qua
94 http://www.zlib.net/zpipe.c[zpipe -d], hay gõ:
96  $ git cat-file -p aa823728ea7d592acc69b36875a482cdf3fd5c8d
98 lệnh này trình bày đối tượng được cho ở dạng dễ đọc trên màn hình.
100 === Đối Tượng Tree ===
102 Nhưng mà tên tệp tin ở đâu? Chúng phải được lưu giữ ở đâu đó chứ.
103 Git lấy tên tệp tin trong quá trình commit:
105  $ git commit  # Gõ chú thích.
106  $ find .git/objects -type f
108 Bạn sẽ thấy ba đối tượng. Ở thời điểm này tôi không thể nói hai tệp tin mới này là cái gì, hãy nghĩ nó là một phần của tên tệp tin bạn đang xét. Chúng ta sẽ xuất phát từ giả định bạn chọn ``rose''. Nếu bạn không làm thế, bạn có thể viết lại lịch sử để làm cho nó giống như bạn đã làm thế:
110  $ git filter-branch --tree-filter 'mv YOUR_FILENAME rose'
111  $ find .git/objects -type f
113 Bây giờ bạn có lẽ nhìn thấy tệp tin
114 +.git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9+, bởi vì đây là giá trị băm
115 SHA1 của nội dung của nó:
117  "tree" SP "32" NUL "100644 rose" NUL 0xaa823728ea7d592acc69b36875a482cdf3fd5c8d
119 Xác thực tệp tin này chứa thông tin như trên bằng cách gõ:
121  $ echo 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 | git cat-file --batch
123 Với lệnh zpipe, ta có thể dễ dàng xác thực một giá trị băm:
125  $ zpipe -d < .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9 | sha1sum
127 Sự thẩm tra giá trị băm thì rắc rối hơn thông qua lệnh cat-file bởi vì phần kết xuất của nó chứa nhiều thông tin hơn
128 đối tượng tệp tin thường không bị nén.
130 Tệp tin này là một đối tượng cây 'tree': một danh sách các hàng bao gồm kiểu tệp tin,
131 tên tệp tin, và giá trị băm. Trong ví dụ của chúng ta, kiểu tệp tin là 100644, điều này
132 có nghĩa `rose` là tệp tin bình thường, và giá trị băm là một đối tượng blob mà nó chứa
133 nội dung của `rose'. Dạng tệp tin khác có thể là tệp tin thực thi, liên kết mềm hay
134 các thư mục. Trong trường hợp cuối, giá trị băm sẽ chỉ đến đối tượng cây 'tree'.
136 Nếu bạn đã chạy lệnh filter-branch, bạn sẽ có các đối tượng cũ bạn không cần đến sau này nữa. Mặc dù
137 chúng sẽ bị loại bỏ một cách tự động một khi thời hạn chấm dứt đã đến, nhưng chúng ta sẽ
138 xóa chúng ngay bây giờ theo cách dưới đây:
140  $ rm -r .git/refs/original
141  $ git reflog expire --expire=now --all
142  $ git prune
144 Với các dự án thật bạn nên tránh việc sử dụng lệnh như trên, làm như thế bạn
145 đã phá hủy dữ liệu sao lưu dự phòng. Nếu bạn muốn làm sạch kho chứa, cách hay nhất là tạo
146 một bản sao mới. Cũng thế, hãy cẩn thận khi thao tác trực tiếp với thư mục +.git+: điều gì xảy ra nếu một lệnh
147 Git khác cũng đang thực thi cùng lúc, hay là mất điện đột ngột?
148 Đại khái, refs có thể được xóa bằng lệnh *git update-ref -d*,
149 mặc dù thường thường nó an toàn hơn xóa +refs/original+ bằng tay.
151 === Commit ===
153 Chúng tôi đã giảng giải cho bạn 2 trong số 3 đối tượng của Git. Cái thứ 3 chính là 'commit'. Nội dung
154 của nó buộc chặt vào phần chú thích của lần commit cũng như thời gian, ngày tháng chúng được
155 tạo ra. Để cho khớp với những thứ chúng ta có ở đây, chúng ta sẽ phải chỉnh nó một chút:
157  $ git commit --amend -m Shakespeare  # Thay đổi phần chú thích.
158  $ git filter-branch --env-filter 'export
159      GIT_AUTHOR_DATE="Fri 13 Feb 2009 15:31:30 -0800"
160      GIT_AUTHOR_NAME="Alice"
161      GIT_AUTHOR_EMAIL="alice@example.com"
162      GIT_COMMITTER_DATE="Fri, 13 Feb 2009 15:31:30 -0800"
163      GIT_COMMITTER_NAME="Bob"
164      GIT_COMMITTER_EMAIL="bob@example.com"'  # dấu vết thời gian và tác giả đã bị gian lận.
165  $ find .git/objects -type f
167 Bạn có thể thấy
168 +.git/objects/49/993fe130c4b3bf24857a15d7969c396b7bc187+
169 là giá trị băm SHA1 của nội dung của nó:
171  "commit 158" NUL
172  "tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9" LF
173  "author Alice <alice@example.com> 1234567890 -0800" LF
174  "committer Bob <bob@example.com> 1234567890 -0800" LF
175  LF
176  "Shakespeare" LF
178 Như ở phần trước, bạn có thể chạy lệnh zpipe hay cat-file để tự mình trông thấy.
180 Đây là lần commit đầu tiên, do vậy lần commit này không có cha, nhưng những lần commit sau
181 sẽ luôn luôn chứa it nhất là một dòng chỉ định commit cha.
183 === Khó Phân Biệt Được sự Thần Kỳ ===
185 Bí mật của Git dường như có vẻ đơn giản. Nó giống như bạn có thể trộn lẫn cùng nhau một ít kịch bản và một ít mã C mà đun trong vài giờ: nhào trộn của quá trình hoạt động của hệ thống tệp tin và mã băm SHA1, bày biện thêm với các khóa và đồng bộ hóa tệp tin để tăng vị ngon. Trên thực tế, những mô tả như thế với Git các phiên bản trước kia là chính xác. Tuy nhiên, ngoài chiêu bài đóng gói để tiết kiệm không gian lưu trữ, sử dụng mục lục để tiết kiệm thời gian ra, giờ chúng ta còn biết thêm làm cách nào Git khéo léo thay đổi hệ thống tệp tin thành một cơ sở dữ liệu hoàn hảo cho việc quản lý mã nguồn.
187 Ví dụ, nếu một tệp tin bất kỳ nào đó trong đối tượng cơ sở dữ liệu bị sai hỏng bởi lỗi do ổ đĩa,
188 thế thì giá trị băm tương ứng của nó sẽ không đúng nữa, điều này sẽ mang lại rắc rối cho chúng ta. Bằng
189 việc băm giá trị băm của đối tượng khác, chúng ta có thể duy trì tính toàn vẹn ở tất cả các mức. Commit
190 là hạt nhân, thật vậy đấy, mỗi lần commit không bao giờ ghi lại nửa vời: chúng ta có thể
191 chỉ tính toán mã băm của lần commit và lưu giữ giá trị của nó trong cơ sở dữ liệu sau khi chúng ta đã sẵn sàng
192 lưu tất cả các đối tượng là trees, blobs và cha của các lần commit thích hợp. Đối tượng
193 cơ sở dữ liệu không bị ảnh hưởng bởi các sự cố ngắt quãng bất ngờ như là mất điện đột ngột chẳng hạn.
195 Chúng ta có thể làm thất bại ngay cả những kẻ phá hoại ranh mãnh. Giả sử người nào đó lén lút
196 sửa chữa nội dung của một tệp tin trong một phiên bản cũ của dự án. Để giữ đối tượng
197 cơ sở dữ liệu vẫn hoạt động tốt, họ đồng thời cũng phải thay đổi giá trị băm của
198 đối tượng blob tương ứng vì lẽ rằng nó bây giờ đã khác trước. Điều đó có nghĩa là
199 họ sẽ phải thay đổi giá trị băm của một đối tượng tree có liên quan đến tệp tin,
200 và việc chỉnh sửa giá trị băm của tất cả các đối tượng commit kéo theo như là tree, thêm
201 nữa là các giá trị băm của toàn bộ các lần commit con cháu của nó. Cái này kéo theo
202 giá trị băm của head tại kho trung tâm không giống với thứ đó tại kho chứa sai hỏng. Bằng cách
203 theo dõi sự tương khớp giá trị băm chúng ta có thể xác định được tệp tin bị sai hỏng,
204 cũng như là lần commit nơi mà nó lần đầu bị hư hỏng.
206 Nói ngắn gọn, dùng 20 byte để đại diện cho lần commit cuối là an toàn,
207 việc cố tình sửa đổi nội dung một kho chứa Git là điều không thể thực hiện được.
209 Đặc tính nào của Git là trứ danh nhất? Nhánh? Trộn? Hay Tags?
210 Chỉ là chi tiết. Head hiện hành được giữ trong tệp tin +.git/HEAD+,
211 mà nó có chứa giá trị băm của một đối tượng commit. Giá trị băm được cập nhật trong quá trình commit
212 cũng như là một số lệnh khác. Nhánh đại thể cũng tương tự: chúng là các tệp tin trong thư mục
213 +.git/refs/heads+. Tags cũng thế: chúng ở tại +.git/refs/tags+ nhưng chúng
214 được cập nhật bởi các lệnh khác nhau.