رفتن به محتوا
LoopX

branch و merge

توی این درس یاد می‌گیری روی ویژگی‌های جدید کار کنی بدون اینکه شاخه‌ی اصلی (main) را خراب کنی. می‌فهمی branch (شاخه) در Git فقط یک برچسب سبک روی یک commit است (برای همین ساختنش آنی است)، با git branch و git switch -c شاخه می‌سازی و جابه‌جا می‌شوی، با git merge کارت را به main برمی‌گردانی (دو حالت: fast-forward و three-way merge) و با git branch -d شاخه‌ی تمام‌شده را پاک می‌کنی. تمرین: یک ویژگی را در branch جدا بساز و merge کن.

مسئله: کار نیمه‌تمام و پروژه‌ی سالم

Section titled “مسئله: کار نیمه‌تمام و پروژه‌ی سالم”

تو در حال ساختن یک ویژگی بزرگ هستی (مثلاً جستجو). چند روز طول می‌کشد و وسطش پروژه کار نمی‌کند. ولی همین الان یک همکار باید یک باگ فوری را در main درست کند و سایت باید سالم بماند. اگر همه روی یک خط تاریخچه کار کنند، یا کار نیمه‌تمام تو سایت را خراب می‌کند یا باگ منتظر می‌ماند. راه‌حل: هر کار یک خط جدا. وقتی تمام شد، آن را به خط اصلی ادغام (merge) می‌کنی.

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

بیشتر ابزارها برای شاخه، پوشه را کپی می‌کنند و کند هستند. در Git شاخه فقط یک اشاره‌گر به یک commit (یک فایل ۴۱ بایتی) است. ساختن شاخه یعنی نوشتن یک فایل کوچک؛ پس آنی است و بی‌هزینه. HEAD هم می‌گوید «الآن روی کدام شاخه هستم».

دو شاخه از یک commit مشترک (C2) جدا شده‌اند. main و feature فقط دو برچسب‌اند؛ commit ها همه در یک مخزن‌اند. HEAD روی main است، یعنی commit بعدی به main اضافه می‌شود.

یک پروژه‌ی کوچک «وب‌سایت» با دو commit اولیه روی main:

Terminal window
mkdir -p ~/gitlab/site && cd ~/gitlab/site && git init -q
echo "<h1>Home</h1>" > index.html
git add index.html && git commit -qm "Add homepage"
echo "<p>About us</p>" > about.html
git add about.html && git commit -qm "Add about page"
git log --oneline
خروجی
2d0f343 Add about page
1433671 Add homepage

مثال ۱: شاخه‌ها را ببین

Section titled “مثال ۱: شاخه‌ها را ببین”
Terminal window
cd ~/gitlab/site
echo "--- git branch (ستاره = شاخه‌ی فعلی):"
git branch
echo "--- با commit آخر هر شاخه (-v):"
git branch -v
echo "--- شاخه‌ی فعلی را همین‌جا هم می‌گوید:"
git status | head -1
echo "--- HEAD و برچسب شاخه، فقط دو فایل متنی کوچک‌اند:"
cat .git/HEAD
cat .git/refs/heads/main
خروجی
--- git branch (ستاره = شاخه‌ی فعلی):
* main
--- با commit آخر هر شاخه (-v):
* main 2d0f343 Add about page
--- شاخه‌ی فعلی را همین‌جا هم می‌گوید:
On branch main
--- HEAD و برچسب شاخه، فقط دو فایل متنی کوچک‌اند:
ref: refs/heads/main
2d0f343a29fe455cd77a441116d1279a1685bf11

HEAD یک «اشاره‌گر به اشاره‌گر» است: به refs/heads/main اشاره می‌کند و آن فایل هش یک commit را دارد. (در «پشت پرده» برمی‌گردیم.)

مثال ۲: ساختن و جابه‌جایی، git switch -c

Section titled “مثال ۲: ساختن و جابه‌جایی، git switch -c”

