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

شاخه: فقط یک اشاره‌گر

Branches: just movable pointers

اگر شاخه را «یک کپی از پروژه» ببینی، خیلی از رفتارهای Git عجیب می‌شود. این فصل با یک آزمایش ساده نشان می‌دهد شاخه در اصل فقط یک نام سبک است که به یک commit اشاره می‌کند.

“I created a branch, so Git must have copied the whole project.” It is a natural guess, but if true, branching would be expensive. Instead of guessing, let’s inspect the refs before and after a commit.

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

وقتی یک شاخه می‌سازیم، کپی کجاست؟When we create a branch, where is the copy?

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

The previous chapter showed commits as nodes in a graph. In a repository with one commit, we’ll inspect the current branch and create another. Predict first: will a new file appear? Will the commit ID change?

PowerShell · make a disposable repository
mkdir branch-pointer-lab
Set-Location branch-pointer-lab
git init -b main
git config user.name 'Nika Example'
git config user.email 'nika@example.test'
'v1' | Out-File -Encoding utf8 app.txt
git add app.txt
git commit -m "Add first version"
git rev-parse refs/heads/main
git branch experiment
git show-ref --heads
3a91c208ed61424d9fdd16f7998c378b52c04b6c refs/heads/experiment
3a91c208ed61424d9fdd16f7998c378b52c04b6c refs/heads/main

در ویندوز PowerShell این نمونهٔ ساخت فایل کار می‌کند؛ در Bash می‌توانی به‌جایش printf 'v1\n' > app.txt بنویسی. دو شناسهٔ کنار refs/heads/main و refs/heads/experiment باید برابر باشند. هنوز commit تازه‌ای نساخته‌ایم؛ فقط یک نام دیگر برای همان نقطهٔ گراف ساخته شده است.

The file-creation line works in PowerShell; in Bash, use printf 'v1\n' > app.txt instead. The IDs beside refs/heads/main and refs/heads/experiment should match. No commit was created: Git added another name for the same graph position.

مدل پایهThe core model

شاخه یک اشاره‌گر نام‌دار است که commit نوک شاخه را مشخص می‌کند. اشاره‌گر با ساخت شاخه جابه‌جا نمی‌شود؛ فعلاً فقط نام تازه‌ای به همان commit اشاره می‌کند. فایل‌های پروژه از قبل در شیءهای Git هستند؛ شاخه‌سازی آن‌ها را دوباره کپی نمی‌کند.

A branch is a named ref that identifies the tip commit. Creating it does not move the ref; for now, a new name points to the same commit. The project files already live in Git objects—branch creation does not copy them again.

Two branch references point to one commit main experiment commit C1 one snapshot · one object ID
نمودار ۱ — دو اشاره‌گر متفاوت به یک commit می‌رسند؛ هیچ شاخه‌ای کپی جداگانهٔ فایل‌ها نیست.
Diagram 1 — Two distinct refs resolve to one commit; neither branch is a separate copy of the files.

commit بعدی، کدام نام را جلو می‌برد؟Which name moves when we make the next commit?

تا اینجا هر دو شاخه هم‌مکان‌اند. حالا روی experiment می‌رویم و تغییر کوچکی commit می‌کنیم. سؤال دقیق این است: آیا Git شاخهٔ دیگر را هم جلو می‌برد، یا فقط اشاره‌گر شاخهٔ جاری را؟

So far both branches occupy the same point. Switch to experiment and commit a small change. The precise question is: does Git advance both names, or only the ref for the current branch?

PowerShell · move one branch tip
git switch experiment
git symbolic-ref HEAD
'v2 from experiment' | Out-File -Encoding utf8 app.txt
git add app.txt
git commit -m "Try alternate version"
git show-ref --heads
git log --oneline --graph --decorate --all
b7c4e11 (HEAD -> experiment) Try alternate version
3a91c20 (main) Add first version

بعد از switch، خروجی git symbolic-ref HEAD باید refs/heads/experiment باشد. بعد از commit، شناسهٔ آزمایش تغییر می‌کند و main روی C1 می‌ماند. commit جدید C2 فرزند C1 است؛ «جدا شدن شاخه‌ها» یعنی دو اشاره‌گر اکنون نوک‌های متفاوتی از گراف را نام می‌برند.

