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

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

Advanced Git tools: worktree, submodule, sparse-checkout, hooks, and LFS

این فصل جعبه‌ابزار عجیب‌وغریب Git نیست. پنج درد مشخص داریم و برای هرکدام یک ابزار تخصصی: worktree، submodule، sparse-checkout، hook و Git LFS. اگر آن درد را نداری، احتمالاً به ابزارش هم نیاز نداری.

You need a hotfix alongside unfinished work, only part of a monorepo, an independently maintained library, an early check for a recurring mistake, and versioned large files. These are different problems, so we will first identify which part of the workflow each tool changes.

۱۲بخشsections
۸۵دقیقهminutes
۱۸تمرین با پاسخsolved exercises
۵نمودارdiagrams

اول مسئله را بشناسیمName the problem before the tool

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

Imagine preparing an urgent fix, inspecting only part of a large repository, keeping an independent library beside an application, preventing a recurring mistake, and versioning large files—all at once. It is tempting to search for “an advanced Git tool,” but these are five different problems.

هر ابزار یک بُعد متفاوت را تغییر می‌دهد: worktree محل‌های کاری هم‌زمان می‌سازد؛ submodule یک مخزن مستقل را به نسخه‌ای مشخص از مخزن والد وصل می‌کند؛ sparse-checkout تعیین می‌کند چه مسیرهایی در پوشه‌ کاری دیده شوند؛ hook یک فرمان محلی را در نقطه‌ای از گردش کار اجرا می‌کند؛ و Git LFS محتوای فایل‌های بزرگ را بیرون از مخزن عادی نگه می‌دارد و در Git به آن اشاره می‌کند.

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

Each tool changes a different dimension: worktree creates concurrent working trees; submodule pins an independent repository to a specific commit; sparse-checkout chooses which paths appear in the working tree; a hook runs a local command at a workflow event; Git LFS keeps large-file payloads outside ordinary Git objects while Git stores a pointer.

We will begin each topic with a real frustration, run a small experiment, and then state the tool’s boundary. Advanced tools do not replace understanding Git’s model; they help only after we identify the right problem.

۱. اصلاح فوری، بدون به‌هم‌زدن کار نیمه‌تمام1. Make a hotfix without disturbing unfinished work

روی شاخهٔ feature/search مشغول کاری و فایل‌هایت هنوز آمادهٔ commit نیستند. ناگهان یک باگ مهم گزارش می‌شود که باید روی main اصلاح شود. stash کردن ممکن است، اما اگر این جابه‌جایی چند بار تکرار شود، احتمال اشتباه بالا می‌رود. آیا لازم است هر بار یک پوشه‌ کاری را جمع کنیم تا شاخه عوض شود؟

git worktree اجازه می‌دهد یک مخزن، چند پوشه‌ کاری داشته باشد. داده‌ها و مخزن Git مشترک‌اند، اما هر محل کاری پوشه و شاخهٔ خودش را دارد. به این ترتیب، کار نیمه‌تمام در پوشهٔ خودش می‌ماند و اصلاح فوری در پوشه‌ای دیگر انجام می‌شود.

چند working tree روی یک مخزن Git دو پوشهٔ جدا برای feature و hotfix، هر دو به دادهٔ مشترک مخزن Git وصل‌اند. feature/search working tree A hotfix working tree B shared Git repository objects · refs · config
یک مخزن، دو پوشهٔ کاری؛ تاریخچه و اشیای Git مشترک‌اند، فایل‌های در حال ویرایش جدا.One repository, two working trees: shared Git data, separate checked-out files.

برای اینکه آزمایش روی مخزن واقعی یا کاری ناتمام اثر نگذارد، یک مخزن disposable بساز:

mkdir worktree-lab
cd worktree-lab
git init -b main
git config user.name "Learner"
git config user.email "learner@example.test"
echo "base" > app.txt
git add app.txt
git commit -m "base"
git worktree add ../hotfix-lab -b hotfix
git worktree list
git -C ../hotfix-lab status

حالا در پوشهٔ اصلی یک فایل را تغییر بده و در پوشهٔ hotfix-lab فایل دیگری را. هر کدام وضعیت جداگانه دارند. شاخه‌ها و اشیای commit اما متعلق به همان مخزن مشترک‌اند.

یک محدودیت مهم: به‌طور معمول Git اجازه نمی‌دهد یک شاخه را هم‌زمان در دو worktree checkout کنی. اگر دستور می‌گوید شاخه از قبل در جای دیگری استفاده می‌شود، اول با git worktree list محلش را پیدا کن؛ با force کردن، مسئله را پنهان نکن. مستند رسمی این رفتار و فرمان‌های مدیریت worktree را توضیح می‌دهد: worktree.

بعد از تمام‌شدن کار، از ریشهٔ مخزن می‌توانی محل اضافه را با git worktree remove ../hotfix-lab حذف کنی. Git اگر آن worktree تغییر ثبت‌نشده داشته باشد از حذف عادی محافظت می‌کند. اگر پوشه را بیرون از Git پاک کرده‌ای و رکوردش مانده، ابتدا git worktree prune --dry-run را ببین؛ فقط بعد از بررسی خروجی، prune واقعی را اجرا کن. پوشه‌ای را که هنوز به تغییرهایش نیاز داری حذف نکن.

کِی استفاده نکنیم؟ اگر فقط گاهی شاخه عوض می‌کنی و stash یا commit موقت مسئله را ساده حل می‌کند، چند worktree مدیریت اضافه‌ای است. برای اجرای موازی ساختها یا اصلاح فوری کنار یک کار نیمه‌تمام، ارزشش بیشتر می‌شود.

You are midway through feature/search, with uncommitted files, when an important bug must be fixed on main. Stashing is possible, but repeated switching increases the chance of mistakes. Must we keep packing away one working tree to change branches?

git worktree lets one repository have multiple working trees. Repository data is shared, but each working location has its own directory and checked-out branch. The unfinished feature stays where it is while the hotfix happens elsewhere.

Run the commands above in a disposable repository. Change different files in the original directory and hotfix-lab; each location has its own status, while commits and repository objects belong to the same repository.

Important limit: Git normally prevents the same branch from being checked out in two worktrees at once. If a command says the branch is already in use, locate it with git worktree list; do not hide the problem with force. The official git-worktree documentation describes this behavior and the management commands.

When finished, remove the additional location from the main repository with git worktree remove ../hotfix-lab. Git protects a worktree with uncommitted changes from ordinary removal. If you deleted its directory outside Git, inspect git worktree prune --dry-run before pruning stale records. Do not prune a worktree that is merely on a temporarily disconnected drive.

