کدنامهمرجع‌های مهندسی نرم‌افزار، به فارسی
گیت · فصل ۶Git · Chapter 6

merge و حل تعارض

Merging and resolving conflicts

دو نفر از یک نقطه شروع می‌کنند و هرکدام چیزی را تغییر می‌دهند. بعضی وقت‌ها Git بدون حرف اضافه آن‌ها را کنار هم می‌گذارد؛ بعضی وقت‌ها می‌ایستد و از تو تصمیم می‌خواهد. این فصل می‌فهمیم چرا.

Two teammates started at one commit. One improved the greeting; the other changed the team list. Git combined both quietly. Next time, they rewrote the same greeting line differently, and Git stopped. Why could it combine the first pair but not the second?

۱۱بخشsections
۸۵دقیقهminزمان مطالعهreading time
۱۸تمرین با پاسخsolved exercises
۴نمودارdiagrams

یک بار Git جلو رفت؛ بار دوم مکث کردGit moved forward once, then paused

در فصل ۰۵ دیدیم دو شاخه می‌توانند از یک commit شروع شوند و هرکدام اشاره‌گر مستقلی داشته باشند. حالا وقت برگرداندن یک مسیر به شاخهٔ اصلی است. اول پیش‌بینی کن: اگر شاخهٔ قابلیت فقط یک commit جلوتر باشد و main هیچ commit تازه‌ای نداشته باشد، آیا Git باید commit جدیدی بسازد؟

Chapter 05 showed two branches starting at one commit, each with its own ref. Now we need to bring one line back to the main branch. Predict first: if feature is one commit ahead and main has not added a commit, must Git create a new commit?

برای آزمایش، مخزن جداگانه می‌سازیم. یک شاخه جلو می‌رود؛ بعد main آن را merge می‌کند. فایل اصلی را نگاه کن، اما مهم‌تر از آن، شناسهها و شکل گراف را بخوان.

We’ll use a separate repository. One branch advances, then main merges it. Inspect the file, but more importantly, compare commit IDs and graph shape.

bash · disposable fast-forward experiment
mkdir merge-lab && cd merge-lab
git init -b main
git config user.name 'Nika Example'
git config user.email 'nika@example.test'
printf 'سلام\n' > greeting.txt
git add greeting.txt
git commit -m 'Add greeting'
git switch -c feature/welcome
printf 'سلام به همه\n' > greeting.txt
git add greeting.txt
git commit -m 'Improve greeting'
git switch main
git rev-parse HEAD
git rev-parse feature/welcome
git merge feature/welcome
git log --oneline --graph --decorate --all

قبل از merge، main نیاکان مستقیم feature/welcome است؛ شاخه‌ها از هم جدا نشده‌اند. merge پیش‌فرض فقط اشاره‌گر شاخهٔ جاری را به commit جلوتر می‌برد. اگر دو شناسه آخر را بعد از merge مقایسه کنی، main و قابلیت روی یک commit‌اند و commit سومی ساخته نشده است. این حرکت مستقیم را fast-forward می‌گوییم.

Before merging, main is a direct ancestor of feature/welcome; the tips have not diverged. The default merge simply advances the current branch ref to the descendant. Afterward, the two refs resolve to the same commit, and no third commit was created. That direct move is a fast-forward.

Fast-forward moves main from an ancestor commit to its descendant without a new commit C1 · shared base main + feature C2 · feature commit main moves here one pointer update · no merge commit
نمودار ۱ — خط، رابطهٔ والد و فرزند را نشان می‌دهد؛ چون main روی نیاکان C2 است، اشاره‌گر آن مستقیم تا C2 جلو می‌رود.
Diagram 1 — The line is a parent-child link. Since main is an ancestor of C2, its ref can move straight to C2.
شکل تاریخچهHistory shapeکار معمول mergeDefault merge resultcommit تازه؟New commit?
نوک شاخهٔ جاری نیاکان شاخهٔ ورودی است.Current tip is an ancestor of the incoming tip.اشاره‌گر شاخهٔ جاری به نوک جلوتر حرکت می‌کند.Current branch ref advances to the descendant.نه؛ fast-forward است.No; it is a fast-forward.
هر دو شاخه از نقطهٔ مشترک جلو رفته‌اند.Both branches advanced from a shared point.Git نتیجه را ادغام و commit دووالدی می‌سازد.Git combines the result and creates a two-parent commit.معمولاً بله؛ merge commit.Usually yes; a merge commit.
نوک ورودی از قبل در تاریخچهٔ جاری است.Incoming tip is already in current history.پیام Already up to date.“Already up to date.”نه؛ چیزی برای افزودن نیست.No; there is nothing new to add.

وقتی هر دو شاخه جلو رفته‌اندWhen both branches have advanced

حالا شکل سخت‌تر را بسازیم. بعد از C1، main روی C2 تغییر مستقلی می‌دهد و قابلیت هم روی C3 تغییر خودش را. هیچ‌کدام نیاکان دیگری نیست. Git برای ساخت نتیجه باید بفهمد هر طرف از نقطهٔ مشترک چه تغییری داده است.

Now create the harder shape. After C1, main makes an independent change at C2 and feature makes its own at C3. Neither tip is an ancestor of the other. To build a result, Git must determine what each side changed since their shared point.

bash · divergent histories
git switch -c feature/notes
printf 'notes enabled\n' > notes.txt
git add notes.txt
git commit -m 'Add notes'
git switch main
printf 'release=1\n' > release.txt
git add release.txt
git commit -m 'Record release'
git merge-base main feature/notes
git merge feature/notes
git rev-list --parents -n 1 HEAD
git log --oneline --graph --decorate --all

در این مثال تغییرها به فایل‌های جدا می‌رسند، پس می‌توانند بی‌تعارض کنار هم قرار بگیرند. چون نوک‌ها واگرا شده‌اند، Git commit تازه‌ای می‌سازد که دو والد دارد: نوک قبلی main و نوک feature. git rev-list --parents -n 1 HEAD یک شناسه برای merge commit و دو شناسه والد نشان می‌دهد.

Here the changes touch different files, so Git can combine them without conflict. Because the tips diverged, Git creates a new commit with two parents: the former main tip and the feature tip. git rev-list --parents -n 1 HEAD prints the merge commit ID followed by its two parent IDs.

Divergent branches share a merge base and join in a two-parent merge commit B · merge base shared ancestor M · main tip ours in this merge F · feature tip theirs in this merge merge two parents Git compares both sides to B; it does not replay one on top of the other
نمودار ۲ — B شاخهٔ مشترک‌شدن مسیرهاست. Git تغییرهای main و قابلیت را نسبت به B مقایسه می‌کند؛ دو پیکان ورودی به commit آخر همان دو والد هستند.
Diagram 2 — B is where the lines share history. Git compares each side's changes against B; the two incoming links become the merge commit's parents.

