GIT-RANGE-DIFF(1) Git Manual GIT-RANGE-DIFF(1)

git-range-diff - مقایسه دو بازه کامیت (مثلاً دو نسخه از یک شاخه)

git range-diff [--color=[<when>]] [--no-color] [<diff-options>]
        [--no-dual-color] [--creation-factor=<factor>]
        [--left-only | --right-only] [--diff-merges=<format>]
        [--remerge-diff] [--no-notes | --notes[=<ref>]]
        ( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )
        [[--] <path>...]

این دستور تفاوت‌های میان دو نسخه از یک مجموعه پچ (patch series)، یا به طور کلی‌تر، دو بازه کامیت را (با نادیده گرفتن کامیت‌های ادغام یا merge) نمایش می‌دهد.

در صورت ارائه آرگومان‌های <path>، این بازه‌های کامیت متناسب با آن‌ها محدود می‌شوند.

برای این منظور، ابتدا جفت کامیت‌هایی را از هر دو بازه کامیت پیدا می‌کند که متناظر با یکدیگرند. دو کامیت زمانی متناظر در نظر گرفته می‌شوند که diff میان پچ‌های آن‌ها (یعنی اطلاعات نویسنده، پیام کامیت و diff کامیت) در مقایسه با اندازه پچ‌ها به اندازه کافی کوچک باشد. برای جزئیات به بخش الگوریتم (Algorithm) در ادامه مراجعه کنید.

در نهایت، فهرست کامیت‌های منطبق به ترتیب بازه کامیت دوم نشان داده می‌شود، در حالی که کامیت‌های نامنطبق درست پس از نمایش همه نیاکان (ancestors) خود درج می‌گردند.

سه روش برای تعیین بازه‌های کامیت وجود دارد:

•<range1> <range2>: هر یک از بازه‌های کامیت می‌تواند به شکل <base>..<rev>، <rev>^! یا <rev>^-<n> باشد. برای جزئیات بیشتر به بخش SPECIFYING RANGES در gitrevisions(7) مراجعه کنید.
•<rev1>...<rev2>. این معادل است با <rev2>..<rev1> <rev1>..<rev2>.
•<base> <rev1> <rev2>: این معادل است با <base>..<rev1> <base>..<rev2>.

--no-dual-color