When not to use it: if you switch branches occasionally and stash or a temporary commit is simple, extra worktrees add management overhead. They are more useful for parallel builds or a hotfix beside unfinished work.

۲. کتابخانهٔ جداگانه را به نسخهٔ مشخص وصل کنیم2. Pin an independent library to a specific version

تیم یک کتابخانهٔ داخلی دارد که تاریخچه، دسترسی و انتشار خودش را دارد. کپی‌کردن فایل‌هایش داخل برنامه، ارتباط با مخزن اصلی را از بین می‌برد. در عوض می‌توانیم آن مخزن را به‌عنوان submodule اضافه کنیم.

submodule «پوشه‌ای که Git والد همهٔ فایل‌هایش را مثل بقیه دنبال کند» نیست. والد یک gitlink نگه می‌دارد: اشاره‌ای به commit مشخص از مخزن فرزند. مسیر و نشانی اولیهٔ مخزن فرزند هم در .gitmodules ثبت می‌شود. تاریخچه و commitهای کتابخانه همچنان در مخزن خودش‌اند.

To add one, run git submodule add URL vendor/library with a reachable child-repository URL in a disposable parent repository. Inspect the staged .gitmodules and gitlink, then commit them in the parent. The URL here is a placeholder, not a working public repository.

git submodule add URL vendor/library
git status --short
git diff --cached -- .gitmodules
git commit -m "Add library submodule"
رابطهٔ مخزن والد و submodule مخزن والد در commit خود به یک commit ثابت در مخزن فرزند اشاره می‌کند؛ فایل gitmodules مسیر و URL را نگه می‌دارد. parent repository .gitmodules: path + URL gitlink: child commit ID child repository its own commits + branches checked out at pinned commit
والد، مسیر و URL را معرفی می‌کند و یک commit فرزند را pin می‌کند؛ مالکیت تاریخچه جدا می‌ماند.The parent records a path, URL, and pinned child commit; histories remain separate.

فردی که مخزن والد را تازه می‌گیرد، ممکن است پوشهٔ submodule را خالی ببیند؛ چون clone معمولی لزوماً محتوای فرزند را checkout نمی‌کند. برای دریافت همهٔ submoduleهای تو‌در‌تو:

git clone --recurse-submodules URL
# یا پس از clone معمولی:
git submodule update --init --recursive
git submodule status

در خروجی وضعیت، پیشوندها سرنخ‌اند: - یعنی هنوز initialize نشده، + یعنی commit checkout‌شده با commit ثبت‌شده در والد فرق دارد، و فاصله یعنی با نسخهٔ ثبت‌شده هم‌خوان است. به‌روزرسانی معمول submodule می‌تواند آن را روی commit مشخص و جداشده HEAD بگذارد؛ این به‌خودی‌خود خطا نیست. مستندات رسمی، رفتار clone، update و وضعیت را شرح می‌دهند: submodule و gitsubmodules.

اگر می‌خواهی نسخهٔ کتابخانه را جلو ببری، وارد پوشهٔ فرزند شو، شاخهٔ مناسب را checkout کن، تغییر را در خود مخزن فرزند commit و به مخزن راه دور آن push کن. بعد برگرد به والد و تغییر gitlink را commit کن. اگر commit فرزند را push نکنی، هم‌تیمی‌ها شاید به commit اشاره‌شده دسترسی نداشته باشند.

کِی استفاده نکنیم؟ اگر وابستگی نسخهٔ بسته‌بندی‌شده و مدیریت‌شده‌ای دارد، package مدیر معمولاً نصب و انتشار ساده‌تری می‌دهد. submodule وقتی معنادار است که واقعاً می‌خواهی کد و تاریخچهٔ آن مخزن مستقل بماند ولی پروژه روی یک commit مشخص تکیه کند.

Suppose another team owns an internal library with its own history, access rules, and releases. Copying its files into your application loses the link to its source repository. A submodule can instead connect the repositories while keeping their ownership separate.

A submodule is not an ordinary directory whose files the parent tracks normally. The parent stores a gitlink—a reference to a particular commit in the child repository—and records the child path and initial URL in .gitmodules. The child keeps its own commits and branches.

A fresh clone may show an empty submodule directory because the child has not yet been checked out. Use the recursive clone command above, or initialize an existing clone. In git submodule status, - means uninitialized, + means the checked-out commit differs from the parent’s recorded commit, and a leading space indicates a match. Updating commonly checks out the pinned commit in detached-HEAD state; that is not automatically an error. See the official git-submodule and gitsubmodules references.

To advance the library, work inside the child repository: check out the intended branch, commit there, and push to its remote. Then return to the parent and commit the updated gitlink. If the child commit is not pushed, teammates may be unable to retrieve the commit the parent references.

When not to use it: if the dependency is released and managed by a package manager, that is usually simpler. A submodule makes sense when the child’s repository and history should remain independent while the parent pins an exact commit.

۳. مخزن بزرگ است؛ همهٔ فایل‌ها را لازم نداریم3. A large repository does not mean every file is needed

در یک monorepo چندین سرویس وجود دارد، اما تو فقط روی services/catalog کار می‌کنی. حذف بقیه با دست، فایل‌ها را از دید Git پنهان نمی‌کند و دوباره‌سازی محیط هم شکننده می‌شود. sparse-checkout مشخص می‌کند کدام مسیرها در پوشه‌ کاری ظاهر شوند.

از کل درخت پروژه تا working tree انتخابی مخزن شامل چند سرویس و مستندات است، اما working tree فقط مسیر انتخاب‌شده و مسیرهای سطح بالا را نشان می‌دهد. repository tree services/catalog · included services/billing · omitted docs · omitted working tree catalog + selected roots other paths stay in repository
انتخاب sparse-checkout روی فایل‌های پوشه‌ کاری اثر می‌گذارد؛ مسیرهای دیگر از تاریخچه حذف نمی‌شوند.Sparse checkout shapes the working tree; it does not erase other paths from repository history.

در مخزن آزمایشی‌ای که مسیرهای services/catalog، services/billing و docs دارد، از حالت cone استفاده کن:

git sparse-checkout init --cone
git sparse-checkout set services/catalog
git sparse-checkout list
git status --short
git ls-tree --name-only HEAD

