'\" t .\" Title: git-filter-branch .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 2026-06-29 .\" Manual: Git Manual .\" Source: Git 2.55.0 .\" Language: English .\" .TH "GIT\-FILTER\-BRANCH" "1" "2026\-06\-29" "Git 2\&.55\&.0" "Git Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "نام (NAME)" git-filter-branch \- بازنویسی شاخه‌ها .SH "خلاصه دستور (SYNOPSIS)" .sp .nf \fIgit filter\-branch\fR [\-\-setup ] [\-\-subdirectory\-filter ] [\-\-env\-filter ] [\-\-tree\-filter ] [\-\-index\-filter ] [\-\-parent\-filter ] [\-\-msg\-filter ] [\-\-commit\-filter ] [\-\-tag\-name\-filter ] [\-\-prune\-empty] [\-\-original ] [\-d ] [\-f | \-\-force] [\-\-state\-branch ] [\-\-] [\&...] .fi .sp .SH "هشدار (WARNING)" .sp دستور \fIgit filter\-branch\fR دارای دام‌های فراوانی است که می‌توانند منجر به خرابی‌های غیرواضح در بازنویسی هدفمند تاریخچه شوند (و به دلیل کارایی بسیار ضعیف آن، زمان اندکی برای بررسی چنین مشکلاتی برایتان باقی می‌گذارد)\&. این مسائل امنیتی و عملکردی را نمی‌توان با حفظ سازگاری با گذشته اصلاح کرد و به همین دلیل، استفاده از آن توصیه نمی‌شود\&. لطفاً از یک ابزار جایگزین برای فیلتر کردن تاریخچه مانند \m[blue]\fBgit filter\-repo\fR\m[]\&\s-2\u[1]\d\s+2 استفاده کنید\&. اگر همچنان نیاز به استفاده از \fIgit filter\-branch\fR دارید، لطفاً بخش «امنیت (SAFETY)» (و بخش «کارایی (PERFORMANCE)») را به دقت بخوانید تا با خطرات پنهان filter\-branch آشنا شوید، و سپس تا جای ممکن و هوشیارانه از خطرات ذکرشده در آنجا اجتناب کنید\&. .SH "توضیحات (DESCRIPTION)" .sp به شما امکان می‌دهد تا با بازنویسی شاخه‌های ذکرشده در و اعمال فیلترهای سفارشی روی هر بازنگری، تاریخچه بازنگری‌های گیت را بازنویسی کنید\&. این فیلترها می‌توانند هر درخت (مانند حذف یک فایل یا اجرای یک اسکریپت بازنویسی perl روی تمام فایل‌ها) یا اطلاعات مربوط به هر کامیت را تغییر دهند\&. در غیر این صورت، تمام اطلاعات (از جمله زمان‌های اصلی کامیت یا اطلاعات ادغام) حفظ خواهند شد\&. .sp این دستور تنها ارجاع‌های \fIمثبت\fR ذکرشده در خط فرمان را بازنویسی خواهد کرد (برای مثال، اگر \fIa\&.\&.b\fR را بدهید، تنها \fIb\fR بازنویسی می‌شود)\&. اگر هیچ فیلتری مشخص نکنید، کامیت‌ها بدون هیچ تغییری دوباره ثبت می‌شوند که در حالت عادی هیچ اثری نخواهد داشت\&. با این وجود، این کار ممکن است در آینده برای جبران برخی باگ‌های گیت یا موارد مشابه مفید باشد، بنابراین چنین کاربردی مجاز است\&. .sp \fBنکته\fR: این دستور فایل \fB\&.git/info/grafts\fR و ارجاع‌های موجود در فضای نام \fBrefs/replace/\fR را محترم می‌شمارد\&. اگر پیوندها (grafts) یا ارجاع‌های جایگزینی تعریف کرده باشید، اجرای این دستور آن‌ها را دائمی خواهد کرد\&. .sp \fBهشدار\fR! تاریخچه بازنویسی‌شده دارای شناسه‌های شیء متفاوتی برای تمامی اشیاء خواهد بود و با شاخه اصلی همگرا نخواهد شد\&. شما نمی‌توانید به آسانی شاخه بازنویسی‌شده را روی شاخه اصلی ارسال (push) و توزیع کنید\&. اگر پیامدهای کامل آن را نمی‌دانید لطفاً از این دستور استفاده نکنید، و در هر صورت اگر یک کامیت ساده تکی برای حل مشکلتان کفایت می‌کند، از به‌کارگیری آن بپرهیزید\&. (برای اطلاعات بیشتر پیرامون بازنویسی تاریخچه منتشرشده، بخش "RECOVERING FROM UPSTREAM REBASE" را در \fBgit-rebase\fR(1) ببینید\&.) .sp همیشه بررسی کنید که نسخه بازنویسی‌شده درست باشد: ارجاع‌های اصلی، در صورتی که با ارجاع‌های بازنویسی‌شده متفاوت باشند، در فضای نام \fIrefs/original/\fR ذخیره خواهند شد\&. .sp توجه داشته باشید که از آنجا که این عملیات از نظر ورودی/خروجی (I/O) بسیار سنگین است، انتقال مسیر پوشه موقت به خارج از دیسک با گزینه \fB\-d\fR (برای مثال روی tmpfs) ایده خوبی خواهد بود\&. طبق گزارش‌ها، افزایش سرعت بسیار چشمگیر است\&. .SS "فیلترها (Filters)" .sp فیلترها به ترتیبی که در زیر آمده اعمال می‌شوند\&. آرگومان همیشه در محیط پوسته با استفاده از دستور \fIeval\fR ارزیابی می‌شود (به استثنای فیلتر commit، به دلایل فنی)\&. پیش از آن، متغیر محیطی \fB$GIT_COMMIT\fR طوری تنظیم می‌شود که شامل شناسه کامیت در حال بازنویسی باشد\&. همچنین GIT_AUTHOR_NAME، GIT_AUTHOR_EMAIL، GIT_AUTHOR_DATE، GIT_COMMITTER_NAME، GIT_COMMITTER_EMAIL و GIT_COMMITTER_DATE از کامیت جاری گرفته شده و به متغیرهای محیطی صادر می‌شوند تا هویت پدیدآورنده و ثبت‌کننده کامیت جایگزین که توسط \fBgit-commit-tree\fR(1) پس از اجرای فیلترها ایجاد می‌شود را تحت تأثیر قرار دهند\&. .sp اگر هر گونه ارزیابی وضعیت خروج غیر صفر برگرداند، کل عملیات متوقف خواهد شد\&. .sp یک تابع \fImap\fR در دسترس است که یک آرگومان "شناسه sha1 اصلی" را می‌گیرد و اگر کامیت قبلاً بازنویسی شده باشد "شناسه sha1 بازنویسی‌شده" و در غیر این صورت "شناسه sha1 اصلی" را خروجی می‌دهد؛ اگر فیلتر commit شما چندین کامیت تولید کرده باشد، تابع \fImap\fR می‌تواند چندین شناسه را در خطوط جداگانه برگرداند\&. .SH "گزینه‌ها (OPTIONS)" .PP \-\-setup .RS 4 این یک فیلتر واقعی که برای هر کامیت اجرا شود نیست، بلکه یک راه‌اندازی یک‌باره درست پیش از آغاز حلقه است\&. بنابراین هنوز هیچ متغیر ویژه کامیت تعریف نشده است\&. توابع یا متغیرهای تعریف‌شده در اینجا را می‌توان در مراحل فیلتر بعدی استفاده کرد یا تغییر داد (به دلایل فنی، به جز فیلتر commit)\&. .RE .PP \-\-subdirectory\-filter .RS 4 تنها تاریخچه‌ای را بررسی می‌کند که زیرپوشه داده‌شده را لمس کرده باشد\&. نتیجه شامل آن پوشه (و تنها همان) به عنوان ریشه پروژه خواهد بود\&. مستلزم بخش موسوم به «نگاشت مجدد به نیای والد» است\&. .RE .PP \-\-env\-filter .RS 4 اگر تنها نیاز به تغییر محیطی دارید که کامیت در آن انجام خواهد شد، این فیلتر می‌تواند استفاده شود\&. به طور خاص، ممکن است بخواهید متغیرهای محیطی مربوط به نام/رایانامه/زمان پدیدآورنده/ثبت‌کننده را بازنویسی کنید (برای جزئیات \fBgit-commit-tree\fR(1) را ببینید)\&. .RE .PP \-\-tree\-filter .RS 4 این فیلتر برای بازنویسی درخت و محتویات آن است\&. آرگومان در پوسته همراه با تنظیم پوشه کاری بر روی ریشه درخت تحویل‌گرفته‌شده ارزیابی می‌شود\&. سپس درخت جدید همان‌گونه که هست به کار می‌رود (فایل‌های جدید به طور خودکار اضافه می‌شوند، فایل‌های ناپدیدشده به طور خودکار حذف می‌شوند \- نه فایل‌های \&.gitignore و نه هیچ قانون نادیده‌گرفتن دیگری \fBهیچ اثری ندارند\fR!)\&. .RE .PP \-\-index\-filter .RS 4 این فیلتر برای بازنویسی نمایه (index) است\&. این فیلتر شبیه فیلتر tree است اما درخت را تحویل (checkout) نمی‌گیرد، که این موضوع آن را بسیار سریع‌تر می‌کند\&. به طور مکرر همراه با \fBgit\fR \fBrm\fR \fB\-\-cached\fR \fB\-\-ignore\-unmatch\fR \&.\&.\&. استفاده می‌شود، بخش مثال‌ها در زیر را ببینید\&. برای موارد پیچیده‌تر، \fBgit-update-index\fR(1) را ببینید\&. .RE .PP \-\-parent\-filter .RS 4 این فیلتر برای بازنویسی فهرست والد کامیت است\&. رشته والد را در ورودی استاندارد دریافت خواهد کرد و باید رشته والد جدید را در خروجی استاندارد ارائه دهد\&. رشته والد در قالبی است که در \fBgit-commit-tree\fR(1) شرح داده شده است: خالی برای کامیت اولیه، "\-p parent" برای یک کامیت عادی و "\-p parent1 \-p parent2 \-p parent3 \&..." برای یک کامیت ادغام\&. .RE .PP \-\-msg\-filter .RS 4 این فیلتر برای بازنویسی پیام‌های کامیت است\&. آرگومان در پوسته همراه با پیام کامیت اصلی در ورودی استاندارد ارزیابی می‌شود؛ خروجی استاندارد آن به عنوان پیام کامیت جدید استفاده خواهد شد\&. .RE .PP \-\-commit\-filter .RS 4 این فیلتر برای انجام خود کامیت است\&. اگر این فیلتر مشخص شود، به جای دستور \fIgit commit\-tree\fR همراه با آرگومان‌هایی در قالب " [(\-p )\&...]" و پیام لاگ در ورودی استاندارد فراخوانی خواهد شد\&. انتظار می‌رود شناسه کامیت در خروجی استاندارد چاپ شود\&. .sp به عنوان یک گسترش ویژه، فیلتر commit ممکن است چندین شناسه کامیت تولید کند؛ در آن صورت، فرزندان بازنویسی‌شده کامیت اصلی همه آن‌ها را به عنوان والد خواهند داشت\&. .sp می‌توانید از تابع کمکی \fImap\fR و همچنین سایر توابع کمکی در این فیلتر استفاده کنید\&. برای مثال، فراخوانی \fIskip_commit "$@"\fR کامیت جاری را حذف خواهد کرد (اما نه تغییرات آن را! اگر چنان چیزی می‌خواهید، در عوض از \fIgit rebase\fR استفاده کنید)\&. .sp همچنین می‌توانید از \fBgit_commit_non_empty_tree\fR "$@" به جای \fBgit\fR \fBcommit\-tree\fR "$@" استفاده کنید اگر مایل نیستید کامیت‌هایی با یک والد تک که هیچ تغییری در درخت ایجاد نمی‌کنند را نگه دارید\&. .RE .PP \-\-tag\-name\-filter .RS 4 این فیلتر برای بازنویسی نام برچسب‌ها است\&. هنگام ارسال، برای هر ارجاع برچسبی که به یک شیء بازنویسی‌شده اشاره دارد (یا به شیء برچسبی که به یک شیء بازنویسی‌شده اشاره می‌کند) فراخوانی خواهد شد\&. نام برچسب اصلی از طریق ورودی استاندارد فرستاده می‌شود و انتظار می‌رود نام برچسب جدید در خروجی استاندارد دریافت شود\&. .sp برچسب‌های اصلی حذف نمی‌شوند، اما می‌توان روی آن‌ها دوباره نوشت؛ از "\-\-tag\-name\-filter cat" برای به‌روزرسانی ساده برچسب‌ها استفاده کنید\&. در این حالت، بسیار محتاط باشید و اطمینان حاصل کنید که از برچسب‌های قدیمی نسخه پشتیبان تهیه کرده‌اید تا در صورتی که تبدیل به بیراهه رفت، مشکلی پیش نیاید\&. .sp بازنویسی تقریباً مناسب اشیاء برچسب پشتیبانی می‌شود\&. اگر برچسب دارای پیامی ضمیمه‌شده باشد، یک شیء برچسب جدید با همان پیام، پدیدآورنده و مهر زمانی ایجاد خواهد شد\&. اگر برچسب دارای یک امضا باشد، امضا حذف خواهد شد؛ زیرا طبق تعریف، حفظ امضاها غیرممکن است\&. دلیل اینکه این کار "تقریباً" مناسب است این است که در حالت ایده‌آل اگر برچسب تغییر نکرده باشد (به همان شیء اشاره کند، همان نام را داشته باشد و...) باید هر گونه امضا را حفظ کند\&. در عمل چنین نیست و امضاها همواره حذف خواهند شد؛ بنابراین هوشیار باشید\&. همچنین هیچ پشتیبانی برای تغییر پدیدآورنده یا مهر زمانی (یا در واقع پیام برچسب) وجود ندارد\&. برچسب‌هایی که به برچسب‌های دیگر اشاره می‌کنند طوری بازنویسی خواهند شد که به کامیت بنیادین اشاره نمایند\&. .RE .PP \-\-prune\-empty .RS 4 برخی فیلترها کامیت‌های خالی تولید می‌کنند که درخت را دست‌نخورده باقی می‌گذارد\&. این گزینه به git\-filter\-branch دستور می‌دهد تا اگر چنین کامیت‌هایی دقیقاً یک یا صفر والد هرس‌نشده دارند، آن‌ها را حذف کند؛ بنابراین کامیت‌های ادغام دست‌نخورده باقی خواهند ماند\&. این گزینه نمی‌تواند همراه با \fB\-\-commit\-filter\fR استفاده شود، اگرچه می‌توان با استفاده از تابع ارائه‌شده \fBgit_commit_non_empty_tree\fR در یک فیلتر commit به همین نتیجه دست یافت\&. .RE .PP \-\-original .RS 4 از این گزینه برای تنظیم فضای نامی که کامیت‌های اصلی در آن ذخیره می‌شوند استفاده کنید\&. مقدار پیش‌فرض \fIrefs/original\fR است\&. .RE .PP \-d .RS 4 از این گزینه برای تعیین مسیر پوشه موقت مورداستفاده برای بازنویسی استفاده کنید\&. هنگام اعمال فیلتر tree، دستور نیازمند تحویل گرفتن موقت درخت در یک پوشه است، که در مورد پروژه‌های بزرگ ممکن است فضای قابل‌توجهی را مصرف کند\&. به صورت پیش‌فرض این کار در پوشه \fB\&.git\-rewrite/\fR انجام می‌شود اما می‌توانید این انتخاب را با این پارامتر لغو کنید\&. .RE .PP \-f, \-\-force .RS 4 دستور \fIgit filter\-branch\fR از شروع به کار با یک پوشه موقت موجود یا هنگامی که از پیش ارجاع‌هایی با شروع \fIrefs/original/\fR وجود داشته باشند خودداری می‌کند، مگر اینکه اجبار شود\&. .RE .PP \-\-state\-branch .RS 4 این گزینه موجب می‌شود تا نگاشت از اشیاء قدیمی به جدید در زمان راه‌اندازی از شاخه نام‌برده بارگیری شده و هنگام خروج به عنوان یک کامیت جدید در آن شاخه ذخیره شود، که امکان بازنویسی افزایشی درخت‌های بزرگ را فراهم می‌سازد\&. اگر \fI\fR وجود نداشته باشد، ایجاد خواهد شد\&. .RE .PP \&... .RS 4 آرگومان‌هایی برای \fIgit rev\-list\fR\&. تمامی ارجاع‌های مثبت مشمول این گزینه‌ها بازنویسی می‌شوند\&. همچنین می‌توانید گزینه‌هایی مانند \fB\-\-all\fR را مشخص کنید، اما باید از \fB\-\-\fR برای جدا کردن آن‌ها از گزینه‌های \fIgit filter\-branch\fR استفاده کنید\&. مستلزم بخش موسوم به «نگاشت مجدد به نیای والد» است\&. .RE .SS "نگاشت مجدد به نیای والد" .sp با استفاده از آرگومان‌های \fBgit-rev-list\fR(1)، به عنوان مثال محدودکننده‌های مسیر، می‌توانید مجموعه بازنگری‌هایی را که بازنویسی می‌شوند محدود کنید\&. با این حال، ارجاع‌های مثبت در خط فرمان متمایز هستند: ما اجازه نمی‌دهیم که آن‌ها توسط چنین محدودکننده‌هایی کنار گذاشته شوند\&. برای این منظور، آن‌ها در عوض طوری بازنویسی می‌شوند که به نزدیک‌ترین نیای والدی که کنار گذاشته نشده بود اشاره کنند\&. .SH "وضعیت خروج (EXIT STATUS)" .sp در صورت موفقیت، وضعیت خروج \fB0\fR است\&. اگر فیلتر نتواند هیچ کامیتی برای بازنویسی پیدا کند، وضعیت خروج \fB2\fR خواهد بود\&. در هر خطای دیگری، وضعیت خروج ممکن است هر مقدار غیر صفر دیگری باشد\&. .SH "مثال‌ها (EXAMPLES)" .sp فرض کنید می‌خواهید فایلی (حاوی اطلاعات محرمانه یا نقض حق تکثیر) را از تمام کامیت‌ها حذف کنید: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-tree\-filter \*(Aqrm filename\*(Aq HEAD .fi .if n \{\ .RE .\} .sp .sp با این حال، اگر فایل در درخت برخی از کامیت‌ها غایب باشد، یک دستور ساده \fBrm\fR \fBfilename\fR برای آن درخت و کامیت ناموفق خواهد بود\&. بنابراین ممکن است بخواهید به جای آن از \fBrm\fR \fB\-f\fR \fBfilename\fR به عنوان اسکریپت استفاده کنید\&. .sp استفاده از \fB\-\-index\-filter\fR همراه با \fIgit rm\fR نسخه‌ای به مراتب سریع‌تر را به دست می‌دهد\&. مشابه استفاده از \fBrm\fR \fBfilename\fR، دستور \fBgit\fR \fBrm\fR \fB\-\-cached\fR \fBfilename\fR نیز اگر فایل در درخت یک کامیت موجود نباشد، با شکست مواجه می‌شود\&. اگر می‌خواهید فایلی را «کاملاً به فراموشی بسپارید»، مهم نیست چه زمانی وارد تاریخچه شده است، بنابراین ما \fB\-\-ignore\-unmatch\fR را نیز می‌افزاییم: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-index\-filter \*(Aqgit rm \-\-cached \-\-ignore\-unmatch filename\*(Aq HEAD .fi .if n \{\ .RE .\} .sp .sp اکنون، تاریخچه بازنویسی‌شده ذخیره‌شده در HEAD را در اختیار خواهید داشت\&. .sp برای بازنویسی مخزن به گونه‌ای که گویی \fBfoodir/\fR ریشه پروژه آن بوده است، و دور انداختن سایر بخش‌های تاریخچه: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-subdirectory\-filter foodir \-\- \-\-all .fi .if n \{\ .RE .\} .sp .sp بدین ترتیب می‌توانید برای مثال، یک زیرپوشه کتابخانه را به مخزنی مستقل برای خود تبدیل کنید\&. به \fB\-\-\fR که گزینه‌های \fIfilter\-branch\fR را از گزینه‌های revision جدا می‌کند، و به \fB\-\-all\fR برای بازنویسی تمام شاخه‌ها و برچسب‌ها دقت کنید\&. .sp برای تعیین یک کامیت (که معمولاً در رأس یک تاریخچه دیگر قرار دارد) به عنوان والد کامیت اولیه کنونی، جهت چسباندن تاریخچه دیگر در پشت سر تاریخچه جاری: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-parent\-filter \*(Aqsed "s/^\e$/\-p /"\*(Aq HEAD .fi .if n \{\ .RE .\} .sp .sp (اگر رشته والد خالی باشد \- که هنگام برخورد با کامیت اولیه رخ می‌دهد \- graftcommit را به عنوان والد بیفزا)\&. توجه داشته باشید که این دستور فرض می‌کند تاریخچه دارای یک ریشه واحد است (یعنی هیچ ادغامی بدون اجداد مشترک رخ نداده است)\&. در غیر این صورت، از این دستور استفاده کنید: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-parent\-filter \e \*(Aqtest $GIT_COMMIT = && echo "\-p " || cat\*(Aq HEAD .fi .if n \{\ .RE .\} .sp .sp یا حتی ساده‌تر: .sp .if n \{\ .RS 4 .\} .nf git replace \-\-graft $commit\-id $graft\-id git filter\-branch $graft\-id\&.\&.HEAD .fi .if n \{\ .RE .\} .sp .sp برای حذف کامیت‌های ثبت‌شده توسط «Darl McBribe» از تاریخچه: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-commit\-filter \*(Aq if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ]; then skip_commit "$@"; else git commit\-tree "$@"; fi\*(Aq HEAD .fi .if n \{\ .RE .\} .sp .sp تابع \fIskip_commit\fR به صورت زیر تعریف شده است: .sp .if n \{\ .RS 4 .\} .nf skip_commit() { shift; while [ \-n "$1" ]; do shift; map "$1"; shift; done; } .fi .if n \{\ .RE .\} .sp .sp ترفند shift ابتدا شناسه tree و سپس پارامترهای \-p را دور می‌اندازد\&. توجه کنید که این ترفند ادغام‌ها را به درستی مدیریت می‌کند! چنانچه Darl یک ادغام میان P1 و P2 را کامیت کرده باشد، این تغییر به درستی منتشر خواهد شد و تمام فرزندان آن ادغام، به جای کامیت ادغام، تبدیل به کامیت‌های ادغامی با والدینی متشکل از P1,P2 می‌شوند\&. .sp \fBتوجه\fR تغییرات ایجادشده توسط کامیت‌ها که توسط کامیت‌های پسین لغو (revert) نشده باشند، همچنان در شاخه بازنویسی‌شده باقی خواهند ماند\&. اگر می‌خواهید \fIتغییرات\fR را همراه با خود کامیت‌ها به دور بیندازید، باید از حالت تعاملی (interactive) دستور \fIgit rebase\fR استفاده کنید\&. .sp می‌توانید پیام‌های گزارش کامیت را با استفاده از \fB\-\-msg\-filter\fR بازنویسی کنید\&. برای نمونه، رشته‌های \fIgit svn\-id\fR در مخزنی که توسط \fIgit svn\fR ایجاد شده است را می‌توان به این صورت حذف نمود: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-msg\-filter \*(Aq sed \-e "/^git\-svn\-id:/d" \*(Aq .fi .if n \{\ .RE .\} .sp .sp چنانچه لازم است خطوط \fIAcked\-by\fR را مثلاً به ۱۰ کامیت پایانی (که هیچ‌کدام ادغام نیستند) بیفزایید، از این دستور استفاده کنید: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-msg\-filter \*(Aq cat && echo "Acked\-by: Bugs Bunny " \*(Aq HEAD~10\&.\&.HEAD .fi .if n \{\ .RE .\} .sp .sp گزینه \fB\-\-env\-filter\fR را می‌توان برای تغییر هویت ثبت‌کننده و/یا پدیدآورنده به کار برد\&. برای نمونه، اگر متوجه شدید که کامیت‌های شما به دلیل تنظیم نادرست user\&.email هویت اشتباهی دارند، پیش از انتشار پروژه می‌توانید تصحیحی به این صورت انجام دهید: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-env\-filter \*(Aq if test "$GIT_AUTHOR_EMAIL" = "root@localhost" then GIT_AUTHOR_EMAIL=john@example\&.com fi if test "$GIT_COMMITTER_EMAIL" = "root@localhost" then GIT_COMMITTER_EMAIL=john@example\&.com fi \*(Aq \-\- \-\-all .fi .if n \{\ .RE .\} .sp .sp برای محدود کردن بازنویسی تنها به بخشی از تاریخچه، یک بازه بازنگری (revision range) را علاوه بر نام شاخه جدید مشخص کنید\&. نام شاخه جدید به بالاترین بازنگری‌ای اشاره خواهد کرد که یک \fIgit rev\-list\fR از این بازه چاپ می‌کند\&. .sp این تاریخچه را در نظر بگیرید: .sp .if n \{\ .RS 4 .\} .nf D\-\-E\-\-F\-\-G\-\-H / / A\-\-B\-\-\-\-\-C .fi .if n \{\ .RE .\} .sp .sp برای بازنویسی تنها کامیت‌های D، E، F، G و H، اما دست‌نخورده گذاشتن A، B و C، از این دستور استفاده کنید: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \&.\&.\&. C\&.\&.H .fi .if n \{\ .RE .\} .sp .sp برای بازنویسی کامیت‌های E، F، G و H، از یکی از این دستورات استفاده کنید: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \&.\&.\&. C\&.\&.H \-\-not D git filter\-branch \&.\&.\&. D\&.\&.H \-\-not C .fi .if n \{\ .RE .\} .sp .sp برای انتقال تمام ساختار درخت به یک زیرپوشه، یا حذف آن از آنجا: .sp .if n \{\ .RS 4 .\} .nf git filter\-branch \-\-index\-filter \e \*(Aqgit ls\-files \-s | sed "s\-\et\e"*\-&newsubdir/\-" | GIT_INDEX_FILE=$GIT_INDEX_FILE\&.new \e git update\-index \-\-index\-info && mv "$GIT_INDEX_FILE\&.new" "$GIT_INDEX_FILE"\*(Aq HEAD .fi .if n \{\ .RE .\} .sp .SH "فهرست بررسی برای کوچک‌سازی مخزن (CHECKLIST FOR SHRINKING A REPOSITORY)" .sp می‌توان از git\-filter\-branch برای خلاص شدن از زیرمجموعه‌ای از فایل‌ها استفاده کرد، معمولاً با ترکیبی از \fB\-\-index\-filter\fR و \fB\-\-subdirectory\-filter\fR\&. افراد انتظار دارند مخزن حاصل کوچک‌تر از نسخه اولیه باشد، اما برای کوچک‌تر کردن واقعی آن به چند مرحله دیگر نیاز دارید، زیرا گیت سخت تلاش می‌کند اشیاء شما را تا زمانی که صراحتاً نگویید از دست ندهد\&. نخست مطمئن شوید که: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} واقعاً تمامی گونه‌های یک نام فایل را حذف کرده‌اید، اگر یک شیء داده (blob) در طول عمر خود جابجا شده باشد\&. \fBgit\fR \fBlog\fR \fB\-\-name\-only\fR \fB\-\-follow\fR \fB\-\-all\fR \fB\-\-\fR \fBfilename\fR می‌تواند به شما در یافتن تغییر نام‌ها کمک کند\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} واقعاً تمامی ارجاع‌ها را فیلتر کرده‌اید: هنگام فراخوانی git\-filter\-branch از \fB\-\-tag\-name\-filter\fR \fBcat\fR \fB\-\-\fR \fB\-\-all\fR استفاده کنید\&. .RE .sp سپس دو راه برای رسیدن به مخزنی کوچک‌تر وجود دارد\&. راه ایمن‌تر شبیه‌سازی (clone) است، که نسخه اصلی شما را دست‌نخورده نگه می‌دارد\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} آن را با \fBgit\fR \fBclone\fR \fBfile:///path/to/repo\fR کلون کنید\&. مخزن کلون‌شده اشیاء حذف‌شده را نخواهد داشت\&. \fBgit-clone\fR(1) را ببینید\&. (توجه داشته باشید که کلون کردن با یک مسیر معمولی فقط همه چیز را به صورت سخت پیوند می‌دهد!)\&. .RE .sp اگر واقعاً به هر دلیلی تمایلی به کلون کردن آن ندارید، به جای آن موارد زیر را بررسی کنید (به همین ترتیب)\&. این یک رویکرد بسیار مخرب است، بنابراین \fBیک نسخه پشتیبان تهیه کنید\fR یا به روش کلون کردن برگردید\&. به شما هشدار داده شده است\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} ارجاع‌های اصلی پشتیبان‌گیری‌شده توسط git\-filter\-branch را حذف کنید: مانند \fBgit\fR \fBfor\-each\-ref\fR \fB\-\-format=\fR"%(\fBrefname\fR)" \fBrefs/original/\fR | \fBxargs\fR \fB\-n\fR \fB1\fR \fBgit\fR \fBupdate\-ref\fR \fB\-d\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} تمام reflogها را با \fBgit\fR \fBreflog\fR \fBexpire\fR \fB\-\-expire=now\fR \fB\-\-all\fR منقضی کنید\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} تمام اشیاء ارجاع‌نشده را با بازیافت حافظه (garbage collect) حذف کنید با \fBgit\fR \fBgc\fR \fB\-\-prune=now\fR (یا اگر git\-gc شما آن‌قدر جدید نیست که از آرگومان‌های \fB\-\-prune\fR پشتیبانی کند، به جای آن از \fBgit\fR \fBrepack\fR \fB\-ad\fR; \fBgit\fR \fBprune\fR استفاده کنید)\&. .RE .SH "کارایی (PERFORMANCE)" .sp کارایی git\-filter\-branch بسیار کُند و لاک‌پشتی است؛ طراحی آن باعث می‌شود که یک پیاده‌سازی سازگار با گذشته هرگز نتواند سریع باشد: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} در ویرایش فایل‌ها، git\-filter\-branch طبق طراحی خود تک‌تک کامیت‌ها را دقیقاً همان‌گونه که در مخزن اصلی وجود داشتند تحویل (checkout) می‌گیرد\&. اگر مخزن شما دارای \fB10^5\fR فایل و \fB10^5\fR کامیت باشد، اما هر کامیت تنها پنج فایل را تغییر دهد، آن‌گاه git\-filter\-branch شما را وادار به انجام \fB10^10\fR تغییر می‌کند، با وجود اینکه (در بیشترین حالت) تنها \fB5*10^5\fR شیء حبابی (blob) یکتا دارد\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} اگر تلاش کنید تقلب کنید و سعی نمایید کاری کنید که git\-filter\-branch تنها روی فایل‌های تغییریافته در یک کامیت کار کند، دو اتفاق می‌افتد: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} هر زمان که کاربر به سادگی در تلاش برای تغییر نام فایل‌ها باشد، با مشکلاتی در حذف فایل‌ها مواجه می‌شوید (زیرا تلاش برای حذف فایل‌هایی که وجود ندارند مانند عملیات بدون اثر به نظر می‌رسد؛ نگاشت مجدد حذف‌ها در میان تغییر نام فایل‌ها زمانی که تغییر نام‌ها از طریق یک پوسته دلخواه ارائه‌شده توسط کاربر رخ می‌دهد، نیاز به فریب‌کاری و ترفندهای پیچیده دارد) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} حتی اگر در این فریب‌کاری نگاشت حذف‌ها برای تغییر نام موفق شوید، از نظر فنی همچنان سازگاری با گذشته را نقض می‌کنید زیرا کاربران مجازند فایل‌ها را به روش‌هایی فیلتر کنند که به توپولوژی کامیت‌ها وابسته است، به جای اینکه صرفاً بر اساس محتوا یا نام فایل‌ها فیلتر نمایند (اگرچه این مورد در عمل دیده نشده است)\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} حتی اگر نیازی به ویرایش فایل‌ها نداشته باشید و فقط بخواهید به عنوان مثال برخی را تغییر نام دهید یا حذف کنید و بنابراین بتوانید از تحویل گرفتن تک‌تک فایل‌ها اجتناب کنید (یعنی بتوانید از \-\-index\-filter استفاده کنید)، همچنان در حال ارسال قطعه‌کدهای پوسته برای فیلترهای خود هستید\&. این بدان معنی است که برای هر کامیت، باید یک مخزن گیت آماده داشته باشید که این فیلترها بتوانند در آن اجرا شوند\&. این یک بار راه‌اندازی قابل‌توجه است\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} علاوه بر این، چندین فایل اضافی به ازای هر کامیت توسط git\-filter\-branch ایجاد یا به‌روزرسانی می‌شوند\&. برخی از این فایل‌ها برای پشتیبانی از توابع کمکی ارائه‌شده توسط git\-filter\-branch (مانند ()map) هستند، در حالی که برخی دیگر برای ردیابی وضعیت داخلی به کار می‌روند (اما می‌توانستند توسط فیلترهای کاربر نیز قابل دسترسی باشند؛ یکی از آزمایش‌های رگرسیون git\-filter\-branch چنین کاری می‌کند)\&. این در اصل به منزله استفاده از سیستم فایل به عنوان یک سازوکار ارتباط بین‌فرآیندی (IPC) میان git\-filter\-branch و فیلترهای ارائه‌شده توسط کاربر است\&. دیسک‌ها معمولاً سازوکار IPC کُندی هستند، و نوشتن این فایل‌ها همچنین در عمل نشان‌دهنده یک نقطه همگام‌سازی اجباری میان فرآیندهای مجزا است که در هر کامیت با آن مواجه می‌شویم\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} دستورات پوسته ارائه‌شده توسط کاربر احتمالاً شامل یک خط لوله (pipeline) از دستورات خواهد بود که منجر به ایجاد فرآیندهای متعددی به ازای هر کامیت می‌شود\&. ایجاد و اجرای یک فرآیند دیگر میان سیستم‌عامل‌های گوناگون زمان بسیار متغیری می‌برد، اما در هر بستری نسبت به فراخوانی یک تابع بسیار کُند است\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} خود git\-filter\-branch با اسکریپت پوسته نوشته شده است که تا حدودی کُند است\&. این تنها مشکل کارایی است که می‌توانست با حفظ سازگاری با گذشته برطرف شود، اما در مقایسه با مشکلات پیشین که ذاتی طراحی git\-filter\-branch هستند، زبان نگارش خود ابزار یک مسئله نسبتاً جزئی است\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} یادداشت حاشیه‌ای: متأسفانه، افراد تمایل دارند روی جنبه نوشته‌شدن با پوسته تمرکز کنند و مرتباً بپرسند که آیا می‌توان git\-filter\-branch را به زبان دیگری بازنویسی کرد تا مشکلات عملکردی برطرف شود\&. این کار نه تنها مشکلات ذاتی بزرگ‌تر طراحی را نادیده می‌گیرد، بلکه بسیار کمتر از آنچه انتظار می‌رود سودمند خواهد بود: اگر خود git\-filter\-branch پوسته نبود، آن‌گاه توابع کمکی (()map، ()skip_commit و غیره) و آرگومان \fB\-\-setup\fR دیگر نمی‌توانستند یک بار در ابتدای برنامه اجرا شوند، بلکه در عوض باید به ابتدای هر فیلتر کاربر افزوده می‌شدند (و بنابراین با هر کامیت از نو اجرا می‌شدند)\&. .RE .RE .sp ابزار \m[blue]\fBgit filter\-repo\fR\m[]\&\s-2\u[1]\d\s+2 جایگزینی برای git\-filter\-branch است که از این مشکلات عملکردی یا مشکلات امنیتی (که در زیر ذکر شده) رنج نمی‌برد\&. برای کسانی که ابزارهای موجود مبتنی بر git\-filter\-branch دارند، \fIgit filter\-repo\fR همچنین \m[blue]\fBfilter\-lamely\fR\m[]\&\s-2\u[2]\d\s+2 را ارائه می‌دهد که یک جایگزین مستقیم برای git\-filter\-branch است (با چند نکته قابل توجه)\&. اگرچه filter\-lamely از تمام همان مشکلات امنیتی git\-filter\-branch رنج می‌برد، اما دست‌کم کمی از مشکلات عملکردی را التیام می‌بخشد\&. .SH "امنیت (SAFETY)" .sp دستور git\-filter\-branch پر از دام‌هایی است که منجر به روش‌های مختلفی برای خراب کردن آسان مخازن یا رسیدن به وضعیتی به مراتب آشفته‌تر از آنچه شروع کرده‌اید می‌شود: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} شخصی می‌تواند مجموعه‌ای از «فیلترهای کارآمد و آزموده‌شده» داشته باشد که آن‌ها را مستند کرده یا در اختیار یک همکار قرار می‌دهد، و سپس آن همکار آن‌ها را روی سیستم‌عامل دیگری اجرا می‌کند که همان دستورات در آنجا کار نمی‌کنند یا آزمایش نشده‌اند (برخی از مثال‌های موجود در صفحه راهنمای git\-filter\-branch نیز تحت تأثیر این موضوع هستند)\&. تفاوت‌های میان فضای کاربری BSD و GNU واقعاً می‌تواند دردسرساز شود\&. اگر خوش‌شانس باشید، پیام‌های خطا ظاهر می‌شوند\&. اما به همان اندازه محتمل است که دستورات یا فیلتر درخواستی را انجام ندهند، یا با اعمال تغییراتی ناخواسته به طور خاموش داده‌ها را مخدوش کنند\&. تغییر ناخواسته ممکن است تنها بر چند کامیت تأثیر بگذارد، بنابراین لزوماً واضح نیز نخواهد بود\&. (این واقعیت که مشکلات لزوماً آشکار نخواهند بود به این معنی است که احتمالاً تا زمانی که تاریخچه بازنویسی‌شده برای مدتی طولانی مورد استفاده قرار نگیرد متوجه آن‌ها نخواهید شد، در این نقطه توجیه یک دگرگونی سراسری دیگر برای یک بازنویسی جدید بسیار دشوار خواهد بود\&.) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} نام فایل‌های حاوی فاصله اغلب توسط قطعه‌کدهای پوسته به نادرستی مدیریت می‌شوند زیرا برای خطوط لوله پوسته مشکل ایجاد می‌کنند\&. همه با find \-print0، xargs \-0، git\-ls\-files \-z و غیره آشنا نیستند\&. حتی افرادی که با این موارد آشنا هستند ممکن است تصور کنند چنین فلگ‌هایی مرتبط نیستند زیرا شخص دیگری قبل از پیوستن فرد مجری فیلتر به پروژه، نام چنین فایل‌هایی را در مخزن تغییر داده است\&. و اغلب، حتی کسانی که با مدیریت آرگومان‌های دارای فاصله آشنا هستند ممکن است صرفاً به این دلیل که در ذهنیت فکر کردن به هر چیزی که احتمال دارد خراب شود نیستند، این کار را انجام ندهند\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} نام فایل‌های غیر اسکی (non\-ascii) با وجود اینکه در یک پوشه مورد نظر قرار دارند می‌توانند به صورت خاموش حذف شوند\&. نگه‌داشتن تنها مسیرهای مورد نظر اغلب با استفاده از خطوط لوله‌ای مانند \fBgit\fR \fBls\-files\fR | \fBgrep\fR \fB\-v\fR \fB^WANTED_DIR/\fR | \fBxargs\fR \fBgit\fR \fBrm\fR انجام می‌شود\&. دستور ls\-files تنها در صورت نیاز نام فایل‌ها را نقل‌قول می‌کند، بنابراین ممکن است افراد متوجه نشوند که یکی از فایل‌ها با عبارت باقاعده مطابقت نداشته است (دست‌کم نه تا زمانی که خیلی دیر شده باشد)\&. بله، کسی که از core\&.quotePath اطلاع دارد می‌تواند از این مشکل جلوگیری کند (مگر اینکه کاراکترهای خاص دیگری مانند \et، \en یا " داشته باشند)، و افرادی که از ls\-files \-z با چیزی غیر از grep استفاده می‌کنند می‌توانند از این مشکل دوری کنند، اما این بدان معنا نیست که حتماً چنین خواهند کرد\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} به طور مشابه، هنگام جابجایی فایل‌ها، ممکن است متوجه شوید نام فایل‌های دارای کاراکترهای غیراسکی یا خاص سر از پوشه متفاوتی درمی‌آورند، پوشه‌ای که شامل کاراکتر علامت نقل‌قول جفت (double quote) است\&. (این از نظر فنی همان مسئله نقل‌قول در بالا است، اما شاید روش جالب و متفاوتی باشد که می‌تواند به عنوان یک مشکل خود را نشان دهد و نشان داده است\&.) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} مخلوط کردن تصادفی تاریخچه قدیم و جدید بسیار آسان است\&. با هر ابزاری هنوز هم این احتمال وجود دارد، اما git\-filter\-branch تقریباً به آن دعوت می‌کند! در صورت خوش‌شانسی، تنها نکته منفی این است که کاربران از ندانستن نحوه کوچک کردن مخزن خود و حذف موارد قدیمی کلافه می‌شوند\&. در صورت بدشانسی، آن‌ها تاریخچه قدیمی و جدید را ادغام می‌کنند و با چندین «نسخه» از هر کامیت مواجه می‌شوند، که برخی از آن‌ها دارای فایل‌های ناخواسته یا حساس هستند و برخی دیگر ندارند\&. این وضعیت به چندین روش مختلف رخ می‌دهد: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} پیش‌فرض بودن انجام تنها بازنویسی جزئی تاریخچه (\fI\-\-all\fR پیش‌فرض نیست و مثال‌های کمی آن را نشان می‌دهند) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} این واقعیت که هیچ پاک‌سازی خودکاری پس از اجرا وجود ندارد .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} این واقعیت که \-\-tag\-name\-filter (هنگامی که برای تغییر نام برچسب‌ها استفاده می‌شود) برچسب‌های قدیمی را حذف نمی‌کند، بلکه تنها برچسب‌های جدید را با نام جدید اضافه می‌کند .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} این واقعیت که اطلاعات آموزشی کمی برای آگاه کردن کاربران از پیامدهای بازنویسی و نحوه جلوگیری از ترکیب تاریخچه قدیم و جدید ارائه شده است\&. برای مثال، این صفحه راهنما توضیح می‌دهد که کاربران باید درک کنند که باید تغییرات خود را برای تمامی شاخه‌هایشان بر فراز تاریخچه جدید بازپایه‌ریزی (rebase) کنند (یا حذف کرده و دوباره کلون نمایند)، اما این تنها یکی از چندین دغدغه‌ای است که باید در نظر گرفته شود\&. برای جزئیات بیشتر بخش "DISCUSSION" در صفحه راهنمای git filter\-repo را ببینید\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} برچسب‌های حاشیه‌نویسی‌شده (annotated tags) ممکن است به دلیل یکی از این دو مشکل، به طور تصادفی به برچسب‌های سبک‌وزن (lightweight tags) تبدیل شوند: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} شخصی می‌تواند بازنویسی تاریخچه را انجام دهد، متوجه شود که خرابکاری کرده است، از نسخه‌های پشتیبان در refs/original/ بازیابی کند، و سپس دستور git\-filter\-branch خود را دوباره اجرا نماید\&. (پشتیبان موجود در refs/original/ یک پشتیبان واقعی نیست؛ ابتدا ارجاع‌زدایی برچسب‌ها را انجام می‌دهد\&.) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} اجرای git\-filter\-branch با \-\-tags یا \-\-all در \&. برای حفظ برچسب‌های حاشیه‌نویسی‌شده به همان صورت حاشیه‌نویسی‌شده، باید از \-\-tag\-name\-filter استفاده کنید (و نباید در یک بازنویسی خراب‌شده قبلی از refs/original/ بازیابی کرده باشید)\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} هر پیام کامیتی که یک رمزگذاری (encoding) را مشخص کند بر اثر بازنویسی خراب خواهد شد؛ git\-filter\-branch رمزگذاری را نادیده می‌گیرد، بایت‌های اصلی را می‌گیرد و آن را بدون اعلام رمزگذاری مناسب به commit\-tree تحویل می‌دهد\&. (این اتفاق چه از \-\-msg\-filter استفاده شود و چه نشود رخ می‌دهد\&.) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} پیام‌های کامیت (حتی اگر همگی UTF\-8 باشند) به صورت پیش‌فرض به دلیل به‌روزرسانی نشدن خراب می‌شوند \(em هر ارجاعی به سایر هش‌های کامیت در پیام‌های کامیت اکنون به کامیت‌هایی ارجاع خواهد داد که دیگر وجود خارجی ندارند\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} هیچ امکاناتی برای کمک به کاربران در پیدا کردن ضایعات ناخواسته‌ای که باید حذف کنند وجود ندارد، که این بدان معناست که آن‌ها بسیار بیشتر در معرض پاک‌سازی‌های ناقص یا جزئی قرار دارند که گاهی اوقات منجر به سردرگمی و تلف شدن وقت افراد برای درک آن می‌شود\&. (برای مثال، افراد معمولاً به جای پوشه‌های بزرگ یا پسوندها، فقط به دنبال فایل‌های بزرگ برای حذف می‌گردند، و هنگامی که چنین می‌کنند، مدتی بعد افرادی که از مخزن جدید استفاده می‌کنند و تاریخچه را مرور می‌کنند، متوجه یک پوشه مربوط به مصنوعات ساخت می‌شوند که برخی فایل‌ها را دارد و برخی دیگر را ندارد، یا یک حافظه پنهان وابستگی‌ها (node_modules یا موارد مشابه) که هرگز نمی‌توانسته کار کند زیرا برخی فایل‌هایش گم شده است\&.) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} اگر \-\-prune\-empty مشخص نشود، فرآیند فیلتر کردن می‌تواند انبوهی از کامیت‌های خالی گیج‌کننده ایجاد کند .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} اگر \-\-prune\-empty مشخص شود، کامیت‌های تعمداً خالی از قبل از عملیات فیلتر کردن نیز به جای هرس کردن صرفاً کامیت‌هایی که به دلیل قوانین فیلتر خالی شده‌اند، هرس می‌شوند\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} اگر \-\-prune\-empty مشخص شود، گاهی اوقات کامیت‌های خالی جا افتاده و به هر حال باقی می‌مانند (یک باگ تا حدی نادر، اما رخ می‌دهد\&...) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} یک مسئله جزئی، اما کاربرانی که هدفشان به‌روزرسانی همه نام‌ها و رایانامه‌ها در یک مخزن است ممکن است به سمت \-\-env\-filter هدایت شوند که تنها پدیدآورندگان و ثبت‌کنندگان را به‌روزرسانی می‌کند و برچسب‌گذاران (taggers) را جا می‌اندازد\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} اگر کاربر یک \-\-tag\-name\-filter ارائه دهد که چندین برچسب را به یک نام نگاشت کند، هیچ هشدار یا خطایی داده نمی‌شود؛ git\-filter\-branch به سادگی روی هر برچسب در یک ترتیب از پیش تعریف‌شده و مستندنشده بازنویسی می‌کند که در نهایت تنها به یک برچسب منجر می‌شود\&. (یک آزمون رگرسیون git\-filter\-branch به این رفتار تعجب‌آور نیاز دارد\&.) .RE .sp همچنین، عملکرد ضعیف git\-filter\-branch اغلب منجر به مسائل امنیتی می‌شود: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} رسیدن به قطعه‌کد صحیح پوسته برای انجام فیلتر مورد نظرتان گاهی اوقات دشوار است مگر اینکه فقط در حال انجام یک تغییر جزئی مانند حذف دو فایل باشید\&. متأسفانه، افراد اغلب با امتحان کردن متوجه می‌شوند که قطعه‌کد درست است یا غلط، اما درستی یا نادرستی می‌تواند بسته به شرایط خاص (فاصله در نام فایل‌ها، نام فایل‌های غیر اسکی، نام‌ها یا رایانامه‌های نامتعارف نویسنده، مناطق زمانی نامعتبر، وجود پیوندها یا اشیاء جایگزین و...) متغیر باشد، به این معنی که ممکن است مجبور شوند مدت طولانی صبر کنند، با خطا مواجه شوند، و سپس دوباره شروع کنند\&. عملکرد git\-filter\-branch آن‌قدر بد است که این چرخه عذاب‌آور است و زمان موجود برای بررسی دقیق را کاهش می‌دهد (صرف نظر از تأثیری که بر صبر و شکیبایی فرد انجام‌دهنده بازنویسی می‌گذارد حتی اگر از نظر فنی وقت بیشتری داشته باشد)\&. این مشکل دوچندان تشدید می‌شود زیرا خطاهای ناشی از فیلترهای معیوب ممکن است برای مدتی طولانی نشان داده نشوند و/یا در دریایی از خروجی‌ها گم شوند\&. بدتر از آن، فیلترهای خراب اغلب فقط منجر به بازنویسی‌های نادرست بی‌صدا می‌شوند\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} علاوه بر همه این‌ها، حتی زمانی که کاربران سرانجام دستورات کارآمدی پیدا می‌کنند، طبیعتاً می‌خواهند آن‌ها را به اشتراک بگذارند\&. اما ممکن است از این موضوع بی‌خبر باشند که مخزن آن‌ها برخی از حالات خاص را که مخزن فرد دیگری دارد، نداشته است\&. بنابراین، هنگامی که شخص دیگری با یک مخزن متفاوت همان دستورات را اجرا می‌کند، دچار مشکلات بالا می‌شود\&. یا اینکه کاربر دستوراتی را اجرا می‌کند که واقعاً برای حالات خاص بررسی شده بودند، اما همان‌گونه که در بالا ذکر شد، آن را روی سیستم‌عامل دیگری اجرا می‌کند که در آنجا کار نمی‌کند\&. .RE .SH "GIT" .sp بخشی از مجموعه \fBgit\fR(1) .SH "نکات (NOTES)" .IP " 1." 4 git filter-repo .RS 4 \%https://github.com/newren/git-filter-repo .RE .IP " 2." 4 filter-lamely .RS 4 \%https://github.com/newren/git-filter-repo/blob/master/contrib/filter-repo-demos/filter-lamely .RE