ورک‌تری‌ها در گیت‌هاب (Git Worktrees) مکانیزمی برای اتصال چند پوشه کاری به یک مخزن واحد هستند که امکان کار موازی روی چند شاخه را بدون clone دوباره یا stash کردن تغییرات فراهم می‌کنند و در پروژه‌های پیچیده، بهره‌وری توسعه‌دهنده را به‌طور چشمگیری افزایش می‌دهند.

در پروژه‌های متعددی که تیم‌های توسعه را همراهی کرده‌ام، بارها دیده‌ام که توسعه‌دهندگان برای رفع یک باگ فوری، مجبور می‌شوند تغییرات نیمه‌کاره خود را stash کنند، شاخه عوض کنند، باگ را رفع کنند، برگردند و stash را بازیابی کنند. این چرخه، هم زمان‌بر است و هم مستعد خطاست. Git Worktree که در نسخه ۲.۵ معرفی شد، این مشکل را به‌شکل ساختاری حل می‌کند: به‌جای یک پوشه کاری، چند پوشه کاری که همه به یک مخزن اشاره می‌کنند. آمار نشان می‌دهد توسعه‌دهندگانی که Worktree را جدی گرفته‌اند، تا ۳۰ درصد زمان خود را در مدیریت شاخه‌ها صرفه‌جویی می‌کنند. در این نوشتار، این ویژگی را از پایه تا الگوهای پیشرفته بررسی می‌کنم.

هر بار که برای رفع یک باگ فوری، مجبور می‌شوید تغییرات خود را stash کنید، یک بدهی کوچک در ذهن خود ایجاد کرده‌اید. Worktree، این بدهی را حذف می‌کند.

Worktree چیست و چه تفاوتی با clone دارد؟

Worktree (پوشه کاری)، یک دایرکتوری مستقل است که به یک مخزن Git متصل است. یک مخزن می‌تواند چند Worktree داشته باشد که هرکدام روی یک شاخه متفاوت کار می‌کنند اما همه از یک تاریخچه و یک پوشه .git مشترک استفاده می‌کنند.

Git در ویکی‌پدیا مرور کاملی از معماری داخلی آن ارائه می‌دهد. دستورات پرکاربرد Git که هر توسعه‌دهنده باید بداند به‌طور مفصل درباره مبانی Git بحث کرده‌ام.

تفاوت Worktree و Clone

ویژگی Clone Worktree
پوشه .git مستقل مشترک با مخزن اصلی
فضای دیسک کامل کمتر (فقط فایل‌های کاری)
همگام‌سازی دستی با fetch خودکار (مخزن مشترک)
شاخه‌ها مستقل مشترک (همه Refها)
مناسب برای پروژه‌های مستقل کار موازی روی یک پروژه

چرا Worktree بهتر از Clone دوباره است؟

  • صرفه‌جویی فضای دیسک: Clone دوباره، کل تاریخچه را کپی می‌کند. Worktree فقط فایل‌های کاری را.
  • همگام‌سازی خودکار: یک git fetch در مخزن اصلی، همه Worktreeها را به‌روز می‌کند.
  • مدیریت متمرکز: تنها یک مخزن برای مدیریت.
  • سرعت: ساخت Worktree، چند ثانیه است. Clone، چند دقیقه.
  • بدون تنظیم مجدد: تنظیمات Git (remote، config) مشترک است.

چرا Worktree بهتر از Stash است؟

  • حفظ وضعیت: تغییرات نیمه‌کاره در جای خود باقی می‌مانند.
  • بدون ریسک بازیابی: Stash ممکن است اشتباه اعمال شود.
  • حفظ محیط: فایل‌های موقت، node_modules و IDE settings دست‌نخورده باقی می‌مانند.
  • بدون انتظار: جابه‌جایی بین شاخه‌ها، آنی است.

چرا Worktree حیاتی است؟

در جریان‌های کاری واقعی، توسعه‌دهندگان به‌طور مداوم بین چند کار جابه‌جا می‌شوند.

سناریوی رایج