حالت cone انتخاب را حول پوشه‌ها نگه می‌دارد و شکل ساده‌تر و قابل‌پیش‌بینی‌تری دارد؛ این حالت پیش‌فرض مستندات فعلی است. مسیرهای سطح بالا نیز ممکن است دیده شوند. فایل‌های بیرون الگو در پوشه‌ کاری حاضر نیستند، اما commitها همچنان در مخزن‌اند. قبل از تغییر الگو، فایل‌های محلی مهم را بررسی کن: تغییر قوانین sparse می‌تواند فایل‌های نادیده‌گرفته‌شده‌ای را که زیر مسیر حذف‌شونده‌اند پاک کند.

نکتهٔ ظریف: sparse-checkout به‌تنهایی تضمین نمی‌کند clone اولیه حجم کمتری از شبکه بگیرد؛ عمدتاً شکل پوشه‌ کاری را کنترل می‌کند. برای دریافت تدریجی محتوای فایل‌ها، partial clone را جداگانه بررسی می‌کنیم:

git clone --filter=blob:none --sparse URL
cd repository
git sparse-checkout set services/catalog

--filter=blob:none دریافت blobها را تا زمان نیاز به تعویق می‌اندازد، اگر سرور از فیلتر پشتیبانی کند؛ Git ممکن است بعداً برای نمایش یا checkout فایل، آن داده را بگیرد. پس sparse انتخاب مسیر است و partial clone انتخاب میزان دریافت شیء؛ یکی را به‌جای دیگری فرض نکن. مرجع‌ها: sparse-checkout و clone.

کِی استفاده نکنیم؟ در مخزن کوچک، پیچیدگی الگوها سودی ندارد. برای monorepo بزرگ و کار محدود به چند پوشه مفید است؛ اگر مسئله حجم انتقال اولیه است، باید filtering را هم جداگانه ارزیابی کنی.

A monorepo contains several services, but you work only on services/catalog. Manually deleting the other directories is fragile and does not tell Git to ignore them. Sparse checkout selects which paths appear in your working tree.

In a disposable repository containing services/catalog, services/billing, and docs, try cone mode with the commands above. Cone mode selects directories and is the default in current documentation. Top-level paths may also appear. Excluded files remain in repository history, but changing the sparse patterns can remove ignored files beneath directories that are no longer selected—inspect local files first.

A subtle distinction: sparse checkout alone does not guarantee that the initial clone transfers fewer objects; it primarily shapes the working tree. Partial clone separately defers blob downloads with --filter=blob:none, when the server supports filtering. Git may fetch those objects later when needed. Sparse checkout chooses paths; partial clone filters object transfer. See git-sparse-checkout and git-clone.

When not to use it: pattern management is not worth it for a small repository. It helps in a large monorepo when work is limited to a few directories; if the problem is initial transfer size, evaluate filtering separately.

۴. اشتباه تکراری را زودتر متوقف کنیم4. Catch a recurring mistake earlier

در تیم چند بار رشتهٔ آزمایشی DEBUG_ONLY با commit وارد مخزن شده و بعداً دردسر ساخته است. یک کنترل سبک قبل از commit می‌تواند همان لپ‌تاپ را خبر کند. Git hook اسکریپتی است که در رویدادی مشخص اجرا می‌شود؛ مثلاً pre-commit قبل از ساخت commit، یا commit-msg برای بررسی پیام.

hook محلی میان درخواست commit و ساخت commit درخواست commit به pre-commit می‌رسد؛ کد صفر اجازهٔ ادامه می‌دهد و کد غیرصفر commit را متوقف می‌کند. git commit request pre-commit hook check staged changes exit 0 commit proceeds non-zero commit stops
hook محلی می‌تواند جلوی ادامهٔ یک عملیات را بگیرد؛ تضمین سازمانی یا جایگزین CI نیست.A local hook can stop an operation; it is not an organization-wide guarantee or a CI replacement.

در ریشهٔ مخزن آزمایشی، این hook کوچک را بساز. این فقط یک نمونهٔ آموزشی برای محتوای آماده‌شده است:

mkdir .githooks
cat > .githooks/pre-commit <<'EOF'
#!/bin/sh
if git diff --cached --unified=0 | grep '^+' | grep -F 'DEBUG_ONLY' >/dev/null; then
  echo "Remove DEBUG_ONLY from staged changes." >&2
  exit 1
fi
exit 0
EOF
chmod +x .githooks/pre-commit
git config core.hooksPath .githooks

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

برای اجراشدن، hook باید executable باشد و مسیر hooks درست پیکربندی شده باشد. می‌توانی مسیر را با git config --get core.hooksPath بررسی کنی. Git hookهای مخزن را به‌طور خودکار برای clone جدید فعال نمی‌کند؛ و درست هم همین است، چون اجرای خودکار اسکریپت دریافت‌شده می‌تواند ناامن باشد. همچنین کاربر محلی می‌تواند بعضی hookها را با گزینهٔ --no-verify دور بزند. پس hook برای بازخورد سریع خوب است، اما قانون مهم باید در CI یا سمت سرور هم بررسی شود. جزئیات hookها و نقاط اجرای آن‌ها در مستند رسمی githooks آمده است.

کِی استفاده نکنیم؟ برای سیاستی که باید همه رعایت کنند، به hook محلی تنها تکیه نکن. از hook برای کنترل سریع و کم‌هزینه روی دستگاه توسعه‌دهنده استفاده کن و کنترل نهایی را جای قابل‌اعتمادتر اجرا کن.

A team has repeatedly committed the temporary marker DEBUG_ONLY. A lightweight local check can catch it before the commit is created. A Git hook is a script invoked at a workflow event, such as pre-commit or commit-msg.

Create the small teaching hook shown above in a disposable repository. Stage a line containing the marker and try to commit: the hook should print a message and return nonzero, so no commit is created while the staged changes remain. Remove the marker, stage the correction, and retry.

The hook must be executable and Git must be configured to use its directory; check git config --get core.hooksPath. Git does not automatically enable repository hooks in a fresh clone, which avoids silently running received code. A local user can also bypass some hooks with --no-verify. Use hooks for fast feedback, but enforce important policy in CI or on the server. See the official githooks documentation.

When not to use it: do not rely on a local hook alone for a rule everyone must follow. Use it for cheap developer feedback and run the authoritative check somewhere trustworthy.

۵. فایل حجیم را کجا نگه داریم؟5. Where should large files live?

در یک بازی، فایل‌های PSD و ویدیوی خام چندصد مگابایت‌اند. هر تغییرشان می‌تواند اندازهٔ clone و تاریخچه را سنگین کند. Git برای متن و فایل‌های معمول عالی است، اما نگهداری نسخه‌های متعدد از فایل‌های دودویی حجیم می‌تواند برای مخزن و تیم هزینه‌ساز شود.