برای ویژگی جدید یک شاخه می‌سازم و همان لحظه به آن می‌روم (-c = create). در آن commit می‌زنم و بعد به main برمی‌گردم و می‌بینم فایل‌های پوشه واقعاً عوض می‌شوند:

Terminal window
cd ~/gitlab/site
git switch -c feature/search
echo "<form>search</form>" > search.html
git add search.html && git commit -qm "Add search page"
echo "--- روی feature/search فایل‌ها:"
ls
git switch main
echo "--- بعد از برگشتن به main (search.html رفت!):"
ls
git switch feature/search
echo "--- دوباره برگشتم به feature (search.html برگشت):"
ls
git switch -q main
خروجی
Switched to a new branch 'feature/search'
--- روی feature/search فایل‌ها:
about.html
index.html
search.html
Switched to branch 'main'
--- بعد از برگشتن به main (search.html رفت!):
about.html
index.html
Switched to branch 'feature/search'
--- دوباره برگشتم به feature (search.html برگشت):
about.html
index.html
search.html

جادو نیست: git switch پوشه‌ی کاری را مطابق commit آن شاخه می‌کند. فایل‌های شاخه‌ی دیگر در .git امن‌اند. (قبل از Git ۲.۲۳ همین کار git checkout شاخه بود؛ switch فقط برای شاخه است و گیج‌کننده نیست. دستور git branch نام فقط شاخه می‌سازد بدون رفتن به آن.)

مثال ۳: ادغام ساده، fast-forward

Section titled “مثال ۳: ادغام ساده، fast-forward”

main از زمان جداشدن شاخه، commit جدید ندارد. پس ادغام فقط یعنی «برچسب main را جلو ببر تا به آخر شاخه برسد». Git این را fast-forward می‌نامد و commit جدیدی نمی‌سازد:

Terminal window
cd ~/gitlab/site
git switch -q main
git log --oneline --graph --all
echo "--- merge:"
git merge feature/search
echo "--- بعد از merge:"
git log --oneline --graph --all
خروجی
* c27aadf Add search page
* 2d0f343 Add about page
* 1433671 Add homepage
--- merge:
Updating 2d0f343..c27aadf
Fast-forward
search.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 search.html
--- بعد از merge:
* c27aadf Add search page
* 2d0f343 Add about page
* 1433671 Add homepage

Fast-forward: تاریخچه خطی ماند؛ بدون commit ادغام. حالا main و feature/search به یک commit اشاره می‌کنند.

مثال ۴: ادغام واقعی، three-way merge

Section titled “مثال ۴: ادغام واقعی، three-way merge”

وقتی هر دو شاخه از جداشدن، commit جدید گرفته‌اند، fast-forward ممکن نیست (باید دو خط را به هم وصل کرد). Git یک commit ادغام با دو والد می‌سازد. به آن «سه‌طرفه» می‌گویند چون Git سه commit را مقایسه می‌کند: آخر هر شاخه و جدّ مشترکشان. این بار دو تغییر نامرتبط در دو شاخه می‌دهم:

Terminal window
cd ~/gitlab/site
git switch -qc feature/contact
echo "<p>Contact: 021</p>" > contact.html
git add contact.html && git commit -qm "Add contact page"
git switch -q main
echo "<footer>2026</footer>" > footer.html
git add footer.html && git commit -qm "Add footer"
echo "--- قبل از merge (دو خط جدا):"
git log --oneline --graph --all
git merge --no-edit feature/contact
echo "--- بعد از merge:"
git log --oneline --graph --all
خروجی
--- قبل از merge (دو خط جدا):
* c08164d Add contact page
| * cbbbe95 Add footer
|/
* c27aadf Add search page
* 2d0f343 Add about page
* 1433671 Add homepage
Merge made by the 'ort' strategy.
contact.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 contact.html
--- بعد از merge:
* 64ab011 Merge branch 'feature/contact'
|\
| * c08164d Add contact page
* | cbbbe95 Add footer
|/
* c27aadf Add search page
* 2d0f343 Add about page
* 1433671 Add homepage
بعد از three-way merge: commit M دو والد دارد (آخر main و آخر feature). تاریخچه هر دو شاخه همان‌طور که اتفاق افتاد حفظ می‌شود.