این نقطهٔ مشترک را merge base می‌نامیم. در گراف‌های ساده یک merge base روشن داریم؛ تاریخچه‌های پیچیده‌تر ممکن است چند بهترین merge base داشته باشند و الگوریتم پیش‌فرض آن‌ها را هم مدیریت می‌کند. فعلاً لازم نیست در آن پیچیدگی فرو برویم. نکتهٔ امروز این است: Git فقط دو فایل آخر را کنار هم نمی‌گذارد؛ تغییرهای هر دو را از پایهٔ مشترک می‌سنجد.

That shared point is the merge base. Simple graphs have one obvious base; more complex histories can have multiple best merge bases, which the default strategy can handle. We do not need that complexity yet. The key idea is that Git does not merely compare two final files—it evaluates both sides' changes from their common base.

fast-forward سیاست، نه نسخهٔ اخلاقیFast-forward policy, not a moral rule

--ff-only فقط وقتی جلو می‌رود که نوک فعلی نیاکان شاخهٔ ورودی باشد؛ اگر مسیرها واگرا باشند، متوقف می‌شود. --no-ff حتی در حالت امکان fast-forward، merge commit می‌سازد تا مرز ادغام در تاریخچه بماند. هیچ‌کدام همیشه بهترین نیست؛ تیم باید بر اساس نیاز به گراف خطی یا ثبت مرز کار تصمیم بگیرد.

--ff-only proceeds only when the current tip is an ancestor of the incoming tip; it refuses diverged histories. --no-ff creates a merge commit even when a fast-forward is possible, preserving an explicit merge boundary. Neither is universally best; choose based on whether your team wants a linear graph or an explicit integration record.

تعارض یعنی نیتِ لازم را Git نمی‌داندA conflict means Git lacks the intent it needs

تا وقتی دو تغییر در بخش‌های جدا باشند، Git معمولاً می‌تواند هر دو را نگه دارد. اما اگر main یک خط را «سلام به محصول» و قابلیت همان خط را «سلام به مهندسی» کند، کدام‌یک باید نسخهٔ نهایی باشد؟ این سؤال فنی نیست؛ تصمیم محصول است.

When changes affect separate regions, Git can usually retain both. But if main changes one line to “Hello product” and feature changes that same line to “Hello engineering,” which should the final version say? That is a product decision, not a technical fact.

Git خراب نشده. ابزار merge تغییرها را نسبت به پایه تشخیص می‌دهد، اما قرارداد تیم یا معنای متن را نمی‌داند. وقتی دو تغییر با هم ناسازگارند، Git به‌جای انتخاب تصادفی merge را متوقف می‌کند تا تو تصمیم بگیری.

Git is not broken. The merge machinery can compare changes against the base, but it does not know the team's contract or the meaning of the text. When edits are incompatible, Git stops rather than choosing arbitrarily.

Three-way comparison of base, ours, and theirs produces a clean or unresolved result Base · stage 1original line Ours · stage 2current branch Theirs · stage 3incoming branch compare editssame region? cleancombine overlapask a human merge base + current + incoming → one intended result
نمودار ۳ — Git پایه، نسخهٔ شاخهٔ جاری و نسخهٔ شاخهٔ ورودی را می‌سنجد. تغییر جدا قابل ترکیب است؛ هم‌پوشانی ناسازگار به تصمیم انسانی نیاز دارد.
Diagram 3 — Git compares the base, current branch, and incoming branch. Separate edits can combine; incompatible overlap needs a human decision.
تغییر دو طرفBoth sides changed…نتیجهٔ محتملLikely resultچه چیزی هنوز لازم است؟What is still needed?
فایل‌های متفاوتDifferent filesادغام خودکارAutomatic combinationبازبینی حاصل؛ ادغام خودکار تضمین درستی معنایی نیست.Review the result; automatic does not mean semantically correct.
یک فایل، ناحیه‌های جداOne file, separate regionsاغلب ادغام خودکارOften automaticکنترل کن که دو تغییر کنار هم معنی بدهند.Check that both edits make sense together.
یک ناحیه، محتوای ناسازگارSame region, incompatible contentتعارض و توقف mergeConflict; merge pausesانسان باید قصد نهایی را انتخاب/ترکیب کند.A human must choose or combine the intended result.
یک طرف حذف، دیگری تغییرOne deletes, the other modifiesتعارض modify/deleteModify/delete conflictتصمیم بگیر فایل بماند یا حذف شود.Decide whether the file should remain or be deleted.

حل تعارض: اول قصد، بعد ویرایشResolve a conflict: intent before editing

تعارض را در یک مخزن دورریختنی می‌سازیم. قبل از merge، git status باید بدون تغییر باشد؛ این کار احتمال گیرکردن تغییرهای نامرتبط را کم می‌کند و abort را قابل‌پیش‌بینی‌تر نگه می‌دارد. اگر پروژهٔ واقعی داری، اول تغییرها را commit کن؛ merge را روی پوشهٔ نیمه‌کاره امتحان نکن.

We’ll create a conflict in a disposable repository. Before merging, git status should be clean; this reduces the chance that unrelated work becomes entangled and makes abort more predictable. In a real project, commit your work first—do not experiment on a half-finished tree.

bash · same-line conflict
printf 'سلام به تیم\n' > greeting.txt
git add greeting.txt
git commit -m 'Add shared greeting'
git switch -c feature/product
printf 'سلام به تیم محصول\n' > greeting.txt
git add greeting.txt
git commit -m 'Address product team'
git switch main
printf 'سلام به تیم مهندسی\n' > greeting.txt
git add greeting.txt
git commit -m 'Address engineering team'
git status --short
git merge feature/product

پیام CONFLICT (content) و Automatic merge failed یعنی Git ترکیب نهایی را ثبت نکرده و merge هنوز در جریان است. این خطا نمی‌گوید کدام جمله بهتر است. فایل را باز کن و قبل از دست‌زدن به نشانگرها تصمیم بگیر: آیا باید محصول، مهندسی، یا هر دو در متن باشند؟

A CONFLICT (content) message and Automatic merge failed mean Git did not record a final combination and the merge is still in progress. The error does not say which sentence is better. Open the file and decide before touching markers: should the message address product, engineering, or both?

representative conflicted file
<<<<<<< HEAD
سلام به تیم مهندسی
=======
سلام به تیم محصول
>>>>>>> feature/product