Git LFS در Git یک فایل اشاره‌گر کوچک نگه می‌دارد که شناسه و اندازهٔ محتوای واقعی را توصیف می‌کند. محتوای اصلی در سرویس LFS ذخیره می‌شود. هنگام checkout، فیلترهای LFS می‌توانند محتوای واقعی را دریافت کنند و هنگام push، Git LFS آن محتوای اصلی را به endpoint مربوط می‌فرستد. پس Git معمولی به‌تنهایی کل انتقال و میزبانی LFS را تضمین نمی‌کند؛ نصب ابزار و پشتیبانی میزبان و دسترسی شبکه/سهمیه هم لازم است.

Git LFS pointer و محتوای حجیم مخزن Git نسخهٔ pointer را نگه می‌دارد و سرویس LFS فایل حجیم را؛ clone و push با کمک فیلتر و فرایند LFS محتوا را منتقل می‌کنند. Git repository small pointer object ID + size LFS storage large binary payload served by LFS endpoint push payload fetch payload
Git تاریخچهٔ اشاره‌گر را ثبت می‌کند؛ سرویس LFS محتوای حجیم را نگه می‌دارد و ابزار LFS این دو را هماهنگ می‌کند.Git versions the pointer; LFS storage holds the large content and the LFS client coordinates transfer.

روی مخزن disposable و میزبان سازگار، ابتدا Git LFS را نصب و برای کاربر فعال کن، سپس الگو را ثبت کن:

git lfs install
git lfs track "*.psd"
git check-attr filter diff merge -- assets/mock.psd
git add .gitattributes assets/mock.psd
git lfs ls-files
git show :assets/mock.psd

در انتهای آزمایش، نسخهٔ ناحیه‌ آماده‌سازی‌شدهٔ فایل تحت ردیابی معمولاً اشاره‌گر متنی LFS را نشان می‌دهد، نه محتوای باینری. .gitattributes باید commit شود تا هم‌تیمی‌ها همان الگو را داشته باشند. فرمان‌های track در راهنمای رسمی git-lfs-track آمده‌اند؛ معرفی پروژه و سازوکار اشاره‌گر در مخزن رسمی Git LFS است.

اگر فایل حجیم را قبل از فعال‌کردن LFS commit کرده‌ای، اجرای git lfs track فایل‌های قدیمی تاریخچه را به‌تنهایی تبدیل نمی‌کند. انتقال تاریخی نیازمند عملیات جداگانه‌ای است که شناسهٔ commitها را عوض می‌کند؛ روی مخزن مشترک بدون هماهنگی انجامش نده. برای این فصل، تاریخچهٔ واقعی را بازنویسی نمی‌کنیم.

کِی استفاده نکنیم؟ برای فایل‌های کوچک یا میزبان بدون پشتیبانی LFS، خود Git یا راهکار بسته‌بندی معمولی ساده‌تر است. LFS وقتی مناسب است که فایل‌های دودویی بزرگ واقعاً بخشی از نسخهٔ پروژه‌اند و تیم ظرفیت/سهمیهٔ ذخیره‌سازی و انتقالش را دارد.

A game project includes large PSD files and raw video. Each revision can make clones and history heavier. Git is excellent for text and ordinary files, but repeated versions of large binaries can impose substantial storage and transfer costs.

Git LFS stores a small pointer in Git describing the content’s identifier and size, while an LFS service stores the actual payload. LFS filters can fetch the content during checkout and send it to the LFS endpoint during push. Ordinary Git alone does not guarantee LFS hosting or transfer: the client, host support, network access, and quota also matter.

In a disposable repository and on a compatible host, install Git LFS, track a harmless test file, stage it, and inspect it. The staged version of a tracked file should be a small text pointer rather than the binary payload. Commit .gitattributes so teammates share the tracking rule. See the official git-lfs-track guide and Git LFS project.

If a large file was committed before LFS tracking was enabled, git lfs track does not convert old history. Historical migration is a separate operation that changes commit IDs; do not run it on a shared repository without coordination. We will not rewrite real history in this chapter.

When not to use it: ordinary Git or a packaging system is simpler for small files or a host without LFS support. LFS is appropriate when large binaries are part of the versioned project and the team can support the storage, transfer, and quota requirements.

کدام ابزار برای کدام درد؟Which tool fits which problem?

مسئلهابزار محتملچه چیزی را عوض می‌کند؟مرزش را یادت بماند
دو کار هم‌زمان روی شاخه‌های جداworktreeچند پوشه‌ کاری متصل به مخزنیک شاخه را هم‌زمان در چند محل checkout نکن
وابستگی با تاریخچه و مالکیت جداsubmoduleثبت یک commit فرزند در والدclone و به‌روزرسانی فرزند مرحلهٔ جدا دارد
کار فقط روی بخشی از monoreposparse-checkoutمجموعهٔ مسیرهای حاضر در پوشه‌ کاریبه‌تنهایی دریافت اولیهٔ شیءها را کم نمی‌کند
بازخورد محلی هنگام عملیات Githookاجرای اسکریپت در یک نقطهٔ مشخصclone آن را خودکار فعال نمی‌کند و قابل دورزدن است
فایل دودویی حجیم نسخه‌دارGit LFSاشاره‌گر در Git، محتوای اصلی در سرویس LFSبه نصب، میزبان، شبکه و سهمیه نیاز دارد
وابستگی نسخه‌ انتشار‌شده با نسخه‌بندی جاافتادهpackage مدیردریافت فایل تولیدی نسخه‌دارشاید به checkout هم‌زمان سورس وابستگی نیاز نداشته باشی
مخزن کوچک و گردش کار سادههیچ‌کدامپیچیدگی جدیدی وارد نمی‌شود«پیشرفته» بودن دلیل استفاده نیست
ProblemLikely toolWhat changes?Remember its boundary
Work on two branches concurrentlyworktreeMultiple working trees attached to one repositoryDo not check out one branch in multiple locations
Dependency with separate ownership and historysubmoduleRecords a child repository commit in the parentChild initialization and updates are separate steps
Work on only part of a monoreposparse-checkoutPaths present in the working treeDoes not by itself reduce the initial object transfer
Local feedback during a Git operationHookRuns a script at a specific workflow eventNot automatically enabled on clone; can be bypassed
Versioned large binary filesGit LFSPointer in Git, payload in LFS storageRequires client, host support, access, and quota
Released dependency with managed versionsPackage managerFetches a versioned artifactYou may not need the dependency source checked out
Small repository and simple workflowNoneAvoids introducing new complexity“Advanced” is not a reason to use a tool

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