After switching, git symbolic-ref HEAD should print refs/heads/experiment. After the commit, experiment’s ID changes while main stays at C1. C2 is a child of C1; the branches have diverged in the sense that their refs now name different graph tips.

Experiment advances while main remains at the earlier commit C1shared starting commit C2new experiment commit main → C1 experiment → C2 only the current branch ref advances on commit
نمودار ۲ — مسیر commit ادامه دارد، اما فقط اشاره‌گر شاخهٔ جاری به C2 منتقل می‌شود؛ main هنوز C1 را نام می‌برد.
Diagram 2 — Commit history advances, but only the current branch ref moves to C2; main still names C1.
کارActionچه چیزی تغییر می‌کند؟What changes?چه چیزی خودبه‌خود تغییر نمی‌کند؟What does not change automatically?
git branch experimentاشاره‌گر تازه به commit جاری می‌رسد.A new ref points to the current commit.فایل‌ها و commitها کپی نمی‌شوند.Files and commits are not copied.
git switch experimentHEAD شاخهٔ جاری را عوض می‌کند؛ فایل‌های ردیابی‌شده با مقصد هماهنگ می‌شوند.HEAD changes its current branch; tracked files update to match the target.خود commit یا اشاره‌گرهای شاخه‌های دیگر جابه‌جا نمی‌شوند.The commit and other branch refs do not move.
git commitcommit تازه ساخته و اشاره‌گر شاخهٔ جاری به آن جلو می‌رود.A new commit is created and the current branch ref advances to it.شاخه‌های دیگر روی نوک قبلی می‌مانند.Other branches remain at their previous tips.

اگر HEAD به شاخه اشاره نکند چه؟What if HEAD does not name a branch?

گاهی می‌خواهی یک commit قدیمی را فقط بررسی کنی. git switch --detach <commit> این کار را می‌کند: HEAD مستقیماً به commit می‌رسد. می‌توانی فایل‌ها را ببینی یا حتی commit بسازی؛ اما commit تازه اشاره‌گر شاخه‌ای را جلو نمی‌برد، چون شاخه‌ای انتخاب نشده است.

Sometimes you only want to inspect an older commit. git switch --detach <commit> checks it out with HEAD pointing directly to that commit. You can inspect files or even commit, but no branch ref advances because no branch is selected.

PowerShell · a commit without a branch name
git switch --detach main
git symbolic-ref -q HEAD
git status --short --branch
'temporary probe' | Out-File -Encoding utf8 probe.txt
git add probe.txt
git commit -m "Temporary detached experiment"
git rev-parse HEAD
git switch -c rescue/probe

در حالت جداشده، git symbolic-ref -q HEAD خروجی ندارد و با کد غیرصفر تمام می‌شود؛ اینجا یعنی HEAD symbolic نیست، نه اینکه مخزن خراب شده. فرمان آخر را بلافاصله بعد از commit اجرا کن تا شاخه روی همان commit ساخته شود. اگر قبلاً به شاخهٔ دیگری رفته‌ای، باید شناسهٔ commit را از شواهد مطمئن پیدا کنی و با git branch rescue/probe COMMIT_ID نام‌گذاری‌اش کنی؛ این فصل بازیابی آن شناسه را تضمین نمی‌کند.

In detached state, git symbolic-ref -q HEAD prints nothing and exits non-zero: HEAD is not symbolic, not broken. Run the final command immediately after the commit so the branch starts there. If you already switched away, identify the commit ID from reliable evidence and name it with git branch rescue/probe COMMIT_ID; this chapter does not guarantee recovery of that ID.

commit آزمایشی را بی‌نام رها نکنDo not leave an experimental commit unnamed

اگر از commit جداشده به شاخه‌ای دیگر بروی، ممکن است هیچ شاخه اشاره‌گری به commit آزمایشی اشاره نکند. این به معنی حذف فوری شیء نیست، اما آن را به‌عنوان راه بازیابی تضمین‌شده فرض نکن. اگر ارزش نگه‌داشتن دارد، قبل از switch کردن برایش شاخه بساز. فصل reflog بعداً سرنخ‌های بازیابی را جداگانه بررسی می‌کند.

After switching away from a detached commit, no branch ref may name the experiment. That does not mean the object disappears immediately, but do not treat that as a guaranteed recovery path. If it matters, create a branch before switching away. The reflog chapter will later cover recovery clues separately.