تصور کنید در حال کار روی یک ویژگی جدید هستید. ناگهان یک باگ بحرانی در Production گزارش می‌شود. باید فوراً شاخه عوض کنید، باگ را رفع کنید، دیپلوی کنید و برگردید. بدون Worktree، این فرآیند شامل:

  • Stash کردن تغییرات فعلی
  • Checkout شاخه hotfix
  • رفع باگ
  • Push و دیپلوی
  • Checkout شاخه قبلی
  • Stash pop و حل تعارضات احتمالی
  • تلاش برای ادامه کار

با Worktree، تنها یک پوشه جدید باز می‌کنید و کار را ادامه می‌دهید. تغییرات قبلی، دست‌نخورده باقی می‌مانند. چگونه بر مشکلات پروژه‌های وردپرسی غلبه کنیم؟ به مدیریت موقعیت‌های مشابه اشاره دارد.

مزایای کلیدی

  • کار موازی: چند شاخه، همزمان.
  • کاهش خطا: حذف Stash و Checkout مکرر.
  • افزایش بهره‌وری: صرفه‌جویی زمان در جابه‌جایی.
  • تست همزمان: اجرای تست در یک شاخه، همزمان با کار روی شاخه دیگر.
  • بازبینی PR: بازبینی PR در Worktree جداگانه، بدون تداخل با کار فعلی.

در برنچ در Git راهنمای مدیریت شاخه‌ها به‌طور مفصل درباره استراتژی‌های شاخه‌بندی بحث کرده‌ام. Pull Request در GitHub راهنمای حرفه‌ای نیز به بازبینی PR اشاره دارد.

تأثیر بر کیفیت کد

وقتی توسعه‌دهنده نگران از دست دادن تغییرات نیست، آزادانه‌تر آزمایش می‌کند. این آزادی، کیفیت را بالا می‌برد. اصول کدنویسی تمیز در پروژه‌های وردپرس به این موضوع اشاره دارد.

مبانی دستورات Worktree

Git مجموعه‌ای از دستورات برای مدیریت Worktreeها ارائه می‌دهد.

ساخت Worktree جدید

git worktree add ../my-project-hotfix hotfix/urgent-bug

این دستور، یک Worktree جدید در ../my-project-hotfix ایجاد می‌کند که روی شاخه hotfix/urgent-bug کار می‌کند. اگر شاخه وجود نداشته باشد، با -b می‌توان ساخت:

git worktree add -b feature/new-ui ../my-project-feature main

فهرست Worktreeها

git worktree list

خروجی نمونه:

/home/user/my-project         abc1234 [main]
/home/user/my-project-hotfix  def5678 [hotfix/urgent-bug]
/home/user/my-project-feature 789abcd [feature/new-ui]

حذف Worktree

git worktree remove ../my-project-hotfix

اگر تغییرات uncommitted وجود داشته باشد، Git اجازه حذف نمی‌دهد. برای Force:

git worktree remove --force ../my-project-hotfix

پاک‌سازی Worktreeهای قدیمی

اگر Worktree به‌صورت دستی حذف شود (مثلاً rm -rf)، Git آن را در فهرست نگه می‌دارد. برای پاک‌سازی:

git worktree prune

قفل کردن Worktree

اگر Worktree روی یک دیسک قابل جابه‌جایی است (مثل USB)، می‌توانید آن را قفل کنید:

git worktree lock ../my-project-usb
git worktree unlock ../my-project-usb

انتقال Worktree

برای انتقال Worktree به مسیر جدید:

git worktree move ../old-path ../new-path

جدول خلاصه دستورات

دستور کاربرد
worktree add ساخت Worktree جدید
worktree list فهرست Worktreeها
worktree remove حذف Worktree
worktree prune پاک‌سازی Worktreeهای حذف‌شده
worktree lock قفل Worktree
worktree unlock باز کردن قفل
worktree move انتقال Worktree

کاربردهای عملی

Worktree در سناریوهای متعددی ارزشمند است.

رفع باگ فوری