هر دو تغییر (footer و contact) در main هستند و یک commit ادغام ساخته شد (--no-edit یعنی «پیام پیش‌فرض را همان‌طور نگه دار»؛ بدون آن ویرایشگر باز می‌شد). اگر دو شاخه یک خط را عوض کرده بودند، Git نمی‌دانست کدام را نگه دارد و conflict می‌داد؛ درس بعد.

مثال ۵: --no-ff، حفظ شکل شاخه

Section titled “مثال ۵: --no-ff، حفظ شکل شاخه”

اگر ادغام fast-forward باشد، بعداً در تاریخچه معلوم نیست آن چند commit یک «ویژگی» بودند. با --no-ff (no fast-forward) Git حتی در حالت ساده هم یک commit ادغام می‌سازد تا شاخه دیده شود:

Terminal window
cd ~/gitlab/site
git switch -qc feature/faq
echo "faq" > faq.html && git add faq.html && git commit -qm "Add FAQ page"
echo "faq 2" >> faq.html && git commit -qam "Extend FAQ"
git switch -q main
echo "--- با --no-ff (commit ادغام ساخته می‌شود، با اینکه fast-forward ممکن بود):"
git merge --no-ff --no-edit feature/faq
git log --oneline --graph -6
خروجی
--- با --no-ff (commit ادغام ساخته می‌شود، با اینکه fast-forward ممکن بود):
Merge made by the 'ort' strategy.
faq.html | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 faq.html
* c79fb1c Merge branch 'feature/faq'
|\
| * 7641d6c Extend FAQ
| * 1980381 Add FAQ page
|/
* 64ab011 Merge branch 'feature/contact'
|\
| * c08164d Add contact page
* | cbbbe95 Add footer
|/

بعضی تیم‌ها همیشه --no-ff را می‌خواهند تا «این ویژگی از کجا تا کجا بود» در گراف پیدا باشد؛ بعضی دیگر تاریخچه‌ی خطی را ترجیح می‌دهند (با rebase یا squash، درس‌های بعد). هر دو درست‌اند؛ مهم این است که تیم یکی را انتخاب کند.

مثال ۶: پاک‌کردن شاخه‌ی تمام‌شده

Section titled “مثال ۶: پاک‌کردن شاخه‌ی تمام‌شده”

بعد از ادغام، شاخه کارش را کرده. حذفش فقط برچسب را پاک می‌کند، نه commit ها را:

Terminal window
cd ~/gitlab/site
echo "--- شاخه‌هایی که کامل ادغام شده‌اند (--merged):"
git branch --merged
git branch -d feature/search feature/contact feature/faq
echo "--- باقی‌مانده:"
git branch
خروجی
--- شاخه‌هایی که کامل ادغام شده‌اند (--merged):
feature/contact
feature/faq
feature/search
* main
Deleted branch feature/search (was c27aadf).
Deleted branch feature/contact (was c08164d).
Deleted branch feature/faq (was 7641d6c).
--- باقی‌مانده:
* main

-d (کوچک) امن است: فقط وقتی پاک می‌کند که شاخه ادغام شده باشد. اگر ادغام نشده باشد، Git جلویت را می‌گیرد، چون commit های آن شاخه با حذف برچسب از دسترس خارج می‌شوند:

Terminal window
cd ~/gitlab/site
git switch -qc experiment
echo "idea" > idea.txt && git add idea.txt && git commit -qm "Try an idea"
git switch -q main
echo "--- حذف شاخه‌ی ادغام‌نشده با -d:"
git branch -d experiment
echo "--- شاخه‌هایی که هنوز ادغام نشده‌اند (--no-merged):"
git branch --no-merged
خروجی
--- حذف شاخه‌ی ادغام‌نشده با -d:
error: the branch 'experiment' is not fully merged.
If you are sure you want to delete it, run 'git branch -D experiment'
--- شاخه‌هایی که هنوز ادغام نشده‌اند (--no-merged):
experiment

