توی این درس یاد میگیری تاریخچهی یک پروژه را مثل یک کارآگاه بخوانی: با git log و فرمتها و فیلترهایش (--oneline، --graph، --author، --since، -S)، git show برای دیدن یک commit، git diff و git diff --staged برای دیدن تفاوتها، و git blame برای دانستن اینکه هر خط را چه کسی و کی نوشته. تمرین: پیدا کن یک خط مشخص در کدام commit اضافه شده.
مسئله: «این را چه کسی خراب کرد؟»
Section titled “مسئله: «این را چه کسی خراب کرد؟»”یک تاریخچهی Git فقط برای برگشتن نیست؛ حافظهی پروژه است. وقتی چیزی خراب میشود، سؤالها همیشه همانهاست: چه چیزی عوض شده؟ کی؟ چه کسی؟ چرا؟ آیا آن خط همیشه اینطور بود؟ Git جواب همه را دارد، به شرطی که بلد باشی بپرسی.
تشبیه: دوربین مداربستهی پروژه
Section titled “تشبیه: دوربین مداربستهی پروژه”git log فیلم کامل دوربین است، commit به commit. git show یک فریم را بزرگ میکند. git diff دو فریم را کنار هم میگذارد و فقط تفاوت را نشان میدهد. و git blame روی هر خط از کد میگوید «این را چه کسی و در کدام فریم آنجا گذاشت».
مثالهای عملی
Section titled “مثالهای عملی”برای تمرین به یک تاریخچهی غنیتر از «یک commit» نیاز داریم: چند نفر، چند روز. یک پروژهی کوچک با شش commit از سه نویسنده میسازم. چون commit ها همین الآن ساخته میشوند، با متغیرهای محیطی GIT_AUTHOR_NAME، GIT_AUTHOR_EMAIL و GIT_AUTHOR_DATE نویسنده و تاریخ هر کدام را مشخص کردهام (روی یک پروژهی واقعی خودکار ثبت میشوند؛ این فقط برای ساختن نمونه است):
mkdir -p ~/gitlab/shop && cd ~/gitlab/shop && git init -qc() { # c نام ایمیل «چند روز قبل» پیام local d; d=$(date -d "$3 days ago" --iso-8601=seconds) GIT_AUTHOR_NAME="$1" GIT_AUTHOR_EMAIL="$2" GIT_AUTHOR_DATE="$d" GIT_COMMITTER_DATE="$d" git commit -qam "$4"}printf 'print("Hello")\n' > app.pygit add app.py && c Ali ali@example.com 6 "Add greeting script"printf '\ndef total(price, qty):\n return price * qty\n' >> app.pyc Sara sara@example.com 5 "Add price calculation"sed -i 's/return price \* qty/return price * qty * 0.9/' app.pyc Reza reza@example.com 4 "Apply 10 percent discount to total"printf '# Shop\nA tiny price calculator.\n' > README.mdgit add README.md && c Sara sara@example.com 3 "Add README"sed -i 's/print("Hello")/print("Welcome to the shop")/' app.pyc Ali ali@example.com 2 "Change greeting to a welcome message"sed -i 's/return price \* qty \* 0.9/return round(price * qty * 0.9, 2)/' app.pyc Reza reza@example.com 1 "Round the total to two decimals"git log --oneline | wc -lcat app.py6print("Welcome to the shop")
def total(price, qty): return round(price * qty * 0.9, 2)مثال ۱: git log و فرمتهای اصلی
Section titled “مثال ۱: git log و فرمتهای اصلی”cd ~/gitlab/shopecho "=== git log (کامل، دو commit آخر):"git log -n 2echo "=== git log --oneline (یک خط برای هر commit):"git log --onelineecho "=== با آمار فایلها (--stat) برای سه commit:"git log --stat -n 3 --format='%h %an: %s'=== git log (کامل، دو commit آخر):commit 44478ec45f778277890da9e5151912c86c60ea9cAuthor: Reza <reza@example.com>Date: Sat Oct 3 08:12:45 2026 +0000
Round the total to two decimals
commit 2a061efca9e14553bc046142c157f3af3a5bfab9Author: Ali <ali@example.com>Date: Fri Oct 2 08:12:45 2026 +0000
Change greeting to a welcome message=== git log --oneline (یک خط برای هر commit):44478ec Round the total to two decimals2a061ef Change greeting to a welcome messagef39a552 Add READMEac77b84 Apply 10 percent discount to total445e7b1 Add price calculationafa6f60 Add greeting script=== با آمار فایلها (--stat) برای سه commit:44478ec Reza: Round the total to two decimals
app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)2a061ef Ali: Change greeting to a welcome message
app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)f39a552 Sara: Add README
README.md | 2 ++ 1 file changed, 2 insertions(+)پیشفرض git log از جدید به قدیم و با ۴ چیز در هر commit است: شناسهی کامل (hash)، نویسنده، تاریخ، پیام. در ترمینال واقعی خروجی طولانی در یک pager (less) باز میشود: با Space ورق بزن و با q خارج شو. (در این درس خروجی را مستقیم میبینی.) فرمتها:
| گزینه | کار |
|---|---|
-n 3 یا -3 |
فقط ۳ commit آخر |
--oneline |
هر commit یک خط: هش کوتاه + عنوان |
--stat |
فایلهای عوضشده و تعداد خطها |
-p (--patch) |
خود تغییر خطبهخط (diff) |
--graph |
شاخهها را با خط و دایره نشان بده |
--decorate |
نام شاخه و tag کنار commit (پیشفرض روشن است) |
--all |
همهی شاخهها، نه فقط شاخهی فعلی |
--format='...' |
قالب دلخواه (%h هش کوتاه، %an نویسنده، %ar زمان نسبی، %s عنوان) |
مثال ۲: قالب دلخواه و آمار
Section titled “مثال ۲: قالب دلخواه و آمار”cd ~/gitlab/shopecho "=== قالب دلخواه:"git log --format='%h | %<(6)%an | %<(14)%ar | %s'echo "=== چند commit دارد؟"git rev-list --count HEADecho "=== هر نفر چند commit زده؟ (shortlog)"git shortlog -sn HEAD=== قالب دلخواه:44478ec | Reza | 24 hours ago | Round the total to two decimals2a061ef | Ali | 2 days ago | Change greeting to a welcome messagef39a552 | Sara | 3 days ago | Add READMEac77b84 | Reza | 4 days ago | Apply 10 percent discount to total445e7b1 | Sara | 5 days ago | Add price calculationafa6f60 | Ali | 6 days ago | Add greeting script=== چند commit دارد؟6=== هر نفر چند commit زده؟ (shortlog) 2 Ali 2 Reza 2 Sara--format با علامتهای % ساخته میشود (git help log، بخش PRETTY FORMATS؛ %<(6) یعنی ستونی به عرض ۶). git shortlog -sn HEAD نویسندهها را بر اساس تعداد commit مرتب میکند (-s فقط تعداد، -n مرتب بر اساس عدد؛ HEAD را صریح نوشتهام چون وقتی ورودی ترمینال نیست shortlog منتظر ورودی میماند)، و git rev-list --count HEAD تعداد commit ها را برای اسکریپت میدهد.
مثال ۳: گراف شاخهها، --graph
Section titled “مثال ۳: گراف شاخهها، --graph”وقتی چند شاخه داریم، --graph ساختار را رسم میکند. یک شاخهی ویژگی میسازم و با main ترکیبش میکنم (درس بعدی کامل توضیح میدهد؛ اینجا فقط خروجی log مهم است):
mkdir -p ~/gitlab/graph && cd ~/gitlab/graph && git init -qecho 1 > f && git add f && git commit -qm "Start"echo 2 >> f && git commit -qam "Second on main"git switch -qc featureecho a > g && git add g && git commit -qm "Feature part 1"echo b >> g && git commit -qam "Feature part 2"git switch -q mainecho 3 >> f && git commit -qam "Third on main"git merge -q --no-edit featureecho "=== git log --oneline --graph --decorate:"git log --oneline --graph --decorate=== git log --oneline --graph --decorate:* f11fd6f (HEAD -> main) Merge branch 'feature'|\| * 114ad1a (feature) Feature part 2| * bd7ba74 Feature part 1* | cb081a4 Third on main|/* 2e534ea Second on main* f7349cd Startهر ستاره (*) یک commit است، خطهای | و \ و / شاخهها و ادغام را نشان میدهند، و داخل پرانتز میبینی HEAD، main و feature به کدام commit اشاره میکنند. این ترکیب (--oneline --graph --decorate) آنقدر مفید است که معمولاً برایش alias میسازند (درس قبل: alias.lg).
مثال ۴: فیلتر کردن تاریخچه
Section titled “مثال ۴: فیلتر کردن تاریخچه”تاریخچهی بزرگ را با فیلتر کوچک کن (روی پروژهی shop):
cd ~/gitlab/shopecho "=== فقط commit های «Sara»:"git log --author=Sara --format='%h %an %s'echo "=== فقط ۶۰ ساعت اخیر:"git log --since="60 hours ago" --format='%h %ar %s'echo "=== پیامهایی که کلمهی discount دارند:"git log --grep=discount --format='%h %s'echo "=== تاریخچهی فقط یک فایل (README.md):"git log --format='%h %s' -- README.mdecho "=== commit هایی که تعداد «0.9» در کد را عوض کردهاند (-S، pickaxe):"git log -S"0.9" --format='%h %an %s'=== فقط commit های «Sara»:f39a552 Sara Add README445e7b1 Sara Add price calculation=== فقط ۶۰ ساعت اخیر:44478ec 24 hours ago Round the total to two decimals2a061ef 2 days ago Change greeting to a welcome message=== پیامهایی که کلمهی discount دارند:ac77b84 Apply 10 percent discount to total=== تاریخچهی فقط یک فایل (README.md):f39a552 Add README=== commit هایی که تعداد «0.9» در کد را عوض کردهاند (-S، pickaxe):ac77b84 Reza Apply 10 percent discount to totalآخری شگفتانگیز است: -S"متن" (به آن pickaxe یا کلنگ میگویند) commit هایی را پیدا میکند که تعداد دفعات آمدن آن متن را در کد تغییر دادهاند؛ یعنی commit ای که آن را اضافه یا حذف کرده. اینجا فقط commit تخفیف است، نه commit گردکردن (که 0.9 را داشت ولی تعدادش را عوض نکرد). گزینههای همخانواده: -G"regex" (با عبارت منظم)، --author، --until، --no-merges، و ترکیبشان.
مثال ۵: git show، یک commit از نزدیک
Section titled “مثال ۵: git show، یک commit از نزدیک”cd ~/gitlab/shopecho "=== git show HEAD~3 (چهارمین commit از آخر؛ تخفیف):"git show HEAD~3 --format='%h %an (%ar)%n%s%n'echo "=== فایل در آن زمان (git show commit:مسیر):"git show HEAD~3:app.py=== git show HEAD~3 (چهارمین commit از آخر؛ تخفیف):ac77b84 Reza (4 days ago)Apply 10 percent discount to total
diff --git a/app.py b/app.pyindex decd307..c5b551b 100644--- a/app.py+++ b/app.py@@ -1,4 +1,4 @@ print("Hello")
def total(price, qty):- return price * qty+ return price * qty * 0.9=== فایل در آن زمان (git show commit:مسیر):print("Hello")
def total(price, qty): return price * qty * 0.9git show دو چیز نشان میدهد: پیام و نویسنده و تغییر دقیق (diff آن commit). و با شکل commit:فایل محتوای یک فایل را همانطور که در آن commit بود چاپ میکند (بدون اینکه چیزی در پوشهی کاری عوض شود). HEAD~3 یعنی «سه commit قبل از HEAD». شکلهای دیگر آدرسدهی: هش کوتاه (git show 1a2b3c4)، HEAD^ (والد، مثل HEAD~1)، و نام شاخه یا tag.
مثال ۶: git diff، چه چیزی تغییر کرده؟
Section titled “مثال ۶: git diff، چه چیزی تغییر کرده؟”git diff دو چیز را با هم مقایسه میکند. بدون آرگومان: پوشهی کاری با ناحیهی staging. با --staged: staging با آخرین commit. ببین هر کدام چه میگوید:
cd ~/gitlab/shopecho "total = total(10, 3)" >> app.pyecho "=== ۱) git diff (پوشهی کاری ← staging):"git diffgit add app.pyecho "=== ۲) بعد از add، دوباره git diff:"git diffecho "(خالی! چون staging و پوشهی کاری یکیاند)"echo "=== ۳) git diff --staged (staging ← آخرین commit):"git diff --stagedecho "print(total)" >> app.pyecho "=== ۴) git diff HEAD (پوشهی کاری ← آخرین commit؛ هر دو تغییر):"git diff HEAD=== ۱) git diff (پوشهی کاری ← staging):diff --git a/app.py b/app.pyindex 2be6b70..b6f34a9 100644--- a/app.py+++ b/app.py@@ -2,3 +2,4 @@ print("Welcome to the shop")
def total(price, qty): return round(price * qty * 0.9, 2)+total = total(10, 3)=== ۲) بعد از add، دوباره git diff:(خالی! چون staging و پوشهی کاری یکیاند)=== ۳) git diff --staged (staging ← آخرین commit):diff --git a/app.py b/app.pyindex 2be6b70..b6f34a9 100644--- a/app.py+++ b/app.py@@ -2,3 +2,4 @@ print("Welcome to the shop")
def total(price, qty): return round(price * qty * 0.9, 2)+total = total(10, 3)=== ۴) git diff HEAD (پوشهی کاری ← آخرین commit؛ هر دو تغییر):diff --git a/app.py b/app.pyindex 2be6b70..a67b7bd 100644--- a/app.py+++ b/app.py@@ -2,3 +2,5 @@ print("Welcome to the shop")
def total(price, qty): return round(price * qty * 0.9, 2)+total = total(10, 3)+print(total)یک خروجی diff را اینطور بخوان:
| بخش | معنی |
|---|---|
diff --git a/app.py b/app.py |
فایل a (قبل) در مقابل b (بعد) |
--- a/app.py و +++ b/app.py |
فایل قدیم و جدید |
@@ -2,3 +2,4 @@ |
hunk: از خط ۲، سه خط در قدیم ← از خط ۲، چهار خط در جدید |
خطهای با - (قرمز) |
در قدیم بود، حذف شد |
خطهای با + (سبز) |
اضافه شد |
| خطهای بدون علامت | بافت اطراف (برای فهمیدن محل) |
مثال ۷: diff بین دو commit و گزینههای مفید
Section titled “مثال ۷: diff بین دو commit و گزینههای مفید”cd ~/gitlab/shop# تغییرهای آزمایشی مثال قبل را برمیگردانم (git restore: درس «برگرداندن تغییرات»)git restore --staged app.py && git restore app.pyecho "=== بین دو commit (قدیم..جدید):"git diff HEAD~3 HEAD --statecho "=== فقط نام فایلهای عوضشده:"git diff HEAD~5 HEAD --name-onlyecho "=== با دید «کلمهای» (--word-diff):"git diff HEAD~1 HEAD --word-diff=== بین دو commit (قدیم..جدید): README.md | 2 ++ app.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-)=== فقط نام فایلهای عوضشده:README.mdapp.py=== با دید «کلمهای» (--word-diff):diff --git a/app.py b/app.pyindex 4e96212..2be6b70 100644--- a/app.py+++ b/app.py@@ -1,4 +1,4 @@print("Welcome to the shop")
def total(price, qty): return [-price-]{+round(price+} * qty * [-0.9-]{+0.9, 2)+}git diff قدیم جدید (یا قدیم..جدید) هر دو commit را مقایسه میکند. گزینههای پرکاربرد: --stat (خلاصه)، --name-only (فقط نامها)، --name-status (نام با نوع تغییر: A/M/D)، --word-diff (تفاوت در سطح کلمه؛ برای متن عالی است)، -w (فاصلههای اضافه را نادیده بگیر)، و -- مسیر برای محدودکردن به یک فایل.
مثال ۸: git blame، هر خط را چه کسی نوشت؟
Section titled “مثال ۸: git blame، هر خط را چه کسی نوشت؟”cd ~/gitlab/shopecho "=== git blame app.py:"git blame app.pyecho "=== فقط خطهای ۳ تا ۴ (-L):"git blame -L 3,4 app.py=== git blame app.py:2a061efc (Ali 2026-10-02 08:12:45 +0000 1) print("Welcome to the shop")445e7b16 (Sara 2026-09-29 08:12:45 +0000 2)445e7b16 (Sara 2026-09-29 08:12:45 +0000 3) def total(price, qty):44478ec4 (Reza 2026-10-03 08:12:45 +0000 4) return round(price * qty * 0.9, 2)=== فقط خطهای ۳ تا ۴ (-L):445e7b16 (Sara 2026-09-29 08:12:45 +0000 3) def total(price, qty):44478ec4 (Reza 2026-10-03 08:12:45 +0000 4) return round(price * qty * 0.9, 2)برای هر خط میبینی: هش commit ای که آن خط را آخرین بار عوض کرد، نویسنده، تاریخ و شمارهی خط. حالا تمرین اصلی: «خط return round(...) (خط ۴) در کدام commit اضافه شده؟». از blame هش را میگیری و با git show معنیاش را میخوانی:
cd ~/gitlab/shoph=$(git blame -L 4,4 --porcelain app.py | head -1 | cut -d' ' -f1)echo "هش commit ای که خط ۴ را آخر بار عوض کرد: ${h:0:7}"git show -s --format='%h %an: %s (%ar)' $hecho "--- ولی این خط از اول اینطور نبود؛ کی «0.9» اضافه شد؟ (با -S)"git log -S"0.9" --format='%h %an: %s (%ar)' | tail -1هش commit ای که خط ۴ را آخر بار عوض کرد: 44478ec44478ec Reza: Round the total to two decimals (24 hours ago)--- ولی این خط از اول اینطور نبود؛ کی «0.9» اضافه شد؟ (با -S)ac77b84 Reza: Apply 10 percent discount to total (4 days ago)نکتهی مهم: git blame فقط آخرین commit ای را که خط را عوض کرده نشان میدهد. اگر دنبال commit ای هستی که یک ایده یا متن را برای اولین بار وارد کرد، با git log -S بگرد (یا blame را روی نسخهی قدیمیتر اجرا کن: git blame HEAD~2 -- app.py).
پشت پرده: diff و log چطور کار میکنند؟
Section titled “پشت پرده: diff و log چطور کار میکنند؟”Git diff نگه نمیدارد؛ هر commit یک عکس کامل است (درس اول). git diff و git show در لحظهی درخواست دو عکس را برمیدارند و با یک الگوریتم (بهصورت پیشفرض Myers) کوتاهترین فهرست «حذف/اضافه» را حساب میکنند. git log هم از HEAD شروع میکند و پشتسرهم به والد (parent) هر commit میرود تا به اولین برسد. blame همین کار را برای هر خط انجام میدهد: عقب میرود تا جایی که آن خط آخرین بار عوض شده. ببین log دقیقاً از زنجیرهی والدها ساخته میشود:
cd ~/gitlab/shopecho "=== والد هر commit (هش کوتاه ← والدش):"git log --format='%h والد: %p %s' -n 3echo "=== و diff حسابشدهی یک commit با نسخهی بدون تفاوت:"git diff HEAD HEAD && echo "(تفاوت یک commit با خودش خالی است)"=== والد هر commit (هش کوتاه ← والدش):44478ec والد: 2a061ef Round the total to two decimals2a061ef والد: f39a552 Change greeting to a welcome messagef39a552 والد: ac77b84 Add README=== و diff حسابشدهی یک commit با نسخهی بدون تفاوت:(تفاوت یک commit با خودش خالی است)جدولهای مرجع
Section titled “جدولهای مرجع”| دستور | کار |
|---|---|
git log --oneline |
تاریخچهی کوتاه |
git log --oneline --graph --all |
گراف همهی شاخهها |
git log -p / --stat |
با تغییر کامل / با آمار |
git log --author=نام / --since="2 days ago" |
فیلتر نویسنده / زمان |
git log --grep=متن |
جستجو در پیامها |
git log -S"متن" |
commit هایی که تعداد آن متن را عوض کردهاند |
git log -- مسیر |
تاریخچهی یک فایل |
git show commit / commit:فایل |
یک commit / محتوای فایل در آن commit |
git diff |
پوشهی کاری در برابر staging |
git diff --staged |
staging در برابر آخرین commit |
git diff HEAD |
پوشهی کاری در برابر آخرین commit |
git diff قدیم جدید |
دو commit |
git blame فایل / -L 4,9 |
نویسندهی هر خط / فقط چند خط |
git shortlog -sn HEAD |
تعداد commit هر نفر |
| آدرس | معنی |
|---|---|
HEAD |
commit فعلی |
HEAD~1 یا HEAD^ |
والد |
HEAD~3 |
سه commit قبل |
1a2b3c4 |
هش کوتاه (کافی است یکتا باشد) |
main، v1.0 |
نام شاخه یا tag |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) git diff بعد از git add خالی است
Section titled “۱) git diff بعد از git add خالی است”mkdir -p ~/gitlab/mistake && cd ~/gitlab/mistake && git init -qecho a > a.txt && git add a.txt && git commit -qm "Add a"echo b >> a.txt && git add a.txtecho "--- git diff:"git diffecho "(خالی)"echo "--- git diff --staged:"git diff --staged--- git diff:(خالی)--- git diff --staged:diff --git a/a.txt b/a.txtindex 7898192..422c2b7 100644--- a/a.txt+++ b/a.txt@@ -1 +1,2 @@ a+bهیچ خطایی نیست؛ git diff بدون آرگومان فقط پوشهی کاری را با staging مقایسه میکند و چون تازه add کردهای، هیچ تفاوتی نیست. راهحل: برای دیدن آنچه قرار است commit شود git diff --staged (یا --cached).
۲) فکر اینکه blame مقصر را نشان میدهد
Section titled “۲) فکر اینکه blame مقصر را نشان میدهد”git blame فقط میگوید چه کسی آن خط را آخرین بار لمس کرده، که ممکن است یک بازآرایی (فاصلهگذاری، تغییر نام متغیر) باشد، نه نوشتن اصلی. راهحل: git blame -w (نادیدهگرفتن فاصلهها) و -C (دنبالکردن کد جابهجاشده)، و کاربرد git log -S. و کارکرد blame پیدا کردن context است، نه مقصر؛ فرهنگ تیمی «blame-free» را حفظ کن.
۳) گیرکردن در pager
Section titled “۳) گیرکردن در pager”وقتی git log طولانی است، خروجی در less باز میشود و کاربر تازهکار نمیداند چطور خارج شود. راهحل: کلید q. برای چاپ مستقیم: git --no-pager log یا git config --global core.pager cat.
۴) آدرسدهی اشتباه commit
Section titled “۴) آدرسدهی اشتباه commit”cd ~/gitlab/shopgit show HEAD~99 2>&1 | head -3git show nosuchbranch 2>&1 | head -3fatal: ambiguous argument 'HEAD~99': unknown revision or path not in the working tree.Use '--' to separate paths from revisions, like this:'git <command> [<revision>...] -- [<file>...]'fatal: ambiguous argument 'nosuchbranch': unknown revision or path not in the working tree.Use '--' to separate paths from revisions, like this:'git <command> [<revision>...] -- [<file>...]'fatal: ambiguous argument ... unknown revision or path not in the working tree: Git آن آدرس را نه بهعنوان commit و نه بهعنوان فایل میشناسد. راهحل: با git log --oneline هش یا HEAD~n درست را پیدا کن.
۵) فراموشکردن -- قبل از اسم فایل
Section titled “۵) فراموشکردن -- قبل از اسم فایل”اگر اسم فایلی با اسم یک شاخه یکی باشد، Git گیج میشود. git log -- مسیر (دو خط تیرهی جدا) صریحاً میگوید «بعدش مسیر است، نه commit».
شش commit اخیر shop را در یک خط هر کدام ببین، بههمراه نام نویسنده و زمان نسبی (%ar).
دیدن جواب
cd ~/gitlab/shopgit log -n 6 --format='%h %an %ar: %s'44478ec Reza 24 hours ago: Round the total to two decimals2a061ef Ali 2 days ago: Change greeting to a welcome messagef39a552 Sara 3 days ago: Add READMEac77b84 Reza 4 days ago: Apply 10 percent discount to total445e7b1 Sara 5 days ago: Add price calculationafa6f60 Ali 6 days ago: Add greeting scriptتمرین اصلی: پیدا کن یک خط مشخص در کدام commit اضافه شده. خط def total(price, qty): را چه کسی و در کدام commit وارد کرد؟ (از git blame و git log -S هر دو استفاده کن و جوابشان را مقایسه کن.)
دیدن جواب
cd ~/gitlab/shopecho "--- با blame (آخرین کسی که این خط را لمس کرد):"git blame -L '/def total/,+1' app.pyecho "--- با log -S (اولین commit ای که این متن را اضافه کرد):"git log -S"def total" --format='%h %an: %s (%ar)'--- با blame (آخرین کسی که این خط را لمس کرد):445e7b16 (Sara 2026-09-29 08:12:45 +0000 3) def total(price, qty):--- با log -S (اولین commit ای که این متن را اضافه کرد):445e7b1 Sara: Add price calculation (5 days ago)فهرست یکتای همهی فایلهایی را که در پنج commit آخر عوض شدهاند بساز (هر نام یک بار)، و برای هر نویسنده تعداد خطهای اضافهشدهاش را در کل تاریخچه بشمار.
دیدن جواب
cd ~/gitlab/shopecho "--- فایلهای عوضشده در ۵ commit آخر (یکتا):"git log -5 --name-only --format= | sort -u | grep -v '^$'echo "--- خطهای اضافهشده به تفکیک نویسنده (numstat):"git log --numstat --format='AUTHOR:%an' | awk '/^AUTHOR:/ {a=substr($0,8); next} NF==3 {add[a]+=$1} END {for (k in add) print add[k], k}' | sort -rn--- فایلهای عوضشده در ۵ commit آخر (یکتا):README.mdapp.py--- خطهای اضافهشده به تفکیک نویسنده (numstat):5 Sara2 Reza2 Aliآزمونک
Section titled “آزمونک”بعد از git add file.txt، دستور git diff (بدون آرگومان) چه چیزی نشان میدهد؟
برای دیدن آنچه staged شده و در commit بعدی میرود از git diff --staged استفاده کن.
HEAD~2 یعنی چه؟
HEAD~1 والد، HEAD~2 والدِ والد و الی آخر.
کدام دستور فقط commit هایی را نشان میدهد که تعداد متن «0.9» را در کد عوض کردهاند (یعنی اضافه یا حذفش کردهاند)؟
--grep در پیام commit ها میگردد؛ -S در تغییرهای کد.
git diff --staged چه دو چیزی را مقایسه میکند؟
یعنی آنچه با commit بعدی ثبت میشود.
git blame چه میگوید؟
برای پیدا کردن context؛ ممکن است آخرین تغییر فقط یک بازآرایی باشد.
در خروجی diff یک خط با علامت + در ابتدا یعنی؟
- حذفشده، + اضافهشده، بدون علامت: بافت اطراف.
جمعبندی
Section titled “جمعبندی”git log:--oneline(کوتاه)،--graph --decorate --all(شاخهها)،--stat/-p(تغییر)،--format='...'(قالب دلخواه)؛ فیلتر با--author،--since،--grep،-- مسیرو-S"متن".git show commitپیام و تغییر یک commit را میدهد؛git show commit:فایلمحتوای فایل را در آن لحظه.git diff(کاری ← staging)،git diff --staged(staging ← commit)،git diff HEAD(کاری ← commit)،git diff قدیم جدید(دو commit). خطهای-حذف،+اضافه.git blame فایلبرای هر خط commit و نویسندهی آخرین تغییر را میدهد؛ برای اولین ورود یک متن ازgit log -Sاستفاده کن.- آدرسدهی:
HEAD،HEAD~n، هش کوتاه، نام شاخه یا tag. در pager باqخارج شو. - Git تفاوت ذخیره نمیکند؛ هر لحظه دو عکس را مقایسه میکند.
| دستور | کاری که میکند |
|---|---|
git log --oneline --graph --all | گراف کوتاه همهی شاخهها |
git log -p -n 3 | سه commit آخر با تغییر کامل |
git log --author=نام --since="1 week ago" | فیلتر نویسنده و زمان |
git log -S"متن" | commit هایی که آن متن را اضافه/حذف کردهاند |
git log -- فایل | تاریخچهی یک فایل |
git show HEAD~2 | commit دوم از آخر |
git show commit:فایل | فایل در آن commit |
git diff / git diff --staged / git diff HEAD | سه مقایسهی اصلی |
git diff قدیم جدید --stat | تفاوت دو commit، خلاصه |
git blame -L 4,9 فایل | نویسندهی خطهای ۴ تا ۹ |
git shortlog -sn HEAD | تعداد commit هر نفر |