GIT-MERGE-BASE(1) دستورات عمومی کاربر GIT-MERGE-BASE(1)

git-merge-base - یافتن بهترین نیاکان مشترک ممکن برای یک ادغام

git merge-base [-a | --all] <commit> <commit>...
git merge-base [-a | --all] --octopus <commit>...
git merge-base --is-ancestor <commit> <commit>
git merge-base --independent <commit>...
git merge-base --fork-point <ref> [<commit>]

دستور git merge-base بهترین نیا(کان) مشترک بین دو کامیت را برای استفاده در یک ادغام سه‌طرفه (three-way merge) می‌یابد. یک نیاء مشترک از نیاء مشترک دیگر بهتر است اگر دومی نیاء اولی باشد. نیاء مشترکی که هیچ نیاء مشترک بهتری نداشته باشد، یک بهترین نیاء مشترک است، یعنی یک پایه ادغام (merge base). توجه داشته باشید که برای یک جفت کامیت می‌تواند بیش از یک پایه ادغام وجود داشته باشد.

در متداول‌ترین حالت خاص، تعیین تنها دو کامیت در خط فرمان به معنای محاسبه پایه ادغام بین آن دو کامیت داده‌شده است.

به‌طور کلی‌تر، در میان دو کامیتی که پایه ادغام از آن‌ها محاسبه می‌شود، یکی توسط اولین آرگومان کامیت در خط فرمان مشخص می‌شود؛ کامیت دیگر یک کامیت (احتمالاً فرضی) است که حاصل ادغام تمام کامیت‌های باقی‌مانده در خط فرمان می‌باشد.

در نتیجه، اگر بیش از دو کامیت مشخص شده باشد، پایه ادغام لزوماً در هر یک از آرگومان‌های کامیت گنجانده نشده است. این با رفتار git-show-branch(1) هنگام استفاده با گزینه --merge-base متفاوت است.

--octopus

محاسبه بهترین نیاکان مشترک تمام کامیت‌های ارائه‌شده، جهت آماده‌سازی برای یک ادغام چندطرفه (n-way merge). این رفتار از git show-branch --merge-base تقلید می‌کند.

--independent

به‌جای چاپ پایه‌های ادغام، یک زیرمجموعه کمینه از کامیت‌های ارائه‌شده با نیاکان یکسان را چاپ می‌کند. به عبارت دیگر، در میان کامیت‌های داده‌شده، آن‌هایی را که از هیچ کامیت دیگری قابل دسترسی نیستند فهرست می‌کند. این رفتار از git show-branch --independent تقلید می‌کند.

--is-ancestor

بررسی می‌کند که آیا <commit> اول نیاء <commit> دوم است یا خیر، و در صورت درست بودن با وضعیت 0، یا در غیر این صورت با وضعیت 1 خارج می‌شود. خطاها با یک وضعیت غیرصفر که 1 نیست نشان داده می‌شوند.

--fork-point

نقطه‌ای را می‌یابد که یک شاخه (یا هر تاریخچه‌ای که به <commit> منتهی می‌شود) از شاخه دیگر (یا هر ارجاع دیگر) <ref> منشعب شده است. این حالت فقط به دنبال نیاء مشترک دو کامیت نمی‌گردد، بلکه لاگ ارجاع (reflog) مربوط به <ref> را نیز در نظر می‌گیرد تا ببیند آیا تاریخچه منتهی به <commit> از نگارش قبلی شاخه <ref> منشعب شده است یا خیر (به بحث مربوط به این حالت در ادامه مراجعه کنید).

-a, --all

خروجی دادن تمام پایه‌های ادغام برای کامیت‌ها، به‌جای تنها یکی.

با فرض دو کامیت A و B، دستور git merge-base A B کامیتی را در خروجی نمایش می‌دهد که از طریق رابطه والدینی از هر دو کامیت A و B قابل دسترسی باشد.

برای مثال، با این توپولوژی:

         o---o---o---B
        /
---o---1---o---o---o---A

پایه ادغام بین A و B برابر با 1 است.

با فرض سه کامیت A، B و C، دستور git merge-base A B C پایه ادغام بین A و یک کامیت فرضی M را محاسبه می‌کند که ادغامی بین B و C است. برای مثال، با این توپولوژی:

       o---o---o---o---C
      /
     /   o---o---o---B
    /   /
---2---1---o---o---o---A

نتیجه دستور git merge-base A B C برابر با 1 است. دلیل این امر آن است که توپولوژی معادل با یک کامیت ادغام M بین B و C به این صورت است:

       o---o---o---o---o
      /                 \
     /   o---o---o---o---M
    /   /
---2---1---o---o---o---A

و نتیجه git merge-base A M برابر با 1 است. کامیت 2 نیز یک نیاء مشترک بین A و M است، اما 1 نیاء مشترک بهتری است، زیرا 2 نیاء 1 می‌باشد. بنابراین، 2 یک پایه ادغام نیست.

نتیجه دستور git merge-base --octopus A B C برابر با 2 است، زیرا 2 بهترین نیاء مشترک تمام کامیت‌ها است.

هنگامی که تاریخچه شامل ادغام‌های ضربدری (criss-cross merges) باشد، ممکن است بیش از یک بهترین نیاء مشترک برای دو کامیت وجود داشته باشد. برای مثال، با این توپولوژی:

---1---o---A
    \ /
     X
    / \
---2---o---o---B

