5 điểm bởi GN⁺ 2024-02-14 | 1 bình luận | Chia sẻ qua WhatsApp
  • Ngay cả những người đã dùng Git lâu năm cũng dễ bỏ lỡ nhiều tính năng ít được biết đến, làm lung lay giả định rằng kiến thức dòng lệnh nâng cao đã trở nên phổ biến
  • Không giống thế hệ chuyển sang từ SVN, CVS, những lập trình viên chỉ dùng Git từ đầu có ít cơ hội học một số cách dùng nâng cao
  • Theo thời gian, Git liên tục bổ sung các tính năng nhỏ nhưng hữu ích, và những thay đổi này có thể mang giá trị thực tiễn trong những tình huống nhất định
  • Dành cho người dùng từ trung cấp đến nâng cao, các chủ đề về tính năng cũ nhưng hữu ích, tính năng mới được thêm gần đây, và kho mã lớn·monorepo được chia thành loạt 3 bài ngắn
  • Nếu xem lại những tính năng không dễ nhận ra chỉ với thói quen dùng Git quen thuộc, bạn có thể xử lý công việc hằng ngày với kho mã hiệu quả hơn

Vì sao nên nhìn lại Git

  • Khi gần đây thuyết trình về Git và GitButler, tác giả nhận ra rằng rất nhiều lập trình viên vẫn có những phần chưa biết về Git
  • Trước đây từng có các buổi nói chuyện về Git nâng cao, nhưng khoảng 10 năm qua, mọi người thường được cho là đã biết sẵn các tính năng dòng lệnh nâng cao
  • Thế hệ lập trình viên chỉ dùng Git không có dịp chuyển từ các công cụ như SVN, CVS sang Git hoặc học lại các khái niệm trước đó
  • Bản thân Git cũng đã học thêm các tính năng mới theo thời gian; phần lớn là những thay đổi tinh tế hoặc nhắm đến mục đích cụ thể, nhưng vẫn có thể giúp ích cho công việc thực tế
  • Loạt bài blog được xây dựng dựa trên bài trình bày FOSDEM 2024 little known Git stuff

Loạt mẹo Git gồm 3 phần

  • Đối tượng là người dùng Git từ trung cấp đến nâng cao, và bài viết đề cập đến những tính năng mà ngay cả người dùng lâu năm cũng có thể đã bỏ lỡ
  • Thay vì gói gọn mọi thứ trong một bài, nội dung được chia thành 3 bài ngắn theo từng nhóm chủ đề
  • Các chủ đề gồm có:
  • Bài đầu tiên tiếp nối tại Oldies but Goodies