The table separates the tools by the problem they solve and the boundary each one keeps. If the problem is still unclear, do not add another tool yet. In the final chapter, we will inspect a damaged repository; the habit of diagnosis will matter more than memorizing commands.

میز عیب‌یابی: نشانه را به مدرک وصل کنTroubleshooting desk: connect symptoms to evidence

نشانهاول چه چیزی را بررسی کنیم؟برداشت عجولانه‌ای که باید کنار گذاشت
شاخه را در worktree جدید نمی‌سازدgit worktree list؛ شاید شاخه در محل دیگری checkout استاین‌که فوراً باید force کنیم
پوشهٔ submodule خالی استgit submodule status و سپس init/updateاین‌که محتوا از commit والد حذف شده
فایل در ls-tree هست ولی در پوشه نیستقواعد git sparse-checkout list و وضعیت مسیراین‌که فایل از تاریخچه پاک شده
hook اجرا نشدcore.hooksPath، مجوز executable و نام فایلاین‌که Git hookها را از clone فعال می‌کند
فایل LFS به شکل اشاره‌گر دیده می‌شودنصب Git LFS، دسترسی endpoint و دریافت محتوای اصلیاین‌که اشاره‌گر یعنی فایل برای همیشه گم شده
push موفق بود اما محتوای اصلی در دسترس نیستپشتیبانی میزبان، دسترسی/سهمیه و خطای فرمان LFSاین‌که Git معمولی محتوای اصلی را حتماً فرستاده
فایل از قبل در تاریخچه بود و هنوز سنگین استبررسی تاریخچه و تصمیم هماهنگ برای مهاجرتاین‌که track کردن الگو، commitهای قدیمی را تغییر داده
SymptomFirst evidence to inspectDo not assume
Cannot add a worktree for a branchgit worktree list; it may already be checked out elsewhereThat force is the right first move
Submodule directory is emptygit submodule status, then initialize/updateThat the parent commit deleted its files
Path exists in the tree but not on diskgit sparse-checkout list and path statusThat the path was removed from history
Hook did not runcore.hooksPath, executable permission, and filenameThat Git enables hooks automatically on clone
LFS file appears as a pointerGit LFS installation, endpoint access, and payload fetchThat the pointer proves the file is permanently lost
Push succeeded but payload is unavailableHost support, access/quota, and LFS command errorsThat ordinary Git necessarily sent the payload
History clone remains large after trackingHistory and a coordinated migration decisionThat tracking changed old commits

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

Use the same safe order practiced in earlier chapters: inspect state, gather evidence, then change something. A command that merely hides the symptom can make the next diagnosis harder.

مینی‌پروژه: پنج درخواست از یک تیمMini-project: five requests from one team

پنج درخواست کوتاه از یک تیم می‌گیری و برای هرکدام باید تصمیم بگیری کدام ابزار واقعاً مناسب است. نکته اینجاست که «هیچ‌کدام» هم می‌تواند جواب درست باشد؛ ابزار پیشرفته فقط به خاطر جذاب‌بودنش وارد معماری نمی‌شود.

  1. hotfix در کنار feature: شاخهٔ feature تغییر staged‌نشده دارد و باید اصلاح فوری را جدا آماده کنی. دو worktree بساز، فهرستشان را ثبت کن و نشان بده هر کدام روی چه شاخه‌ای است.
  2. کتابخانهٔ متعلق به تیم دیگر: یک مخزن آزمایشی را submodule کن. در clone تازه، نبودن محتوای checkoutشده را مشاهده و با دستور recursive آن را آماده کن. commit ثبت‌شدهٔ والد را با وضعیت فرزند تطبیق بده.
  3. monorepo آزمایشی: سه پوشهٔ سرویس بساز و فقط یکی را در working tree نگه دار. تفاوت فهرست مسیر انتخابی و مسیرهای موجود در tree را با مدرک نشان بده.
  4. کنترل کیفیت سریع: hook بررسی DEBUG_ONLY را اضافه کن؛ یک بار commit را متوقف کن و بار دوم پس از اصلاح اجازه بده. در یادداشتت توضیح بده چرا تیم باز هم به CI نیاز دارد.
  5. دارایی حجیم: فقط اگر میزبان و دسترسی Git LFS داری، یک فایل آزمایشی کوچک و بی‌ارزش را track و round-trip آن را بررسی کن. اگر میزبان نداری، به‌جای جعل موفقیت، پیش‌نیازهای لازم را مستند کن و آزمایش را متوقف نگه دار.

چه وقت از هرکدام استفاده نکنیم؟ worktree را برای تعویض شاخهٔ عادی اضافه نکن؛ submodule را جای package منتشرشده نگذار؛ sparse-checkout را برای مخزن کوچک فعال نکن؛ hook محلی را مرجع نهایی سیاست تیم ندان؛ LFS را برای فایل کم‌حجم یا میزبان ناسازگار انتخاب نکن. گاهی بهترین راه، ساده‌ترین روند کار فعلی است.

پایان کار، فقط پوشه‌های آزمایشی را بعد از بررسی تغییرهایشان جمع کن. برای worktree از فرمان خود Git کمک بگیر؛ submodule یا فایل آزمایشی را از پروژهٔ واقعی حذف نکن. در گزارش، فرمان و خروجی‌ای را نگه دار که نفر بعدی بتواند انتخابت را بازبینی کند.

Use disposable repositories for these tasks; do not test removal or rewriting on a working project or valuable files. You do not need to combine all five tools in one repository. For each scenario, submit a short note: the problem, chosen tool, evidence supporting the choice, and the solution’s limitation.

  1. Hotfix beside a feature: the feature branch has unstaged work, and you need a separate urgent fix. Create two worktrees, list them, and show which branch each uses.
  2. A library owned by another team: add a test repository as a submodule. In a fresh clone, observe the uninitialized child and then initialize it recursively. Compare its checked-out commit with the parent’s recorded commit.
  3. A sample monorepo: create three service directories and keep only one in the working tree. Show evidence distinguishing selected paths from paths present in the tree.
  4. Fast local quality check: add the DEBUG_ONLY hook, block one commit, then allow a commit after fixing it. Explain why the team still needs CI.
  5. A large asset: only if your host and access support Git LFS, track a small disposable file and test a round trip. Otherwise document the prerequisites and stop without pretending the test succeeded.