پرکاربردترین سناریو. یک Worktree برای hotfix باز می‌کنید، باگ را رفع می‌کنید، دیپلوی می‌کنید و Worktree را حذف می‌کنید.

بازبینی PR

برای بازبینی PR، یک Worktree روی شاخه PR ایجاد کنید، کد را بررسی و تست کنید، بدون تداخل با کار فعلی. Pull Request در GitHub راهنمای حرفه‌ای به این رویه اشاره دارد.

تست چند نسخه

اگر پروژه روی چند نسخه زبان یا فریم‌ورک تست می‌شود، هر نسخه در یک Worktree مجزا. تفاوت PHP ۷ و PHP ۸ به اهمیت تست چند نسخه اشاره دارد.

مقایسه پیاده‌سازی‌ها

برای مقایسه دو رویکرد پیاده‌سازی، هر رویکرد در یک Worktree. این کار، تصمیم‌گیری را ساده می‌کند.

آموزش و Onboarding

برای آموزش توسعه‌دهنده جدید، می‌توانید Worktree جداگانه برای تمرین بسازید بدون ریسک برای مخزن اصلی. توسعه وردپرس با محیط لوکال چگونه انجام می‌شود؟ به محیط‌های تمرینی اشاره دارد.

مستندسازی همزمان

اگر مستندات در همان مخزن کد است، می‌توانید یک Worktree برای مستندسازی باز کنید و همزمان کد بنویسید. برنامه کسب‌وکار (Business Plan) چگونه نوشته می‌شود؟ به اهمیت مستندسازی اشاره دارد.

GitHub Pages

برای انتشار GitHub Pages، الگوی رایج استفاده از یک Worktree روی شاخه gh-pages است. این الگو، از شاخه اصلی جدا می‌ماند.

ساختار داخلی و فایل‌ها

درک ساختار داخلی Worktree، برای استفاده حرفه‌ای ضروری است.

پوشه .git در مخزن اصلی

در مخزن اصلی، پوشه .git کامل است. داخل آن، پوشه worktrees/ وجود دارد که هر Worktree یک زیرپوشه دارد:

.git/worktrees/
  my-project-hotfix/
    gitdir
    HEAD
    ORIG_HEAD
    commondir

فایل .git در Worktree

در Worktree، به‌جای پوشه .git، یک فایل .git وجود دارد که مسیر مخزن اصلی را نشان می‌دهد:

gitdir: /home/user/my-project/.git/worktrees/my-project-hotfix

مخزن مشترک

همه Worktreeها، از یک پوشه .git/objects و .git/refs مشترک استفاده می‌کنند. یعنی:

  • یک git fetch در هر Worktree، همه Refها را به‌روز می‌کند.
  • یک کامیت در هر Worktree، در همه Worktreeها دیده می‌شود.
  • فضای دیسک، به‌طور چشمگیری کاهش می‌یابد.

Staging Area مستقل

هر Worktree، Index و HEAD مستقل دارد. یعنی تغییرات Staged در یک Worktree، در Worktree دیگر دیده نمی‌شود. این ویژگی، کار موازی را ممکن می‌کند.

تنظیمات مشترک

تنظیمات مخزن (مثل user.email، remote.origin.url) مشترک است. تنظیمات محلی Worktree (مثل core.bare) مستقل.

نمونه ساختار کامل

/home/user/
  my-project/              (Worktree اصلی، شاخه main)
    .git/
      objects/             (مشترک)
      refs/                (مشترک)
      worktrees/
        my-project-hotfix/
        my-project-feature/
  my-project-hotfix/       (Worktree دوم، شاخه hotfix)
    .git                   (فایل، نه پوشه)
  my-project-feature/      (Worktree سوم، شاخه feature)
    .git                   (فایل، نه پوشه)

محدودیت‌ها و نکات ظریف

Worktree محدودیت‌هایی دارد که باید شناخت.

یک شاخه در یک Worktree

یک شاخه نمی‌تواند در دو Worktree همزمان checked out باشد. اگر تلاش کنید، Git خطا می‌دهد:

fatal: 'main' is already checked out at '/home/user/my-project'

برای رفع، می‌توانید از --force استفاده کنید اما این کار خطرناک است و باعث تداخل تغییرات می‌شود.

Detached HEAD

می‌توانید یک Worktree در حالت Detached HEAD بسازید (روی یک کامیت خاص). این کار برای تست یا بازبینی نسخه‌های قدیمی مفید است:

git worktree add --detach ../my-project-inspect abc1234

Submodules

هر Worktree، Submoduleهای مستقل خود را دارد. یعنی باید در هر Worktree جداگانه git submodule update --init اجرا شود. این نکته در پروژه‌های با Submodule اهمیت دارد.

Hooks

هوک‌های Git در مخزن اصلی تعریف می‌شوند و در همه Worktreeها اعمال می‌شوند. این رفتار، برای استانداردسازی خوب است اما در برخی موارد ممکن است مشکل‌ساز باشد. هوک‌های سمت کلاینت در گیت‌هاب: چرا با یک فلگ ساده دور زده می‌شوند و چگونه جلوی آن را بگیریم؟ به این موضوع می‌پردازد.

Stash مشترک

Stash، مشترک بین همه Worktreeها است. یعنی git stash list در هر Worktree، همه Stashها را نشان می‌دهد. این ویژگی می‌تواند گیج‌کننده باشد.

Reflog مشترک

Reflog نیز مشترک است. یعنی تاریخچه تغییرات HEAD در همه Worktreeها در یک Reflog ذخیره می‌شود.

IDE و Worktree

برخی IDEها ممکن است Worktree را به‌عنوان مخزن مستقل تشخیص ندهند. این نکته در انتخاب ابزار اهمیت دارد.

فضای دیسک

اگرچه Worktree فضای کمتری از Clone مصرف می‌کند، اما فایل‌های کاری (مثل node_modules) در هر Worktree جداگانه هستند. یعنی اگر پروژه وابستگی‌های سنگین دارد، هر Worktree باید آن‌ها را نصب کند.

یکپارچگی با IDE و ابزارها

Worktree با اکثر IDEها و ابزارها سازگار است، اما نیازمند آگاهی از تنظیمات است.

VS Code

VS Code از Worktree پشتیبانی می‌کند. هر Worktree، یک پنجره جداگانه است. چرا Visual Studio Code استاندارد Editor صنعت شده است؟ به قابلیت‌های این IDE اشاره دارد. کدام افزونه‌های VS Code واقعاً برای توسعه ضروری‌اند؟ نیز به افزونه‌های مفید اشاره دارد.

JetBrains IDEs

IntelliJ، WebStorm و PHPStorm از Worktree پشتیبانی می‌کنند. هر Worktree، یک پروژه جداگانه در IDE است.

Terminal و Shell

در Terminal، هر Worktree یک پوشه جداگانه است. می‌توانید از ابزارهایی مانند tmux یا screen برای مدیریت چند Terminal استفاده کنید.

ابزارهای Git GUI

Sourcetree، GitKraken و Tower از Worktree پشتیبانی می‌کنند. دستورات پرکاربرد Git که هر توسعه‌دهنده باید بداند به ابزارهای مشابه اشاره دارد.

Docker و Containerها

هر Worktree می‌تواند Container مستقل خود را داشته باشد. این ویژگی در تست موازی مفید است. آموزش Docker با مثال‌های واقعی به این موضوع اشاره دارد.

CI/CD و Worktree

در GitHub Actions، هر Job معمولاً در یک Clone تازه اجرا می‌شود. اما در Self-Hosted Runnerها، می‌توان از Worktree استفاده کرد. GitHub Actions راهنمای خودکارسازی گردش کار به این موضوع اشاره دارد. ورک‌فلوهای قابل استفاده مجدد در گیت‌هاب: چرا کپی-پیست YAML، بزرگ‌ترین بدهی فنی CI/CD است؟ و هم‌روندی در گیت‌هاب اکشنز نیز به این الگوها اشاره دارند.

