Заміна та графт
git replace каже git: там, де ти збирався прочитати об’єкт A, читай натомість
B. Нічого не переписується. Жоден sha не змінюється. Кожен коміт лишається рівно
там, де був — git просто дивиться дорогою в інше місце.
Це звучить як курйоз, доки вам не знадобиться менший клон. Тоді це чесна альтернатива переписуванню історії: зробіть графт коміту на порожній список батьків — і все, що було до нього, зникає з логу, з графа і з кожного клону, зробленого звідти, — при цьому все ще зберігаючись, все ще будучи доступним для фетчу і за один видалений реф від повернення.
⌘K → Заміна та графт.

Графт
| Що ви даєте | Що отримуєте |
|---|---|
| Коміт, без батьків | Цей коміт стає початком історії |
| Коміт, один або більше батьків | Він чіпляється туди, замість того місця, де реально сидить |
Друга форма — цікавіша. Тримайте повну історію в архівному репозиторії, обріжте робочий, і графт, що вказує на верхівку архіву, знову з’єднає ці двоє — той самий трюк, яким GitHub віддає поверхневий клон, який усе одно можна поглибити.
Графт на порожній список батьків спершу перепитає, бо «історії немає» і
«історія прихована» виглядають з логу однаково, а насправді це зовсім не те саме.
Об’єкти живуть, доки їх не підчистить gc; див.
обслуговування.
Життя з цим
Заміни — це рефи, під refs/replace/. З цього випливають три наслідки, які
варто знати:
- Вони локальні, доки їх не запушити:
git push origin "refs/replace/*"ділиться ними, а той, хто клонує без них, бачить недоторкану історію. - Скасування працює — видалення рефа миттєво повертає справжню родинну лінію, і Gitcito записує графт як дію, яку можна скасувати, як і будь-яку іншу.
core.useReplaceRefs=falseзмушує git проігнорувати їх усі одним махом. Перемикач тут пише саме це, і діалог про це повідомляє, коли він вимкнений, бо репозиторій, який тихцем ігнорує власні заміни, — заплутане місце.
З командного рядка git --no-replace-objects log показує справжню історію, не
змінюючи жодного налаштування.
Коли братися за це замість переписування
| Мета | Інструмент |
|---|---|
| Клон завеликий, з історією все гаразд | Графт — нічого не переписано, оборотно |
| Секрет чи величезний блоб мають зникнути | Видалення файлу з історії — справжнє переписування |
| Просто хочеться менше качати один раз | git clone --depth — поверхнево, жодних рефів для догляду |
Графт нічого не видаляє. Якщо причина, з якої вам треба прибрати старі коміти, у тому, що вони містять щось, чого ніколи не мало бути закомічено, — це не та сторінка: об’єкти й далі на місці, й далі доступні за sha, й далі в кожному наявному клоні.
Обмеження, які варто знати
- Те, що ви бачите, перестає збігатися з тим, що збережено. Це і є фіча, і це ж і небезпека. Кожен, хто налагоджує клон із замінами, має знати, що вони є.
- Заміни за замовчуванням не подорожують, тож
git logколеги і ваш можуть цілком законно не погоджуватися. - Заміна може сховати коміт від інструментів, але не від git.
git cat-fileі оглядач об’єктів все одно відкриють оригінал за sha. - Gitcito не пропонує
git replace --edit(редагування вмісту об’єкта руками). Це робота текстового редактора над сирим об’єктом, і граблі, навколо яких намалювали UI.
Дивіться також: Оглядач об’єктів · Видалення файлу з історії · Обслуговування репозиторію