Về blog

Git Sync Fork With Upstream: 3 cách an toàn

6 tháng 9, 2026

TL;DR: chạy git fetch upstream && git merge upstream/main && git push origin main là fork của bạn đuổi kịp. Đó là trọn bộ quy trình “git sync fork with upstream” gói trong một dòng — kéo thay đổi từ dự án bạn đã fork về, rồi đẩy lên bản copy của mình. Nếu thích lịch sử tuyến tính, đổi merge thành git rebase upstream/main và force-push. Còn nếu bạn chưa bao giờ cắm remote upstream thì hãy bắt đầu từ bước 1 dưới đây, vì cái remote vắng mặt đó là lý do số một khiến một fork “không chịu sync”. Mọi thứ còn lại — rebase, nút Sync của GitHub, các nhánh đã rẽ ngang không đẩy được — chỉ là chi tiết đắp trên ba lệnh đó.

Đồng bộ một fork với upstream nghĩa là gì?

Một fork là bản copy của bạn trên GitHub đối với repository của người khác. Bản gốc là upstream; bản copy của bạn là origin. Fork trên GitHub không tự cập nhật — khi maintainer merge một pull request, bản copy của bạn vẫn giữ code của ngày hôm qua. Đồng bộ fork nghĩa là kéo các commit mới của upstream vào fork của bạn, để nhánh của bạn khớp, hoặc ít nhất chứa, trạng thái hiện tại của dự án.

Việc này quan trọng vì hai lý do. Thứ nhất là đóng góp: mọi pull request bạn mở từ một fork ì ạch đều mang theo nhiễu thừa, và maintainer sẽ yêu cầu bạn cập nhật trước khi merge. Thứ hai là self-hosting hay nghiên cứu: nếu bạn chạy một fork trong production, hay đơn giản chỉ đọc code, thì một fork trễ một tháng là một tháng bản sửa lỗi mà bạn không có.

Tôi đồng bộ fork với upstream từ dòng lệnh bằng cách nào?

Ba bước: khai báo upstream một lần, fetch từ nó, rồi merge và push. Phần đi dây là vĩnh viễn — lần sau bạn chỉ gõ bước 2 và 3.

Bước 1 — thêm remote upstream (một lần cho mỗi bản clone).

# bên trong bản clone cục bộ của fork
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
git remote -v   # xác nhận: origin -> fork của bạn, upstream -> bản gốc

URL đúng nằm ở trang của repo gốc: nút Code màu xanh. Lỗi phổ biến là trỏ cả hai remote vào fork của bạn — khi đó một lần “sync” lặng lẽ không làm gì cả, vì bạn fetch từ một bản copy cũng ì ạch y như bản bạn đang có.

Bước 2 — fetch và merge nhánh upstream.

git checkout main
git fetch upstream
git merge upstream/main
git push origin main

Đó là câu trả lời chuẩn cho “git sync fork with upstream command line”. Kết quả thường thấy là fast-forward — main phía fork của bạn không có gì mới, nên nó chỉ trượt tới upstream/main và không tạo merge commit nào.

Bước 3 — lặp lại khi cần. Không có gì phải nhớ ngoài git fetch upstream && git merge upstream/main && git push origin main. Muốn biết mình tụt bao xa trước khi merge, chạy git rev-list --count main..upstream/main sau khi fetch.

Nên rebase hay merge khi đồng bộ fork?

Cả hai đều đưa cùng một code vào fork của bạn; chúng khác nhau ở lịch sử để lại. Chọn một chính sách cho mỗi repo và giữ vững:

Phương phápLệnhKết quả lịch sửPhù hợp với
Mergegit merge upstream/mainThêm một merge commit khi các nhánh đã rẽ ngangNhánh feature đang mở PR — không bao giờ viết lại gì cả
Rebasegit rebase upstream/mainCác commit của bạn được replay lên trên, lịch sử tuyến tínhGiữ main của fork sạch; các fork rẽ ngang mà bạn muốn đặt lại
Giao diện GitHubNút Sync branch / merge qua PRNhư mergeBắt kịp nhanh khi không mở bản clone

Biến thể rebase của việc sync:

git fetch upstream
git rebase upstream/main
git push --force-with-lease origin main

Force push là bắt buộc vì rebase viết lại commit ID — nhánh remote của fork bạn không còn là hậu duệ của nhánh cục bộ. Luôn ưu tiên --force-with-lease hơn --force: nó từ chối ghi đè remote nếu ai đó (hoặc một máy khác của chính bạn) đã push trong lúc đó, biến câu lệnh nguy hiểm thành an toàn theo mặc định.

Một quy tắc đáng xăm lên cổ tay: đừng bao giờ rebase một nhánh đang có pull request mở, trừ khi bạn biết mình đang làm gì — rebase làm đổi commit ID, và một PR đang mở có thể bị tách khỏi các commit của nó. Sync main bằng merge (hoặc rebase nó trước khi bắt đầu việc mới), và giữ các nhánh PR ngoài cuộc.

