بازگشت به وبلاگ

همگام‌سازی fork با upstream در Git: 3 روش امن

۱۵ شهریور ۱۴۰۵

TL;DR: دستور git fetch upstream && git merge upstream/main && git push origin main را اجرا کنید و fork تان به‌روز است. کل گردش‌کار «همگام‌سازی fork با upstream» در یک خط همین است — تغییرات پروژه‌ای که از آن fork گرفته‌اید را بکشید، بعد به نسخه خودتان push کنید. اگر تاریخچه خطی می‌پسندید، merge را با git rebase upstream/main عوض کنید و force-push بزنید. و اگر اصلاً remote مربوط به upstream را هنوز وصل نکرده‌اید، از گام 1 پایین شروع کنید، چون همین remote جاافتاده، دلیل شماره یکِ «fork sync نمی‌شود» است. بقیه ماجرا — rebase، دکمه sync در GitHub، شاخه‌های واگرای غیرقابل push — جزئیاتی روی همین سه دستور است.

همگام‌سازی fork با upstream یعنی چه؟

fork نسخه شما از مخزن کسی دیگر روی GitHub است. نسخه اصلی upstream است؛ نسخه شما origin. forkهای GitHub خودشان به‌روز نمی‌شوند — وقتی maintainerها یک pull request را merge می‌کنند، نسخه شما روی کدِ دیروز می‌ماند. همگام‌سازی fork یعنی کشیدن commitهای جدید upstream به fork تان تا شاخه‌تان با وضعیت فعلی پروژه برابر باشد، یا دست‌کم شاملش باشد.

این برای دو دلیل مهم است. اول، مشارکت: هر pull requestی که از یک fork عقب‌مانده باز کنید نویز اضافه دارد و maintainerها قبل از merge از شما به‌روزرسانی می‌خواهند. دوم، self-host کردن یا خواندن کد: اگر fork را در پروداکشن اجرا می‌کنید یا فقط می‌خوانید، یک fork به قدمت یک ماه، یعنی یک ماه رفع باگ که شما ندارید.

چگونه از خط فرمان fork را با upstream همگام کنم؟

سه گام: یک بار upstream را معرفی کنید، از آن fetch بگیرید، بعد merge و push کنید. سیم‌کشی دائمی است — دفعه بعد فقط گام 2 و 3 را می‌نویسید.

گام 1 — اضافه کردن remote مربوط به upstream (یک بار برای هر کلون).

# inside your local clone of the fork
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
git remote -v   # confirm: origin -> your fork, upstream -> the original

URL درست را در صفحه مخزن اصلی پیدا می‌کنید: دکمه سبز Code. اشتباه رایج این است که هر دو remote را به fork خودتان بدهید — در این حالت «sync» بی‌سروصدا هیچ کاری نمی‌کند، چون از کپی‌ای fetch کرده‌اید که به همان اندازه نسخه خودتان عقب است.

گام 2 — گرفتن و merge کردن شاخه upstream.

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

همان پاسخ استاندارد به «دستور همگام‌سازی fork با upstream در خط فرمان». نتیجه عادی فست‌فوروارد است — main روی fork شما چیز تازه‌ای نداشته، پس صرفاً تا upstream/main سُر می‌خورد جلو و هیچ merge commitی ساخته نمی‌شود.

گام 3 — هر وقت خواستید تکرار کنید. چیزی بیش از git fetch upstream && git merge upstream/main && git push origin main برای یادداشتن نیست. برای دیدن میزان عقب‌ماندگی قبل از merge، بعد از fetch دستور git rev-list --count main..upstream/main را اجرا کنید.

موقع همگام‌سازی fork، rebase یا merge؟

هر دو همان کد را به fork تان می‌رسانند؛ در تاریخچه‌ای که پشت سر می‌گذارند فرق دارند. برای هر مخزن یک سیاست انتخاب کنید و سرش بمانید:

روشدستورنتیجه در تاریخچهمناسب برای
Mergegit merge upstream/mainیک merge commit اضافه روی شاخه‌های واگراشاخه‌های feature با pull request باز — هیچ‌چیز را بازنویسی نمی‌کند
Rebasegit rebase upstream/maincommitهای شما از نو روی سرِ جدید، تاریخچه خطیتمیز نگه داشتن main فورک؛ فورک‌های واگرایی که می‌خواهید ریست کنید
رابط GitHubدکمه Sync branch / merge یک PRمثل mergeبه‌روز شدن سریع بدون کلون باز

همان همگام‌سازی، حالت rebase:

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

force push لازم است چون rebase شناسه commitها را بازنویسی می‌کند — شاخه ریموت fork تان دیگر از نسخه محلی شما فرزند نیست. همیشه --force-with-lease را به --force ترجیح دهید: اگر کسی (یا ماشین دیگری از خودتان) در فاصله این بین push کرده باشد، از بازنویسی ریموت امتناع می‌کند؛ همین دستور خطرناک را به‌طور پیش‌فرض امن می‌کند.

یک قاعده که می‌ارزد روی مچ دستتان خالکوبی کنید: شاخه‌ای که pull request باز دارد را rebase نکنید، مگر بدانید دارید چه می‌کنید — rebase شناسه commitها را عوض می‌کند و می‌تواند pull request باز را از commitهایش جدا کند. main را با merge همگام کنید (یا قبل از شروع کار جدید rebase اش کنید) و شاخه‌های PR را از این ماجرا بیرون نگه دارید.

چرا fork من با upstream همگام نمی‌شود؟

چهار مظنون همیشگی، به ترتیب بروز در ترمینال‌های واقعی:

  1. remote ای به نام upstream وجود نداردgit remote -v فقط origin را نشان می‌دهد. علامت: git fetch upstream با خطای 'upstream' does not appear to be a git repository شکست می‌خورد. راه‌حل: گام 1 بالاتر.
  2. fetch کرده‌اید ولی merge نکرده‌اید — fetch فقط upstream/main را در مخزن محلی به‌روز می‌کند و به هیچ شاخه کاری دست نمی‌زند. علامت: بعد از fetch موفق، git log همچنان قدیمی است. راه‌حل: git merge upstream/main.
  3. تاریخچه واگرا شده — روی main فورک خودتان commit زده‌اید و upstream هم جلو رفته. بعدش git pull گیر می‌دهد به unrelated histories یا merge تحمیل می‌کند. راه‌حل، اگر می‌خواهید upstream برنده باشد: git reset --hard upstream/main (commitهای محلیِ مخصوص main دور ریخته می‌شوند — اول git stash list را ببینید یا با یک شاخه بکاپ بگیرید؛ اگر reset بدی از قبل رخ داده، مسیر بازیابی همان است که در لغو آخرین commit در Git آمده: git reflog هنوز سر قدیمی را به یاد دارد).
  4. push بعد از rebase به‌عنوان non-fast-forward رد می‌شود — rebase کرده‌اید ولی push عادی زده‌اید. راه‌حل: git push --force-with-lease origin main.

مورد پنجم، کمیاب: مخزن upstream تغییر نام داده یا حذف شده و حتی URL گام 1 خطای 404 می‌دهد. GitHub مخزن‌های تغییرنام‌یافته را ریدایرکت می‌کند، پس شکست قطعی معمولاً یعنی حذف‌شده یا خصوصی‌شده — چیزی برای همگام شدن باقی نمانده.

آیا می‌توان fork را از وب‌سایت GitHub همگام کرد؟

بله. در صفحه fork تان، هر وقت شاخه عقب باشد، کنار منوی شاخه دکمه Sync fork دیده می‌شود؛ یک کلیک، upstream را داخل می‌کشد. در زیر همان، همان کار به شکل pull request هم می‌شود: از upstream/main به main فورک تان PR باز کنید و merge اش کنید.