در این merge مشخص، بخش بالای ======= نسخهٔ ours یعنی main فعلی است؛ بخش پایین نسخهٔ theirs یعنی feature/product. نشانگرها دستور Git نیستند؛ متن راهنما هستند که باید از نسخهٔ نهایی حذف شوند. انتخاب یک طرف هم همیشه جواب نیست: شاید جملهٔ درست «سلام به تیم محصول و مهندسی» باشد.

In this merge, the section above ======= is ours—the current main branch; below it is theirs—feature/product. Markers are not Git commands; they are guidance that must not remain in the final version. Choosing one side is not always right: perhaps the intended line is “Hello product and engineering teams.”

Conflict alternatives require an explicit human choice before the resolved file is staged Ours · mainengineering team Theirs · featureproduct team human decideskeep / combine / delete edit filethen git add markers identify alternatives; they do not choose the intended sentence
نمودار ۴ — دو نسخه ورودی‌اند، نه جواب نهایی. انسان قصد را تعیین می‌کند، فایل را ویرایش می‌کند و با git add نتیجه را وارد ناحیه‌ آماده‌سازی می‌کند.
Diagram 4 — The two versions are inputs, not the answer. A person decides intent, edits the file, and stages the result with git add.

فایل را به جملهٔ موردنظر تبدیل کن؛ سپس خودت دوباره بخوانش، نشانگرها را جست‌وجو کن و بعد ناحیه‌ آماده‌سازی کن:

Edit the file to the intended sentence; then read it back, search for leftover markers, and only then stage it:

bash · stage the human decision
printf 'سلام به تیم محصول و مهندسی\n' > greeting.txt
git diff --check
git diff -- greeting.txt
git add greeting.txt
git status
git diff --cached
git merge --continue
git status --short --branch
git log --oneline --graph --decorate --all

پس از git add، مسیر از ناحیه‌ آماده‌سازیهای unmerged به یک رد عادی ناحیه‌ آماده‌سازی 0 می‌رود. git merge --continue merge commit را کامل می‌کند؛ git commit هم می‌تواند آن را تمام کند. قبل از ادامه، diff آماده‌شده را بازبینی کن. موفقیت یعنی هم فایل نهایی قصد را نشان بدهد، هم وضعیت از حالت merge بیرون آمده باشد.

After git add, the path moves from unmerged index entries to one ordinary stage-0 entry. git merge --continue completes the merge commit; git commit can complete it too. Review the staged diff first. Success means the file expresses the intended result and status no longer reports a merge in progress.

سه نسخهٔ حل‌نشده در ناحیه‌ آماده‌سازی کجا هستند؟Where do the three unresolved versions live?

وقتی نشانگر را در فایل می‌بینی، شاید فکر کنی Git فقط یک متن مبهم روی دیسک گذاشته. در واقع ناحیه‌ آماده‌سازی هم تا زمان حل، نسخه‌های جداگانه را نگه می‌دارد. با git ls-files -u می‌توانی ببینی هر مسیر چه ردهای unmerged دارد.

When you see markers in a file, it may look as if Git left only one ambiguous text on disk. In fact, the index retains separate versions until resolution. git ls-files -u shows the unmerged entries for each path.

ناحیه‌ آماده‌سازیStageنسخهVersionدر این مثالIn this example
1merge basemerge baseخط اصلی قبل از جداشدن دو branch.The original line before the branches diverged.
2oursoursنسخهٔ شاخهٔ جاری، یعنی HEAD این merge.The current branch version—HEAD for this merge.
3theirstheirsنسخهٔ شاخهٔ ورودی، یعنی MERGE_HEAD.The incoming branch version—MERGE_HEAD.
bash · inspect the unmerged index
git ls-files -u
100644 15ab... 1	greeting.txt
100644 91cd... 2	greeting.txt
100644 6ef0... 3	greeting.txt
git show :1:greeting.txt
git show :2:greeting.txt
git show :3:greeting.txt

سه شناسهٔ متفاوت نشان می‌دهد Git نسخهٔ پایه، ours و theirs را حفظ کرده است؛ هر سه مربوط به یک مسیرند. بعد از حل و git add، git ls-files -u برای آن مسیر دیگر چیزی چاپ نمی‌کند. این فقط می‌گوید ناحیه‌ آماده‌سازی آن مسیر unmerged نیست؛ درست‌بودن معنایی متن را باید خودت بازبینی کنی.

Three different IDs show that Git retained the base, ours, and theirs for one path. After resolving and running git add, git ls-files -u prints nothing for that path. This proves the index is no longer unmerged; you must still review whether the text is semantically correct.

ours/theirs را به rebase تعمیم ندهDo not generalize ours/theirs to rebase

در توضیح این فصل ours یعنی شاخهٔ جاریِ merge و theirs یعنی شاخهی که به git merge داده‌ای. این نام‌ها «کار من/کار همکارم» نیستند و در عملیات دیگری مثل rebase ممکن است از زاویهٔ متفاوتی معنا شوند. فعلاً shortcutهایی مثل --ours و --theirs را حفظ نکن؛ اول ناحیه‌ آماده‌سازیها و گراف را بفهم.

In this chapter, ours means the current branch being merged into, and theirs means the branch passed to git merge. These labels do not mean “my work/the teammate’s work,” and other operations such as rebase can use a different perspective. Do not memorize --ours/--theirs shortcuts yet; understand the graph and stages first.

تعارض همیشه دو متن کنار هم نیستA conflict is not always two text blocks

فرض کن main یک سیاست را اصلاح می‌کند و شاخهٔ دیگر همان فایل را حذف می‌کند. اینجا نشانگرهای سه‌خطی داخل فایل کافی نیستند؛ سؤال انسانی این است که آیا فایل هنوز لازم است؟ Git نمی‌تواند این تصمیم را از تاریخچه حدس بزند.

Suppose main updates a policy while another branch deletes the same file. Three text-marker lines cannot express this decision. The human question is whether the file is still needed—a decision Git cannot infer from history.

bash · inspect both sides of modify/delete
git status
git ls-files -u
git show :1:policy.txt
git show :2:policy.txt
git show :3:policy.txt

در این نمونه فرض کرده‌ایم ours فایل را تغییر داده و theirs حذفش کرده؛ ناحیه‌ آماده‌سازی 1 و 2 وجود دارند، اما ناحیه‌ آماده‌سازی 3 ممکن است اصلاً نباشد. نبودن ناحیه‌ آماده‌سازی یعنی آن سمت برای این مسیر فایل نداشته؛ فرمان git show :3:policy.txt پس شکست می‌خورد. در حالت برعکس، ناحیه‌ آماده‌سازی 2 غایب می‌شود. همیشه خروجی ls-files -u را بخوان، نه اینکه وجود هر سه را فرض بگیری.