پیام not fully merged یعنی «کار این شاخه جای دیگری نیست». اگر مطمئنی آن را نمی‌خواهی، git branch -D experiment (حرف بزرگ) اجباری پاک می‌کند. (و اگر اشتباه کردی، reflog راه برگشت دارد: درس نجات.) یک نمایش عمومی‌تر: git branch -vv شاخه‌ها را با commit و شاخه‌ی راه دور نشان می‌دهد.

Terminal window
cd ~/gitlab/site
git switch -qc old-name
git branch -m new-name
git branch
git switch -q main
git branch -D new-name
خروجی
experiment
main
* new-name
Deleted branch new-name (was c79fb1c).

git branch -m نام-جدید شاخه‌ی فعلی را تغییر نام می‌دهد؛ git branch -m قدیم جدید هر شاخه‌ای را. (همین‌طور مخزن‌های قدیمی master را به main درمی‌آورند: git branch -m master main.) یک قرارداد نام‌گذاری رایج:

پیشوند کاربرد نمونه
feature/ ویژگی جدید feature/search
fix/ یا bugfix/ رفع باگ fix/cart-total
hotfix/ رفع باگ فوری روی نسخه‌ی منتشرشده hotfix/login-crash
docs/ مستندات docs/readme-update
chore/ یا refactor/ کار فنی بدون تغییر رفتار chore/update-deps

مثال ۸: وقتی تغییر commit نشده داری و شاخه عوض می‌کنی

Section titled “مثال ۸: وقتی تغییر commit نشده داری و شاخه عوض می‌کنی”

اگر تغییر commit نشده داشته باشی، Git آن را با خودت می‌برد، مگر اینکه با فایل‌های شاخه‌ی مقصد تداخل کند:

Terminal window
cd ~/gitlab/site
git switch -qc other
echo "<h1>Home on other</h1>" > index.html
git commit -qam "Change home on other"
git switch -q main
echo "--- در main فایل index.html را (commit نکرده) ویرایش می‌کنم:"
echo "<h1>Home draft</h1>" > index.html
git switch other 2>&1
echo "--- در همین حال، یک فایل جدید (بدون تداخل) همراهم می‌آید:"
git restore index.html
echo "note" > note.txt
git switch other 2>&1
git status -s
git switch -q main && rm note.txt && git branch -D other -q
خروجی
--- در main فایل index.html را (commit نکرده) ویرایش می‌کنم:
error: Your local changes to the following files would be overwritten by checkout:
index.html
Please commit your changes or stash them before you switch branches.
Aborting
--- در همین حال، یک فایل جدید (بدون تداخل) همراهم می‌آید:
Switched to branch 'other'
?? note.txt

بار اول، چون index.html در دو شاخه فرق دارد و تغییر commit نشده‌ات روی آن است، Git جابه‌جایی را رد کرد تا کارت پاک نشود (Your local changes ... would be overwritten). بار دوم، فایل note.txt به هیچ فایل شاخه‌ی دیگر مربوط نبود و با تو آمد. راه‌حل‌ها: commit کن، یا git stash (درس بعد‌تر) تا موقتاً کنار بگذاری.

پشت پرده: برچسب‌ها و والدها

Section titled “پشت پرده: برچسب‌ها و والدها”

شاخه‌ها فایل‌های ساده‌اند و commit ادغام فقط یک commit با دو والد:

