Điểm nổi bật từ Git 2.55

Dự án Git nguồn mở vừa phát hành Git 2.55 với các tính năng và sửa lỗi từ hơn 100 người đóng góp, 33 người trong số đó là người mới. Lần cuối cùng chúng tôi cập nhật cho bạn thông tin mới nhất về Git là khi 2.54 được phát hành.
Để kỷ niệm lần phát hành gần đây nhất này, đây là cái nhìn của GitHub về một số tính năng và thay đổi thú vị nhất được giới thiệu kể từ lần trước.
Đóng gói lại với các chỉ mục nhiều gói gia tăng
Những độc giả cũ của loạt bài này có thể nhớ lại phạm vi bao quát của chúng tôi về các chỉ mục nhiều gói gia tăng và các bitmap khả năng tiếp cận nhiều gói gia tăng. Trong trường hợp bạn có thể sử dụng bản cập nhật thì đây là phiên bản ngắn.
Git lưu trữ nội dung kho lưu trữ của bạn dưới dạng các đối tượng riêng lẻ: cam kết, cây và đốm màu. Những đối tượng đó thường nằm trong packfiles, là tập hợp các đối tượng được nén. Một packfile có chỉ mục gói tương ứng cho phép Git định vị bất kỳ đối tượng nào bên trong gói một cách nhanh chóng. Nhưng các kho lưu trữ lớn thường không chỉ có một packfile: theo thời gian, việc tìm nạp, đẩy, nhiệm vụ bảo trì và đóng gói lại có thể để lại nhiều gói.
Chỉ mục nhiều gói (hoặc MIDX) cung cấp cho Git một chỉ mục duy nhất trên nhiều gói. Thay vì mở và tìm kiếm chỉ mục riêng của từng gói, Git có thể hỏi MIDX gói nào chứa một đối tượng nhất định và ở vị trí offset nào. Điều này đặc biệt hữu ích cho các kho lưu trữ lớn và nó là một trong những nền tảng đằng sau chiến lược bảo trì kho lưu trữ của GitHub.
Như chúng tôi đã đề cập khi Git 2.47 giới thiệu định dạng MIDX gia tăng, một kho lưu trữ có thể lưu trữ MIDX của nó dưới dạng một chuỗi các lớp thay vì dưới dạng một MIDX duy nhất bao trùm mọi gói. MIDX một tệp đơn giản và hiệu quả để đọc nhưng nó có chi phí bảo trì quan trọng; vì tệp đó bao gồm mọi gói mà nó bao gồm, ngay cả một bản cập nhật nhỏ cũng có thể yêu cầu ghi lượng lớn vào kho lưu trữ vốn đã lớn.
Các MIDX gia tăng giải quyết vấn đề đó bằng cách lưu trữ một chuỗi các lớp MIDX. Mỗi lớp bao gồm một số tập hợp các gói và tệp chuỗi ghi lại thứ tự của các lớp đó. Việc thêm một lớp mới vào đầu chuỗi không làm mất hiệu lực các lớp cũ hơn, vì vậy Git có thể lập chỉ mục các gói mới được tạo mà không cần viết lại một MIDX duy nhất bao phủ toàn bộ kho lưu trữ.
Git 2.55 dạy git repack cách viết trực tiếp các chuỗi MIDX gia tăng đó:
$ git repack --write-midx=incrementalNếu không có bất kỳ tùy chọn nào khác, chế độ đó chỉ là phần bổ sung: Git viết một lớp mới cho các gói được tạo bởi gói repack và để nguyên các lớp hiện có. Điều đó đã hữu ích khi bạn muốn giảm thiểu số lượng siêu dữ liệu được ghi lại trong quá trình bảo trì.
Nhưng một chuỗi chỉ có phần bổ sung không thể phát triển mãi mãi. Nếu mỗi lần bảo trì thêm một lớp mới thì cuối cùng chính chuỗi đó sẽ trở thành thứ bạn cần bảo trì. Git 2.55 cũng hỗ trợ kết hợp --write-midx=incremental với việc đóng gói lại hình học:
$ git repack --write-midx=incremental --geometric=2 -dKhi các chế độ đó được sử dụng cùng nhau, mỗi lần đóng gói lại sẽ tạo ra một lớp đầu mới, sau đó quyết định xem các lớp liền kề có nên được nén lại với nhau hay không. Quy tắc mặc định được kiểm soát bởi repack.midxSplitFactor: nếu số lượng đối tượng tích lũy trong các lớp mới hơn tăng đủ lớn so với lớp cũ hơn tiếp theo, Git sẽ hợp nhất các lớp đó thành một lớp thay thế duy nhất. Nếu không, các lớp cũ hơn sẽ không bị ảnh hưởng.
Ở cấp độ cao, thuật toán hoạt động như thế này. Bên dưới, NN đề cập đến giá trị repack.midxNewLayerThreshold và ff đề cập đến giá trị repack.midxSplitFactor:
Để xem các phần khớp với nhau như thế nào, hãy bắt đầu với một kho lưu trữ đã có chuỗi MIDX gia tăng. Các lớp cũ hơn ở bên trái và lớp đầu ở bên phải. Trong khi đó, hoạt động bình thường của kho lưu trữ vẫn tiếp tục tạo ra các gói mới. Các gói đó chưa được bao phủ bởi bất kỳ lớp MIDX nào, điều đó có nghĩa là lần bảo trì tiếp theo có hai công việc: quyết định đóng gói lại những gì và quyết định viết lại bao nhiêu chuỗi MIDX.
Thông thường, các gói không có MIDX đó là ứng cử viên đóng gói lại hình học duy nhất: Git có thể viết một gói mới và một lớp MIDX đầu mới mà không làm ảnh hưởng đến bất kỳ lớp hiện có nào. Hình bên dưới cho thấy trường hợp thú vị hơn, trong đó lớp mẹo hiện tại đã tích lũy đủ gói để đáp ứng repack.midxNewLayerThreshold đã được định cấu hình. Khi ngưỡng đó được đáp ứng, các gói từ lớp đầu có thể tham gia các gói mới được viết dưới dạng ứng cử viên đóng gói lại hình học.
Sau đó, đóng gói lại hình học sẽ đặt câu hỏi cục bộ về các gói ứng cử viên mới nhất. Sau đó, việc đóng gói lại hình học sẽ đặt một câu hỏi cục bộ về các gói ứng cử viên mới nhất: gói ngay bên trái của một số hậu tố của gói (𝒫\mathcal{P}) có đủ lớn để duy trì cấp số nhân nếu Git cuộn lên 𝒫\mathcal{P} không? Trong lần thử đầu tiên bên dưới, 𝒫\mathcal{P} chứa gói nhỏ nhất từ lớp mẹo hiện tại cùng với các gói mới không có MIDX. Nhưng gói ở bên trái của phần tách chỉ có 30.000 đối tượng, nhỏ hơn hai lần kích thước của 𝒫\mathcal{P}, do đó phần tách này quá xa về bên phải.
Vì vậy, Git di chuyển phần chia một gói sớm hơn và hỏi lại câu hỏi tương tự. Bây giờ 𝒫\mathcal{P} bao gồm thêm một gói nữa từ lớp mẹo. Gói ngay bên trái có 100.000 đối tượng, ít nhất gấp đôi kích thước của hậu tố đã chọn. Đó là điểm giữ nguyên bất biến hình học, vì vậy Git có thể cuộn chính xác các gói đó vào một gói mới.
Sau khi viết gói mới đó, Git viết một lớp MIDX mẹo mới lên trên gói còn sót lại từ lớp mẹo trước đó và gói cuộn lên mới được viết. Tại thời điểm này, bản thân các gói tin đang ở trạng thái tốt, nhưng chuỗi MIDX có thể vẫn tích lũy quá nhiều lớp nhỏ liền kề. Git áp dụng cùng một bản năng “mới hơn so với cũ hơn” cho chính các lớp MIDX: nếu lớp mới hơn đủ lớn so với lớp lân cận, hãy thu gọn siêu dữ liệu của chúng thành một lớp thay thế.
Bước nén đó chỉ dành cho siêu dữ liệu. Git không đóng gói lại các đối tượng từ các lớp đó; nó ghi một lớp MIDX mới bao gồm các tệp gói giống nhau. Sau đó nó sẽ xem xét lớp cũ hơn tiếp theo. Ở đây, lớp được nén vẫn nhỏ hơn một nửa lớp sâu hơn nên Git dừng lại. Lớp cũ hơn vẫn chưa được xử lý, đây là thuộc tính quan trọng giúp duy trì quá trình bảo trì này.
Kết quả là sự dung hòa giữa hai thái cực. MIDX một tệp giúp giảm thiểu độ phức tạp của việc tra cứu nhưng có thể yêu cầu ghi lại nhiều lần trong quá trình bảo trì. MIDX gia tăng hoàn toàn chỉ bổ sung sẽ giảm thiểu mỗi lần ghi nhưng cho phép chuỗi phát triển mà không bị ràng buộc. Việc đóng gói lại tăng dần hình học giữ số lớp logarit trong tổng số đối tượng, đồng thời đảm bảo rằng các lớp mới nhất, nhỏ nhất được viết lại thường xuyên hơn các lớp cũ hơn, lớn hơn.
Điều này cũng tích hợp với máy đóng gói lại hiện có của Git. Các gói mới được viết chưa được chuỗi MIDX bao phủ luôn là ứng cử viên cho việc đóng gói lại hình học; các gói trong các lớp MIDX sâu hơn sẽ được giữ nguyên. Các gói trong lớp MIDX của mẹo chỉ tham gia nhóm ứng cử viên sau khi lớp mẹo có ít nhất các gói repack.midxNewLayerThreshold. Nếu lớp đầu vẫn nhỏ hơn ngưỡng đó, Git sẽ bỏ qua việc làm phiền nó hoàn toàn và chỉ cần thêm một lớp mới cho các gói mới được viết.
Đối với các kho lưu trữ nhận được luồng đối tượng mới ổn định, điều này có nghĩa là việc bảo trì định kỳ có thể cập nhật dần dần siêu dữ liệu gói của kho lưu trữ mà không buộc mỗi lần chạy bảo trì phải ghi lại một MIDX duy nhất bao trùm toàn bộ kho đối tượng.
Sửa các cam kết trước đó bằng lịch sử git
Bất cứ ai đã hoàn thiện một chuỗi cam kết trước khi gửi nó đi xem xét đều có thể đã có trải nghiệm này: bạn nhận thấy rằng một thay đổi trong cây làm việc của bạn thực sự thuộc về một cam kết trước đó, chứ không phải ở đầu nhánh.
Ngày nay, một cách phổ biến để xử lý việc đó là tạo một cam kết sửa lỗi và sau đó tự động xóa nó:
$ git commit --fixup=<commit> $ git rebase --autosquash <commit>^Cách đó hiệu quả nhưng nó yêu cầu bạn giải thích cơ chế thay vì mục đích. Git 2.55 được xây dựng dựa trên lệnh lịch sử git thử nghiệm mà Git 2.54 đã giới thiệu bằng cách thêm một lệnh con sửa lỗi mới. Nó áp dụng các thay đổi hiện được thực hiện trong chỉ mục cho một cam kết trước đó:
$ git history fixup <commit>Đây là một ví dụ nhỏ. Cam kết đầu tiên giới thiệu một công thức làm bánh kếp, sau đó là một vài cam kết khác ở trên cùng. Sau đó, chúng tôi nhận ra rằng công thức này thiếu xi-rô cây phong. Sau khi thực hiện thay đổi một dòng đó, git history fixup <commit> xếp nó vào cam kết công thức ban đầu và phát lại các cam kết con cháu ở trên cùng.
Ở đây, thay đổi theo giai đoạn trở thành một phần của chính cam kết mục tiêu. Cam kết đích giữ nguyên thông báo và quyền tác giả của nó theo mặc định, trừ khi bạn chuyển --reedit-message và Git viết lại các cam kết tiếp theo để nhánh kết thúc ở một lịch sử tương đương với bản sửa lỗi ở đúng vị trí.
Giống như phần còn lại của lịch sử git, lệnh này vẫn đang thử nghiệm. Nó cũng có chủ ý bảo thủ. Bởi vì bản sửa lỗi đọc từ chỉ mục nên nó cần một cây làm việc và không thể hoạt động trong một kho lưu trữ trống; nếu việc áp dụng thay đổi theo giai đoạn sẽ tạo ra xung đột thì lệnh sẽ hủy bỏ thay vì khiến bạn phải viết lại giữa chừng.
Phần nổi của tảng băng chìm…
Bây giờ chúng tôi đã đề cập chi tiết hơn về những thay đổi lớn nhất, hãy cùng xem xét tuyển tập một số tính năng và bản cập nhật mới khác trong bản phát hành này.
• Những độc giả cũ của loạt bài này có thể nhớ phạm vi của chúng tôi về các hook dựa trên cấu hình từ Git 2.54, cho phép bạn xác định các hook trong cấu hình Git của mình thay vì chỉ dưới dạng các tệp thực thi trong $GIT_DIR/hooks. Móc là các tập lệnh mà Git chạy tại các điểm nổi tiếng trong quy trình làm việc của bạn, như trước khi tạo cam kết hoặc sau khi nhận được lệnh đẩy. Việc chuyển chúng vào cấu hình giúp các hook đó dễ dàng chia sẻ, soạn thảo và vô hiệu hóa có chọn lọc hơn mà không cần sao chép tập lệnh vào thư mục hook của mỗi kho lưu trữ. Git 2.55 mở rộng công việc đó bằng cách cho phép các hook được cấu hình tương thích chạy song song. Ví dụ: một dự án có thể có các móc nối trước cam kết độc lập để kiểm tra linting và đơn vị; nếu cả hai đều khai báo hook.<name>.parallel = true, Git có thể chạy chúng cùng một lúc. Số lượng công việc đồng thời có thể được kiểm soát trên toàn cầu bằng hook.jobs, trên mỗi sự kiện với hook.<event>.jobs hoặc trên dòng lệnh bằng git hook run -j. Các hook cần trạng thái chia sẻ, như hook thông báo cam kết hoặc các hook khác kiểm tra chỉ mục hoặc cây làm việc, sẽ tiếp tục chạy tuần tự.[nguồn]
• Nếu bạn đã từng chạy git status chỉ để nhận được một khoảng dừng dài trên thiết bị đầu cuối của mình, bạn có thể đã sử dụng trình giám sát hệ thống tệp tích hợp của Git để tăng tốc độ sao lưu mọi thứ. Khi core.fsmonitor được bật, các lệnh như trạng thái git có thể hỏi một trình nền chạy dài xem đường dẫn nào đã thay đổi thay vì quét toàn bộ cây đang hoạt động. Cho đến nay, trình nền tích hợp đó chỉ khả dụng trên macOS và Windows. Git 2.55 bổ sung hỗ trợ cho Linux, trong đó việc triển khai sử dụng inotify. Tính năng này hoạt động mà không cần đặc quyền nâng cao nhưng yêu cầu một lượt xem cho mỗi thư mục, vì vậy các kho lưu trữ rất lớn có thể cần tăng giới hạn fs.inotify.max_user_watches. Giống như trên các nền tảng khác, daemon thận trọng đối với các kho lưu trữ gắn trên mạng, vẫn được chọn tham gia.[nguồn]
• Bitmap khả năng tiếp cận là một trong những thủ thuật mà Git sử dụng để trả lời các câu hỏi như “đối tượng nào có thể truy cập được từ cam kết này?” mà không cần đi lại toàn bộ đồ thị đối tượng từ đầu. Chúng làm cho việc truyền tải đối tượng nhanh hơn, nhưng Git vẫn phải xây dựng và cập nhật các bitmap đó trong các tác vụ bảo trì như git repack --write-midx-bitmaps.Git 2.55 làm cho đường dẫn tạo đó nhanh hơn bằng cách tránh đệ quy cây không cần thiết, sử dụng lại các bitmap đã chọn đã được tính toán, lưu vị trí đối tượng vào bộ nhớ đệm và sắp xếp các bitmap trước khi XOR chúng lại với nhau. Trong các điểm chuẩn từ loạt bản vá, những cải tiến chung đó đã giảm thời gian tạo bitmap trong một kho lưu trữ lớn từ khoảng 612 giây xuống còn khoảng 294 giây. Chuỗi tương tự cũng cải thiện các bitmap giả hợp nhất, nhóm các tham chiếu có liên quan lại với nhau để Git có thể kết hợp các mảng bit được tính toán trước trong quá trình truyền tải thay vì khám phá lại các đối tượng giống nhau nhiều lần. Trong một điểm chuẩn, các phép hợp nhất giả đã tạo ra một quá trình truyền tải git rev-list --objects --use-bitmap-index đầy đủ nhanh hơn gần 20 lần, nhưng trước đó đã tăng gần gấp đôi thời gian tạo bitmap. Sau những thay đổi này, việc hợp nhất giả giữ phần lớn tốc độ truyền tải của chúng trong khi thêm ít công việc hơn vào đường dẫn tạo bitmap.[nguồn, nguồn]
• Nếu bạn sử dụng bản sao một phần, gói được lọc hoặc quy trình làm việc khác mà Git cố tình bỏ qua một số đối tượng thì kích thước gói vẫn quan trọng. Chế độ git pack-objects --path-walk, được giới thiệu trong Git 2.51, nhóm các đối tượng theo đường dẫn trước khi thực hiện lần nén thứ hai, điều này có thể tạo ra vùng delta tốt hơn khi vị trí đường dẫn quan trọng. Trong Git 2.55, --path-walk có thể được kết hợp với các bộ lọc bao gồm blob:none, blob:limit=<n>, tree:0, object:type=<type>, thưa thớt:<oid> và kết hợp: bộ lọc tương thích. Điều đó làm cho việc đóng gói bằng cách sử dụng --path-walk có sẵn trong các quy trình làm việc gói sao chép một phần và gói được lọc hơn. Trong một điểm chuẩn trên kho lưu trữ riêng của Git, việc đóng gói lại đường dẫn không có blob đã tạo ra một gói nhỏ hơn khoảng 16%, với chi phí tính toán vùng đồng bằng mới chậm hơn.[nguồn]
• Git đã học một lệnh thử nghiệm mới, git format-rev, để sửa đổi định dạng đẹp từ đầu vào tiêu chuẩn. Không giống như git log, ghi lại một loạt lịch sử, git format-rev được thiết kế cho các trường hợp bạn gặp phải từng lần xác nhận hoặc được nhúng vào văn bản khác. Ví dụ: giả sử bạn đang sử dụng git được sửa đổi lần cuối để in cam kết sửa đổi lần cuối từng đường dẫn trong một số thư mục. Điều gì sẽ xảy ra nếu bạn muốn biết ai đã sửa đổi từng đường dẫn lần cuối chứ không chỉ là cam kết nào đã thực hiện điều đó? Bạn có thể thay thế những cam kết đó bằng tên tác giả bằng cách chuyển đầu ra của nó thông qua một cái gì đó như thế này: $ git sửa đổi lần cuối | perl -F'\t' -lane ' chomp($F[0] = qx(git show -s --format=%an $F[0])); in tham gia "\t", @F ' Junio C Hamano dựng sẵn/commit.c […] Điều đó có hiệu quả, nhưng nó phải bắt đầu một quy trình Git mới cho mỗi hàng chỉ để định dạng cam kết. Trong Git 2.55, git format-rev có thể xử lý phần đó như một đường dẫn thông thường: $ git sửa đổi lần cuối | git format-rev --stdin-mode=text --format=%an Junio C Hamano dựng sẵn/commit.c […] Chế độ văn bản của lệnh cũng có thể viết lại tên đối tượng cam kết đầy đủ được tìm thấy trong văn bản dạng tự do, điều này hữu ích cho các hook thông báo cam kết hoặc các quy trình công việc tập lệnh khác.[nguồn]
• Khi bạn đẩy kho lưu trữ của mình đến một nơi nào đó, bạn có thể nhận thấy đầu ra bắt đầu bằng remote:: $ git đẩy nguồn gốc chính Liệt kê các đối tượng: 5, xong. […] từ xa: Giải quyết vùng đồng bằng: 100% (2/2), hoàn thành với 1 đối tượng cục bộ. Khi máy khách tìm nạp hoặc đẩy, Git có thể ghép nhiều luồng khác nhau trên cùng một kết nối: một dải bên mang dữ liệu packfile (các đối tượng thực tế đang được truyền), một dải bên khác mang thông báo tiến trình mà máy khách thường in ra stderr và luồng thứ ba mang lỗi từ điều khiển từ xa. Những thông báo tiến trình đó rất hữu ích nhưng chúng cũng đến từ phía bên kia của kết nối và có thể được in trực tiếp đến thiết bị đầu cuối của bạn. Trước Git 2.55, điều đó có nghĩa là máy chủ có thể bao gồm các chuỗi điều khiển đầu cuối tùy ý trong đầu ra dải biên, bao gồm các chuỗi di chuyển con trỏ hoặc xóa văn bản. Giờ đây, Git che giấu hầu hết các ký tự điều khiển đó theo mặc định trong khi vẫn cho phép các chuỗi màu ANSI, do đó, đầu ra tiến trình được tô màu tiếp tục hoạt động.[nguồn]
• Giả sử bạn đang chỉnh sửa một tập tin được nửa chừng thì bạn nhận ra rằng mình đã bắt đầu từ sai nhánh. Nếu nhánh mà bạn muốn chuyển sang đã thay đổi cùng một đường dẫn, một gitcheck <branch> đơn giản sẽ từ chối di chuyển và có nguy cơ làm tắc nghẽn công việc của bạn. git kiểm tra -m <branch> là phiên bản "cố gắng mang theo các chỉnh sửa cục bộ của tôi" của hoạt động đó. Nhưng điều gì sẽ xảy ra khi phía bên kia có các sửa đổi đối với cùng một đường dẫn đó? Trước đây, gitcheck -m đã cho bạn một cơ hội để giải quyết xung đột ngay lập tức. Git 2.55 giúp điều đó an toàn hơn bằng cách sử dụng tính năng tự động lưu trữ nội bộ, do đó, các thay đổi cục bộ xung đột sẽ được lưu dưới dạng mục nhập lưu trữ mà bạn có thể giải quyết ngay lập tức hoặc áp dụng lại sau.[nguồn]
• Một số dự án cần xuất bản cùng một nhánh tới nhiều nơi, như máy chủ chính và một hoặc nhiều máy nhân bản. Các nhóm từ xa từ lâu đã có sẵn để tìm nạp git, trong đó một nhóm được định cấu hình với các điều khiển từ xa.<name> dưới dạng danh sách các điều khiển từ xa được phân tách bằng khoảng trắng. Git 2.55 cho phép git push sử dụng cách viết tắt tương tự: $ git config remotes.publish "github gitlab mirror" $ git đẩy xuất bản chính Điều này tương đương với việc đẩy tới từng điều khiển từ xa trong nhóm theo trình tự. Vì tính nguyên tử chỉ có thể được đảm bảo cho một kết nối vận chuyển duy nhất, --atomic không được hỗ trợ khi đẩy vào một nhóm.[nguồn]
• git log --graph rất tốt để hiển thị cấu trúc nhánh, cho đến khi biểu đồ quá rộng để đọc. Trong các kho lưu trữ có nhiều nhánh song song, các làn biểu đồ có thể sử dụng phần lớn thiết bị đầu cuối trước khi bạn đến chủ đề cam kết. Git 2.55 thêm --graph-lane-limit=<n> vào git log --graph và các lệnh liên quan. Các làn vượt quá giới hạn được thay thế bằng `~`, làm cho đầu ra biểu đồ dễ quản lý hơn trong các kho lưu trữ có lịch sử rất rộng.[nguồn]
• Giả sử bạn muốn liệt kê 10 lần xác nhận gần đây nhất trên nhánh của mình. Điều đó đủ dễ dàng: git log -n 10 thực hiện chính xác điều đó. Nhưng nếu bạn muốn 10 cam kết lâu đời nhất thì sao? Nếu bạn đang nghĩ, “chắc chắn đó không phải là git log --reverse --10,” thì xin chúc mừng: bạn là người dùng Git kỳ cựu! Thay vì đảo ngược lịch sử và sau đó in 10 lần xác nhận, Git lấy 10 lần xác nhận gần đây nhất và đảo ngược thứ tự của chúng. Bạn có thể đạt được điều đó bằng cách xử lý hậu kỳ toàn bộ phạm vi (ví dụ: với git log --reverse <range> | tail -10) nhưng làm như vậy vẫn yêu cầu Git in và định dạng tất cả các lần xác nhận mà shell sẽ loại bỏ. Git 2.55 thêm tùy chọn --max-count-oldest=<n> mới vào git rev-list và nhóm lệnh git log, thay vào đó sẽ chọn n cam kết cũ nhất trong một phạm vi.[nguồn]
• Trong quá trình tìm nạp, máy khách và máy chủ thương lượng bằng cách yêu cầu máy khách quảng cáo cam kết rằng nó đã có dòng. Điều đó cho phép máy chủ tránh gửi các đối tượng mà máy khách đã có thể tiếp cận. Nhưng trong các kho lưu trữ có nhiều tài liệu tham khảo, thuật toán đàm phán có thể bỏ qua một tham chiếu đặc biệt quan trọng để tìm kiếm lịch sử chung. Git 2.55 bổ sung thêm các điều khiển mới cho những tham chiếu nào tham gia đàm phán. Các tùy chọn bao gồm và hạn chế mới, cùng với cấu hình remote.* tương ứng, cho phép người dùng yêu cầu gửi một số giới thiệu nhất định dưới dạng dòng có hoặc giới hạn thương lượng ở một nhóm giới thiệu cụ thể.[nguồn]
Những độc giả cũ của loạt bài này có thể nhớ phạm vi bao quát của chúng tôi về các hook dựa trên cấu hình từ Git 2.54, cho phép bạn xác định các hook trong cấu hình Git của mình thay vì chỉ dưới dạng các tệp thực thi trong $GIT_DIR/hooks. Móc là các tập lệnh mà Git chạy tại các điểm nổi tiếng trong quy trình làm việc của bạn, như trước khi tạo cam kết hoặc sau khi nhận được lệnh đẩy. Việc chuyển chúng vào cấu hình giúp các hook đó dễ dàng chia sẻ, soạn thảo và vô hiệu hóa có chọn lọc hơn mà không cần sao chép tập lệnh vào thư mục hook của mỗi kho lưu trữ.
Git 2.55 mở rộng công việc đó bằng cách cho phép các hook được cấu hình tương thích chạy song song. Ví dụ: một dự án có thể có các móc nối trước cam kết độc lập để kiểm tra linting và đơn vị; nếu cả hai đều khai báo hook.<name>.parallel = true, Git có thể chạy chúng cùng một lúc. Số lượng công việc đồng thời có thể được kiểm soát trên toàn cầu bằng hook.jobs, trên mỗi sự kiện với hook.<event>.jobs hoặc trên dòng lệnh bằng git hook run -j. Các móc cần trạng thái chia sẻ, như móc thông báo cam kết hoặc các móc khác kiểm tra chỉ mục hoặc cây làm việc, tiếp tục chạy tuần tự.
Nếu bạn đã từng chạy trạng thái git chỉ để được chào đón bằng một khoảng dừng dài ở thiết bị đầu cuối của mình, bạn có thể đã sử dụng trình giám sát hệ thống tệp tích hợp của Git để tăng tốc độ sao lưu mọi thứ. Khi core.fsmonitor được bật, các lệnh như trạng thái git có thể hỏi một trình nền chạy dài xem đường dẫn nào đã thay đổi thay vì quét toàn bộ cây làm việc.
Cho đến thời điểm hiện tại, daemon tích hợp đó chỉ có trên macOS và Windows. Git 2.55 bổ sung hỗ trợ cho Linux, trong đó việc triển khai sử dụng inotify. Tính năng này hoạt động mà không cần đặc quyền nâng cao nhưng yêu cầu một lượt xem cho mỗi thư mục, vì vậy các kho lưu trữ rất lớn có thể cần tăng giới hạn fs.inotify.max_user_watches. Giống như trên các nền tảng khác, daemon được bảo thủ đối với các kho lưu trữ gắn trên mạng, vẫn được chọn tham gia.
Bitmap khả năng tiếp cận là một trong những thủ thuật mà Git sử dụng để trả lời các câu hỏi như “đối tượng nào có thể truy cập được từ cam kết này?” mà không cần đi lại toàn bộ đồ thị đối tượng từ đầu. Chúng làm cho việc truyền tải đối tượng nhanh hơn, nhưng Git vẫn phải xây dựng và cập nhật các bitmap đó trong các tác vụ bảo trì như git repack --write-midx-bitmaps.
Git 2.55 làm cho đường dẫn thế hệ đó nhanh hơn bằng cách tránh đệ quy cây không cần thiết, sử dụng lại các bitmap đã chọn đã được tính toán, lưu vị trí đối tượng vào bộ nhớ đệm và sắp xếp các bitmap trước khi XOR chúng lại với nhau. Trong các điểm chuẩn từ loạt bản vá, những cải tiến chung đó đã giảm thời gian tạo bitmap trong một kho lưu trữ lớn từ khoảng 612 giây xuống còn khoảng 294 giây.
Chuỗi tương tự cũng cải thiện các bitmap giả hợp nhất, nhóm các tham chiếu liên quan lại với nhau để Git có thể kết hợp các mảng bit được tính toán trước trong quá trình truyền tải thay vì khám phá lại cùng một đối tượng nhiều lần. Trong một điểm chuẩn, các phép hợp nhất giả đã tạo ra một quá trình truyền tải git rev-list --objects --use-bitmap-index đầy đủ nhanh hơn gần 20 lần, nhưng trước đó đã tăng gần gấp đôi thời gian tạo bitmap. Sau những thay đổi này, việc hợp nhất giả giữ phần lớn tốc độ truyền tải của chúng trong khi thêm ít công việc hơn vào đường dẫn tạo bitmap.
[nguồn, nguồn]
Nếu bạn sử dụng bản sao một phần, gói được lọc hoặc quy trình làm việc khác mà Git cố tình bỏ qua một số đối tượng thì kích thước gói vẫn quan trọng. Chế độ git pack-objects --path-walk, được giới thiệu trong Git 2.51, nhóm các đối tượng theo đường dẫn trước khi thực hiện lần nén thứ hai, điều này có thể tạo ra vùng đồng bằng tốt hơn khi vị trí đường dẫn quan trọng.
Trong Git 2.55, --path-walk có thể được kết hợp với các bộ lọc bao gồm blob:none, blob:limit=<n>, tree:0, object:type=<type>,sparse:<oid> và kết hợp tương thích: bộ lọc. Điều đó làm cho việc đóng gói bằng cách sử dụng --path-walk có sẵn trong các quy trình làm việc gói sao chép một phần và gói được lọc hơn. Trong một điểm chuẩn trên kho lưu trữ riêng của Git, gói repack không có blob-less path-walk đã tạo ra gói nhỏ hơn khoảng 16%, với chi phí tính toán delta mới chậm hơn.
Git đã học một lệnh thử nghiệm mới, git format-rev, để sửa đổi định dạng đẹp từ đầu vào tiêu chuẩn. Không giống như git log, ghi lại một loạt lịch sử, git format-rev được thiết kế cho các trường hợp bạn gặp phải từng lần một hoặc được nhúng trong văn bản khác.
Ví dụ: giả sử bạn đang sử dụng git được sửa đổi lần cuối để in cam kết sửa đổi lần cuối từng đường dẫn trong một số thư mục. Điều gì sẽ xảy ra nếu bạn muốn biết ai đã sửa đổi từng đường dẫn lần cuối chứ không chỉ là cam kết nào đã thực hiện điều đó? Bạn có thể thay thế những cam kết đó bằng tên tác giả bằng cách chuyển đầu ra của nó thông qua một cái gì đó như thế này:
$ git last-modified | perl -F'\t' -lane ' chomp($F[0] = qx(git show -s --format=%an $F[0])); print join "\t", @F ' Junio C Hamano builtin/commit.c [...]Điều đó có hiệu quả, nhưng nó phải bắt đầu một quy trình Git mới cho mỗi hàng chỉ để định dạng cam kết. Trong Git 2.55, git format-rev có thể xử lý phần đó như một đường dẫn thông thường:
$ git last-modified | git format-rev --stdin-mode=text --format=%an Junio C Hamano builtin/commit.c [...]Chế độ văn bản của lệnh cũng có thể viết lại tên đối tượng cam kết đầy đủ được tìm thấy trong văn bản dạng tự do, điều này rất hữu ích cho các hook thông báo cam kết hoặc các quy trình viết tập lệnh khác.
Khi bạn đẩy kho lưu trữ của mình đến một nơi nào đó, bạn có thể nhận thấy đầu ra bắt đầu bằng remote::
$ git push origin main Enumerating objects: 5, done. [...] remote: Resolving deltas: 100% (2/2), completed with 1 local object.Khi máy khách tìm nạp hoặc đẩy, Git có thể ghép nhiều luồng khác nhau trên cùng một kết nối: một dải bên mang dữ liệu packfile (các đối tượng thực tế đang được truyền), một dải bên khác mang thông báo tiến trình mà máy khách thường in ra stderr và dải thứ ba mang lỗi từ điều khiển từ xa.
Những thông báo tiến trình đó rất hữu ích nhưng chúng cũng đến từ phía bên kia của kết nối và có thể được in trực tiếp đến thiết bị đầu cuối của bạn. Trước Git 2.55, điều đó có nghĩa là máy chủ có thể bao gồm các chuỗi điều khiển đầu cuối tùy ý trong đầu ra dải biên, bao gồm các chuỗi di chuyển con trỏ hoặc xóa văn bản. Git hiện che giấu hầu hết các ký tự điều khiển đó theo mặc định trong khi vẫn cho phép các chuỗi màu ANSI, do đó, đầu ra tiến trình được tô màu tiếp tục hoạt động.
Giả sử bạn đang chỉnh sửa một tập tin được nửa chừng thì bạn nhận ra rằng mình đã bắt đầu từ sai nhánh. Nếu nhánh mà bạn muốn chuyển sang đã thay đổi cùng một đường dẫn, một gitcheck <branch> đơn giản sẽ từ chối di chuyển và có nguy cơ làm tắc nghẽn công việc của bạn. git kiểm tra -m <branch> là phiên bản "cố gắng mang theo các chỉnh sửa cục bộ của tôi" của hoạt động đó.
Nhưng điều gì sẽ xảy ra khi phía bên kia có những sửa đổi đối với con đường tương tự? Trước đây, gitcheck -m đã cho bạn một cơ hội để giải quyết xung đột ngay lập tức. Git 2.55 làm cho điều đó an toàn hơn bằng cách sử dụng tính năng tự động lưu trữ nội bộ, do đó, các thay đổi cục bộ xung đột sẽ được lưu dưới dạng mục nhập lưu trữ mà bạn có thể giải quyết ngay lập tức hoặc áp dụng lại sau.
Một số dự án cần xuất bản cùng một nhánh tới nhiều nơi, chẳng hạn như máy chủ chính và một hoặc nhiều máy nhân bản. Các nhóm từ xa từ lâu đã có sẵn để tìm nạp git, trong đó một nhóm được định cấu hình với các điều khiển từ xa.<name> dưới dạng danh sách các điều khiển từ xa được phân tách bằng khoảng trắng. Git 2.55 cho phép git push sử dụng cách viết tắt tương tự:
$ git config remotes.publish "github gitlab mirror" $ git push publish mainĐiều này tương đương với việc đẩy tới từng điều khiển từ xa trong nhóm theo trình tự. Vì tính nguyên tử chỉ có thể được đảm bảo cho một kết nối vận chuyển duy nhất, nên --atomic không được hỗ trợ khi đẩy vào một nhóm.
git log --graph rất tốt để trực quan hóa cấu trúc nhánh, cho đến khi biểu đồ quá rộng để đọc. Trong các kho lưu trữ có nhiều nhánh song song, các làn biểu đồ có thể sử dụng phần lớn thiết bị đầu cuối trước khi bạn đến chủ đề cam kết.
Git 2.55 thêm --graph-lane-limit=<n> vào git log --graph và các lệnh liên quan. Các làn vượt quá giới hạn được thay thế bằng `~`, làm cho đầu ra biểu đồ dễ quản lý hơn trong các kho có lịch sử rất rộng.
Giả sử bạn muốn liệt kê 10 cam kết gần đây nhất trên chi nhánh của mình. Điều đó đủ dễ dàng: git log -n 10 thực hiện chính xác điều đó. Nhưng nếu bạn muốn 10 cam kết lâu đời nhất thì sao? Nếu bạn đang nghĩ, “chắc chắn đó không phải là git log --reverse --10,” thì xin chúc mừng: bạn là người dùng Git kỳ cựu! Thay vì đảo ngược lịch sử và sau đó in 10 lần xác nhận, Git lấy 10 lần xác nhận gần đây nhất và đảo ngược thứ tự của chúng.
Bạn có thể đạt được điều đó bằng cách xử lý hậu kỳ toàn bộ phạm vi (ví dụ với git log --reverse <range> | tail -10) nhưng làm như vậy vẫn yêu cầu Git in và định dạng tất cả các cam kết mà shell sẽ loại bỏ. Git 2.55 bổ sung tùy chọn --max-count-oldest=<n> mới cho git rev-list và nhóm lệnh git log, thay vào đó sẽ chọn n cam kết cũ nhất trong một phạm vi.
Trong quá trình tìm nạp, máy khách và máy chủ thương lượng bằng cách yêu cầu máy khách quảng cáo cam kết rằng nó đã có dòng. Điều đó cho phép máy chủ tránh gửi các đối tượng mà máy khách đã có thể tiếp cận. Nhưng trong các kho có nhiều tài liệu tham khảo, thuật toán đàm phán có thể bỏ qua một tham chiếu đặc biệt quan trọng để tìm kiếm lịch sử chung.
Git 2.55 bổ sung thêm các điều khiển mới để các tài liệu tham khảo tham gia đàm phán. Các tùy chọn bao gồm và hạn chế mới, cùng với cấu hình remote.* tương ứng, cho phép người dùng yêu cầu gửi một số giới thiệu nhất định dưới dạng dòng có hoặc giới hạn thương lượng ở một nhóm giới thiệu cụ thể.
…phần còn lại của tảng băng trôi
Đó chỉ là một mẫu thay đổi so với bản phát hành mới nhất. Để biết thêm, hãy xem ghi chú phát hành cho 2.55 hoặc bất kỳ phiên bản nào trước đó trong kho Git.
Bài đăng Điểm nổi bật từ Git 2.55 xuất hiện đầu tiên trên Blog GitHub.