هنگامی که diffهای کامیت متفاوت باشند، دستور ‘git range-diff` رنگ‌بندی diffهای اصلی را بازسازی کرده و نشانگرهای diff بیرونی -/+ را با پس‌زمینه (background) قرمز/سبز اضافه می‌کند تا مثلاً دیدن تغییر دقیق خطوط اضافه‌شده آسان‌تر شود.

علاوه بر این، خطوط diff کامیت که فقط در اولین بازه کامیت وجود دارند به صورت «کم‌رنگ» (dimmed) نشان داده می‌شوند (این رفتار را می‌توان با استفاده از تنظیم پیکربندی color.diff.<slot> تغییر داد که در آن <slot> یکی از مقادیر contextDimmed، oldDimmed و newDimmed است)، و خطوط diff کامیت که فقط در بازه کامیت دوم حضور دارند به صورت پررنگ (bold) نمایش می‌یابند (که با تنظیمات پیکربندی color.diff.<slot> با <slot> برابر با یکی از contextBold، oldBold یا newBold قابل سفارشی‌سازی است).

این قابلیت در range-diff به عنوان «رنگ‌آمیزی دوگانه» (dual coloring) شناخته می‌شود. از --no-dual-color استفاده کنید تا رنگ‌آمیزی تمام خطوط بر اساس نشانگرهای diff بیرونی انجام شود (و diff درونی از نظر رنگ کاملاً نادیده گرفته شود).

--creation-factor=<percent>

ضریب تعدیل (fudge factor) هزینه ایجاد/حذف را روی <percent> تنظیم می‌کند. مقدار پیش‌فرض ۶۰ است. اگر git range-diff به اشتباه یک تغییر بزرگ را بازنویسی کامل تلقی کند (حذف یک کامیت و افزودن کامیتی دیگر)، مقدار بزرگ‌تری را امتحان کنید، و در حالت برعکس مقدار کوچک‌تری را قرار دهید. برای توضیح علت نیاز به این ضریب، بخش الگوریتم (Algorithm) در ادامه را ببینید.

--left-only

کامیت‌هایی را که در اولین بازه مشخص‌شده غایب هستند (یا «بازه چپ» هنگام استفاده از فرم <rev1>...<rev2>) پنهان می‌کند.

--right-only

کامیت‌هایی را که در دومین بازه مشخص‌شده غایب هستند (یا «بازه راست» هنگام استفاده از فرم <rev1>...<rev2>) پنهان می‌کند.

--diff-merges=<format>

به جای نادیده گرفتن کامیت‌های ادغام (merge commits)، با استفاده از گزینه متناظر --diff-merges=<format> در git-log(1) برای آن‌ها diff تولید کرده و آن‌ها را در مقایسه لحاظ می‌کند.

نکته: در حالت معمول، حالت remerge طبیعی‌ترین حالت برای استفاده خواهد بود، زیرا فقط diff را روی خروجی حاصل از مکانیزم ادغام گیت نشان می‌دهد. به عبارت دیگر، اگر یک کامیت ادغام نتیجه یک git merge بدون تداخل باشد، حالت remerge آن را با یک diff خالی نمایش خواهد داد.

--remerge-diff

گزینه میان‌بر و راحت، معادل --diff-merges=remerge.

--notes[=<ref>], --no-notes

این فلگ به برنامه git log (به git-log(1) مراجعه کنید) که پچ‌ها را تولید می‌کند ارسال می‌شود.

<range1> <range2>

کامیت‌های مشخص‌شده توسط دو بازه را مقایسه می‌کند، که در آن <range1> به عنوان نسخه قدیمی‌ترِ <range2> در نظر گرفته می‌شود.

<rev1>...<rev2>

معادل ارسال <rev2>..<rev1> و <rev1>..<rev2>.

<base> <rev1> <rev2>

معادل ارسال <base>..<rev1> و <base>..<rev2>. توجه داشته باشید که <base> نیازی نیست نقطه انشعاب دقیق شاخه‌ها باشد. مثال: پس از ری‌بیس شاخه my-topic، دستور git range-diff my-topic@{u} my-topic@{1} my-topic تفاوت‌های ایجادشده توسط ری‌بیس را نشان می‌دهد.

دستور git range-diff همچنین گزینه‌های معمولی diff را می‌پذیرد (به git-diff(1) مراجعه کنید)، به‌ویژه گزینه‌های --color[=<when>] و --no-color. این گزینه‌ها هنگام تولید «diff میان پچ‌ها» استفاده می‌شوند، یعنی برای مقایسه نویسنده، پیام کامیت و diff کامیت‌های متناظر قدیم/جدید. در حال حاضر روشی برای دستکاری بیشتر گزینه‌های diff ارسال‌شده به git log هنگام تولید این پچ‌ها وجود ندارد.

خروجی دستور range-diff ممکن است تغییر کند. این خروجی برای خوانایی توسط انسان طراحی شده است (خروجی پرسلین یا porcelain)، نه چیزی که بتوان در نسخه‌های مختلف گیت برای دستیابی به یک range-diff متنی پایدار استفاده کرد (برخلاف گزینه‌ای مانند --stable در git-patch-id(1)). همچنین هیچ معادلی برای git-apply(1) در range-diff وجود ندارد؛ خروجی این دستور برای ماشین‌خوان بودن در نظر گرفته نشده است.

این موضوع به ویژه هنگام ارسال گزینه‌های diff صادق است. در حال حاضر برخی گزینه‌ها مانند --stat می‌توانند اثر جانبی داشته باشند و خروجی‌ای تولید کنند که در زمینه range-diff کاملاً بی‌فایده است. ممکن است نسخه‌های آینده range-diff نحوه تفسیر این گزینه‌ها را به روشی ویژه range-diff یاد بگیرند (برای مثال برای --stat خروجی خوانا برای انسان تولید کنند که نحوه تغییر diffstat را خلاصه کند).

این دستور از تنظیمات diff.color.* و pager.range-diff استفاده می‌کند (مورد دوم به طور پیش‌فرض فعال است). به git-config(1) مراجعه کنید.

هنگامی که یک ری‌بیس نیازمند حل تداخل‌های ادغام بود، بلافاصله پس از آن تغییرات ایجادشده توسط ری‌بیس را با دستور زیر مقایسه کنید:

$ git range-diff @{u} @{1} @

یک خروجی نمونه از git range-diff به این صورت خواهد بود:

-:  ------- > 1:  0ddba11 Prepare for the inevitable!
1:  c0debee = 2:  cab005e Add a helpful message at the start
2:  f00dbal ! 3:  decafe1 Describe a bug
    @@ -1,3 +1,3 @@
     Author: A U Thor <author@example.com>
    -TODO: Describe a bug
    +Describe a bug
    @@ -324,5 +324,6
      This is expected.
    -+What is unexpected is that it will also crash.
    ++Unexpectedly, it also crashes. This is a bug, and the jury is
    ++still out there how to fix it best. See ticket #314 for details.
      Contact
3:  bedead < -:  ------- TO-UNDO

در این مثال، ۳ کامیت قدیمی و ۳ کامیت جدید وجود دارد، که در آن توسعه‌دهنده کامیت سوم را حذف کرده، یک کامیت جدید قبل از دو کامیت اول اضافه کرده، و پیام کامیت دوم و همچنین diff آن را ویرایش کرده است.

هنگامی که خروجی به یک ترمینال ارسال می‌شود، به طور پیش‌فرض رنگ‌بندی می‌شود، درست مانند خروجی معمول git diff. علاوه بر این، خط اول (افزودن یک کامیت) سبز است، خط آخر (حذف یک کامیت) قرمز است، خط دوم (با تطابق کامل) مانند هدر کامیت در خروجی git show زرد است، و خط سوم کامیت قدیمی را قرمز، کامیت جدید را سبز و بقیه را مانند هدر کامیت git show رنگ‌آمیزی می‌کند.

با این حال، یک diff ساده از diffها که با رنگ تفکیک شده باشد، خواندنش کمی دشوار است، زیرا کل خطوط را قرمز یا سبز می‌کند. به عنوان مثال، خطی که "+What is unexpected" را در کامیت قدیمی اضافه کرده بود کاملاً قرمز است، حتی اگر هدف کامیت قدیمی اضافه کردن چیزی بوده باشد.

برای حل این مشکل، دستور range-diff به طور پیش‌فرض از حالت --dual-color استفاده می‌کند. در این حالت، diff از diffها رنگ‌های اصلی diff را حفظ کرده و خطوط را با نشانگرهای -/+ که دارای پس‌زمینه قرمز یا سبز هستند پیشوندگذاری می‌کند تا واضح‌تر شود که آن‌ها چگونگی تغییر خود diff را توصیف می‌کنند.

ایده کلی به این صورت است: یک ماتریس هزینه بین کامیت‌های هر دو بازه کامیت تولید می‌کنیم، سپس مسئله تخصیص کمترین هزینه (least-cost assignment) را حل می‌کنیم.

ماتریس هزینه به این شیوه مقداردهی می‌شود: برای هر جفت کامیت، هر دو diff تولید می‌شوند و سپس «diff از diffها» با ۳ خط بافت (context) ایجاد می‌شود، سپس تعداد خطوط موجود در آن diff به عنوان هزینه در نظر گرفته می‌شود.

برای جلوگیری از مثبت‌های کاذب (false positives ‏- مثلاً هنگامی که یک پچ حذف شده و پچ نامرتبط دیگری بین دو تکرار از همان مجموعه پچ اضافه شده است)، ماتریس هزینه با افزودن ورودی‌های دارای هزینه ثابت برای حذف‌ها/افزودن‌های کلی گسترش می‌یابد.

مثال: فرض کنید کامیت‌های 1--2 اولین تکرار از یک مجموعه پچ و A--C دومین تکرار باشند. فرض کنیم A یک cherry-pick از 2 باشد، و C یک cherry-pick از 1 ولی با تغییری کوچک (مثلاً رفع یک اشتباه تایپی). کامیت‌ها را به صورت یک گراف دوبخشی تجسم کنید:

1            A
2            B
             C

ما به دنبال «بهترین» توضیح برای مجموعه جدید بر حسب مجموعه قدیمی هستیم. می‌توانیم یک «توضیح» را به صورت یک یال در گراف نشان دهیم:

1            A
           /
2 --------'  B
             C

این توضیح «رایگان» (بدون هزینه) تمام می‌شود چون هیچ تغییری وجود نداشته است. به طور مشابه C می‌تواند با استفاده از 1 توضیح داده شود، اما این کار به دلیل وجود تغییر با مقداری هزینه c>0 همراه است:

1 ----.      A
      |    /
2 ----+---'  B
      |
      `----- C
      c>0