Terminal window
cd ~/gitlab/site
echo "--- شاخه‌ها فایل‌هایی با یک هش هستند:"
ls .git/refs/heads
cat .git/HEAD
echo "--- یک شاخه‌ی تازه فقط یک فایل جدید است:"
git branch demo
cat .git/refs/heads/demo
git rev-parse main
git branch -D demo -q
echo "--- commit ادغام دو والد (parent) دارد:"
git log --merges --oneline | head -1
git cat-file -p $(git log --merges --format=%h -1) | head -5
خروجی
--- شاخه‌ها فایل‌هایی با یک هش هستند:
experiment
main
ref: refs/heads/main
--- یک شاخه‌ی تازه فقط یک فایل جدید است:
c79fb1c04cf712d614f3c8f10bece3877f31258e
c79fb1c04cf712d614f3c8f10bece3877f31258e
--- commit ادغام دو والد (parent) دارد:
c79fb1c Merge branch 'feature/faq'
tree 7ad72379df66380d495dce08633e0669dd41401d
parent 64ab011f8f91b97e849f9450152d7cbce60fb440
parent 7641d6cc0220b1db80e1315acfa5051ffcd4744e
author Ali <ali@example.com> 1791102177 +0000
committer Ali <ali@example.com> 1791102177 +0000

دو خط parent یعنی «این commit از ادغام دو خط ساخته شد». برای همین git log --graph می‌تواند دو خط را رسم کند. و git merge در حالت fast-forward فقط فایل برچسب را عوض می‌کند و چیزی نمی‌سازد. (بعد از ساخت شاخه‌ی demo هر دو برچسب به یک commit اشاره می‌کردند و هش یکسان چاپ شد.)

دستور کار
git branch / git branch -v فهرست شاخه‌ها / با commit آخر
git branch نام ساخت شاخه (بدون رفتن به آن)
git switch نام رفتن به شاخه
git switch -c نام ساخت و رفتن
git switch - برگشت به شاخه‌ی قبلی
git merge نام ادغام آن شاخه در شاخه‌ی فعلی
git merge --no-ff نام همیشه commit ادغام بساز
git branch -d نام حذف امن (فقط ادغام‌شده)
git branch -D نام حذف اجباری ⚠
git branch -m قدیم جدید تغییر نام
git branch --merged / --no-merged شاخه‌های ادغام‌شده / نشده
git log --oneline --graph --all گراف همه‌ی شاخه‌ها
نوع ادغام چه زمانی نتیجه
fast-forward شاخه‌ی مقصد بعد از جداشدن commit جدید ندارد فقط برچسب جلو می‌رود؛ commit جدید ندارد؛ تاریخچه خطی
three-way هر دو شاخه commit جدید دارند یک commit ادغام با دو والد
--no-ff همیشه commit ادغام حتی اگر fast-forward ممکن باشد

۱) commit روی main به‌جای شاخه‌ی ویژگی

Section titled “۱) commit روی main به‌جای شاخه‌ی ویژگی”

خیلی رایج است: یادت می‌رود شاخه بسازی و دو commit روی main می‌زنی. تاریخچه را بدون از دست‌دادن کار این‌طور درست کن: یک شاخه از همین‌جا بساز (commit ها را نگه می‌دارد)، و main را به عقب ببر:

Terminal window
mkdir -p ~/gitlab/oops && cd ~/gitlab/oops && git init -q
echo 1 > a && git add a && git commit -qm "Base"
echo 2 > b && git add b && git commit -qm "Feature work 1 (on main by mistake)"
echo 3 > c && git add c && git commit -qm "Feature work 2 (on main by mistake)"
echo "--- main حالا دو commit اضافه دارد:"
git log --oneline
git branch feature
git reset -q --hard HEAD~2
echo "--- بعد: main سالم، کار روی feature:"
git log --oneline
git log --oneline feature
خروجی
--- main حالا دو commit اضافه دارد:
a3726de Feature work 2 (on main by mistake)
5b3e801 Feature work 1 (on main by mistake)
5afbcd9 Base
--- بعد: main سالم، کار روی feature:
5afbcd9 Base
a3726de Feature work 2 (on main by mistake)
5b3e801 Feature work 1 (on main by mistake)
5afbcd9 Base

git branch feature یک برچسب روی همین commit می‌گذارد؛ بعد reset --hard HEAD~2 فقط برچسب main را عقب می‌برد و commit ها با برچسب feature در امان می‌مانند. (این reset فقط چون هیچ‌چیز push نشده امن است؛ درس قبل.)