Vì sao fork của tôi không chịu sync với upstream?

Bốn nghi phạm thường trực, theo đúng thứ tự chúng xuất hiện trong các terminal thật:

  1. Không có remote upstreamgit remote -v chỉ thấy origin. Triệu chứng: git fetch upstream hỏng với thông báo 'upstream' does not appear to be a git repository. Cách sửa: bước 1 ở trên.
  2. Bạn fetch nhưng chưa bao giờ merge — fetch chỉ cập nhật upstream/main trong repo cục bộ và không đụng đến nhánh làm việc nào. Triệu chứng: git log vẫn cũ sau một lần fetch thành công. Cách sửa: git merge upstream/main.
  3. Lịch sử đã rẽ ngang — bạn commit trên main của fork, và upstream cũng tiến tới. git pull khi đó dỗi về unrelated histories hoặc ép merge. Cách sửa, nếu bạn muốn upstream thắng: git reset --hard upstream/main (vứt bỏ các commit chỉ tồn tại trên main cục bộ của bạn — kiểm tra git stash list hoặc sao lưu bằng một nhánh trước; nếu một cú reset tồi đã xảy ra rồi, con đường cứu vẫn y như trong git undo last commit: git reflog vẫn nhớ đỉnh cũ).
  4. Push bị từ chối vì non-fast-forward sau một lần rebase — bạn rebase nhưng push bình thường. Cách sửa: git push --force-with-lease origin main.

Một trường hợp thứ năm, hiếm: repo upstream đã bị đổi tên hoặc xóa, nên đến URL của bước 1 cũng 404. GitHub chuyển hướng các repo bị đổi tên, vì vậy một thất bại dứt khoát thường có nghĩa là đã bị xóa hoặc chuyển thành riêng tư — hết thứ gì để sync.

Có thể sync một fork từ trang web GitHub không?

Được. Ở trang của fork, dropdown nhánh hiện nút Sync fork bất cứ khi nào nhánh của bạn tụt hậu; một cú bấm kéo upstream về. Dưới nấc thang thấp hơn, cùng việc đó làm được qua pull request: mở một PR từ upstream/main vào main của fork rồi merge nó.

Giới hạn của nút này chính là lúc quay về CLI: nó chỉ fast-forward hoặc merge — không rebase, và từ chối thẳng khi hai nhánh đã rẽ ngang, bảo bạn bỏ các commit hoặc dùng dòng lệnh. Nó cũng chỉ sync nhánh mặc định. Với mọi thứ vượt qua một cú bắt kịp đơn giản, ba lệnh ở trên mới là công cụ.

Nên sync fork của bạn bao lâu một lần?

Trước mỗi mảng việc mới là câu trả lời trung thực: tách nhánh từ một main mới toanh, và không PR nào của bạn mở đầu bằng “cái này dựa trên bản cách đây ba tuần”. Với fork bạn đóng góp thường xuyên, sync main mỗi ngày hay mỗi phiên chỉ tốn vài giây. Với fork bạn chỉ đọc hoặc deploy, sync khi upstream tung ra thứ bạn cần — đăng ký releases feed của repo gốc và sync theo từng bản phát hành. Sync rẻ chính vì nó là việc thường ngày; một fork trễ sáu tháng thường cần phẫu thuật thay vì một lần merge, và đó là cách “sync my fork” hóa thành một buổi chiều.

Cheat sheet

# thiết lập một lần
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git

# sync thường ngày (chính sách merge)
git fetch upstream && git merge upstream/main && git push origin main

# sync thường ngày (chính sách rebase, lịch sử tuyến tính)
git fetch upstream && git rebase upstream/main && git push --force-with-lease origin main

# tôi đang tụt bao nhiêu?
git fetch upstream && git rev-list --count main..upstream/main

# rẽ ngang quá chỗ sửa — biến main thành giống hệt upstream (phá hủy)
git fetch upstream && git reset --hard upstream/main && git push --force-with-lease origin main

Nhớ thuộc hai dòng sync thường ngày, và một fork rẽ ngang sẽ mãi là chuyện lạ để đọc, không phải sự cố để sửa. Nếu công việc dọn dẹp git của bạn mở rộng sang server, cheat sheet journalctl lo nửa còn lại của việc giữ lịch sử một máy luôn đọc được.

— mrsaynothing

— mrsaynothing

Ghi chú thực địa về AI, Linux và self-hosting.

Thảo luận bài này trên dev.to dev.to ↗

Nhận how-to tiếp theo qua email

Một email mỗi bài viết. Sửa xong rồi đi tiếp.

self-hosted · không bên thứ ba · hủy đăng ký một cú bấm

cái này là gì?

ss vs netstat: Dùng lệnh nào để xem port trên Linux

Thích kiểu viết này? Tôi build như vậy để kiếm sống. thuê tôi