Detached HEAD points to a commit and can be rescued by creating a branch commit C2experimental child detached HEAD branch rescue/probea durable name for C2 git switch -c create the ref before leaving the commit
نمودار ۴ — ابتدا HEAD مستقیماً commit آزمایشی را نام می‌برد؛ ساختن شاخه قبل از ترک آن، یک اشاره‌گر ماندگار برای commit ایجاد می‌کند.
Diagram 4 — HEAD first names the experimental commit directly; creating a branch before leaving gives that commit a durable ref.

ساختن، رفتن، نام‌گذاری و کنارگذاشتن شاخهCreate, switch, rename, and retire branches

وقتی مدل اشاره‌گر روشن شد، فرمان‌ها دیگر فهرستی برای حفظ‌کردن نیستند. هرکدام پاسخی به یک وضعیت‌اند: ساختن نام، انتخاب شاخهٔ کاری، مرتب‌کردن نام‌ها، یا حذف اشاره‌گری که دیگر لازم نیست.

Once the ref model is clear, commands are not a list to memorize. Each answers a situation: create a name, select working branch, tidy a name, or remove an unneeded ref.

نیازNeedفرمانCommandشاهد / محدودیتEvidence / limit
ساختن شاخه بدون رفتن به آنCreate without switchinggit branch feature/nameاشاره‌گر از commit فعلی آغاز می‌شود؛ شاخهٔ کاری عوض نمی‌شود.The ref starts at the current commit; the working branch stays selected.
ساختن و رفتن به شاخهCreate and switchgit switch -c feature/nameاگر switch موفق نشود، شاخه ساخته/تنظیم نمی‌شود.If switching fails, the branch is not created/reset.
دیدن شاخه‌ها / جاریList / current branchgit branch --list
git branch --show-current
ستاره یعنی جاری؛ خروجی دوم نام را جدا می‌دهد.The asterisk marks current; the second command prints its name.
تغییر نام شاخهRename a branchgit branch -m old newنام عوض می‌شود، commitها نه؛ برای شاخهٔ جاری هم کار می‌کند.The name changes, not commits; it also works for the current branch.
حذف امن‌تر اشاره‌گرSafer ref deletiongit branch -d nameاگر commitهای شاخه در upstream یا HEAD ادغام‌نشده باشند، معمولاً رد می‌شود.Usually refuses if the branch is not fully merged into its upstream or HEAD.

-d و -D یکی نیستند: دومی بررسی ادغام‌شدن را نادیده می‌گیرد و اشاره‌گر را به‌زور حذف می‌کند. این کار فایل‌های پروژه را از worktree جاری پاک نمی‌کند؛ اما ممکن است commitهای منحصربه‌فرد دیگر شاخهٔ نام‌داری نداشته باشند. اگر دربارهٔ ارزششان مطمئن نیستی، حذف نکن. -D را فقط در مخزن دورریختنی این فصل آزمایش کن.

-d and -D differ: the latter skips the merged check and force-deletes the ref. It does not remove files from the current worktree, but unique commits may lose their branch name. If unsure whether they matter, keep the branch. Try -D only in this chapter’s disposable repository.

پیش‌نمایش fast-forward؛ merge برای فصل بعدFast-forward preview; merge belongs next

اگر main هنوز C1 باشد و آزمایش روی C2 فرزند آن، از دید گراف main می‌تواند با جلو رفتن مستقیم به C2 برسد؛ به این شکل fast-forward می‌گویند. فعلاً فقط رابطه را از git log --graph --oneline --decorate --all بخوان. فرمان ادغام و حالت‌های دیگر را در فصل ۰۶ باز می‌کنیم.

If main is still at C1 and experiment is at child C2, main could move directly forward to C2—a fast-forward shape. For now, only read the relationship with git log --graph --oneline --decorate --all. Chapter 06 handles the merge operation and its other forms.

وقتی Git اجازهٔ حرکت نمی‌دهد، اول شاهد را بخوانWhen Git refuses a move, read the evidence first

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

A branch error usually does not mean Git is broken; often it is protecting a change or a name. Instead of forcing the operation, identify which condition is not met.

این نام شاخه از قبل هست

That branch name already exists

git branch experiment نام تکراری را overwrite نمی‌کند. با git branch --list و git show-ref --heads ببین اشاره‌گر موجود کجاست؛ نام تازه انتخاب کن یا همان شاخه را آگاهانه switch کن.