When not to use each: do not add a worktree for ordinary branch switching; do not replace a published package with a submodule; do not enable sparse checkout for a tiny repository; do not treat a local hook as final team policy; and do not choose LFS for small files or an incompatible host. Sometimes the best choice is the existing simple workflow.

At the end, clean up only disposable locations after checking their changes. Use Git’s worktree command for worktrees, and do not remove a real project’s submodule or files. Keep commands and output in the report so another person can review the decision.

۱۸ تمرین حل‌شده18 solved exercises

در این تمرین‌ها انتخاب ابزار مهم‌تر از شکل دستور آن است. قبل از بازکردن پاسخ، یک جمله بنویس: «مسئلهٔ اصلی این تیم چیست؟» اگر همان جمله روشن باشد، معمولاً worktree، submodule، sparse-checkout، hook یا LFS خودش را نشان می‌دهد.

These exercises begin with recognizing a situation and build toward choosing several tools together. Decide first, then open the short hint and explanation.

۱ کار روی قابلیت نیمه‌تمام است و اصلاح فوری فوری لازم شده؛ کم‌دردسرترین مدل چیست؟A feature is unfinished and an urgent hotfix is needed. Which workflow causes the least disruption?
راهنماHint

آیا واقعاً باید همان پوشه یک شاخه را جایگزین شاخهٔ دیگر کند؟

Must the same directory replace one checked-out branch with another?

پاسخ: اگر دو شاخه باید هم‌زمان در دسترس باشند، یک worktree برای اصلاح فوری بساز. فایل‌های قابلیت در محل فعلی دست‌نخورده می‌مانند. اگر شاخه‌اش هنوز جای دیگری checkout است، اول فهرست worktreeها را بررسی کن.

Answer: Use a second worktree for the hotfix when both branches must remain available. The feature files stay in place; first check that the target branch is not already checked out elsewhere.

۲ ساخت worktree برای شاخهٔ release رد می‌شود و Git می‌گوید شاخه در worktree دیگری استفاده می‌شود. چه می‌کنی؟Git refuses a worktree for release because that branch is already in use elsewhere. What do you do?
راهنماHint

قبل از هر حذف یا force، محل checkout فعلی را پیدا کن.

Locate the current checkout before removing anything or forcing the operation.

پاسخ: git worktree list را اجرا و worktree مربوط به release را پیدا می‌کنم. اگر آن محل هنوز لازم است، شاخهٔ دیگری انتخاب می‌کنم؛ اگر تمام شده، تغییرهایش را بررسی و سپس با فرمان remove جمعش می‌کنم. force راه تشخیص نیست.

Answer: Run git worktree list, inspect the existing checkout, and either choose another branch or safely remove the finished worktree after checking its changes. Force is not diagnosis.

۳ پوشهٔ یک worktree را دستی پاک کرده‌ای، ولی هنوز در فهرست دیده می‌شود. قدم امن بعدی چیست؟You manually deleted a worktree directory, but it still appears in the list. What is the safe next step?
راهنماHint

پیش‌نمایش پاک‌سازی را پیش از اجرای واقعی ببین.

Preview the cleanup before running it for real.

پاسخ: از مخزن اصلی git worktree prune --dry-run اجرا می‌کنم و خروجی را بررسی می‌کنم؛ فقط رکوردهای stale موردنظر را بعد از اطمینان prune می‌کنم. اگر دیسک جداگانه موقتاً وصل نیست، prune نکن؛ شاید worktree فقط در دسترس نباشد.

Answer: Preview with git worktree prune --dry-run and prune only confirmed stale records. If a separate drive is merely offline, do not prune it as if it were deleted.

۴ بعد از clone، پوشهٔ کتابخانهٔ submodule خالی است. آیا commit والد فایل‌ها را حذف کرده؟After cloning, the submodule library directory is empty. Did the parent commit delete its files?
راهنماHint

وضعیت submodule را بخوان و تفاوت اشاره‌گر با محتوای checkoutشده را به یاد بیاور.

Inspect submodule status and distinguish a recorded pointer from checked-out child content.

پاسخ: لزوماً نه. ابتدا git submodule status را می‌بینم؛ سپس git submodule update --init --recursive را اجرا می‌کنم. والد commit فرزند را ثبت می‌کند، اما clone تازه ممکن است هنوز محتوای فرزند را initialize نکرده باشد.

Answer: Not necessarily. Inspect git submodule status, then initialize recursively. The parent pins a child commit, but a fresh clone may not yet have checked out child content.

۵ commit تازهٔ submodule روی رایانهٔ تو هست، اما هم‌تیمی با update نمی‌تواند آن را بگیرد. کدام مدرک را بررسی می‌کنی؟A new submodule commit exists on your machine, but a teammate cannot retrieve it during update. What evidence do you check?
راهنماHint

commit فرزند فقط در کدام مخزن وجود دارد؟

In which repository does the child commit exist?

پاسخ: بررسی می‌کنم commit در مخزن فرزند به مخزن راه دور قابل‌دسترسی push شده باشد. commit کردن gitlink در والد به‌تنهایی محتوای اصلی یا commit فرزند را به مخزن والد منتقل نمی‌کند؛ بعد از انتشار commit فرزند، اشارهٔ والد را ثبت می‌کنم.

Answer: Verify that the child commit was pushed to a remote the teammate can access. Committing the parent gitlink does not transfer the child commit into the parent repository.

۶ بعد از submodule update، داخل کتابخانه جداشده HEAD می‌بینی. آیا باید فوراً آن را اصلاح کنی؟After updating a submodule, its HEAD is detached. Must you fix this immediately?
راهنماHint

هدف والد، نسخهٔ شاخه‌ای است یا commit دقیق؟

Does the parent need a moving branch, or an exact commit?

پاسخ: نه؛ checkout روی commit pin‌شده رفتار عادی submodule است و ممکن است جداشده باشد. اگر قرار است کتابخانه را ویرایش کنم، در مخزن فرزند یک شاخه بسازم یا checkout کنم، commit و push را آن‌جا انجام دهم و سپس gitlink والد را به‌روزرسانی کنم.

Answer: No. A pinned child commit is commonly checked out detached. For edits, create or switch to a branch in the child repository, publish its commit, then update the parent gitlink.

تا اینجا پنج ابزار را جدا دیده‌ای. از اینجا تمرین‌ها اسم ابزار را پنهان می‌کنند و فقط مسئله را می‌دهند. این همان جایی است که باید جلوی وسوسهٔ «ابزار پیشرفته‌تر حتماً بهتر است» را بگیری.