Here we assume ours modified the file and theirs deleted it: stages 1 and 2 exist, but stage 3 may be absent. A missing stage means that side had no file at this path, so git show :3:policy.txt fails. In the reverse case, stage 2 is absent. Read ls-files -u; never assume all three exist.

اگر تصمیم این است که نسخهٔ اصلاح‌شده بماند، فایل را بازبینی و با git add policy.txt ثبت کن. اگر باید حذف بماند، git rm policy.txt را بزن. هر دو فرمان به Git می‌گویند «این تصمیم نهایی من برای ناحیه‌ آماده‌سازی است»؛ هیچ‌کدام جای تصمیم را نمی‌گیرند.

If the decision is to keep the revised file, review it and stage it with git add policy.txt. If deletion is intended, use git rm policy.txt. Either tells Git “this is my final index decision”; neither makes the decision for you.

اگر تصمیم نداریم، یا کار اشتباه پیش رفتWhen you cannot decide—or the merge went wrong

وسط تعارض لازم نیست قهرمان‌بازی دربیاوری. اگر هنوز تصمیم درست را نمی‌دانی، وضعیت را ثبت کن و در صورت نیاز merge را لغو کن. مهم این است که بفهمی Git کجا متوقف شده و کدام تصمیم را از انسان می‌خواهد.

You do not have to rush through a conflict. If the tree was clean before the merge and you do not have a decision yet, you can abort the in-progress merge. But if you had unfinished work, do not treat abort as a guaranteed rewind button.

bash · leave a clean-tree conflict safely
git status
git merge --abort
git status --short --branch
git log --oneline --graph --decorate --all

git merge --abort تلاش می‌کند وضعیت قبل از merge را بازسازی کند. اگر تغییرهای محلیِ ثبت‌نشده هنگام شروع داشته‌ای—به‌خصوص اگر بعد از آغاز merge آن‌ها را دستکاری کرده باشی—ممکن است بازسازی کامل ممکن نباشد. برای همین پیش‌بررسی مهم است: git status، و اگر در کار واقعی چیزی ناتمام است، اول آن را جداگانه ثبت یا حفظ کن.

git merge --abort tries to reconstruct the pre-merge state. If you had uncommitted changes when it began—especially if you edited them further after the merge started—Git may not be able to reconstruct everything. That is why the pre-check matters: inspect git status, and preserve unfinished real work separately before merging.

Already up to date دیدی

You saw “Already up to date”

این شکست نیست. نوک شاخهٔ ورودی از قبل در تاریخچهٔ شاخهٔ جاری هست. با git log --graph --decorate --oneline --all مطمئن شو شاخه درست را merge کرده‌ای؛ اگر انتظار commit تازه داشتی، شاید روی شاخه اشتباهی ایستاده‌ای.

This is not a failure. The incoming tip is already in current history. Verify the graph with git log --graph --decorate --oneline --all; if you expected new commits, perhaps you are on the wrong branch.

قبل از حل، commit زدی

You tried to commit before resolving

Git ناحیه‌ آماده‌سازی مسیرهای unmerged دارد و اجازهٔ commit معمولی نمی‌دهد. git status را بخوان، هر مسیر را با قصد درست ویرایش کن و ناحیه‌ آماده‌سازی کن. بعد git merge --continue یا git commit.

The index still has unmerged paths, so a normal commit cannot finish. Read git status, edit each path to the intended result, and stage it. Then use git merge --continue or git commit.

برای خلاص‌شدن نشانگرها را پاک کردی

You deleted markers just to make them disappear

حذف نشانگر کافی نیست؛ ممکن است یکی از جمله‌های لازم را هم حذف کرده باشی. با git show :1:FILE، :2: و :3: نسخه‌ها را ببین، قصد نهایی را بنویس، سپس diff را بخوان و ناحیه‌ آماده‌سازی کن.

Removing markers is not enough; you may have deleted needed content too. Inspect versions with git show :1:FILE, :2:, and :3:, write the intended result, review the diff, and stage it.

تغییر نامرتبط را قبل از merge نگه داشتی

Unrelated work was left dirty before merging

merge ممکن است برای محافظت از آن متوقف شود یا تغییرهای هم‌پوشان را در معرض خطر بگذارد. git status --short و پیام خطا را بخوان. در مخزن آزمایشی پاک شروع کن؛ در کار واقعی قبل از merge تغییرها را commit یا با روشی مطمئن نگه دار. force نکن.

The merge may stop to protect that work or put overlapping changes at risk. Read git status --short and the message. Start clean in experiments; in real work, commit or safely preserve changes before merging. Do not force it.

یک طرف را انتخاب کردی و بخش لازم از طرف دیگر پرید

Choosing one side dropped needed content

از روی نام ours/theirs تصمیم نگیر. مرجع و قصد را بخوان، اگر لازم است سه نسخه را از ناحیه‌ آماده‌سازی بیرون بکش، متن نهایی را بنویس و با git diff --cached ثابت کن که هر دو نیاز مهم باقی مانده‌اند.

Do not decide from the labels alone. Read the context and intent, inspect the three versions if needed, write the final text, and use git diff --cached to confirm both required ideas remain.

تمرین‌ها: از پیش‌بینی گراف تا تصمیم انسانیExercises: from graph prediction to human decisions

در تمرین‌ها اول گراف را نگاه کن، بعد متن فایل را. بعضی سؤال‌ها اصلاً تعارض ندارند و فقط با حرکت شاخه حل می‌شوند؛ بعضی‌ها merge commit می‌سازند و بعضی‌ها واقعاً به تصمیم انسانی نیاز دارند.

Predict before opening the solution. The exercises move from reading a graph to incidents where Git evidence and product decisions must be separated.

۱۸ تمرین حل‌شده · مفهوم، خروجی، عیب‌یابی و تصمیم18 solved exercises · model, output, debugging, and decisions
۰۱پیش‌بینی / Predict

main روی C1 است و قابلیت به C2 فرزند C1 رسیده؛ main commit دیگری ندارد. merge پیش‌فرض چه می‌کند؟

main is at C1; feature is at child C2; main has no other commit. What does a default merge do?

راهنماییHint

آیا دو نوک شاخه واگرا شده‌اند؟

Have the branch tips diverged?

پاسخ و دلیلAnswer with evidence

fast-forward: اشاره‌گر main به C2 می‌رود، commit تازه ساخته نمی‌شود. بعد از merge، git rev-parse main و git rev-parse feature باید یک شناسه بدهند.