1 bình luận

 
GN⁺ 2024-02-14
Ý kiến trên Hacker News
  • Với tư cách tác giả, tôi thừa nhận rằng mình chỉ mới học được khá nhiều điều trong số này gần đây. Các tính năng liên quan đến repo lớn là những thứ Microsoft và GitHub đã dần đưa vào lõi Git trong vài năm qua, nên khá khó tìm được một tài liệu gom toàn bộ những gì họ đã làm vào một chỗ
    Tôi cũng đã có những cuộc trò chuyện thú vị với phía Mercurial, và gần đây họ nói rằng khi viết lại một phần nội bộ của Hg bằng Rust, họ đã đạt được mức cải thiện tốc độ đáng kinh ngạc
    Tôi cũng đang nghĩ đến Pro Git bản 3, nên nếu có điều gì bạn đã học được khi chật vật với Git, hoặc điều gì bạn muốn biết, hãy cho tôi biết
    • Có thể bạn đã biết rồi, nhưng dùng difftastic thay cho diff của Git rất hay: https://difftastic.wilfred.me.uk/
      Các bí danh gitconfig tôi hay dùng là fza, gone, root. git fza mở các tệp đã sửa/tệp mới trong cửa sổ fzf rồi chuyển tệp đã chọn sang git add: https://github.com/junegunn/fzf
      git gone xóa các nhánh cục bộ không còn trên remote, còn git root in ra thư mục gốc của repo để tiện quay về từ các thư mục sâu. Gần đây tôi dùng zoxide nên ít cần hơn: https://github.com/ajeetdsouza/zoxide
    • Ở phần về khác biệt khoảng trắng, sẽ tốt hơn nếu thêm cả ignore-revs-file. Bạn commit một tệp ignore-revs vào repo, rồi người thực hiện đợt định dạng lớn sẽ thêm SHA đó vào để git blame không bị hỏng
      https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revltrevgt
    • Một trong những điều tôi khó khăn mới học được về Git là các thao tác như merge, cherry-pick, rebase hoạt động dựa trên sự khác biệt và patch, chính xác hơn là hợp nhất 3 chiều, chứ không phải dựa trên snapshot. Pro Git nhấn mạnh rất tốt mô hình lưu trữ snapshot của Git, nhưng nếu chỉ nghĩ theo mô hình đó thì rất dễ rối, đặc biệt là với rebase
      Ví dụ, tôi đã không hiểu vì sao chỉ xóa một commit trong lúc rebase mà mọi commit sau đó cũng đều thay đổi. Chỉ đến khi nhận ra rằng việc lưu trữ là dựa trên snapshot nhưng thao tác là dựa trên khác biệt, tôi mới hiểu rebase, và nếu nhấn mạnh phần này hơn khi dạy thì sẽ rất hữu ích
  • Tôi không muốn học các tuyệt kỹ Git, tôi muốn dùng nó đơn giản nhất có thể. Tôi chỉ muốn push code, xong việc với Git rồi tiếp tục làm việc
    Tôi tôn trọng những người thích Git, nhưng với tôi nó chỉ là một công cụ buộc phải dùng
    • Một phần sự phức tạp của Git đến từ việc ban đầu nó được thiết kế như plumbing cấp thấp. Người ta từng kỳ vọng sẽ có một lớp bề mặt thân thiện hơn cho người dùng, tức porcelain, xây trên mô hình dữ liệu Git, nên nếu muốn có một UI đơn giản và nhất quán thì hướng đó đến giờ vẫn có thể tốt hơn. Jujutsu và Got(game of trees) có thể là ví dụ như vậy
    • Tôi hiểu cảm giác đó, nhưng Git không khó đến thế. Ngoài những thao tác cơ bản như checkout/commit/push, chỉ cần biết thêm một vài thứ, đặc biệt là viết lại lịch sử, thì chất lượng lịch sử commit sẽ tốt hơn rất nhiều và các kỹ sư khác trong dự án cũng dễ hiểu luồng hơn
      Git có vẻ gần như là một hằng số lâu dài trong ngành, và là một trong những công cụ bạn đụng tới nhiều nhất mỗi ngày khi phát triển, nên đáng để tìm hiểu thêm một chút
    • Có những chi tiết vốn nằm trong chính bản chất của vấn đề, và cũng có những thứ không phải vậy. Tôi nghĩ mọi người có xu hướng đánh giá thấp phần khó khăn nội tại
      Vì thế tôi thấy việc Git có một mức độ phức tạp nhất định là chấp nhận được
    • Nghe giống như nói rằng bạn không muốn học lập trình, chỉ muốn dùng máy tính đơn giản nhất có thể. Kiểu như chỉ muốn nói việc cần làm rồi xong
    • Giao diện Git tạo cảm giác như một abstraction bị rò rỉ. Tôi không muốn học các trò Git, nhưng cuối cùng lại biết nhiều hơn mức mình mong muốn
  • Tôi vừa mới biết về core.fsmonitor. Ở góc độ mono-repo lớn, tôi ước git clone có tùy chọn tiếp tục tải dở
    Hồi những năm 2000 tôi từng gặp đúng vấn đề này khi cố clone repo kernel qua kết nối băng thông thấp, và chỉ sau khi hỏi trên mailing list thì mới có người đăng toàn bộ repo dưới dạng tar nén lên trang cá nhân để tôi tải được
    Đến giờ thỉnh thoảng tôi vẫn gặp vấn đề tương tự khi VPN công ty chập chờn trong lúc clone các repo lớn. Cứ tưởng tượng bạn đã tải được 95% kho mã Windows 300GB rồi mà Wi‑Fi ngắt trong chốc lát
    Thật lạ khi Git và Docker, hai công cụ ngốn băng thông hàng đầu trong stack phát triển hiện đại, lại không hỗ trợ tốt việc tiếp tục tải xuống
    • Nghe có vẻ thứ bạn muốn gần với git bundle hơn. Chỉ là điều kiện tiên quyết là phải có ai đó tạo bundle từ đầu
      https://git-scm.com/docs/git-bundle
    • Có lẽ có thể làm bằng cách clone nông rồi mở rộng dần nhiều lần. Dù vậy, giao thức fetch/push về cơ bản vẫn giả định các repo nhỏ hơn hoặc kết nối Internet và máy chủ rất tốt
  • Rất thú vị. Tôi muốn xem ai có thể giải quyết bằng một giao diện dễ hơn cho bài toán nhiều người cùng đóng góp vào các bản phát hành, tính năng và hotfix khác nhau, gắn thẻ bản phát hành, rồi quay ngược quá khứ để tìm lỗi
    Cũng giống như việc muốn một ngôn ngữ bậc thấp mà lại che giấu được độ phức tạp của hệ thống, hai điều này về cơ bản loại trừ lẫn nhau. Git đủ ổn và không quá khó học, nên một phần là bạn cứ phải học Git thôi
    • Vì vậy tôi thường mạnh dạn khuyên dùng GitKraken. Đây là sản phẩm trả phí nên tôi cũng hơi dè dặt, nhưng tôi đã thử nhiều công cụ và chưa thấy thứ nào gỡ mở được sức mạnh của Git tốt như GitKraken
      Nó xóa đi cảm giác hộp đen mà nhiều lập trình viên thấy ở terminal, đưa đồ thị lên vị trí trung tâm, và khiến các thao tác rebase trở nên trực quan, tự nhiên đến mức Git trở nên thú vị
      Kỹ năng dùng CLI vẫn rất có giá trị, nhưng thật bực khi thấy các lập trình viên đã 10 năm kinh nghiệm vẫn loay hoay với những vấn đề cơ bản hoặc phá hỏng lịch sử dự án vì bầu không khí kiểu “nếu là kỹ sư thực thụ thì phải chỉ dùng Git CLI”
      Giờ đây ngay cả khi dùng CLI, tôi vẫn khuyên mọi người cứ mở đồ thị ở một cửa sổ khác cả ngày. VS Code, JetBrains, thậm chí cả CLI cũng làm được điều đó miễn phí