هر دو کامیت 1 و 2 پایه‌های ادغام A و B هستند. هیچ‌کدام بر دیگری برتری ندارد (هر دو بهترین پایه‌های ادغام هستند). هنگامی که گزینه --all داده نشود، مشخص نیست که کدام‌یک از بهترین‌ها در خروجی نمایش داده می‌شود.

یک الگوی رایج برای بررسی «پیش‌روی سریع» (fast-forward-ness) بین دو کامیت A و B این است (یا دست‌کم در گذشته چنین بود) که پایه ادغام بین A و B محاسبه شده و بررسی شود که آیا با A یکسان است یا خیر؛ در صورتی که یکسان باشد، A نیاء B است. این الگو را اغلب در اسکریپت‌های قدیمی‌تر مشاهده خواهید کرد.

A=$(git rev-parse --verify A)
if test "$A" = "$(git merge-base A B)"
then
        ... A is an ancestor of B ...
fi

در گیت امروزی، می‌توانید این کار را به شیوه‌ای مستقیم‌تر بیان کنید:

if git merge-base --is-ancestor A B
then
        ... A is an ancestor of B ...
fi

به‌جای آن.

پس از کار بر روی شاخه topic که با دستور git switch -c topic origin/master ایجاد شده است، ممکن است تاریخچه شاخه ردیابی از دور (remote-tracking branch) به نام origin/master به عقب برگردانده شده و بازسازی شده باشد، که به تاریخچه‌ای با این ساختار منجر می‌شود:

                 o---B2
                /
---o---o---B1--o---o---o---B (origin/master)
        \
         B0
          \
           D0---D1---D (topic)

جایی که origin/master پیش‌تر به کامیت‌های B0، B1 و B2 اشاره می‌کرد و اکنون به B اشاره دارد، و شاخه topic شما در گذشته زمانی که origin/master روی B0 بود بر روی آن آغاز شده بود، و شما سه کامیت D0، D1 و D را بر روی آن ساختید. تصور کنید که اکنون می‌خواهید کارهای انجام‌شده روی topic را بر روی origin/master به‌روزرسانی‌شده بازپایه (rebase) کنید.

در چنین حالتی، دستور git merge-base origin/master topic والد B0 را در تصویر بالا بازمی‌گرداند، اما B0^..D آن بازه‌ای نیست که بخواهید بر روی B مجدداً اعمال کنید (این بازه شامل B0 است که شما آن را ننوشته‌اید؛ بلکه کامیتی است که طرف دیگر هنگام انتقال نوک شاخه خود از B0 به B1 آن را کنار گذاشته است).

دستور git merge-base --fork-point origin/master topic برای کمک در چنین شرایطی طراحی شده است. این دستور نه‌تنها B بلکه B0، B1 و B2 (یعنی نوک‌های قبلی شاخه‌های ردیابی از دور که لاگ ارجاع یا reflog مخزن شما از آن‌ها آگاه است) را نیز در نظر می‌گیرد تا ببیند شاخه topic شما بر روی کدام کامیت ساخته شده است و B0 را می‌یابد، که به شما امکان می‌دهد فقط کامیت‌های مربوط به موضوع خود را بازپخش کنید و کامیت‌هایی را که طرف مقابل بعداً دور انداخته است مستثنی نمایید.

از این رو

$ fork_point=$(git merge-base --fork-point origin/master topic)

کامیت B0 را خواهد یافت، و

$ git rebase --onto origin/master $fork_point topic

کامیت‌های D0، D1 و D را بر روی B بازپخش خواهد کرد تا تاریخچه جدیدی به این شکل ایجاد شود:

                 o---B2
                /
---o---o---B1--o---o---o---B (origin/master)
        \                   \
         B0                  D0'--D1'--D' (topic - updated)
          \
           D0---D1---D (topic - old)

یک نکته قابل توجه این است که ورودی‌های قدیمی‌تر reflog در مخزن شما ممکن است توسط git gc منقضی و پاکسازی شوند. اگر B0 دیگر در reflog شاخه ردیابی از دور origin/master ظاهر نشود، حالت --fork-point بدیهی است که نمی‌تواند آن را بیابد و با شکست مواجه می‌شود، تا از ارائه نتیجه‌ای تصادفی و بی‌فایده جلوگیری کند (مانند والد B0، همان‌طور که همان دستور بدون گزینه --fork-point ارائه می‌دهد).

همچنین، شاخه ردیابی از دوری که در حالت --fork-point استفاده می‌کنید باید همان شاخه‌ای باشد که موضوع شما از نوک آن منشعب شده است. اگر از کامیتی قدیمی‌تر از نوک منشعب شده باشید، این حالت نقطه انشعاب را پیدا نخواهد کرد (تصور کنید در تاریخچه نمونه بالا B0 وجود نداشت، origin/master از B1 شروع شد، به B2 و سپس B منتقل شد، و شما topic خود را در origin/master^ زمانی که origin/master در B1 بود منشعب کردید؛ شکل تاریخچه مانند بالا و بدون B0 خواهد بود، و والد B1 چیزی است که git merge-base origin/master topic به درستی می‌یابد، اما حالت --fork-point نخواهد یافت، زیرا یکی از کامیت‌هایی نیست که قبلاً در نوک origin/master قرار داشته‌اند).

git-rev-list(1), git-show-branch(1), git-merge(1)

بخشی از مجموعه git(1)

2026-06-29 Git 2.55.0