A fast-forward: main moves to C2 without a new commit. Afterward, git rev-parse main and git rev-parse feature should return the same ID.

۰۲شکل گراف / Graph shape

main و topic هر دو یک commit مستقل از B ساخته‌اند. آیا main می‌تواند فقط اشاره‌گر را به نوک topic حرکت دهد و تاریخچهٔ هر دو را نگه دارد؟

main and topic each made an independent commit from B. Can main simply move its ref to topic and retain both histories?

راهنماییHint

ببین کدام‌یک نیاکان دیگری است.

Ask whether either tip is an ancestor of the other.

بیا بازش کنیمReasoning

نه، هر دو از B جدا شده‌اند و هیچ‌یک نیاکان دیگری نیست. برای نگه‌داشتن هر دو مسیر به نتیجهٔ ادغام و معمولاً یک merge commit با دو والد نیاز است.

No. Both diverged from B, so neither tip is an ancestor of the other. Preserving both lines requires a combined result and usually a two-parent merge commit.

۰۳خواندن فرمان / Read a command

git merge-base main topic یک شناسه‌ شیء برگرداند. این شناسه‌ شیء چه چیزی است و چه چیزی را ثابت نمی‌کند؟

git merge-base main topic returns an OID. What is it, and what does it not prove?

راهنماییHint

به نام فرمان و جایگاهش در گراف فکر کن.

Think about the command name and the graph.

راه‌حل و توضیحExplanation

یک بهترین commit مشترک برای دو تاریخچه است؛ شروع مقایسهٔ سه‌طرفه در این شکل ساده. به‌تنهایی نمی‌گوید merge بدون تعارض می‌شود یا هر دو شاخه درست‌اند.

It is a best shared commit for the histories—the base for a three-way comparison in this simple graph. It does not say the merge will be conflict-free or that either branch is correct.

۰۴پیش‌بینی policy / Predict a policy

در شکل fast-forward، git merge --no-ff topic چه تفاوتی با merge عادی دارد؟

On a fast-forwardable graph, how does git merge --no-ff topic differ from a default merge?

راهنماییHint

چه چیزی در گراف اضافه می‌شود؟

What extra node appears in the graph?

چرا این جواب درست استAnswer

merge commit می‌سازد، حتی اگر main بتواند مستقیم جلو برود. این سیاست ثبت مرز ادغام است، نه الزام فنی و نه بهترین انتخاب همیشگی.

It creates a merge commit even though main could advance directly. This is a policy for recording an integration boundary, not a technical requirement or universal best practice.

۰۵معنای عبارت / Interpret output

git merge topic می‌گوید Already up to date. آیا merge شکست خورده؟

git merge topic says Already up to date. Did the merge fail?

راهنماییHint

آیا commit ورودی از قبل در رابطهٔ والدها شاخهٔ جاری هست؟

Is the incoming commit already an ancestor of the current branch?

بررسی جوابInterpretation

نه؛ چیزی برای افزودن وجود ندارد. اگر انتظار تغییر داشتی، شاخه جاری و نام topic را با git branch --show-current و گراف بررسی کن.

No; there is nothing to add. If you expected changes, check the current branch and topic name with git branch --show-current and the graph.

۰۶تغییرهای جدا / Separate edits

هر دو شاخه یک فایل را تغییر داده‌اند، اما در خط‌های جدا. آیا حتماً تعارض می‌شود؟

Both branches edited one file, but on separate lines. Must this conflict?

راهنماییHint

Git ناحیهٔ تغییر را نسبت به چه چیزی مقایسه می‌کند؟

Against what does Git compare each changed region?

پاسخ پیشنهادیPrecise answer

نه. اگر ناحیه‌ها مستقل باشند، Git اغلب هر دو را ادغام می‌کند. بااین‌حال diff نهایی را بخوان؛ ادغام متنی نمی‌فهمد نتیجه از نظر معنا درست است.

No. If the regions are independent, Git often combines both. Still review the final diff; textual merging cannot know whether the result makes sense.

تا اینجا Git خودش بخش بزرگی از ادغام را انجام داده. از اینجا سؤال اصلی بیشتر انسانی می‌شود: اگر دو طرف نیت متفاوتی دارند، خروجی درست محصول کدام است؟ نشانگرهای تعارض فقط محل تصمیم را نشان می‌دهند.

So far Git has done much of the merge work itself. From here the main question becomes human: when the two sides express different intent, what should the product actually contain? Conflict markers only show where that decision is needed.

۰۷تشخیص مرحله / Identify the stage

git ls-files -u برای یک فایل ناحیه‌ آماده‌سازیهای ۱، ۲ و ۳ را نشان می‌دهد. هرکدام چه نسخه‌ای هستند؟

git ls-files -u shows stages 1, 2, and 3 for a path. Which versions are they?

راهنماییHint

base، شاخهٔ فعلی، شاخهٔ ورودی.

Base, current branch, incoming branch.

پاسخ و دلیلMapping

۱ = merge base؛ ۲ = ours، یعنی HEAD جاری در merge؛ ۳ = theirs، یعنی MERGE_HEAD. در modify/delete ممکن است یک ناحیه‌ آماده‌سازی غایب باشد.

1 = merge base; 2 = ours, HEAD in this merge; 3 = theirs, MERGE_HEAD. A modify/delete conflict may lack one stage.

۰۸خواندن marker / Read markers

در فایل، HEAD بالای ======= است. در این merge این نام به کدام سمت اشاره دارد؟

HEAD appears above =======. Which side is it in this merge?

راهنماییHint

کدام شاخه را قبل از اجرای merge checkout کرده‌ای؟

Which branch was checked out before running merge?

بیا بازش کنیمAnswer

بالا ours است: شاخهٔ جاری و HEAD زمان merge. پایین theirs است: شاخه ورودی. این واژه‌ها را به معنی «من» و «دیگری» در عملیات دیگر تعمیم نده.

The top is ours: the current branch and HEAD for this merge. The bottom is theirs: the incoming branch. Do not generalize these labels to “me/other” in different operations.

۰۹ترمیم index / Repair the index

نشانگرها را در فایل حذف کردی، اما git status هنوز unmerged می‌گوید. چه مرحله‌ای جا مانده؟

You removed the markers, but git status still reports unmerged paths. What step remains?

راهنماییHint

فایل و ناحیه‌ آماده‌سازی یکی نیستند.

The file and index are separate.

راه‌حل و توضیحFix