Khi đồng đội merge PR thì tôi xem ngay và rebase nhánh của mình, nên nhánh luôn được cập nhật mới nhất dựa trên main, nhờ đó tránh được địa ngục merge hoặc để lại những commit “fix conflicts” kinh khủng

  • Trong lúc tìm 10 file được sửa nhiều nhất kể từ khi tạo hôm qua, tôi phát hiện ra https://github.com/tj/git-extras/blob/main/Commands.md
    Có khá nhiều lệnh Git bổ sung đáng dùng

  • Tôi không thực sự hiểu vì sao đa số lập trình viên lại cố chấp dùng Git CLI khi các client UI hiện đại như GitKraken đã đủ hữu dụng và hữu ích: https://www.gitkraken.com/

    • Kiến thức về CLI dẫn tới việc viết script, còn kiến thức Git học được từ script lại quay trở lại phục vụ việc dùng hằng ngày. Tôi không muốn trở nên bất lực chỉ vì phải dùng CLI khi SSH vào chiếc Raspberry Pi đang chạy như một máy chủ
      Không phải là tôi hoàn toàn phản đối GUI, nhưng hiện tại CLI hiệu quả hơn và tôi không muốn tốn thời gian tìm một GUI đáp ứng các điều kiện sau
      đẹp mắt, là ứng dụng native chứ không phải kiểu nhét một trình duyệt web cổ lỗ vào bên trong, không có telemetry hoặc mặc định bị tắt, hoàn toàn mã nguồn mở, và có thể kỳ vọng là 5 năm nữa vẫn không biến mất
      Ngoài ra nó cũng không được làm mọi thứ rối hơn. Ở công ty cũ tôi từng phải dùng Visual Studio, và có một nút ghi đầy điềm gở là “Accept merge”, trong khi thực chất nó có nghĩa là “đánh dấu là đã giải quyết xung đột”
      Không nên gây nhầm lẫn cho những người đã quen gán một ý nghĩa nhất định cho một số từ, và cũng khó mà tin tưởng các hành vi kiểu nút “Commit changes” lại tiện tay push luôn lên remote
    • CLI cũng đủ tốt rồi. Tôi cũng dùng plugin trong editor, nhưng nếu đã ở dòng lệnh thì tôi xử lý luôn ở đó
      Nếu chỉ để tạo một commit mà phải chuyển sang chương trình khác thì động lực commit thường xuyên sẽ giảm đi
    • Trừ khi có vấn đề rất cụ thể, tôi cố giảm tối đa những gì phải làm với Git. Với tôi thì thực ra gần như chỉ là push, pull, checkout, nên dùng GUI có cảm giác hơi quá mức cần thiết
    • Trông có vẻ gọn gàng, nhưng giao diện đồ họa rất dễ trở nên xao nhãng. Cuối cùng có vẻ vẫn là vấn đề sở thích cá nhân, còn CLI thì nhanh nhưng đường cong học tập cao
      Ngay cả khi dùng Git trong CLI thì phần lớn cũng không có gì đặc biệt, chỉ là vài lệnh; các mẹo hay thủ thuật ít dùng thì tôi ghi vào một file văn bản
  • Tôi biết -committerdate, nhưng không biết có thể đặt nó làm thứ tự sắp xếp mặc định, và điều đó rất hữu ích. Có vài ghi chú
    git columns khá khó theo dõi nếu không hiển thị hết trên màn hình và phải cuộn, nên sẽ tốt hơn nếu có đánh số
    git maintenance có vẻ hay, nhưng tôi rebase nhiều nên hơi lo. Tôi tự hỏi liệu nó có làm mất loose object nhanh hơn gc không. Tôi có thấy gc bị tắt, nhưng vẫn không rõ ràng
    Liên quan đến git blame, có một script ít người biết nhưng hữu ích là https://github.com/gnddev/git-blameall. Nó ít được biết đến mức tôi phải tự port sang Python 3, dù tôi cũng không phải là lập trình viên Python

    • Trong chế độ maintenance theo lịch, gc bị vô hiệu hóa. Khi chạy maintenance run một cách tường minh thì nó được bật như một tác vụ
      Nó không thu gom loose object nhanh hơn gc. Xét cho cùng thì nó chỉ đơn giản là chạy gc
    • Tôi tự hỏi có thể sắp xếp ngược không. Có vẻ một cách đơn giản để giải quyết chuyện nhánh bị đẩy ra ngoài màn hình là để nhánh mới nhất ở cuối. Tôi đang làm vậy bằng script tự viết
    • Nó không làm mất nhanh hơn. Nó chỉ lấy dữ liệu từ remote thường xuyên hơn và đóng gói lại dữ liệu. Nếu GC bị tắt thì dữ liệu sẽ không bị xóa
      git-blameall trông khá ổn, tôi sẽ thử dùng xem sao
  • Tôi đã đơn giản hóa đáng kể luồng Git bằng vài alias chạy được trong nhiều môi trường
    git synced đồng bộ nhánh hiện tại bằng rebase theo upstream nếu có, còn không thì theo origin. Nó dùng master hoặc main, ưu tiên main
    git pub publish thay đổi lên remote origin và dùng force push with lease
    git pr mở đúng URL PR trên GitHub mà không cần client GH. Nếu có định nghĩa upstream thì nó sẽ gửi PR sang đó
    git hub mở trang GitHub của repository
    https://softwaredoug.com/blog/2022/11/09/idiot-proof-git-aliases.html

    • Tôi tò mò không hiểu vì sao lại chọn cái mũi tên lông lá kỳ lạ đó làm dấu phân cách
  • Tôi đã thôi giả vờ như mình biết mình đang làm gì và dùng các công cụ Git trực quan. Chẳng hạn như SmartGit hay công cụ đi kèm IntelliJ. Tôi thấy các “anh hùng dòng lệnh” của Git phần nhiều chỉ để thể hiện
    Lớp lệnh dành cho người dùng có thể khó chịu đến mức gây rối. Ví dụ, YoursTheirs có thể mang ý nghĩa hoàn toàn trái ngược tùy theo ngữ cảnh
    Không có phong cách hay chủ đề chung xuyên suốt toàn bộ giao diện người dùng, nên cần một lớp trực quan mới nếu không muốn làm người ta phát điên

    • Tôi cũng vậy. Tôi thích việc lúc nào cũng có thể xem diff và nhìn trực quan ngay được chuyện gì sẽ xảy ra. Cũng không cần phải chạy thêm hàng loạt lệnh
      Tôi chỉ biết về ứng dụng và Git ở mức đủ để phục vụ công việc, còn hiếm khi cần nhiều hơn thì tra cứu là được. Trong nhiều năm dùng như vậy, chuyện đó chỉ xảy ra một hai lần
    • Với công việc hằng ngày, tôi luôn dùng công cụ Git trực quan, đặc biệt là Tortoise Git
      Ngay cả với các tác vụ phức tạp để sửa lỗi của người khác hoặc của chính tôi, trước tiên tôi cũng xem history, commit, reflog và diff bằng công cụ trực quan để hiểu xem thứ gì đã bị rối và có gì còn cứu được không
      Nếu chỉ cần quay về một commit thì tôi dùng reset --hard, còn nếu phải ghép thứ gì đó từ nhiều commit thì thường tôi sẽ dùng dòng lệnh
  • Hai thứ này không loại trừ lẫn nhau. Với những việc như xem khác biệt hay xử lý xung đột thì tôi chỉ dùng công cụ trực quan, nhưng tôi cũng học được rất nhiều khi tìm hiểu về đối tượng commit, reflog, những gì rebase làm ở phía sau, rebase tương tác, hard/soft reset, v.v.