-D شاخه‌ی ادغام‌نشده را بی‌پرسش پاک می‌کند و commit هایش را بی‌صاحب می‌گذارد. راه‌حل: -d را بزن؛ اگر شکایت کرد، فکر کن. و اگر پاک شد: git reflog هش آخر آن شاخه را پیدا می‌کند و git branch نام هش برش می‌گرداند.

git merge feature را باید از داخل main بزنی تا feature وارد main شود. اگر روی feature باشی و git merge main بزنی، main وارد feature می‌شود (که گاهی مطلوب است: گرفتن تغییرهای تازه‌ی main). قبل از merge همیشه git status یا git branch را نگاه کن که روی کدام شاخه‌ای.

اگر به‌جای شاخه، به یک commit بروی (git switch --detach commit یا git checkout هش)، HEAD دیگر روی هیچ شاخه‌ای نیست:

Terminal window
cd ~/gitlab/oops
git switch --detach feature~1 2>&1 | head -6
echo "--- شاخه‌ی فعلی؟"
git branch --show-current; echo "(خالی: روی هیچ شاخه‌ای نیستی)"
git status | head -1
echo "--- روی detached یک commit می‌زنم:"
echo "new" > lost.txt && git add lost.txt && git commit -qm "Commit on detached HEAD"
git log --oneline -2
echo "--- با رفتن به main این commit بی‌صاحب می‌شود؛ پس همین‌جا یک شاخه می‌سازم:"
git switch -c rescue 2>&1
git switch -q main
git log --oneline rescue -2
خروجی
HEAD is now at 5b3e801 Feature work 1 (on main by mistake)
--- شاخه‌ی فعلی؟
(خالی: روی هیچ شاخه‌ای نیستی)
HEAD detached at 5b3e801
--- روی detached یک commit می‌زنم:
3b49425 Commit on detached HEAD
5b3e801 Feature work 1 (on main by mistake)
--- با رفتن به main این commit بی‌صاحب می‌شود؛ پس همین‌جا یک شاخه می‌سازم:
Switched to a new branch 'rescue'
3b49425 Commit on detached HEAD
5b3e801 Feature work 1 (on main by mistake)

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

✎ تمرینآسان

یک شاخه‌ی feature/x بساز، در آن یک commit بزن، به main برگرد و ثابت کن فایل آن commit در main نیست.

دیدن جواب
Terminal window
mkdir -p ~/gitlab/ex1 && cd ~/gitlab/ex1 && git init -q
echo base > base.txt && git add base.txt && git commit -qm "Base"
git switch -qc feature/x
echo x > x.txt && git add x.txt && git commit -qm "Add x"
git switch -q main
ls
git log --oneline --all
خروجی
base.txt
755cabd Add x
2294e3b Base
✎ تمرینمتوسط

تمرین اصلی: یک ویژگی را در branch جدا بساز و merge کن. روی main یک فایل app.py با یک تابع بنویس؛ شاخه‌ی feature/greet را بساز و تابع greet را اضافه کن؛ به main برگرد و آن را ادغام کن (چه نوعی؟)، بعد شاخه را پاک کن و گراف را ببین.

دیدن جواب
Terminal window
mkdir -p ~/gitlab/ex2 && cd ~/gitlab/ex2 && git init -q
printf 'def main():\n pass\n' > app.py
git add app.py && git commit -qm "Add app skeleton"
git switch -qc feature/greet
printf '\ndef greet(name):\n return f"Hello {name}"\n' >> app.py
git commit -qam "Add greet function"
git switch -q main
git merge feature/greet
git branch -d feature/greet
git log --oneline --graph --all
cat app.py
خروجی
Updating df1c6a0..4292058
Fast-forward
app.py | 3 +++
1 file changed, 3 insertions(+)
Deleted branch feature/greet (was 4292058).
* 4292058 Add greet function
* df1c6a0 Add app skeleton
def main():
pass
def greet(name):
return f"Hello {name}"