git branch experiment will not overwrite an existing name. Inspect with git branch --list and git show-ref --heads; choose a new name or deliberately switch to the existing branch.

تغییر محلی مانع switch شد

Local changes blocked the switch

پیام را بخوان و git status --short بزن. اگر فایل محلی در شاخهٔ مقصد فرق کند، switch ممکن است آن را overwrite کند و Git متوقف می‌شود. تغییر را commit کن یا با روشی آگاهانه نگهش دار؛ --discard-changes راه‌حل معمول نیست.

Read the message and run git status --short. If a local file differs in the target branch, switching could overwrite it, so Git stops. Commit or deliberately preserve the change; --discard-changes is not the routine fix.

حذف با -d رد شد

Deletion with -d was refused

Git می‌گوید اشاره‌گر هنوز commitهایی را نگه می‌دارد که در مرجع ادغام‌شدنش نیستند. این «آزار بی‌دلیل» نیست؛ قبل از حذف، commitها را با گراف مقایسه کن و تصمیم بگیر واقعاً باید نگه‌شان داری یا نه. -D بررسی را دور می‌زند، نه اینکه دادهٔ مهم را بی‌خطر کند.

Git is telling you the ref still protects commits not merged into its merge target. That is useful information. Compare the graph and decide whether those commits matter before deleting. -D bypasses the check; it does not make valuable data safe.

هشدار جداشده HEAD دیدی

You saw a detached HEAD warning

اگر فقط می‌خواهی ببینی، ادامه بده و commit نساز. اگر تغییرت ارزش دارد، قبل از رفتن به شاخهٔ دیگر git switch -c rescue/name بزن. نام شاخه است که مسیر آزمایش را به‌وضوح نگه می‌دارد.

If you only want to inspect, continue without committing. If the work matters, run git switch -c rescue/name before switching elsewhere. The branch name explicitly retains the experiment.

تمرین‌ها: از پیش‌بینی تا تصمیم امنExercises: from prediction to safe decisions

قبل از جواب هر تمرین، گراف را خیلی ساده بکش: اسم شاخه کجاست؟ HEAD به چه چیزی اشاره می‌کند؟ commit بعدی کدام اسم را جلو می‌برد؟ همین سه علامت بیشتر سؤال‌های شاخه را بدون حفظ دستور حل می‌کنند.

Predict first, then test in a disposable repository when useful. Open each solution to compare the reasoning with the result; commit IDs in your repository will differ.

۱۸ تمرین · از مدل اشاره‌گر تا عیب‌یابی گراف18 exercises · from ref model to graph diagnosis
۰۱پیش‌بینی / Predict

روی commit C1 هستی و git branch demo می‌زنی. چند commit ساخته شد و اشاره‌گر تازه به کجا اشاره می‌کند؟

You are at C1 and run git branch demo. How many commits were created, and where does the new ref point?

پاسخ و دلیلAnswer and reasoning

هیچ commitی ساخته نمی‌شود. اشاره‌گر به همان C1 اشاره می‌کند؛ با git show-ref --heads دو نام و شناسهٔ یکسان را می‌بینی.

No commit is created. The ref points to C1; git show-ref --heads shows two names with the same ID.

۰۲خواندن خروجی / Read output

خروجی می‌گوید abc123 refs/heads/main و abc123 refs/heads/test. چه چیزی را ثابت می‌کند و چه چیزی را نه؟

Output shows abc123 refs/heads/main and abc123 refs/heads/test. What does this prove, and what does it not?

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

هر دو اشاره‌گر در همین لحظه به یک commit حل می‌شوند. این ثابت نمی‌کند فایل جداگانه‌ای ساخته شده یا دو نام همیشه با هم حرکت می‌کنند.

Both refs currently resolve to the same commit. It does not prove a separate file copy exists or that the names always move together.

۰۳پیش‌بینی / Predict

روی main دو شاخه هم‌مکان‌اند. به feature switch می‌کنی و commit می‌سازی. کدام شناسه عوض می‌شود؟

main and feature share a tip. You switch to feature and commit. Which ID changes?

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

شناسهٔ اشاره‌گر شاخهٔ قابلیت به commit تازه می‌رود؛ main همان commit قبلی را نگه می‌دارد. commit والد مشترک است.