فایل نهایی را بازبینی و با git add FILE ناحیه‌ آماده‌سازی کن. ویرایش پوشه‌ کاری به‌تنهایی ناحیه‌ آماده‌سازیهای unmerged ناحیه‌ آماده‌سازی را جایگزین نمی‌کند؛ بعد git ls-files -u را دوباره ببین.

Review the final file and stage it with git add FILE. Editing the working tree alone does not replace the index’s unmerged stages; rerun git ls-files -u.

۱۰تصمیم متن / Text decision

ours می‌گوید «ثبت‌نام باز است»، theirs می‌گوید «ثبت‌نام بسته است»، و زمان انتشار هنوز معلوم نیست. آیا یکی را انتخاب می‌کنی؟

Ours says “registration open,” theirs says “registration closed,” and the release date is unknown. Do you choose one?

راهنماییHint

کدام مدرک Git ندارد؟

What evidence does Git lack?

چرا این جواب درست استResponsible decision

Git فقط دو نسخه و پایه را دارد؛ قصد کسب‌وکار را نمی‌داند. از صاحب نیاز یا قرارداد انتشار بپرس، یا merge را abort کن تا پاسخ روشن شود. انتخاب تصادفی یکی از sideها می‌تواند اطلاعات نادرست منتشر کند.

Git has the two versions and their base, not business intent. Ask the owner or check the release contract, or abort until you know. Randomly choosing a side could publish incorrect information.

۱۱تفاوت policy / Compare policies

گراف قابل fast-forward است. تیم می‌خواهد ادغام قابلیت به‌شکل commit جدا در log بماند. کدام گزینه با این سیاست سازگار است؟

The graph is fast-forwardable. The team wants feature integration to remain an explicit commit in the log. Which option matches?

راهنماییHint

یکی از گزینه‌ها merge commit را حتی در fast-forward می‌سازد.

One option creates a merge commit even when fast-forward is possible.

بررسی جوابAnswer and limit

git merge --no-ff feature. این یک سیاست برای شکل تاریخچه است؛ الزام فنی یا توصیهٔ همیشگی نیست و commit واقعی merge می‌سازد.

git merge --no-ff feature. This is a history policy, not a technical requirement or universal advice; it creates a real merge commit.

۱۲پیش‌بررسی / Pre-merge check

قبل از merge، ناحیه‌ آماده‌سازی تغییر ناحیه‌ آماده‌سازیشده و پوشه‌ کاری هم فایل نیمه‌کاره دارد. امن‌ترین قدم چیست؟

Before merging, the index has staged changes and the working tree has an unfinished file. What is the safest next step?

راهنماییHint

merge قرار است کدام تغییرها را ثبت کند؟

Which changes should the merge record?

پاسخ پیشنهادیReasoning

merge را شروع نکن. git status و git diff --staged را بخوان و تغییرها را جداگانه commit یا محفوظ کن. ناحیه‌ آماده‌سازی غیرتمیز ممکن است باعث توقف یا گره‌خوردن کار نامرتبط شود؛ force راه‌حل نیست.

Do not start the merge. Read git status and git diff --staged, then commit or preserve the work separately. A dirty index can stop the merge or entangle unrelated work; forcing is not the fix.

در تمرین‌های آخر، قبل از انتخاب ours یا theirs یا هر ویرایش دیگری، نسخهٔ پایه را هم ببین. خیلی وقت‌ها جواب درست ترکیبی از هر دو طرف است، نه انتخاب کامل یکی.

In the final exercises, inspect the base before choosing ours, theirs, or another edit. The correct result is often a combination of both sides, not a wholesale choice of one.

۱۳تعارض حذف/تغییر / Modify-delete

در git ls-files -u برای policy.txt ناحیه‌ آماده‌سازی 1 و 2 هست، ناحیه‌ آماده‌سازی 3 نیست. چه اتفاقی محتمل است؟

git ls-files -u shows stages 1 and 2 for policy.txt, but no stage 3. What likely happened?

راهنماییHint

ناحیه‌ آماده‌سازی 3 همان incoming است.

Stage 3 is the incoming side.

پاسخ و دلیلInterpretation

در این جهت merge، ours فایل را نگه داشته/تغییر داده و theirs آن را حذف کرده است. ناحیه‌ آماده‌سازی غایب یعنی نسخهٔ آن سمت برای مسیر وجود ندارد؛ با git status جهت حذف/تغییر را تأیید کن.

In this merge direction, ours retained or modified the file while theirs deleted it. The missing stage means that side has no version for the path; confirm the direction with git status.

۱۴برنامهٔ بازیابی / Recovery choice

merge تعارض شده و می‌خواهی قبل از هر تصمیم به وضعیت قبل برگردی؛ قبل از merge پوشه بدون تغییر بوده. فرمان چیست و بعد چه چیزی را بررسی می‌کنی؟

A merge conflicted and you want to return to the pre-merge state; the tree was clean beforehand. What command do you use, and what do you verify?

راهنماییHint

لغو merge و بعد دوباره وضعیت.

Abort the merge, then inspect state again.

بیا بازش کنیمSafe path

git merge --abort؛ سپس git status --short --branch و گراف را بررسی کن. abort تلاش برای بازسازی است، نه تضمین برای تغییرهای محلی ناتمام قبل از merge.

git merge --abort, then inspect git status --short --branch and the graph. Abort attempts reconstruction; it is not a guarantee for unfinished local work present before merging.

۱۵تفسیر commit / Inspect a merge commit

فرمان git rev-list --parents -n 1 HEAD سه شناسه‌ شیء چاپ می‌کند. چرا؟

git rev-list --parents -n 1 HEAD prints three OIDs. Why?

راهنماییHint

اولی خود commit است؛ چند تای بعدی والدها هستند.

The first is the commit; following IDs are parents.

راه‌حل و توضیحRead it

اولی شناسه خود HEAD و دو شناسه بعدی والدهای merge commit هستند: نوک قبلی شاخهٔ جاری و نوک شاخه ورودی. این شاهد merge commit بودن است؛ معنای فایل‌های نهایی را نشان نمی‌دهد.

The first ID is HEAD; the next two are the merge commit’s parents: the former current tip and the incoming branch tip. This proves it is a merge commit, not what the resulting files mean.

۱۶بازبینی حل / Review a resolution

پس از git add greeting.txt، git ls-files -u خالی است. آیا می‌توانی merge را با اطمینان کامل commit کنی؟

After git add greeting.txt, git ls-files -u is empty. Can you commit the merge with complete confidence?

راهنماییHint

چه چیزی را ناحیه‌ آماده‌سازی نمی‌تواند دربارهٔ معنا بگوید؟

What can the index not tell you about meaning?

چرا این جواب درست استReview required

