Ở bài viết này, anh em mình cùng tìm hiểu cơ chế hoạt động của git ở mức “sâu hơn” bình thường một chút, cũng không hẳn chạm tới low-level nhưng cũng đủ để chúng ta hiểu và sử dụng nó hiệu quả hơn. Mình hiểu anh em ta ngày nay thường rất ngại đọc, nên mình cũng sẽ viết ngắn nhất có thể.
Điều gì xảy ra khi Commit
Mỗi khi commit, Git thực hiện các bước sau:
– Quét các file đang được track và đã add vào staging area
– Tính hash (SHA) dựa trên nội dung file
– Nếu nội dung thay đổi, Git tạo blob object mới cho file đó
– Tạo tree object mô tả cấu trúc thư mục
– Tạo commit object chứa metadata và trỏ tới tree
Các object được nén bằng zlib và lưu trong .git/objects
Sau này khi Git chạy garbage collection (git gc), các object sẽ được đóng gói thành packfile và tối ưu bằng delta compression để tiết kiệm dung lượng.
Điều gì xảy ra khi Merge branch A vào branch B
Để đơn giản, bây giờ mình sẽ mô tả bằng các workflow trực quan.
Ví dụ, ban đầu chỉ một branch main có commit tuần tự như sau:

Khi này, bạn dev01 được yêu cầu tạo tính năng mới, dev01 tiến hành tạo 1 branch “features/001” từ “main” branch, và có vài commit D, E, F tới khi tính năng này hoàn thành. Trong quá trình này, cũng có vài commit phát sinh G,H trên main

Câu hỏi đặt ra là: Khi merge features/001 vào main, điều gì sẽ xảy ra?
Đơn giản, git sẽ tự động tạo 1 commit mới trên main với message mặc định “Merge pull request # from features/001” và gộp chúng lại. Tuy nhiên nếu trong quá trình features/001 hoàn thành, main không có bất cứ commit nào, git sẽ sử dụng cơ chế fast-forward, đặt ngay Commit F làm head của main.

Nếu từ khi tạo features/001 tới khi merge mà main chưa thay đổi, git sẽ không tạo merge commit mà đơn giản di chuyển con trỏ sang features/001 commit (hash commit features/001 trùng hash main)
Hãy lưu ý: Team cần phải thống nhất ai sử dụng các file nào tránh việc conflict.
Kết quả sau khi merge:

Điều gì xảy ra khi Rebase
Hãy xem lại ví dụ ở Merge, nếu một ngày có vài chục merge vào main thì history nhìn sẽ rối như tơ nhện, việc chúng ta nên suy nghĩ là làm sao để graph commit thực sự là một đường thẳng, clean hơn. Vì vậy rebase được sinh ra để giải quyết vấn đề này.
Khi chạy git rebase main, git sẽ clone toàn bộ commit từ main thành commit mới vào branch hiện tại để đảm bảo các commit theo một đường thẳng. Khi merge, do đã có đầy đủ commit từ, git sẽ tiến hành fast-forward, từ đó các merge commit cũng sẽ không được sinh ra.
Hãy xem ví dụ bằng workflow dưới đây, khi này dev01 đã hoàn thành feature của mình và chuẩn bị push lên remote repo

Bây giờ dev01 chạy git rebase main trên current branch features/001, sau đó mới tiến hành merge. Cuối cùng hãy log xem kết quả, các commit thẳng vào không có merge commit


(Commit đã theo đường thẳng)
Thực chất graph sẽ là
A->B->C->Clone of G -> Clone of H -> D -> E -> F (head)
Một số nguyên tắc khi rebase:
- Chỉ rebase trên local và luôn rebase khi bắt đầu làm việc với branch mới (luôn clone các commit mới nhất về trước khi làm việc)
- Không rebase các branch đang có người làm việc (ví dụ ở đây main là repo tổng sẽ nhận PR từ các branch khác, ít người commit thẳng lên branch này)
… Bài viết vẫn còn được tiếp tục update