The feature ref moves to the new commit; main keeps the old commit. Their previous tip is the shared parent.

۰۴انتخاب فرمان / Choose a command

می‌خواهی شاخه‌ای به نام fix/timeout بسازی و همان لحظه روی آن کار کنی. کدام فرمان مستقیم‌تر است؟

You want to create fix/timeout and immediately work on it. Which command is direct?

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

git switch -c fix/timeout هر دو کار را با هم انجام می‌دهد. اگر switch ناموفق باشد، عملیات ایجاد/تنظیم شاخه هم انجام نمی‌شود.

git switch -c fix/timeout does both. If switching fails, the branch is not created or reset.

۰۵تفسیر HEAD / Interpret HEAD

git symbolic-ref HEAD خروجی refs/heads/experiment دارد. دقیقاً چه می‌دانی؟

git symbolic-ref HEAD prints refs/heads/experiment. What exactly do you know?

بررسی جوابPrecise answer

HEAD اکنون symbolic اشاره‌گر است و نام شاخهٔ آزمایش را دنبال می‌کند. برای دانستن commit آن، git rev-parse HEAD را جدا اجرا کن.

HEAD is currently a symbolic ref naming experiment. Run git rev-parse HEAD separately to learn its commit ID.

۰۶تصحیح تصور / Correct a model

هم‌تیمی‌ات می‌گوید «git branch پروژه را دو بار کپی کرد». با یک شاهد CLI پاسخ بده.

A teammate says “git branch copied the project twice.” Give one CLI-based rebuttal.

پاسخ پیشنهادیUseful evidence

git show-ref --heads را قبل و بعد مقایسه کن: اشاره‌گر تازه با همان شناسه‌ شیء commit ظاهر می‌شود و هیچ commit تازه‌ای لازم نیست. این آزمایش اشاره‌گر را نشان می‌دهد، نه مصرف دیسک کل پایگاه اشیای Git را.

Compare git show-ref --heads before and after: a new ref appears with the same commit OID, with no new commit required. This demonstrates refs, not total object-store disk usage.

از اینجا به بعد شاخه را فقط اسم نبین؛ حرکتش را روی گراف دنبال کن. هر commit جدید باید یک سؤال ساده داشته باشد: الان HEAD روی کدام شاخه است و کدام اشاره‌گر قرار است جلو برود؟

From here, do not see a branch as just a name; follow its movement on the graph. For every new commit ask one simple question: which branch does HEAD name, and which pointer will move?

۰۷عیب‌یابی / Diagnose

فرمان git branch demo می‌گوید شاخه از قبل وجود دارد. قدم بعدی چیست؟

git branch demo says the branch already exists. What next?

پاسخ و دلیلNext step

اول git branch --list و git show-ref --heads را ببین تا محل اشاره‌گر روشن شود. اگر همان شاخه مدنظر است، آگاهانه switch کن؛ ایجاد دوباره لازم نیست.

Inspect git branch --list and git show-ref --heads first. If it is the intended branch, switch to it; recreating it is unnecessary.

۰۸علت‌یابی / Diagnose

switch به main به‌خاطر تغییر محلی overwriteپذیر متوقف شد. آیا باید --discard-changes بزنی؟ چرا؟

Switching to main stopped because a local change could be overwritten. Should you use --discard-changes? Why?

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

نه، نه پیش از فهمیدن تغییر. git status --short و پیام خطا مشخص می‌کنند کدام فایل در خطر است. تغییر را commit یا آگاهانه حفظ کن؛ discard ممکن است همان کاری را دور بریزد که قصد نگه‌داشتنش را داشتی.

Not before understanding the change. git status --short and the error identify the at-risk file. Commit or deliberately preserve it; discard may throw away exactly what you meant to keep.

۰۹خواندن ref / Read a ref

چرا git show-ref --heads از بازکردن دستی .git/refs/heads/main بهتر است؟

Why prefer git show-ref --heads over manually opening .git/refs/heads/main?

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

ممکن است اشاره‌گرها بسته‌بندی‌شده باشند و فایل جدا جدا نداشته باشند. فرمان Git فهرست اشاره‌گرهای محلی را از مسیرهای ذخیره‌سازی پشتیبانی‌شده حل می‌کند.