نه هنوز. این فقط می‌گوید مسیر از نظر Git unmerged نیست. git diff --cached، متن نهایی و نیاز محصول را بازبینی کن؛ سپس merge را ادامه بده.

Not yet. It only says Git no longer considers the path unmerged. Review git diff --cached, the final text, and product intent before continuing.

۱۷پروندهٔ عیب‌یابی / Incident ticket

merge خودکار تمام شده اما برنامه بعد از آن رفتار نادرستی دارد؛ هر دو تغییر در فایل‌های جدا بودند. آیا «بدون تعارض» یعنی «درست»؟ قدم تشخیصی چیست؟

An automatic merge completed, but the app behaves incorrectly afterward; the edits were in separate files. Does “no conflict” mean “correct”? What do you inspect?

راهنماییHint

merge متن را می‌سنجد، نه قرارداد برنامه را.

Merging checks text, not application contracts.

بررسی جوابIncident analysis

نه. Git توانست متن را کنار هم بگذارد، اما یکپارچگی معنایی را نمی‌فهمد. merge commit و diff را بخوان، آزمون‌های مربوط را اجرا کن و تعامل دو تغییر را بررسی کن؛ «بدون تغییر merge» فقط نبود تعارض حل‌نشده است.

No. Git could combine text but cannot validate semantic integration. Inspect the merge commit and diff, run relevant tests, and check how the changes interact. A clean merge means no unresolved conflict, not correctness.

۱۸انتخاب اقدام / Choose the next action

در main هستی. همکارت شاخه اشتباه را نام برده و merge با Already up to date تمام شده؛ انتظار تغییر داشتی. به‌جای اجرای مجدد چند فرمان، چه شواهدی می‌گیری؟

You are on main. A teammate named the wrong branch; merge ended with “Already up to date,” though you expected changes. What evidence do you collect before retrying commands?

راهنماییHint

شاخه جاری، اشاره‌گرها و گراف را کنار هم ببین.

Inspect the current branch, refs, and graph together.

پاسخ پیشنهادیDiagnosis

با git branch --show-current جای خودت را تأیید کن؛ git branch -vv و git log --graph --oneline --decorate --all اسم و نوک شاخهها را نشان می‌دهند. بعد نام درست را انتخاب و merge کن. پیام قبلی می‌گوید همان ورودی از قبل در تاریخچه بوده، نه اینکه هیچ شاخه دیگری تغییر تازه ندارد.

Confirm your location with git branch --show-current; use git branch -vv and git log --graph --oneline --decorate --all to inspect names and tips. Then choose the correct branch and merge it. The earlier message means that input was already in history, not that no other branch has new work.

پروژهٔ کوچک: سه تصمیم برای یک محصولMini-project: three integration decisions for one product

مخزن دورریختنی · حدود ۳۵ دقیقهDisposable repository · about 35 minutes

سه شاخه، سه جور نتیجه

Three branches, three different outcomes

این پروژه سه نوع ادغام جلویت می‌گذارد: یکی که Git خودش انجام می‌دهد، یکی که متن با متن درگیر می‌شود و یکی که باید دربارهٔ حذف یا نگه‌داشتن فایل تصمیم بگیری. هدف این نیست که نشانگرهای تعارض را پاک کنی؛ هدف این است که نتیجهٔ نهایی واقعاً همان چیزی باشد که محصول می‌خواهد.

Your team is working on product documentation. Automatically integrate a clean change, resolve a text conflict with explicit intent, and decide whether a policy document survives a modify/delete conflict. Do not “solve” any of them by blindly deleting markers.

پرونده را جدا بساز

Create the case in isolation

این فرمان‌ها فقط پوشهٔ آزمایشی تازه را تغییر می‌دهند. اگر از قبل چنین پوشه‌ای داری، نام دیگری انتخاب کن.

These commands change only a new disposable folder. If that name already exists, choose another.

bash · project setup
mkdir merge-project && cd merge-project
git init -b main
git config user.name 'Nika Example'
git config user.email 'nika@example.test'
printf 'سلام به تیم\n' > greeting.txt
printf 'قانون نسخه: پایدار بماند\n' > policy.txt
printf 'شروع\n' > README.txt
git add .
git commit -m 'Create product docs'

تصمیم اول: فایل‌های جدا، merge خودکار

Decision 1: separate files, clean merge

از main دو شاخه مستقل بساز؛ یکی changelog و دیگری راهنمای سریع اضافه کند. هر دو از یک پایه‌اند. merge اول را بررسی کن، سپس دومی را merge کن و ببین چرا بار دوم ممکن است merge commit بسازد، هرچند تعارضی نیست.

Create two independent branches from main: one adds a changelog, the other a quick guide. Both start at the same base. Inspect the first merge, then merge the second and explain why it may create a merge commit even though there is no conflict.

bash · independent additions
git switch -c feature/changelog
printf 'v1: انتشار آزمایشی\n' > CHANGELOG.txt
git add CHANGELOG.txt && git commit -m 'Add changelog'
git switch main
git switch -c feature/quickstart
printf '۱. نصب\n۲. اجرا\n' > QUICKSTART.txt
git add QUICKSTART.txt && git commit -m 'Add quickstart'
git switch main
git merge feature/changelog
git log --oneline --graph --decorate --all
git merge feature/quickstart
git rev-list --parents -n 1 HEAD
git log --oneline --graph --decorate --all

تصمیم دوم: یک خط، دو خواسته

Decision 2: one line, two intentions

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

Create two new branches from main: one personalizes the greeting for product, the other for engineering. After the first merge, run the second. Before editing, write down a sentence that correctly addresses both audiences; then remove markers, review, and stage it.

bash · same-line conflict
git switch -c feature/product-greeting
printf 'سلام به تیم محصول\n' > greeting.txt
git add greeting.txt && git commit -m 'Address product team'
git switch main
git switch -c feature/engineering-greeting
printf 'سلام به تیم مهندسی\n' > greeting.txt
git add greeting.txt && git commit -m 'Address engineering team'
git switch main
git merge feature/product-greeting
git merge feature/engineering-greeting
git status
git ls-files -u
git show :1:greeting.txt
git show :2:greeting.txt
git show :3:greeting.txt

نتیجهٔ پیشنهادی: سلام به تیم محصول و مهندسی. این تنها جواب ممکن نیست؛ اگر محصول قرارداد لحن دیگری دارد، همان را انتخاب کن و دلیلش را ثبت کن.

One reasonable result is سلام به تیم محصول و مهندسی. It is not the only valid answer; if the product has another tone contract, choose it and record why.

