Git là một hệ thống quản lý phiên bản phân tán mã nguồn mở, giúp việc cộng tác trong các dự án phần mềm trở nên dễ quản lý hơn. Nhiều dự án lưu trữ mã trong kho lưu trữ Git (Git repo), và các nền tảng như GitHub giúp đơn giản hóa quá trình chia sẻ, đóng góp mã nguồn và hợp tác phát triển.
Với các dự án mã nguồn mở được lưu trữ công khai, cộng đồng lập trình viên có thể đóng góp thông qua pull request, yêu cầu nhóm phát triển xem xét và chấp nhận những thay đổi mà bạn đã thực hiện trên repo của họ.
Hướng dẫn này sẽ giới thiệu cách tạo pull request cho một Git repo thông qua dòng lệnh để bạn dễ dàng tham gia đóng góp vào các dự án phần mềm mã nguồn mở.
Cần chuẩn bị gì trước khi bắt đầu?
Bạn cần cài đặt Git trên máy tính. Để kiểm tra xem Git đã được cài đặt hay chưa và cách cài đặt Git phù hợp với hệ điều hành, bạn có thể tham khảo hướng dẫn chính thức.
Bạn cần có hoặc tạo một tài khoản GitHub. Truy cập trang web github.com, sau đó đăng nhập hoặc tạo tài khoản mới.
Từ tháng 11 năm 2020, GitHub đã loại bỏ phương thức xác thực bằng mật khẩu. Vì vậy, bạn cần tạo một personal access token hoặc cấu hình khóa SSH công khai để truy cập repo của GitHub qua giao diện dòng lệnh.
Cuối cùng, bạn cần xác định một dự án mã nguồn mở mà mình muốn đóng góp. Bạn có thể tìm hiểu thêm về các dự án mã nguồn mở thông qua các bài viết giới thiệu.
Tạo bản sao cho Repo
Repository hay viết tắt là repo về cơ bản là thư mục chính của một dự án. Repo chứa toàn bộ tệp liên quan đến dự án, bao gồm tài liệu hướng dẫn, đồng thời lưu trữ lịch sử sửa đổi của từng tệp. Trên GitHub, một repo có thể có nhiều cộng tác viên và được thiết lập là công khai hoặc riêng tư.
Để có thể làm việc với một dự án mã nguồn mở, trước tiên bạn cần tạo một bản sao của repo đó. Việc này bao gồm hai bước: fork repo và clone về máy tính cá nhân để làm việc cục bộ.
Fork repo
Bạn có thể fork một repo trên GitHub bằng cách truy cập vào đường dẫn Github của dự án mã nguồn mở mà bạn muốn đóng góp.
Các URL của repo trên GitHub sẽ bao gồm tên người dùng của chủ sở hữu repo, cũng như tên của repo. Ví dụ, DigitalOcean Community (username: do-community
) là chủ sở hữu của repo tên cloud_haiku
, nên URL của dự án là:
<https://github.com/do-community/cloud_haiku>
Trong ví dụ trên, do-community
là username và cloud_haiku
là tên repo.
Sau khi xác định được dự án mà bạn muốn đóng góp, bạn có thể truy cập vào URL của dự án, có định dạng như sau:
<https://github.com/username/repository>
Hoặc, bạn cũng có thể tìm kiếm dự án thông qua thanh tìm kiếm của GitHub.
Khi đang ở trang chính của repo, bạn sẽ thấy nút Fork ở góc trên bên phải trang, phía dưới biểu tượng tài khoản của bạn:
GitHub Forking
Nhấn vào nút Fork để bắt đầu quá trình fork. Trong cửa sổ trình duyệt, bạn sẽ nhận thông báo cho biết repo mà bạn đang fork đang được xử lý.
Sau khi hoàn tất quá trình fork, trình duyệt sẽ chuyển đến một trang có giao diện gần giống với repo gốc, nhưng ở phần trên cùng bạn sẽ thấy tên người dùng của mình đứng trước tên repo. Đồng thời, URL cũng sẽ bao gồm usename của bạn và tên repo.
Ví dụ, thay vì hiện do-community/cloud_haiku
, bạn sẽ thấy your-username/cloud_haiku
, và URL sẽ giống như:
<https://github.com/your-username/cloud_haiku>
Sau khi đã fork thành công, bạn đã có thể clone repo này về máy để có một bản sao cục bộ để làm việc.
Nhân bản (Clone) repo
Để tạo một bản sao cục bộ của repo, trước tiên bạn hãy mở cửa sổ dòng lệnh (Terminal) trên máy.
URL này sẽ tương tự như URL ở trên, nhưng sẽ kết thúc bằng .git
.
Trong ví dụ cloud_haiku
ở trên, URL sẽ có dạng như sau, đừng quên thay tên người dùng thực tế của bạn vào your-username
:
<https://github.com/your-username/cloud_haiku.git>
Bạn cũng có thể sao chép URL này bằng cách nhấn vào nút “⤓ Code” màu xanh lá ở trang repo mà bạn đã fork. Sau khi nhấn, hãy bấm vào biểu tượng clipboard bên cạnh để sao chép URL:
GitHub Clone or Download
Khi đã có URL, chúng ta có thể tiến hành sao chép repo.
Bạn cần kết hợp lệnh git clone
với URL của repo trong cửa sổ dòng lệnh (terminal):
git clone <https://github.com/your-username/repository.git>
Sau khi đã có bản sao mã nguồn trên máy cục bộ, bước tiếp theo là tạo một nhánh (branch) mới để làm việc với mã nguồn này.
Tạo một nhánh mới
Khi cộng tác trong một dự án, bạn và nhiều lập trình viên có thể cùng lúc đề xuất các tính năng mới hoặc sửa lỗi cho repo, dẫn đến sự thay đổi đồng thời trong mã nguồn. Một số tính năng mới này có thể được triển khai nhanh chóng, nhưng một số khác sẽ cần nhiều thời gian hơn. Vì vậy, việc tạo nhánh cho repo là rất quan trọng để quản lý quy trình làm việc, cô lập phần mã của bạn và kiểm soát những tính năng nào sẽ được đưa trở lại nhánh chính của dự án.
Nhánh chính của một dự án thường được gọi là main
. Theo thông lệ tốt, mọi nội dung trên nhánh này nên luôn ở trạng thái sẵn sàng triển khai để người khác sử dụng bất kỳ lúc nào.
Lưu ý: Tháng 6/2020, GitHub đã thay đổi thuật ngữ, gọi nhánh mặc định là
main
thay vìmaster
. Nếu nhánh mặc định của bạn vẫn hiển thị làmaster
, bạn có thể đổi thànhmain
bằng cách chỉnh trong cài đặt nhánh mặc định.
Khi tạo nhánh mới dựa trên dự án hiện có, bạn phải tạo nhánh từ main
. Đồng thời, tên nhánh cần mang tính mô tả rõ ràng — thay vì đặt là my-branch
, bạn nên dùng tên như frontend-hook-migration
hoặc fix-documentation-typos
.
Để tạo nhánh từ cửa sổ terminal, trước tiên hãy chuyển thư mục làm việc sang thư mục chứa repo. Bạn phải dùng đúng tên kho (ví dụ: cloud_haiku
) khi đổi thư mục.
cd repository
Bây giờ, chúng ta sẽ tạo nhánh mới bằng lệnh git branch
. Bạn cần đặt tên nhánh rõ ràng và có tính mô tả để những người khác trong dự án hiểu bạn đang làm gì:
git branch new-branch
Sau khi tạo xong, chúng ta cần chuyển sang nhánh đó để bắt đầu làm việc bằng lệnh git checkout
:
git checkout new-branch
Khi thực hiện lệnh trên, bạn sẽ nhận được thông báo:
Output
Switched to branch 'new-branch'
Ngoài ra, bạn có thể gộp hai lệnh trên thành một, vừa tạo nhánh mới vừa chuyển sang nhánh đó, bằng cách sử dụng tùy chọn -b
như sau:
git checkout -b new-branch
Nếu muốn quay lại nhánh main, bạn có thể dùng lệnh checkout
cùng với tên của nhánh chính:
git checkout main
Lệnh checkout
cho phép bạn chuyển đổi qua lại giữa nhiều nhánh khác nhau, từ đó có thể phát triển nhiều tính năng song song.
Tại thời điểm này, bạn đã có thể chỉnh sửa các tệp hiện có hoặc thêm tệp mới vào dự án trên nhánh của riêng mình.
Thực hiện thay đổi trên máy cục bộ
Để minh họa cách tạo một pull request, chúng ta sẽ dùng repo cloud_haiku
làm ví dụ và tạo một tệp mới trong bản sao trên máy của mình. Bạn hãy dùng trình soạn thảo văn bản để tạo một tệp mới, qua đó chúng ta sẽ thêm một bài thơ haiku như đã được giải thích trong nguyên tắc đóng góp. Ví dụ, chúng ta có thể dùng nano
và đặt tên tệp là filename.md
. Bạn cần đặt một cái tên độc đáo cho tệp của mình và sử dụng phần mở rộng .md
cho Markdown.
nano filename.md
Tiếp theo, chúng ta sẽ thêm nội dung vào tệp mới, tuân theo các nguyên tắc đóng góp. Chúng ta cần sử dụng định dạng Jekyll và thêm một bài haiku có các thẻ ngắt dòng <br>
. Tệp dưới đây là một ví dụ; bạn sẽ cần đóng góp một bài haiku do chính bạn sáng tác.
--
layout: haiku
title: Octopus Cloud
author: Sammy
---
Distributed cloud <br>
Like the octopuses' minds <br>
Across the network <br>
Sau khi đã thêm văn bản, hãy lưu và đóng tệp. Nếu bạn dùng nano
, hãy nhấn CTRL + X
, sau đó là Y
, và cuối cùng là ENTER
.
Khi bạn đã sửa đổi một tệp hiện có hoặc thêm một tệp mới vào dự án, bạn có thể đưa nó vào staging area của repo cục bộ bằng lệnh git add
. Trong ví dụ của chúng ta, với tệp filename.md
, chúng ta sẽ gõ lệnh sau.
git add filename.md
Chúng ta đã truyền tên của tệp vừa tạo vào lệnh này để đưa nó vào staging area. Vậy là tệp của bạn đã sẵn sàng để được thêm vào.
Nếu bạn muốn thêm tất cả các tệp đã sửa đổi trong một thư mục cụ thể, bạn có thể đưa tất cả chúng vào staging area bằng lệnh sau:
git add .
Ở đây, dấu chấm sẽ thêm tất cả các tệp có liên quan.
Nếu bạn muốn thêm tất cả các thay đổi một cách đệ quy, bao gồm cả những thay đổi trong các thư mục con, bạn có thể gõ:
git add -A
Hoặc, bạn cũng có thể gõ git add --all
để đưa tất cả các tệp mới vào staging area.
Sau khi tệp đã được đưa vào staging area, chúng ta có thể ghi lại những thay đổi đã thực hiện vào repo bằng lệnh git commit
.
Ghi lại thay đổi bằng lệnh commit
Thông điệp commit đóng vai trò thiết yếu trong việc đóng góp mã nguồn, giúp người duy trì dự án và các cộng tác viên khác nắm rõ nội dung, lý do và mức độ quan trọng của các thay đổi bạn thực hiện. Đồng thời, thông điệp này cũng tạo nên lịch sử thay đổi toàn diện cho dự án, hỗ trợ các thành viên tiếp theo trong việc theo dõi và hiểu tiến trình phát triển.
Nếu bạn có một thông điệp ngắn gọn, có thể ghi lại ngay bằng cách sử dụng cờ -m
kèm theo thông điệp trong dấu ngoặc kép. Ví dụ, khi thêm một bài haiku mới, lệnh commit có thể như sau:
git commit -m "Added a new haiku in filename.md file"
Trừ khi thay đổi là nhỏ hoặc đã được dự kiến trước, bạn nên soạn thông điệp commit chi tiết hơn để cộng tác viên có thể hiểu rõ đóng góp của bạn. Để ghi lại thông điệp dài hơn, bạn chỉ cần chạy lệnh:
git commit
Khi chạy lệnh này, bạn có thể thấy mình đang ở trong trình soạn thảo vim, và có thể thoát bằng cách gõ :q
. Nếu muốn thiết lập trình soạn thảo mặc định khác, bạn có thể cấu hình bằng lệnh git config
, ví dụ đặt nano làm trình soạn thảo mặc định như sau:
git config --global core.editor "nano"
Hoặc đặt vim làm trình soạn thảo:
git config --global core.editor "vim"
Sau khi chạy lệnh git commit
, tùy vào trình soạn thảo mặc định, cửa sổ terminal sẽ hiển thị một tài liệu để bạn nhập thông điệp commit, ví dụ như sau trong nano:
GNU nano 2.0.6 File: …username/repository/.git/COMMIT_EDITMSG
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch new-branch
# Your branch is up-to-date with 'origin/new-branch'.
#
# Changes to be committed:
# modified: new-feature.py
#
Dưới phần chú thích này, bạn hãy nhập thông điệp commit của mình.
Một thông điệp commit hiệu quả nên bao gồm:
- Dòng đầu tiên tóm tắt ngắn gọn (khoảng 50 ký tự).
- Phần mô tả chi tiết bên dưới, chia thành các đoạn dễ đọc, nêu rõ lý do bạn thực hiện thay đổi, cách thức hoạt động của mã, và các thông tin bổ sung giúp người khác hiểu rõ hơn khi xem xét hoặc hợp nhất mã.
Bạn hãy cố gắng viết thông điệp rõ ràng, chi tiết và có giá trị, nhằm giúp những người duy trì dự án dễ dàng hiểu và đánh giá đầy đủ đóng góp của bạn.
Đẩy thay đổi
Sau khi bạn đã lưu và thoát khỏi trình chỉnh sửa thông điệp commit, bạn có thể xác minh Git sẽ commit những gì bằng lệnh sau:
git status
Tùy thuộc vào các thay đổi bạn đã thực hiện, bạn sẽ nhận được một kết quả đầu ra tương tự như sau:
Ví dụ kết quả:
On branch new-branch
nothing to commit, working tree clean
Tại thời điểm này, bạn có thể sử dụng lệnh git push
để đẩy các thay đổi lên nhánh hiện tại của repo đã fork:
git push --set-upstream origin new-branch
Lệnh này sẽ hiển thị quá trình đẩy thay đổi, ví dụ:
pgsql
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 336 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To <https://github.com/your-username/repository.git>
a1f29a6..79c0e80 new-branch -> new-branch
Branch new-branch set up to track remote branch new-branch from origin.
Lúc này, bạn có thể truy cập vào repo đã fork trên trang GitHub của mình, chuyển sang nhánh bạn vừa đẩy lên để xem trực tiếp những thay đổi đã thực hiện.
Hiện tại, bạn đã có thể tạo pull request đến repo gốc. Tuy nhiên, nếu chưa từng thực hiện trước đó, bạn cần đảm bảo rằng repo cục bộ của mình đã được đồng bộ với repo upstream.
Cập nhật repo cục bộ
Khi làm việc cùng cộng tác viên trong một dự án, việc giữ repo cục bộ luôn đồng bộ với repo gốc rất quan trọng để hạn chế xung đột khi gửi pull request (dù trong các dự án hợp tác, xung đột mã là điều khó tránh khỏi). Để cập nhật bản sao mã nguồn cục bộ, bạn cần thực hiện đồng bộ hóa.
Chúng ta sẽ bắt đầu bằng việc cấu hình một remote trỏ đến repo upstream, sau đó tiến hành đồng bộ repo fork.
Cấu hình remote cho Fork
Repo remote cho phép bạn hợp tác với những người khác trong một dự án Git. Mỗi repo remote là một phiên bản của dự án được lưu trữ trên internet hoặc trên network mà bạn có quyền truy cập. Tùy thuộc vào quyền hạn của người dùng, bạn có thể truy cập mỗi repo remote với quyền chỉ đọc hoặc đọc-ghi.
Để có thể đồng bộ hóa các thay đổi mà bạn đã thực hiện trong một fork với repo gốc mà bạn đang làm việc, bạn cần cấu hình một remote trỏ đến repo gốc ban đầu. Bạn chỉ cần thiết lập remote đến repo upstream này một lần duy nhất.
Đầu tiên, hãy kiểm tra xem bạn đã cấu hình những server remote nào. Lệnh git remote
sẽ liệt kê bất kỳ repo remote nào mà bạn đã chỉ định. Vì vậy, nếu bạn đã clone repo của mình, bạn sẽ thấy ít nhất một kết quả là origin (đây là tên mặc định mà Git đặt cho repo được clone).
Từ thư mục của repository trong cửa sổ terminal, chúng ta hãy sử dụng lệnh git remote
cùng với cờ -v
để hiển thị các URL mà Git đã lưu trữ, đi kèm với các tên viết tắt tương ứng (chẳng hạn như “origin”):
git remote -v
Nếu bạn đã clone repo như hướng dẫn ở trên, đầu ra sẽ giống như sau:
perl
origin <https://github.com/your-username/forked-repository.git> (fetch)
origin <https://github.com/your-username/forked-repository.git> (push)
Nếu bạn đã từng thiết lập nhiều remote trước đó, lệnh git remote -v
sẽ hiển thị danh sách tất cả các remote đó.
Tiếp theo, chúng ta sẽ chỉ định một remote upstream mới để đồng bộ với fork của mình. Đây sẽ là repo gốc mà bạn đã fork từ đó. Việc này được thực hiện bằng lệnh git remote add
git remote add upstream <https://github.com/original-owner-username/original-repository.git>
Trong ví dụ cloud_haiku
của chúng ta, lệnh sẽ có dạng như sau:
git remote add upstream <https://github.com/do-community/cloud_haiku.git>
Trong ví dụ này, upstream
là tên viết tắt mà chúng ta đặt cho repo remote, bởi trong Git, upstream
dùng để chỉ repo mà chúng ta đã clone từ đó. Nếu muốn thêm remote trỏ đến repo của một cộng tác viên, bạn có thể đặt tên theo tên người dùng của cộng tác viên đó hoặc một biệt danh ngắn gọn làm tên viết tắt.
Chúng ta có thể kiểm tra xem remote trỏ đến repo upstream đã được thêm đúng chưa bằng cách sử dụng lại lệnh git remote -v
trong thư mục của repository.
git remote -v
Kết quả:
origin <https://github.com/your-username/forked-repository.git> (fetch)
origin <https://github.com/your-username/forked-repository.git> (push)
upstream <https://github.com/original-owner-username/original-repository.git> (fetch)
upstream <https://github.com/original-owner-username/original-repository.git> (push)
Giờ đây bạn có thể sử dụng upstream
thay cho URL dài, và sẵn sàng đồng bộ fork với repo gốc.
Đồng bộ Fork
Sau khi cấu hình remote trỏ tới upstream và repo gốc trên GitHub, bạn đã có thể đồng bộ fork của mình để luôn cập nhật.
Để thực hiện đồng bộ, từ thư mục repo cục bộ trên terminal, bạn sử dụng lệnh git fetch
để lấy về các nhánh cùng các commit tương ứng từ repo upstream. Vì đã đặt tên viết tắt là “upstream” cho kho này, chúng ta sẽ truyền tên đó vào lệnh:
git fetch upstream
Tùy thuộc vào số lượng thay đổi kể từ khi bạn fork, kết quả trả về có thể khác nhau, bao gồm một vài dòng đếm, nén và giải nén đối tượng. Kết quả thường kết thúc bằng các dòng tương tự sau, nhưng có thể thay đổi tùy số lượng nhánh trong dự án:
From <https://github.com/original-owner-username/original-repository>
* [new branch] main -> upstream/main
Lúc này, các commit trên nhánh main của kho gốc sẽ được lưu trong nhánh cục bộ có tên là upstream/main
.
Tiếp theo, ta chuyển sang nhánh main cục bộ của repository bằng lệnh:
git checkout main
Kết quả:
Switched to branch 'main'
Sau đó, ta sẽ hợp nhất các thay đổi được thực hiện trên nhánh main của kho gốc (truy cập qua nhánh upstream/main
cục bộ) vào nhánh main cục bộ bằng lệnh:
git merge upstream/main
Kết quả nhận được sẽ khác nhau tùy tình huống. Có thể bắt đầu với updating
nếu có thay đổi, hoặc Already up-to-date.
nếu không có thay đổi nào kể từ khi bạn fork.
Nhánh main trong fork của bạn hiện đã được đồng bộ với repo upstream, đồng thời các thay đổi cục bộ vẫn được giữ nguyên.
Tùy vào quy trình làm việc và thời gian bạn dành để chỉnh sửa mã, bạn có thể đồng bộ fork với mã nguồn upstream bao nhiêu lần tùy ý. Tuy nhiên, bạn nên thực hiện đồng bộ ngay trước khi tạo pull request để đảm bảo không gửi lên mã gây xung đột tự động.
Tạo Pull Request
Đến bước này, bạn đã có thể gửi pull request đến repo gốc.
- Truy cập vào repo đã fork của bạn trên GitHub.
- Nhấn nút New pull request ở bên trái trang.
Ở màn hình tiếp theo, bạn có thể tùy chỉnh nhánh. Ở cả hai bên, hãy chọn kho lưu trữ phù hợp từ menu thả xuống và nhánh tương ứng.
Ví dụ: chọn nhánh main
của kho gốc ở bên trái và nhánh new-branch
của kho fork ở bên phải. Nếu không tồn tại xung đột mã, bạn sẽ thấy thông báo xác nhận rằng các nhánh này có thể được hợp nhất.
Tiếp theo, hãy điền tiêu đề và phần mô tả vào các trường tương ứng, rồi nhấn Create pull request.
Lúc này, những người duy trì kho lưu trữ gốc sẽ tiến hành xem xét và quyết định xem có nên chấp nhận pull request của bạn hay không. Trong quá trình code review, họ có thể yêu cầu bạn chỉnh sửa hoặc điều chỉnh mã nguồn trước khi chấp nhận.
Kết luận
Tại thời điểm này, bạn đã gửi thành công một pull request đến kho lưu trữ của dự án mã nguồn mở. Sau đó, bạn nên tiếp tục duy trì việc cập nhật và rebase nhánh làm việc của mình trong thời gian chờ phản hồi. Người duy trì dự án có thể yêu cầu bạn chỉnh sửa hoặc làm lại một số phần, vì vậy hãy kịp thời điều chỉnh khi cần.
Đóng góp cho các dự án mã nguồn mở và trở thành một lập trình viên tích cực trong cộng đồng là trải nghiệm vừa đáng giá vừa bổ ích. Việc thường xuyên đóng góp vào những phần mềm bạn sử dụng sẽ giúp chúng duy trì chất lượng và mang lại nhiều giá trị hơn cho cộng đồng.