Refs may be packed rather than present as loose files. Git’s command lists local refs regardless of the supported storage form.

۱۰تفسیر / Interpret

در خروجی گراف، main روی C1 و feature روی فرزند C2 است. بدون اجرای merge، چه می‌توانی بگویی؟

In the graph, main names C1 and feature names child C2. What can you say without running a merge?

چرا این جواب درست استScope of the conclusion

گراف شکل fast-forward دارد: main می‌تواند با جابه‌جایی اشاره‌گر به C2 برسد، چون C2 فرزند آن است. این پیش‌بینی شکل گراف است، نه انجام ادغام؛ عملیات در فصل بعد است.

The graph has fast-forward shape: main could move to C2 because it is a descendant. This predicts graph geometry; it does not perform a merge, which comes next.

۱۱پیش‌بینی / Predict

روی main فایل ردیابی‌شده را تغییر داده‌ای ولی commit نکرده‌ای؛ همان فایل در آزمایش محتوای دیگری دارد. چرا switch ممکن است رد شود؟

You changed a tracked file on main without committing; experiment has different content at that path. Why might switching be refused?

بررسی جوابAnswer

به‌روزرسانی worktree ممکن است تغییر محلی را overwrite کند. Git معمولاً برای حفظ آن متوقف می‌شود. پیام و وضعیت را بخوان؛ شاخه اشاره‌گر عوض نشده چون switch کامل نشده است.

Updating the worktree could overwrite the local change, so Git stops to preserve it. Read the message and status; the branch ref was not switched because the operation did not complete.

۱۲انتخاب روش / Choose a method

فقط می‌خواهی محتوای commit قدیمی را بخوانی و تغییرت لازم نیست بماند. کدام روش مناسب است؟

You only want to inspect an old commit and do not need to keep changes. Which approach fits?

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

git switch --detach COMMIT برای بررسی commit بدون ساخت شاخه است. اگر آزمایش را commit کردی و خواستی حفظش کنی، قبل از خروج شاخه بساز.

git switch --detach COMMIT inspects a commit without creating a branch. If you commit an experiment and want to keep it, create a branch before leaving.

تمرین‌های آخر detached HEAD و حذف شاخه را وارد می‌کنند. اینجا عجله با گزینه‌های اجباری خطرناک است. اول ببین commit هنوز از چه نامی قابل دسترسی است، بعد تصمیم بگیر.

The final exercises introduce detached HEAD and branch deletion. Force options are risky here. First determine which name still reaches the commit, then decide what to do.

۱۳تفسیر وضعیت / Interpret status

در جداشده HEAD، git symbolic-ref -q HEAD ساکت و non-zero تمام می‌شود. آیا این خطای مخزن است؟

In detached HEAD, git symbolic-ref -q HEAD is silent and exits non-zero. Is the repository broken?

پاسخ و دلیلInterpret the result

نه. این یعنی HEAD symbolic اشاره‌گر نیست و مستقیماً commit را نام می‌برد. برای تشخیص حالت کلی git status --short --branch را هم ببین.

No. HEAD is not a symbolic ref and names a commit directly. Also inspect git status --short --branch for the broader state.

۱۴نجات commit / Preserve a commit

در جداشده حالت commit ارزشمندی ساختی و هنوز جایی نرفته‌ای. کوتاه‌ترین راه حفظش چیست؟

You made a valuable detached commit and have not switched away. What is the shortest way to preserve it?

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

git switch -c rescue/my-work یک شاخه از commit فعلی می‌سازد و هم‌زمان روی آن می‌رود. بعد git show-ref --heads را بررسی کن تا نام تازه را ببینی.

git switch -c rescue/my-work creates a branch at the current commit and switches to it. Verify the new name with git show-ref --heads.

۱۵ارزیابی ریسک / Assess risk

حذف feature با git branch -d feature رد شد. آیا -D فقط فایل‌های شاخه را پاک می‌کند؟

Deleting feature with git branch -d feature was refused. Does -D merely remove that branch’s files?

راه‌حل و توضیحWhy pause?

-D اشاره‌گر را بدون بررسی ادغام حذف می‌کند. این حذف، پاک‌کردن فایل‌های worktree نیست؛ خطرش این است که commitهای یکتا دیگر نام شاخه نداشته باشند. ابتدا گراف و ارزش commitها را بررسی کن.