از نظر ریاضی، آنچه به دنبال آن هستیم نوعی تطابق دوبخشی با کمترین هزینه است؛ ‘1` با مقداری هزینه با C منطبق می‌شود، و الی آخر. گراف زیربنایی در واقع یک گراف دوبخشی کامل است؛ هزینه‌ای که به هر یال نسبت می‌دهیم اندازه diff میان پچ‌های دو کامیت است. برای توضیح کامیت‌های جدید نیز گره‌های ساختگی (dummy nodes) را در هر دو طرف معرفی می‌کنیم:

1 ----.      A
      |    /
2 ----+---'  B
      |
o     `----- C
      c>0
o            o
o            o

هزینه یک یال o--C اندازه diff کامیت C است که با یک ضریب تعدیل (fudge factor) که باید کمتر از ۱۰۰٪ باشد اصلاح می‌شود. هزینه یک یال o--o رایگان (صفر) است. این ضریب تعدیل ضروری است زیرا حتی اگر 1 و C هیچ اشتراکی نداشته باشند، ممکن است هنوز چند خط خالی و موارد مشابه را به اشتراک بگذارند، و احتمالاً تخصیص 1--C, o--o را کمی ارزان‌تر از 1--o, o--C کند، حتی اگر 1 و C هیچ وجه اشتراکی نداشته باشند. با ضریب تعدیل ما بخش مشترک بسیار بزرگ‌تری را برای متناظر دانستن پچ‌ها نیاز داریم.

کل زمان مورد نیاز برای محاسبه این الگوریتم، زمان لازم برای محاسبه n+m دیف کامیت و سپس n*m دیف پچ‌ها است، به علاوه زمان لازم برای محاسبه کم‌هزینه‌ترین تخصیص بین n و m دیف. گیت از پیاده‌سازی الگوریتم یانکر-ولگنانت (Jonker-Volgenant) برای حل مسئله تخصیص استفاده می‌کند که دارای پیچیدگی زمانی مکعبی (cubic) است. تطابق یافت‌شده در این حالت به این شکل خواهد بود:

1 ----.      A
      |    /
2 ----+---'  B
   .--+-----'
o -'  `----- C
      c>0
o ---------- o
o ---------- o

git-log(1)

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

2026-06-29 Git 2.55.0