اشتباهات رایج

  • حذف دستی Worktree: بدون git worktree remove، Git رکورد باقی می‌ماند.
  • Checked out یک شاخه در دو Worktree: باعث خطا یا تداخل تغییرات می‌شود.
  • نادیده گرفتن Submodule: Submoduleها در هر Worktree مستقل هستند.
  • Naming ضعیف: نام‌های مبهم، مدیریت را دشوار می‌کند.
  • نبود Prune: Worktreeهای حذف‌شده به‌صورت دستی، در فهرست باقی می‌مانند.
  • نصب وابستگی‌های سنگین در هر Worktree: فضای دیسک را پر می‌کند.
  • نادیده گرفتن Stash مشترک: گیج‌کننده در کار موازی.
  • کار روی main در Worktree: بهتر است شاخه‌های موقت در Worktree استفاده شوند.
  • نبود مستندسازی: تیم نمی‌داند چه Worktreeهایی وجود دارد.
  • فراموش کردن حذف Worktree: انباشت Worktreeهای قدیمی.

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

اشتباهات پیشرفته

  • نبود Strategy: استفاده پراکنده از Worktree، مدیریت را دشوار می‌کند.
  • نادیده گرفتن Worktree در Hooks: هوک‌ها در همه Worktreeها اعمال می‌شوند.
  • Worktree روی NFS: ممکن است با مشکل Performance مواجه شود.
  • نبود Backup: از آنجا که Worktree به مخزن اصلی متصل است، Backup مخزن اصلی، همه Worktreeها را پوشش می‌دهد.
  • نادیده گرفتن .gitignore: فایل‌های موقت در هر Worktree جداگانه ذخیره می‌شوند.

الگوهای پیشرفته و مقیاس‌پذیری

Worktree در سناریوهای پیچیده، الگوهای خاص خود را دارد.

الگوی Feature + Hotfix

الگوی رایج: یک Worktree برای Feature اصلی، یک Worktree برای Hotfix. با این الگو، جابه‌جایی بین کارها آنی است.

الگوی Multi-Version

اگر پروژه از چند نسخه زبان یا فریم‌ورک پشتیبانی می‌کند، هر نسخه در یک Worktree. این الگو، تست موازی را ممکن می‌کند. تفاوت PHP ۷ و PHP ۸ به اهمیت تست چند نسخه اشاره دارد.

الگوی Code Review

برای بازبینی PR، یک Worktree موقت بسازید و پس از اتمام، حذف کنید. این الگو، کار فعلی را مختل نمی‌کند. Pull Request در GitHub راهنمای حرفه‌ای به این رویه اشاره دارد.

الگوی Submodule Development

در پروژه‌های با Submodule، می‌توانید Submodule را در Worktree جداگانه باز کنید و توسعه دهید.

الگوی Monorepo

در Monorepoها، Worktree برای کار روی چند پروژه همزمان مفید است. هر Worktree می‌تواند روی یک بخش از Monorepo کار کند.

الگوی CI/CD با Worktree

در Self-Hosted Runnerها، استفاده از Worktree به‌جای Clone تازه، زمان راه‌اندازی را کاهش می‌دهد. بهترین ابزارهای CI/CD؛ کدام برای پروژه شما مناسب است؟ به این موضوع اشاره دارد. GitLab برای تیم‌های DevOps: راهنمای کامل از CI/CD تا امنیت و انتشار نیز به الگوهای مشابه اشاره دارد.

الگوی GitOps و Worktree

در GitOps، تغییرات زیرساخت از طریق PR اعمال می‌شوند. Worktree امکان تست تغییرات را در محیط محلی فراهم می‌کند. گیت در توسعه وردپرس راهنمای حرفه‌ای به این موضوع اشاره دارد. هوک‌های سمت سرور در گیت‌هاب: چرا بیشتر تیم‌ها پتانسیل امنیتی و اتوماسیون آن را نادیده می‌گیرند؟ و وبهوک‌های گیت‌هاب: چرا بیشتر تیم‌ها از قدرت واقعی آن بی‌خبرند؟ نیز به اتوماسیون Git اشاره دارند.