چون main بعد از جداشدن commit جدیدی نداشت، ادغام fast-forward بود.

✎ تمرینسخت

دو ویژگی را موازی در دو شاخه بساز (feature/a و feature/b، هر کدام یک فایل مختلف)، هر دو را به main ادغام کن (اولی fast-forward و دومی three-way)، و در گراف ثابت کن یک commit ادغام با دو والد ساخته شد.

دیدن جواب
Terminal window
mkdir -p ~/gitlab/ex3 && cd ~/gitlab/ex3 && git init -q
echo base > base.txt && git add base.txt && git commit -qm "Base"
git switch -qc feature/a && echo a > a.txt && git add a.txt && git commit -qm "Add a"
git switch -q main
git switch -qc feature/b && echo b > b.txt && git add b.txt && git commit -qm "Add b"
git switch -q main
echo "--- ادغام اول (fast-forward):"
git merge feature/a | head -2
echo "--- ادغام دوم (main حالا جلوتر است، پس three-way):"
git merge --no-edit feature/b | head -2
git log --oneline --graph
echo "--- والدهای commit ادغام:"
git log -1 --format='%h والدها: %p'
خروجی
--- ادغام اول (fast-forward):
Updating 2294e3b..5553204
Fast-forward
--- ادغام دوم (main حالا جلوتر است، پس three-way):
Merge made by the 'ort' strategy.
b.txt | 1 +
* cdc3657 Merge branch 'feature/b'
|\
| * 65e738f Add b
* | 5553204 Add a
|/
* 2294e3b Base
--- والدهای commit ادغام:
cdc3657 والدها: 5553204 65e738f
⚡ بررسی سریع

ساختن یک شاخه‌ی جدید در Git چقدر هزینه دارد و چرا؟

؟ آزمونک
  1. کدام دستور شاخه‌ی جدید می‌سازد و همان لحظه به آن می‌رود؟

  2. ادغام fast-forward چه زمانی ممکن است؟

  3. commit ادغام در three-way merge چه ویژگی دارد؟

  4. git branch -d چه فرقی با -D دارد؟

  5. روی detached HEAD چند commit زده‌ای. برای نگه‌داشتنشان چه می‌کنی؟

  • branch یک برچسب سبک روی یک commit است؛ ساختنش آنی. HEAD می‌گوید روی کدام شاخه‌ای.
  • git switch -c نام می‌سازد و می‌رود؛ git switch نام می‌رود؛ git switch - به قبلی برمی‌گردد. پوشه‌ی کاری با commit آن شاخه یکی می‌شود.
  • git merge نام شاخه را وارد شاخه‌ی فعلی می‌کند: fast-forward (برچسب جلو می‌رود) یا three-way (commit ادغام با دو والد)؛ --no-ff همیشه commit ادغام می‌سازد.
  • git branch -d (امن) بعد از ادغام؛ -D اجباری ⚠. --merged و --no-merged وضعیت ادغام را نشان می‌دهند.
  • commit روی شاخه‌ی اشتباه: git branch درست و بعد reset --hard برای شاخه‌ی اشتباه (فقط قبل از push). detached HEAD: برای نگه‌داشتن کار، git switch -c.
  • شاخه‌ها فایل‌های هش‌دار در .git/refs/heads/ هستند؛ commit ادغام دو parent دارد.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
git branch / git branch -vفهرست شاخه‌ها
git switch -c feature/xساخت و رفتن
git switch main / git switch -رفتن به شاخه / قبلی
git merge feature/xادغام در شاخه‌ی فعلی
git merge --no-ff feature/xهمیشه commit ادغام
git branch -d feature/xحذف امن
git branch -D feature/xحذف اجباری ⚠
git branch -m قدیم جدیدتغییر نام
git branch --merged / --no-mergedادغام‌شده‌ها / نشده‌ها
git log --oneline --graph --allگراف همه‌ی شاخه‌ها
git switch --detach commitنگاه به یک commit (detached)