-D removes the ref without the merged check. It does not delete worktree files; the risk is that unique commits lose their branch name. Inspect the graph and decide whether those commits matter first.

۱۶سناریو / Scenario

دو شاخه یک commit مشترک دارند. dev روی A commit می‌سازد؛ هم‌زمان اشاره‌گر شاخهٔ B هم جلو می‌رود. آیا این رفتار طبیعی است؟

Two branches share a commit. dev commits on A, and B’s ref advances too. Is that expected?

چرا این جواب درست استWhat to check

در مدل معمول، خیر. ببین واقعاً روی کدام شاخه بوده‌ای: git branch --show-current و git symbolic-ref HEAD؛ سپس شناسه‌ شیءها را با show-ref مقایسه کن. شاید B عمداً reset/force-update شده یا اسکریپتی اشاره‌گر را تغییر داده باشد.

Not in the normal model. Check the selected branch with git branch --show-current and git symbolic-ref HEAD, then compare OIDs with show-ref. B may have been deliberately reset/force-updated, or a script may have changed it.

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

توسعه‌دهنده می‌گوید commit کرده، اما نام شاخه‌اش جلو نرفته. git status حالت جداشده نشان می‌دهد. علت محتمل و قدم امن بعدی؟

A developer committed, but their branch name did not move. git status says detached. Likely cause and safe next step?

بررسی جوابAnalysis

commit در حالی ساخته شده که HEAD به شاخه اشاره نمی‌کرد، پس شاخه اشاره‌گری جلو نرفته. اگر هنوز روی commit هست، git switch -c rescue/committed-work بزن؛ اگر جابه‌جا شده، commit شناسه را از شواهد موجود مشخص کن و اشاره‌گر بساز. این فصل بازیابی از reflog را تضمین نمی‌کند.

The commit was made while HEAD named no branch, so no branch ref advanced. If still there, run git switch -c rescue/committed-work; if you moved away, identify the commit ID from available evidence and create a ref. This chapter does not promise reflog recovery.

۱۸تصمیم تیمی / Team decision

تیمی شاخهٔ کوتاه‌عمر قابلیت را بعد از بررسی می‌خواهد کنار بگذارد، اما مطمئن نیست ادغام شده یا نه. چه شواهدی قبل از حذف می‌خواهی؟

A team wants to retire a short-lived feature branch but is unsure whether it was integrated. What evidence do you want before deletion?

پاسخ پیشنهادیPre-deletion check

گراف همهٔ شاخه‌ها را با git log --graph --oneline --decorate --all ببین و وضعیت ادغام‌شدن را با git branch --merged main مقایسه کن. سپس تصمیم بگیر. اگر مطمئن نیستی، اشاره‌گر را نگه دار؛ -D فقط پیام هشدار را دور می‌زند.

Inspect all tips with git log --graph --oneline --decorate --all and compare merged status using git branch --merged main. Decide afterward. If uncertain, keep the ref; -D only bypasses the warning.

پروژهٔ کوچک: آزمایش موازی بدون کپی پوشهMini-project: parallel experiments without copying a folder

اینجا می‌خواهیم چیزی را که خیلی‌ها با کپی پوشه انجام می‌دهند، با شاخه انجام دهیم: دو آزمایش موازی، یک تاریخچهٔ مشترک، بدون دو نسخهٔ مبهم از پروژه. در پایان باید بتوانی از روی گراف نشان بدهی هر آزمایش کجا جدا شد و کدام را نگه داشتی.