You have seen five tools separately. From here the exercises hide the tool name and give only the problem. This is where you resist the temptation to assume a more advanced tool is automatically better.

۷ git ls-tree مسیری را نشان می‌دهد که در فایل‌سیستم نیست. از کجا شروع می‌کنی؟git ls-tree shows a path that is absent from the filesystem. Where do you start?
راهنماHint

آیا این clone sparse است؟

Is this a sparse checkout?

پاسخ: git sparse-checkout list و git status --short را بررسی می‌کنم. اگر مسیر از الگوهای sparse بیرون است، نبودنش در پوشه‌ کاری به معنی پاک‌شدن از commit نیست؛ الگو را آگاهانه اصلاح می‌کنم.

Answer: Check the sparse patterns and status. A path excluded from the working tree can still exist in the commit tree; adjust the pattern intentionally.

۸ برای انتخاب یک پوشهٔ سرویس، cone مجوز را انتخاب می‌کنی یا الگوهای non-cone پیچیده؟To select a service directory, would you use cone mode or complex non-cone patterns?
راهنماHint

شکل نیاز واقعاً پوشه‌محور است؟

Is the requirement naturally expressed as directory selection?

پاسخ: برای انتخاب پوشه، cone مجوز انتخاب طبیعی و ساده‌تر است: git sparse-checkout init --cone و سپس set مسیر. سراغ الگوهای پیچیده‌تر فقط وقتی می‌روم که نیاز دقیقاً با انتخاب پوشه‌ها بیان‌پذیر نباشد و محدودیت نسخهٔ Git را هم بررسی کرده باشم.

Answer: Use cone mode for directory-shaped selection. Reach for more complex patterns only when directories cannot express the requirement and the installed Git behavior has been checked.

۹ sparse-checkout را روی clone معمولی فعال کردی؛ آیا دادهٔ منتقل‌شده در clone اولیه حتماً کمتر شده؟You enabled sparse checkout after a normal clone. Did the initial clone necessarily transfer less data?
راهنماHint

پوشه‌ کاری با شیء transfer یک مفهوم نیست.

The working tree and object transfer are different concerns.

پاسخ: نه. sparse-checkout عمدتاً مسیرهای حاضر در پوشه‌ کاری را محدود می‌کند. برای کاهش دریافت blobهای اولیه، partial clone مانند --filter=blob:none را جداگانه بررسی می‌کنم؛ این راه به پشتیبانی سرور و دریافت احتمالی بعدی نیاز دارد.

Answer: No. Sparse checkout shapes the working tree. Partial clone filters object transfer separately, requires server support, and may fetch blobs later on demand.

۱۰ hook فایلش در مخزن هست اما هنگام commit اجرا نمی‌شود. سه بررسی اول چیست؟The hook file is in the repository but does not run on commit. What are your first three checks?
راهنماHint

نام، مسیر فعال و مجوز اجرا.

Check the name, active path, and executable permission.

پاسخ: نام دقیق hook، مقدار git config --get core.hooksPath و executable بودن فایل را بررسی می‌کنم. همچنین مطمئن می‌شوم Git از همان مخزنی اجرا می‌شود که تنظیم را در آن انجام داده‌ام.

Answer: Check the exact hook filename, active core.hooksPath, executable permission, and that Git is running in the repository with that configuration.

۱۱ hook در رایانهٔ تو اجرا می‌شود ولی هم‌تیمی با clone تازه آن را نمی‌بیند. چه چیزی جا افتاده؟The hook runs on your machine, but a teammate does not get it in a fresh clone. What is missing?
راهنماHint

commit شدن اسکریپت و فعال‌سازی hook یک مرحله نیستند.

Committing a script and enabling a hook are separate steps.

پاسخ: Git hookهای داخل پروژه را به‌طور خودکار فعال نمی‌کند. باید راه setup امن و روشن برای تنظیم core.hooksPath داشته باشیم یا ابزار تیم این کار را انجام دهد؛ کنترل ضروری را هم در CI بگذاریم، چون hook محلی قابل دورزدن است.

Answer: Git does not automatically enable repository hooks on clone. Provide an explicit safe setup path and enforce required checks in CI because local hooks can be bypassed.

۱۲ hook با کد خروج غیرصفر commit را متوقف کرده است. آیا تغییرهای آماده‌شده از بین رفته‌اند؟A hook returned nonzero and stopped the commit. Were the staged changes lost?
راهنماHint

ردشدن عملیات با حذف ناحیه‌ آماده‌سازی یکی نیست.

A rejected operation is not the same as deleting the index.

پاسخ: معمولاً نه؛ commit ساخته نشده و تغییرهای آماده‌شده برای اصلاح باقی می‌مانند. git status را می‌خوانم، علت را رفع می‌کنم، فایل را دوباره ناحیه‌ آماده‌سازی می‌کنم و commit را تکرار می‌کنم.

Answer: Usually not. The commit was blocked while staged changes remain available. Inspect status, fix the cause, stage the correction, and retry.

تمرین‌های آخر عمداً مرز ابزارها را می‌سنجند. sparse-checkout جای partial clone را نمی‌گیرد، submodule یک پوشهٔ معمولی نیست و LFS تاریخچهٔ قدیمی را با یک track ساده پاک نمی‌کند.

The final exercises deliberately test tool boundaries. Sparse-checkout is not a substitute for partial clone, a submodule is not an ordinary folder, and simply tracking with LFS does not erase old large-file history.

۱۳ checkout یک فایل را به شکل اشاره‌گر متنی نشان می‌دهد. از کجا بفهمیم فایل خراب است یا محتوای اصلی دریافت نشده؟A checkout shows a file as a text pointer. How can you tell whether it is corrupt or its payload was not fetched?
راهنماHint

اشاره‌گر در LFS نمایندهٔ محتواست؛ مسیر انتقال را بررسی کن.

An LFS pointer represents content; inspect the transfer path.

پاسخ: ابتدا git lfs ls-files و نصب Git LFS را بررسی می‌کنم، سپس دسترسی endpoint، خطای smudge/fetch و وضعیت شبکه را می‌سنجم. اشاره‌گر به‌تنهایی مدرک گم‌شدن فایل نیست؛ اگر endpoint در دسترس نیست، آن را گزارش می‌کنم و وانمود نمی‌کنم محتوای اصلی موجود است.

Answer: Check LFS installation and tracked files, then endpoint access and fetch/smudge errors. A pointer alone does not prove loss; report unavailable storage rather than claiming the payload exists.