مقیاس‌پذیری با Scripts

برای مدیریت چند Worktree، می‌توانید Scripts سفارشی بنویسید. مثلاً یک Script که همه Worktreeها را فهرست، به‌روزرسانی و پاک‌سازی می‌کند:

#!/bin/bash
# scripts/worktree-cleanup.sh
git worktree prune
for wt in $(git worktree list --porcelain | grep "^worktree" | cut -d" " -f2); do
  if [ "$wt" != "$PWD" ]; then
    echo "Checking $wt..."
    # منطق سفارشی
  fi
done

Cross-Repository Worktree

در برخی سناریوها، Worktree می‌تواند با چند مخزن مرتبط کار کند (مثلاً یک مخزن اصلی و چند Submodule). این الگو، پیچیدگی مدیریتی دارد اما در پروژه‌های بزرگ مفید است.

Worktree و Bare Repository

اگر مخزن اصلی Bare باشد (مثل سرورهای Git)، Worktreeها می‌توانند به آن متصل شوند. این الگو در Self-Hosted Git مفید است.

Observability

برای پایش Worktreeها، از git worktree list --porcelain و ابزارهای پایش استفاده کنید. این داده‌ها، به تصمیم‌گیری درباره پاک‌سازی کمک می‌کنند. بهترین ابزارهای مانیتورینگ سرور؛ کدام برای شما مناسب است؟ به ابزارهای پایش اشاره دارد.

پرسش‌های پرتکرار درباره Worktree

Worktree در Git چیست؟

مکانیزمی برای اتصال چند پوشه کاری به یک مخزن واحد که امکان کار موازی روی چند شاخه را بدون clone دوباره فراهم می‌کند.

تفاوت Worktree و Clone چیست؟

Clone، یک مخزن مستقل با پوشه .git کامل است. Worktree، یک پوشه کاری متصل به مخزن اصلی که از همان .git مشترک استفاده می‌کند.

چرا Worktree بهتر از Stash است؟

Stash تغییرات را موقتاً ذخیره می‌کند اما بازیابی آن ممکن است تعارض ایجاد کند. Worktree تغییرات را در جای خود نگه می‌دارد و جابه‌جایی آنی است.

چگونه Worktree جدید بسازیم؟

با دستور git worktree add ../path branch-name. برای ساخت شاخه جدید: git worktree add -b new-branch ../path main.

آیا می‌توان یک شاخه را در دو Worktree checked out کرد؟

خیر. Git اجازه نمی‌دهد. برای دور زدن، از --force استفاده نکنید چون باعث تداخل تغییرات می‌شود.

چگونه Worktree را حذف کنیم؟

با git worktree remove ../path. اگر تغییرات uncommitted دارد، با --force.

Worktree و Submodule چگونه کار می‌کنند؟

هر Worktree، Submoduleهای مستقل خود را دارد. باید در هر Worktree جداگانه git submodule update --init اجرا شود.

آیا Worktree با IDEها سازگار است؟

بله. VS Code، JetBrains IDEs و ابزارهای Git GUI از Worktree پشتیبانی می‌کنند. هر Worktree، یک پنجره یا پروژه جداگانه است.

چه زمانی از Worktree استفاده نکنیم؟

وقتی کار موازی روی چند شاخه لازم نیست. وقتی وابستگی‌های سنگین در هر Worktree باید نصب شوند و فضای دیسک محدود است.

آیا Worktree در CI/CD استفاده می‌شود؟

بله، در Self-Hosted Runnerها. با Worktree، زمان راه‌اندازی کاهش می‌یابد. GitHub Actions راهنمای خودکارسازی گردش کار به این موضوع اشاره دارد.

Worktree، ابزاری ساده اما قدرتمند برای کار موازی است. اگر تجربه‌ای در استفاده از آن دارید، به‌خصوص اگر با چالش خاصی مواجه شده‌اید، آن را در دیدگاه‌ها بنویسید. تجربه شما می‌تواند راهنمای دیگران باشد. 🌳🔀