A team needs to compare two implementations of a function. It should not duplicate the folder or jump into merging before learning it. Create two paths from one starting point, document the graph, retire one experiment only in a disposable repo, and retain the other.

  1. نقطهٔ مشترک بسازCreate a shared starting point

    در پوشهٔ جدا، git init -b main اجرا کن و یک فایل choice.txt با مقدار baseline commit کن. شناسه‌ شیء را یادداشت کن.

    In a separate folder, run git init -b main and commit choice.txt with value baseline. Record its OID.

  2. راه A را آزمایش کنTry approach A

    با git switch -c experiment/a شاخه بساز، فایل را به approach A تغییر بده و commit کن. سپس git show-ref --heads را ثبت کن.

    Create experiment/a with git switch -c experiment/a, change the file to approach A, and commit. Record git show-ref --heads.

  3. از main، راه B را بسازStart approach B from main

    به main برگرد و experiment/b را از همان نقطه بساز. مقدار approach B را commit کن. این دو راه باید والد مشترک و نوک متفاوت داشته باشند.

    Return to main and create experiment/b from that same point. Commit approach B. The two paths should share a parent and have distinct tips.

  4. گراف را بخوان و تصمیم را ثبت کنRead the graph and record a decision

    با git log --graph --oneline --decorate --all و git branch --show-current ثابت کن هر دو آزمایش از کجا آغاز شدند و اکنون کدام فعال است. توضیح بده این گراف هنوز merge نشده است.

    Use git log --graph --oneline --decorate --all and git branch --show-current to prove the common start and current branch. State that the graph has not been merged.

  5. A را آگاهانه کنار بگذار، B را نگه دارRetire A deliberately; keep B

    ابتدا شناسه‌ شیء آخرین commit A را ثبت و با git show OID بررسی کن. بعد، فقط چون این مخزن دورریختنی است، git branch -D experiment/a را اجرا کن. با show-ref ثابت کن B باقی است و در گزارش بنویس حذف اشاره‌گر، commit را به‌عنوان شاخه نگه نمی‌دارد؛ روی دادهٔ کاری واقعی این کار را تکرار نکن.

    Record A’s tip OID and inspect it with git show OID. Only because this repository is disposable, run git branch -D experiment/a. Prove B remains with show-ref, and note that deleting the ref no longer retains that commit as a branch; do not repeat this casually on real work.

راهنمایی: اگر دو آزمایش از هم جدا نشدندHint: if the experiments did not diverge

به جای ساخت B از شاخهٔ A، اول به main برگرد. شناسه‌ شیء والد هر دو را با git rev-parse و نمودار گراف کنترل کن.

Return to main before creating B rather than branching B from A. Compare parent OIDs with git rev-parse and inspect the graph.

چه چیزی را باید تحویل بدهی؟What to hand in

یک تصویر/خروجی از گراف قبل از حذف، شناسه‌ شیءهای main و A و B، دلیل انتخاب راه B، و خروجی اشاره‌گرها بعد از کنارگذاشتن A. پروژه وقتی کامل است که بتوانی تفاوت «شاخهٔ دیگر را انتخاب کردم» و «commit جدید ساختم» را با همین شواهد توضیح بدهی.

Submit the graph before deletion, OIDs for main/A/B, why you chose B, and refs after retiring A. The project is complete when you can use that evidence to distinguish switching branches from creating a commit.

دو مسیر ساخته شد؛ حالا چطور دوباره به هم می‌رسند؟Two paths exist—how do they come together?

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

You now know why a branch is not a project copy, why commits advance only the current branch ref, and why HEAD can be detached. The team’s next question remains: how do we bring a good change back, and what if two people changed the same area?

فصل بعد سراغ merge می‌رویم: fast-forward را واقعاً اجرا می‌کنیم، merge commit را از گراف می‌خوانیم و تعارض را به‌عنوان نتیجهٔ طبیعی دو مسیر بررسی می‌کنیم—نه نشانهٔ خراب‌شدن Git.

Next, we will actually merge: perform a fast-forward, read a merge commit in the graph, and treat conflicts as a natural result of two lines of work—not evidence that Git is broken.

نقشهٔ سریع شاخه‌هاQuick branch reference

اگر می‌خواهی…If you want to…شروع کن باStart withقبل از نتیجه‌گیری یادت باشدBefore concluding, remember
اشاره‌گرها را ببینیList refsgit show-ref --headsشناسه‌ شیء یک شناسهٔ شیء است؛ نام اشاره‌گر جای خود را دارد.An OID identifies an object; the ref name is separate.
شاخهٔ جاری را بفهمیIdentify current branchgit branch --show-current
git symbolic-ref HEAD
خروجی symbolic-ref در جداشده خالی/non-zero است.symbolic-ref is empty/non-zero when detached.
گراف شاخه‌ها را ببینیSee branch graphgit log --graph --oneline --decorate --allاین نمایش است؛ گراف را تغییر نمی‌دهد.This is a view; it does not change the graph.
یک commit را حفظ کنیRetain a commitgit switch -c rescue/nameدر جداشده، نام شاخه را قبل از ترک commit بساز.In detached state, create the branch before leaving the commit.