הסרת קובץ מההיסטוריה
git rm מונע מקובץ להופיע בקומיטים חדשים. הוא לא עושה דבר לאלה שכבר נעשו:
הבלוב עדיין במסד האובייקטים, עדיין בכל שכפול, ועדיין במרחק git show אחד.
זה משנה פעמיים — כשהקובץ היה אישור, וכשהוא היה 400 מגה־בייט.
⌘K ← הסרת קובץ מההיסטוריה, או לחיצה ימנית על הקובץ — בעץ הפרויקט, ברשימת
הקבצים של קומיט, או במלחין הקומיטים. הקומיט שמחק קובץ הוא בדרך כלל המקום שבו
מישהו מבין שהוא עדיין בהיסטוריה, ולכן הדרך החוצה נמצאת גם בתפריט ההוא.
איתור הנתיב
שתי דרכי כניסה, כי הן עונות על שאלות שונות.
הקלידו אותו — יחסית למאגר, בלי לוכסן מוביל — כשאתם כבר יודעים מה באתם להסיר.
דפדוף בהיסטוריה כשלא. הוא מונה כל נתיב שאי פעם נכנס לקומיט, הכבד ראשון, עם כמה גרסאות יש לכל אחד והאם הוא עדיין במעקב. נתיבים שנמחקו מסומנים ככאלה והם בדרך כלל אלה שאתם רוצים: קובץ שנעלם מעץ העבודה אבל עדיין נמצא בכל שכפול הוא בדיוק המקרה שחלון קבצים רגיל אינו יכול להראות לכם, כי הקובץ פשוט לא שם כדי לבחור בו.
אותה רשימה עונה גם על הסיבה השנייה שאנשים מגיעים לכאן — למה השכפול הזה שני ג׳יגה־בייט — כי היא ממוינת לפי הבייטים שהבלובים של כל נתיב באמת תופסים. בחירת שורה מודדת אותה מיד.

מדדו לפני שאתם מסכימים
לחצו מדידה (או בחרו שורה). שום דבר עדיין לא נכתב. אתם מקבלים:
| קומיטים שייכתבו מחדש | כל קומיט מהראשון שהחזיק את הקובץ והלאה |
| ענפים / תגיות | refs שיזוזו |
| מוחזק על ידי הבלובים שלו | הבייטים שאותן גרסאות באמת תופסות |
| הקומיט הראשון | היכן שהכתיבה מחדש מתחילה — כל מה שאחריו מקבל hash חדש |

אם המונה אפס, הנתיב שגוי. זו בדרך כלל שגיאת כתיב או קידומת תיקייה, לא היעדר.
מה הכתיבה מחדש באמת עושה
Gitcito מעתיק כל ענף וכל תגית אל refs/gitcito/pre-purge/<timestamp>/…, ואז
מריץ:
git filter-branch --force \
--index-filter 'git rm --cached --ignore-unmatch -- <path>' \
--prune-empty --tag-name-filter cat -- --branches --tags
--index-filter כותב מחדש את האינדקס ישירות במקום לעשות צ׳קאאוט לכל קומיט, וזה
ההבדל בין דקות לשעות. --branches --tags במקום --all הוא מכוון: --all היה
כולל את refs הגיבוי, והכתיבה מחדש הייתה אוכלת את רשת הביטחון של עצמה.
קומיטים שלא החזיקו דבר מלבד הקובץ שהוסר נזרקים (--prune-empty). תגיות מוצבעות
מחדש אל הקומיטים שנכתבו מחדש.
הגיבוי, ולמה המקום עדיין לא חוזר
הטיהור ניתן לביטול, והמחיר של זה הוא ששטח הדיסק אינו משוחרר עד שתאמרו זאת. כל עוד הגיבוי קיים הקומיטים הישנים עדיין נגישים, ולכן git לא יאסוף אותם.
| פעולה | השפעה |
|---|---|
| שחזור | כל ענף וכל תגית חוזרים לקומיט שלפני הטיהור; הקובץ חוזר איתם |
| זריקת הגיבוי | מוחקת את refs הגיבוי, מפקיעה את ה־reflog, מריצה git gc --prune=now — המקום חוזר, הטיהור עכשיו קבוע |
שני שלבים ולא אחד, כי הראשון הוא החצי הניתן לשחזור והשני אינו.
החליפו את הסוד בכל מקרה
אם אישור נדחף אי פעם, כתיבה מחדש של ההיסטוריה שלכם אינה מבטלת את הדליפה. מישהו אולי הביא אותו; שרתי מארחים שומרים אובייקטים בלי הפניות; לוג CI אולי הדפיס אותו. הכתיבה מחדש עוצרת את ההתפשטות הלאה — היא לא מבטלת את החשיפה.
החליפו את המפתח. ואז טהרו, כדי שהאדם הבא שמשכפל לא ימצא אותו.
מה הוא לא יעשה
- הוא לא ידחוף. הכתיבה מחדש היא מקומית. פרסום התוצאה פירושו דחיפה כפויה לכל ענף מושפע, וכל אחד אחר חייב לשכפל מחדש או לבצע איפוס קשה — שומר הדחיפה הכפויה הוא המקום שבו ההחלטה הזו חיה.
- הוא מסרב על עץ עבודה מלוכלך או באמצע מיזוג/ריבייס. כתיבה מחדש מזיזה את HEAD שוב ושוב, ולעשות את זה סביב עבודה שלא נכנסה לקומיט זו הדרך שבה היא הולכת לאיבוד.
- הוא כותב מחדש לפי נתיב, לא לפי תוכן. הסרת סוד שהודבק לתוך קובץ מקור, ולא
חי בקובץ משל עצמו, דורשת מסנן תוכן — זה טריטוריה של
git filter-repo --replace-text, ו־Gitcito אינו עוטף אותה. filter-branchאיטי בהיסטוריות גדולות מאוד. זה מה שמגיע עם git בכל מקום, ולכן זה מה ש־Gitcito משתמש בו. במאגר עם עשרות אלפי קומיטים,git filter-repoבטרמינל הוא הכלי המהיר יותר.- השכפולים של אנשים אחרים אינם המאגר שלכם. הם מחזיקים את ההיסטוריה הישנה עד שישכפלו מחדש.