محدودیت‌های دکمه توضیح می‌دهد کی باید برگردید سراغ CLI: فقط فست‌فوروارد یا merge انجام می‌دهد — rebase نمی‌کند و وقتی شاخه‌ها واگرا شده‌اند کلاً سر باز می‌کند و می‌گوید یا commitها را دور بریزید یا خط فرمان را به کار ببرید. فقط شاخه پیش‌فرض را هم همگام می‌کند. برای هر چیزی فراتر از یک به‌روزرسانی ساده، همان سه دستور بالا ابزار شماست.

هر چند وقت یک بار fork را همگام کنید؟

پاسخ صادقانه: قبل از هر کار جدید — از یک main تازه شاخه بزنید تا هیچ PRای با جمله «این بر اساس نسخه سه هفته پیش است» شروع نشود. برای فورک‌هایی که فعالانه به آن‌ها سهم می‌دهید، همگام‌سازی روزانه یا هر نشستِ main چند ثانیه بیشتر خرج ندارد. برای فورکی که فقط می‌خوانید یا دیپلای می‌کنید، وقتی upstream چیزی که می‌خواهید را منتشر کرد همگام کنید — روی feed مربوط به releaseهای مخزن اصلی سابسکرایب کنید و با هر release همگام شوید. همگام‌سازی دقیقاً به این دلیل ارزان است که روتین است؛ فورکی که شش ماه عقب بماند معمولاً به‌جای merge به جراحی نیاز پیدا می‌کند — همان‌جا است که «فورکم را sync کن» تبدیل به یک بعدازظهر می‌شود.

چیت‌شیت

# one-time setup
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git

# routine sync (merge policy)
git fetch upstream && git merge upstream/main && git push origin main

# routine sync (rebase policy, linear history)
git fetch upstream && git rebase upstream/main && git push --force-with-lease origin main

# how far behind am I?
git fetch upstream && git rev-list --count main..upstream/main

# diverged beyond repair — make main identical to upstream (destructive)
git fetch upstream && git reset --hard upstream/main && git push --force-with-lease origin main

همان دو-دستور روتین را در حافظه عضلانی نگه دارید تا فورکِ واگرا موضوعی باشد که درباره‌اش می‌خوانید، نه مشکلی که باید درستش کنید. اگر خانه‌تکانی Git تان به سرورها هم می‌کشد، چیت‌شیت journalctl نیمه دیگرِ خوانا نگه داشتن تاریخچه یک ماشین را پوشش می‌دهد.

FAQ

چگونه fork را با upstream همگام کنم؟

دستور git fetch upstream، بعد rebase یا merge کردن upstream/main در شاخه‌تان و push. دکمه Sync fork در GitHub فست‌فوروارد ساده را انجام می‌دهد.

برای تغییرات upstream، merge یا rebase؟

rebase تاریخچه pull request شما را خطی و قابل ریویو نگه می‌دارد؛ merge روی شاخه‌های مشترک امن‌تر است. شاخه‌ای که دیگران رویش می‌سازند را هرگز rebase نکنید.

چرا بعد از همگام‌سازی fork همچنان عقب است؟

همگام‌سازی شاخه‌ها را جابه‌جا می‌کند، نه tagها و releaseها را. با --tags --prune دریافت کنید و سر شاخه‌ها را مقایسه کنید، نه بنر GitHub را.

— mrsaynothing

— mrsaynothing

یادداشت‌های میدانی درباره AI، لینوکس و self-hosting.

این نوشته را در dev.to بحث کنید dev.to ↗

آموزش بعدی با ایمیل

هر نوشته یک ایمیل. درستش کن، برو سراغ بعدی.

self-hosted · بدون واسطه‌های ثالث · لغو اشتراک با یک کلیک

این چیست؟

ss در مقابل netstat: کدام دستور پورت در Linux را به‌کار ببریم

این نوشته‌ها را می‌پسندید؟ این همان کاری است که برای زندگی از آن درمی‌آورم. استخدامم کنید