bash · record and verify the resolution
printf 'سلام به تیم محصول و مهندسی\n' > greeting.txt
git diff --check
git add greeting.txt
git diff --cached
git merge --continue
git status --short --branch
git log --oneline --graph --decorate --all

تصمیم سوم: سند تغییر کرد یا حذف شد؟

Decision 3: update or delete the policy?

از main، شاخهی بساز که سیاست را دقیق‌تر می‌کند؛ از main دیگری بساز که همان سیاست را حذف می‌کند. بعد یکی را merge و دیگری را اجرا کن. این پرونده تصمیم محصول می‌خواهد، نه مقایسهٔ دو تکه متن؛ سیاست انتشار باید بماند، پس نسخهٔ اصلاح‌شده را نگه دار.

From main, create one branch that clarifies the policy and another that deletes it. Merge one, then attempt the other. This needs a product decision, not a text comparison: the release policy must remain, so keep the revised version.

bash · modify/delete conflict
git switch -c feature/policy-update
printf 'قانون نسخه: پایدار بماند؛ انتشار فقط پس از بازبینی\n' > policy.txt
git add policy.txt && git commit -m 'Clarify release policy'
git switch main
git switch -c feature/remove-old-policy
git rm policy.txt
git commit -m 'Remove obsolete policy'
git switch main
git merge feature/policy-update
git merge feature/remove-old-policy
git status
git ls-files -u
git show :1:policy.txt
git show :2:policy.txt

ناحیه‌ آماده‌سازی 3 برای نسخهٔ حذف‌شده وجود ندارد. تصمیم پروژه نگه‌داشتن سیاست است؛ فایل را بازبینی کن و با git add policy.txt ناحیه‌ آماده‌سازی کن، سپس merge را ادامه بده. اگر تصمیم واقعی تیم حذف بود، باید git rm policy.txt می‌زدی. در دفترچه بنویس چه مدرکی Git داد، چه چیزی را نمی‌دانست و انسان چه تصمیمی گرفت.

Stage 3 is absent for the deleted version. The project decision is to retain the policy: review it and stage it with git add policy.txt, then continue the merge. If the team's real decision were deletion, you would use git rm policy.txt. Record what Git showed, what it could not know, and what the human decided.

bash · verify the project
git add policy.txt
git diff --cached
git merge --continue
git status --short --branch
git log --oneline --graph --decorate --all
git show HEAD:policy.txt
راهنمایی اگر گراف گیج‌کننده شدHint if the graph gets confusing

در هر تعارض، شاخه جاری را با git branch --show-current پیدا کن. اسم شاخه ورودی را از فرمان merge بردار؛ مثلاً در تعارض دوم پروژه git merge-base HEAD feature/engineering-greeting و git log --graph --oneline --decorate --all را بخوان. برای هر فایل فقط وقتی همهٔ نیازها را فهمیدی تصمیم بگیر.

For each conflict, identify the current branch with git branch --show-current. Use the incoming branch name from your merge command; for the second project conflict, for example, run git merge-base HEAD feature/engineering-greeting, then inspect git log --graph --oneline --decorate --all. Decide on each file only after you understand the requirements.

دفترچهٔ ادغامMerge journal

برای هر سه ادغام ثبت کن: Git چه چیزی را خودکار فهمید؟ کدام بخشِ معنا را نمی‌دانست؟ چه تصمیم انسانی نتیجه را تعیین کرد؟ اگر بتوانی جواب‌ها را از روی گراف، ناحیه‌ آماده‌سازی و diff نشان بدهی، پروژه کامل است.

For each of the three integrations, record: What could Git infer automatically? What meaning did it lack? Which human decision determined the result? If you can support your answers with the graph, index, and diff, the project is complete.

merge دو خط تاریخ را نگه می‌دارد؛ قدم بعدی چه می‌شود؟Merge preserves both lines—what comes next?

merge هر دو مسیر تاریخ را نگه می‌دارد و یک نقطهٔ اتصال می‌سازد. فصل بعد راه دیگری را می‌بیند: تغییرهای یک مسیر را دوباره روی پایهٔ تازه می‌سازیم؛ کاری که ظاهر گراف را عوض می‌کند و شناسهٔ commitها را هم تغییر می‌دهد.

You can now distinguish a fast-forward from a merge commit, locate the merge base, and read a conflict as an unresolved decision rather than Git malfunction. A merge joins two lines of history with a multi-parent commit.

فصل ۰۷ سؤال تازه‌ای می‌پرسد: اگر به‌جای وصل‌کردن دو مسیر، commitهای خودمان را روی پایهٔ جدید دوباره اجرا کنیم چه می‌شود؟ جواب، rebase است—و چون commit از والدش شناسه می‌گیرد، شناسهها عوض می‌شوند.

Chapter 07 asks a different question: what if instead of joining two lines, we replay our commits onto a new base? That is rebase—and because a commit’s ID depends on its parent, the IDs change.

نقشهٔ سریع mergeQuick merge reference

اگر این را می‌بینی…If you see…بررسی کن…Check…یادت بماند…Remember…
Already up to dategit log --graph --oneline --decorate --allخطا نیست؛ ورودی احتمالاً از قبل در رابطهٔ والدها هست.Not an error; the input is probably already an ancestor.
Fast-forwardgit rev-parse HEAD topicاشاره‌گر حرکت می‌کند؛ merge commit ساخته نمی‌شود.The ref moves; no merge commit is created.
CONFLICTgit status · git ls-files -uقصد را مشخص کن، بعد فایل را ناحیه‌ آماده‌سازی کن.Determine intent, then stage the result.
حل شد؟Resolved?git diff --cached · git merge --continueخالی‌شدن ناحیه‌ آماده‌سازیها، درستی معنایی را ثابت نمی‌کند.No unmerged stages does not prove semantic correctness.
نمی‌خواهی ادامه بدهیNeed to back out?git merge --abortبازسازی تلاش می‌شود؛ کار dirty قبلی تضمیناً برنمی‌گردد.Reconstruction is attempted; prior dirty work is not guaranteed.
سه جمله برای نگه‌داشتنThree ideas to keep
  • fast-forward فقط اشاره‌گر را جلو می‌برد؛ تاریخچهٔ تازه نمی‌سازد.
  • A fast-forward moves a ref; it creates no new history node.
  • merge commit دو والد دارد و دو مسیر را به هم وصل می‌کند.
  • A merge commit has two parents and joins two lines.
  • تعارض یعنی Git شواهد دارد اما قصد نهایی را نمی‌داند؛ تصمیم و بازبینی با انسان است.
  • A conflict means Git has evidence but lacks intent; a person decides and reviews.