۱۴ Git push موفق شده ولی هم‌تیمی محتوای اصلی فایل حجیم را نمی‌گیرد. چه تفاوتی را باید در نظر گرفت؟Git push succeeded, but a teammate cannot get the large-file payload. What distinction matters?
راهنماHint

موفقیت انتقال Git و سرویس LFS را یکی نگیر.

Do not conflate Git transfer success with LFS service success.

پاسخ: push عادی commit و اشاره‌گر را منتقل می‌کند؛ محتوای اصلی ممکن است از endpoint جداگانهٔ LFS بیاید. پشتیبانی میزبان، دسترسی، سهمیه و خروجی Git LFS را بررسی می‌کنم. تا رفع آن، تحویل فایل را موفق اعلام نمی‌کنم.

Answer: A normal Git push transfers commits and pointers; the payload uses the LFS endpoint. Check host support, access, quota, and LFS output before declaring delivery successful.

۱۵ امروز git lfs track "*.psd" را اجرا کردی، اما clone تاریخچه هنوز حجیم است. چرا؟You ran git lfs track "*.psd" today, but cloning history is still large. Why?
راهنماHint

الگوی آینده تاریخچهٔ گذشته را بازنویسی نمی‌کند.

A rule for future files does not rewrite past history.

پاسخ: track کردن، قواعد attribute را برای فایل‌های بعدی ثبت می‌کند؛ commitهای قدیمی را مهاجرت نمی‌دهد. تبدیل تاریخچه ابزار جداگانه و بازنویسی شناسه‌ها می‌خواهد و باید با همهٔ مصرف‌کنندگان مخزن هماهنگ شود. در مخزن مشترک بی‌اجازه اجرا نمی‌کنم.

Answer: Tracking changes future attributes, not old commits. Historical migration rewrites object IDs and needs coordination with every consumer; do not run it casually on a shared repository.

۱۶ قانون شرکت می‌گوید هیچ commitی نباید تست‌های لازم را دور بزند. hook محلی کافی است؟Company policy says no commit may bypass required tests. Is a local hook enough?
راهنماHint

چه کسی می‌تواند hook محلی را حذف یا دور بزند؟

Who can remove or bypass a local hook?

پاسخ: کافی نیست. hook برای بازخورد زودهنگام است و می‌تواند غیرفعال یا دور زده شود. تست الزامی را در CI یا سیاست سمت سرور اعمال می‌کنم و hook را فقط کمک محلی می‌دانم.

Answer: No. Local hooks improve feedback but can be disabled or bypassed. Enforce mandatory checks in CI or server-side policy.

۱۷ یک کتابخانه نسخهٔ نسخه‌ انتشار دارد و از registry نصب می‌شود؛ آیا submodule انتخاب اول است؟A library has releases and is installed from a registry. Is a submodule the first choice?
راهنماHint

آیا واقعاً به checkout سورس در commit دقیق نیاز داریم؟

Do you actually need the source checked out at an exact commit?

پاسخ: معمولاً package مدیر ساده‌تر است؛ نسخهٔ نسخه‌ انتشار را مانند وابستگی‌های دیگر می‌گیرد. submodule زمانی ارزش دارد که اتصال مستقیم به commit مخزن فرزند یا روند کار توسعهٔ هم‌زمان سورس لازم باشد.

Answer: Usually prefer the package manager for a released dependency. A submodule is justified when the parent needs a precise child commit or coordinated source development.

۱۸ در monorepo، هم‌زمانی اصلاح فوری لازم است، checkout فقط یک سرویس می‌خواهی و فایل‌های ویدیویی حجیم هم داری. ابزارها را چگونه از هم تفکیک می‌کنی؟In a monorepo, you need a concurrent hotfix, only one service checked out, and large video files. How do you assign tools to these needs?
راهنماHint

هر ابزار فقط یک بُعد از مسئله را پاسخ می‌دهد.

Each tool addresses only one dimension of the problem.

پاسخ: برای اصلاح فوری موازی worktree؛ برای محدودکردن مسیرهای حاضر در پوشه‌ کاری، sparse-checkout؛ و فقط اگر میزبان و سهمیه پشتیبانی می‌کند، برای فایل‌های بزرگ Git LFS. اگر کاهش دریافت اولیه هم لازم است، partial clone را جدا می‌سنجم. هیچ‌کدام جای دیگری را نمی‌گیرد و لازم نیست همه را فعال کنیم.

Answer: Use a worktree for parallel hotfix work, sparse checkout for the selected working-tree paths, and LFS for large files only with supported storage and quota. Evaluate partial clone separately for initial transfer; none substitutes for another.

حالا نوبت اتاق نجات استNext: the repository rescue room

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

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

This chapter introduced tools that change working locations, repository boundaries, visible files, local checks, or large-payload storage. None is magic: a worktree does not protect uncommitted changes; a submodule cannot make an unpublished child commit available; sparse checkout does not erase paths from history; a local hook is not universal policy; and LFS cannot transfer a file without a service and access.

The final chapter will not ask you to blindly repeat a new command. We will inspect a troubled repository, collect evidence, and decide what can safely be done—and where we should stop. Good tooling starts with good diagnosis.

برگهٔ همراهQuick reference

ابزاربرای چه؟مدرک شروعاحتیاط
worktreeworking treeهای موازیgit worktree listپیش از حذف، تغییرها را بررسی کن
submoduleاتصال به commit مخزن مستقلgit submodule statusفرزند باید قابل‌دسترسی و initialize باشد
sparse-checkoutانتخاب مسیرهای پوشه‌ کاریgit sparse-checkout listبا partial clone یکی نیست
hookبازخورد محلی هنگام عملیاتcore.hooksPath و مجوز اجراکنترل ضروری را در CI هم داشته باش
Git LFSمدیریت فایل‌های حجیمgit lfs ls-filesendpoint، دسترسی و سهمیه لازم است
ToolUseFirst evidenceCaution
worktreeConcurrent working treesgit worktree listInspect changes before removal
submodulePin a commit from an independent repositorygit submodule statusChild must be accessible and initialized
sparse-checkoutSelect working-tree pathsgit sparse-checkout listNot the same as partial clone
HookLocal feedback during an operationcore.hooksPath and executable bitEnforce required checks in CI too
Git LFSManage large filesgit lfs ls-filesEndpoint, access, and quota are required

قاعدهٔ این فصل ساده است: اول درد و مدرک، بعد ابزار؛ و اگر ساده‌ترین راه جواب می‌دهد، همان را نگه دار.

The rule is simple: identify the problem and evidence before choosing a tool. If the simplest workflow works, keep it.