Git, phần mềm quản lý mã nguồn phân tán được phát triển bởi Linus Torvalds vào năm 2005 (Wikipedia viết thế), một công cụ quen thuộc đến nỗi "không một lập trình viên nào không biết" về nó.
Vậy Git có dễ không? Dễ, rất dễ.
Vậy Git có khó không? Khó, một ngày đẹp trời thấy log đỏ, một ngày khác thấy code ôi sao lạ lạ khóc hai hàng nước mắt chứ chẳng chơi.
Vậy rốt cuộc là Git dễ hay khó?
Câu trả lời là dễ. Cái gì dùng quen cũng dễ thôi. Nhưng nếu không dùng thì sao, hẳn nhiên là khó rồi. 🥲
Quay ngược về cách đây bốn năm, khi mình lần đầu tiên vào đại học, code những dòng code đầu tiên (nếu không tính Pascal =)))))). Năm nhất mà, mạnh ai người ấy code, đến giờ submit, nộp mỗi một file đúng input output lên cho thầy. Hay để dễ dàng hơn, thầy tới từng bàn và đọc vài testcase thầy vừa nghĩ ra, pass qua là pass. Thấm thoát thoi đưa, thế mà cũng vào năm hai. Lần đầu tiên tham gia câu lạc bộ, bữa đầu tiên, các anh đã bảo, push code lên Github em nhé. Github là gì, về mày mò một buổi tối, cuối cùng cũng tự tạo repo, tự viết commit, tự pull request, và cuối cùng, tự merge (thứ lỗi cho tôi, thấy báo xanh thì ấn accept thôi =))))))).
Và cứ thế, ai rồi cũng biết Git.
Từ những câu lệnh ai cũng biết
Về cơ bản, mỗi repository sẽ gồm một vài branch, và mỗi branch chứa một vài phiên bản code.
Git Flow cơ bản ai cũng biết
Git Flow cơ bản nhất như sau: Mỗi thành viên trong nhóm phát triển có thể tạo ra các nhánh riêng của dự án để thực hiện các tính năng mới hoặc sửa lỗi mà họ đang làm việc. Khi họ hoàn thành nhiệm vụ của mình, họ có thể tạo ra yêu cầu kéo (pull request) để các leader (reviewer) xem xét và chấp nhận các thay đổi (hoặc là sửa tiếp đi em =))). Sau khi các thay đổi được chấp nhận, các nhánh có thể được merge vào nhánh chính của dự án.
Các branch trên một repo bao gồm:
- Nhánh main: code chính, code release, niềm vui của dev, phiên bản cuối, chạy hoàn hảo, nhưng lâu lâu có bug lại hotfix đỏ mắt.
- Nhánh develop: cũng là code chính, pull request phải qua cửa ải này trước đã. Đây là nơi để xem thử code đã chạy ổn chưa, trước khi release.
- Và vân vân mây mây các nhánh khác. (ví dụ release 1.0.1, và release 1.0.2)
Git checkout - Đi xa để trở về
Lệnh "git checkout", có chức năng giúp di chuyển giữa các nhánh (branch) khác nhau, để chuyển đổi giữa các phiên bản khác nhau của dự án.
- Khi bạn muốn làm việc trên một nhánh khác để phát triển tính năng mới hoặc sửa lỗi, bạn có thể sử dụng lệnh
"git checkout new_branch"
để chuyển đổi sang nhánh đó. - Khi bạn xóa một tệp hoặc thư mục bất kỳ, bạn có thể sử dụng lệnh "git checkout" để khôi phục lại chúng từ phiên bản trước đó.
- Chuyển đổi sang một nhánh khác và khôi phục tất cả các tệp hoặc thư mục từ một phiên bản cụ thể tại cùng một thời điểm, với
git checkout -b new_branch -- <commit_hash>
Mười giây căng thẳng trước khi checkout, đặt tên branch là gì đây? Tên gì cũng được, nhưng để tích đức thì nên cân nhắc:
- Bắt đầu tên nhánh bằng một tiền tố để cho phép phân biệt rõ ràng giữa các loại nhánh khác nhau. Ví dụ: feature/, hotfix/, release/.
- Sử dụng các từ viết thường để đặt tên nhánh, vì Git không phân biệt chữ hoa và chữ thường trong tên nhánh.
- Và đương nhiên, sử dụng các quy ước đặt tên nhánh được đồng nhất trong toàn dự án để giúp cho các thành viên trong nhóm có thể dễ dàng hiểu và sử dụng.
Git add - Nhiều thay đổi quá, một chấm cho xong
Không có gì để nói về lệnh này cả, chỉ là dạo gần đây tôi bắt đầu add một số file mà tôi biết cần sự thay đổi, bỏ qua ti tỉ file khác mà tôi đã sửa để tiện cho việc fix bug mà thôi.
Git commit - Code một tiếng, viết message commit nửa ngày
Mỗi lần tôi gõ "git log --oneline" và ấn Enter, một dãy dài (tràn màn hình) commit message. Lướt xuống một chút, nhìn cái commit một năm trước của một bạn nào đó chỉ vỏn vẹn "fix". Ừ, thôi vậy. Thực ra tôi cũng chẳng bao giờ lướt đến đấy.
Tuy nhiên, vẫn có những "chuẩn mực đạo đức" khi viết commit. Thông thường, cũng như tên branch, nó bao gồm một số tiền tố:
-
feat : tính năng mới
-
fix : sửa chữa một bug nào đó
-
chore : thông báo rằng các thay đổi không liên quan đến việc sửa chữa lỗi hoặc thêm tính năng và không thay đổi các tệp nguồn hoặc tệp kiểm tra (ví dụ: cập nhật các phụ thuộc).
-
refactor – tái cấu trúc mã nguồn, không liên quan đến tính năng
-
docs – các thay đổi liên quan đến tài liệu như README hoặc các tệp markdown khác.
-
style – các thay đổi không ảnh hưởng đến ý nghĩa của mã nguồn, thường liên quan đến định dạng mã như khoảng trắng, dấu chấm phẩy bị thiếu, v.v.
-
test – các thay đổi liên quan đến việc thêm mới hoặc sửa chữa các bài test
-
perf – các thay đổi liên quan đến cải thiện hiệu suất của mã nguồn
-
ci – các thay đổi liên quan đến việc tích hợp liên tục (continuous integration).
-
build – changes that affect the build system or external dependencies
-
revert – commit này đảo ngược một commit trước đó. Với git mà nói, một khi đã push, bạn không bao giờ có thể xoá giấu vết của nó, chỉ có thể revert mà thôi.
Git pull và git rebase - Cho một PR không báo lỗi
Để có thể merge vào nhánh chính, git tree ở nhánh hiện tại phải được cập nhật code mới nhất đang có trên nhánh chính. Điều này được thực hiện bằng git rebase. Khi rebase, thường sẽ xảy ra conflict. Việc tiếp theo chỉ là nhẹ nhàng fix conflict, git add và sau đó git rebase --continue
là được. Nếu trong quá trình rebase bạn cảm thấy có gì đó không ổn, cứ nhẹ nhành git rebase --abort
để xem xét đã cũng được.
Git push - Gửi hàng đúng nơi là được
Git stash: đang code giữa chừng thì phải rẽ ngang fix bug
Situation cho git stash khá dễ dùng. Một ngày đẹp trời, mình đang code thì partner chạy sang kêu hotfix. Nhưng mình đang code dở, bây giờ commit thì cái code này cũng chưa đến nơi đến chốn, không commit thì đương nhiên mất code. Vậy phải làm sao.
Đương nhiên là git stash
để lưu tạm nó vào đâu đó. Xong việc rồi, có thể lấy lại nó bằng cách git stash pop
, thế là lại nhẹ nhàng rồi. Tuy nhiên, hay cẩn thận với những thứ bạn đã stash. Đừng lỡ tay pop và bạn không biết bạn vừa lôi ra những dòng code từ tận năm nào tháng nào đâu.
Với những câu lệnh thần sầu trên, bạn có thể sống nhàn tản hết đời. Nhưng mà, biết thêm vài chút cũng hay phải không.
Đến những câu lệnh gặp incident mới biết
Git cherry-pick
Ai cũng biết là bạn dùng nó để bê sự thay đổi của một vài commit đi chỗ khác nhưng không muốn merge, không muốn bê theo anh em họ hàng của nó, hoặc vì bạn lười code lại từ đầu (mà tất nhiên không ai code lại từ đầu), thế là bạn dùng cherry-pick.
Git fetch và FETCH_HEAD
FETCH_HEAD là một tham chiếu tạm thời đến commit mới nhất mà đã được lấy về từ một repository khác bằng lệnh git fetch. Khi chạy lệnh git fetch, các thay đổi mới nhất từ repository khác được tải xuống và lưu trữ trong FETCH_HEAD.FETCH_HEAD là một tham chiếu tạm thời và chỉ tồn tại trong thời gian ngắn khi bạn sử dụng lệnh git fetch. Nó sẽ bị ghi đè bởi các lần git fetch tiếp theo, hoặc bởi các lệnh khác như git merge hoặc git pull.
Minh hay dùng nó nhiều nhất khi muốn clone một nhánh, vô hình chung, mà không muốn liên quan gì (không merge, không rebase) đến các nhánh khác. Ví dụ, một ngày đẹp trời, bạn cần bê code của một nhánh xuống chạy thử, mà chẳng muốn checkout ra từ đầu. vậy đơn giản là chúng ta cứ tuần tự.
Git switch
Một ngày đẹp trời, đồng nghiệp bên cạnh hỏi tôi làm sao để checkout mà không dùng git checkout. Đó là git switch.
Khi sử dụng git checkout để chuyển đổi giữa các nhánh, nó sẽ sao chép các tệp đã được sửa đổi từ nhánh hiện tại sang nhánh mới, trong khi git switch không làm điều này. Điều này có thể gây ra sự nhầm lẫn và xung đột giữa các tệp trong các nhánh khác nhau khi sử dụng git checkout.
Git LFS
Có thể bạn chưa biết, không ai khuyến khích lưu một file model nặng vài GB hay một tệp data mấy chục GB trên Git. Nhưng nếu bạn vẫn muốn quản lý nó cùng repo của mình thì sao?
Một công cụ git cực kỳ hữu ích để quản lý và lưu trữ các file lớn, gọi tên GitLFS.
Git grep
Git grep là một công cụ tìm kiếm trong Git cho phép bạn tìm kiếm bất cứ chuỗi, định dạng biểu thức chính quy (RegEx) hay bất kỳ điều gì khác trong toàn bộ repository của mình. Nó giúp bạn tìm kiếm tất cả các tập tin, commits hoặc bất cứ điều gì khác trong repository của mình.
git grep <regexp> <ref>
Thông thường, mình dùng thanh search của GitHub, nhưng trong một vài trường hợp (khi chưa muốn push lên), mình buộc phải dùng giao diện dòng lệnh dưới local.
Các tùy chọn được cung cấp để giới hạn phạm vi tìm kiếm và định dạng kết quả trả về. Ví dụ, bạn có thể sử dụng -l để chỉ trả về tên tệp, -c để chỉ định số lượng kết quả khớp trên mỗi tệp được trả về, -e để loại trừ kết quả khớp với một điều kiện, --and để chỉ định nhiều điều kiện, -n để tìm kiếm theo số dòng.
Tham số thứ hai là một tham chiếu và có thể là tên nhánh, commit, phạm vi các commit hoặc bất cứ thứ gì khác. Ví dụ: git grep "foo" HEAD~1
sẽ tìm kiếm trong commit trước đó. Với git grep, bạn có thể tìm kiếm bất cứ chuỗi, biểu thức chính quy hay bất cứ điều gì khác trong repository của mình một cách nhanh chóng và thuận tiện. Nó giúp mình tìm kiếm bất kỳ tập tin, commit hoặc bất cứ điều gì khác trong repository của mình.
Git bisect
Git bisect là một trong những lệnh Git mạnh mẽ nhất để tìm kiếm commit trong quá trình gỡ lỗi. Và thật sự thì khi cần dùng mới biết đến nó. Nó cho phép bạn sử dụng tìm kiếm nhị phân để tìm ra rốt cuộc commit nào đã gây ra lỗi. (sóng bắt đầu từ gió, lỗi bắt đầu từ đâu)
git bisect start [end] [start]
Trong đó [end] là commit cuối cùng đã được kiểm tra và [start] là commit đầu tiên đã được kiểm tra. Mặc định, [end] sẽ là commit hiện tại và [start] sẽ là commit đầu tiên trong lịch sử của repository.
Sau khi bắt đầu git bisect, bạn sẽ cần xác định commit cuối cùng đã được kiểm tra và commit đầu tiên đã được kiểm tra, bằng cách sử dụng các lệnh:
git bisect bad [commit]
git bisect good [commit]
Sau khi xác đnh commit đầu tiên và cuối cùng đã được kiểm tra, git bisect sẽ tự động chuyển đến commit ở giữa để bạn kiểm tra lỗi. Bạn cần xác định xem commit này có lỗi hay không bằng cách sử dụng lệnh git bisect good hoặc git bisect bad. Tiến trình này sẽ được lặp lại đến khi bạn tìm được commit đã giới thiệu lỗi.
Nếu bạn muốn bỏ qua một số commit không quan trọng trong quá trình tìm kiếm, bạn có thể sử dụng lệnh git bisect skip. Nếu bạn muốn kiểm tra lại một số commit đã được đánh dấu là tốt hoặc xấu, bạn có thể sử dụng lệnh git bisect replay. Khi bạn đã tìm thấy commit đã giới thiệu lỗi, bạn có thể sử dụng lệnh git bisect reset để trở lại trạng thái ban đầu của repository.
Git GC - Dọn dẹp lần cuối
Khi sử dụng git để quản lý phiên bản, các tệp và đối tượng trong repository sẽ tích lũy theo thời gian và tạo ra rác không cần thiết, chiếm dung lượng lưu trữ và làm chậm các hoạt động. Để tối ưu hóa repository, bạn có thể chạy lệnhgit gc
, viết tắt của Garbage Collection. Lệnh này sẽ loại bỏ các commit không được truy cập và không có cha mẹ (orphaned), nén các phiên bản tệp và đối tượng lưu trữ git, cũng như thực hiện một số nhiệm vụ khác như đóng gói các tham chiếu, xóa các bản ghi reflog cũ, cập nhật metadata hoặc các cây làm việc cũ, và cập nhật các chỉ mục.
git gc [--aggressive]
Bạn có thể thêm tùy chọn --aggressive
để tối ưu hóa repository một cách nhanh chóng và hiệu quả hơn. Tuy nhiên, tùy chọn này sẽ loại bỏ tất cả các delta hiện có và tính toán lại chúng, điều này có thể mất nhiều thời gian hơn để chạy, đặc biệt là đối với các repository lớn.Bạn không cần phải lo lắng về việc mất mát dữ liệu, vì những đối tượng này đã bị xóa hoặc không thể truy cập từ trước đó.
Lưu ý rằng bạn không cần thường xuyên chạy git gc, vì Git đã được thiết kế để tự động tối ưu hóa repository của bạn. Tuy nhiên, nếu bạn cảm thấy repository của mình đang hoạt động chậm hoặc hao dung lượng lưu trữ, bạn có thể chạy git gc để tối ưu hóa nó
Không biết bài viết có đem lại thêm thông tin hay ho nào cho mọi người không? Nếu có, hãy để lại Upvote và những comment chia sẻ kinh nghiệm dùng git của các bạn nhé.
Cảm ơn Viblo và chúc MayFest thành công tốt đẹp ♥️♥️♥️