Replace i graft
git replace mówi gitowi: gdziekolwiek zamierzałeś przeczytać obiekt A,
przeczytaj zamiast niego B. Nic nie jest przepisywane. Żadne sha się nie
zmienia. Każdy commit zostaje dokładnie tam, gdzie był — git po prostu patrzy po
drodze gdzie indziej.
Brzmi to jak ciekawostka, dopóki nie zechcesz mniejszego klonu. Wtedy staje się uczciwą alternatywą dla przepisania historii: przeszczep commit na brak rodziców, a wszystko przed nim wypada z logu, z grafu i z każdego klonu zrobionego stamtąd — będąc wciąż przechowywanym, wciąż pobieralnym i o jedną usuniętą referencję od powrotu.
⌘K → Replace i graft.

Graftowanie
| Podaj mu | A dostaniesz |
|---|---|
| Commit, bez rodziców | Ten commit staje się początkiem historii |
| Commit, z jednym lub kilkoma rodzicami | Podczepia się tam, zamiast tam, gdzie naprawdę siedzi |
Ta druga forma jest ciekawsza. Trzymaj pełną historię w repozytorium archiwalnym, obetnij to robocze, a graft wskazujący na czubek archiwum połączy oba z powrotem — tą samą sztuczką GitHub serwuje płytki klon, który wciąż da się pogłębić.
Graftowanie na brak rodziców najpierw pyta, bo „historia zniknęła"
i „historia jest ukryta" wyglądają z poziomu logu identycznie, a wcale nie są
tym samym. Obiekty przeżywają, dopóki nie przytnie ich gc; zobacz
konserwację.
Życie z tym
Podmiany są referencjami, pod refs/replace/. Ma to trzy konsekwencje warte
wiedzy:
- Są lokalne, dopóki ich nie wypchniesz:
git push origin "refs/replace/*"je udostępnia, a każdy, kto sklonuje bez nich, widzi nietkniętą historię. - Cofnij działa — usunięcie referencji natychmiast przywraca prawdziwe pochodzenie, a Gitcito zapisuje graft jako akcję odwracalną, jak wszystko inne.
core.useReplaceRefs=falsesprawia, że git ignoruje je wszystkie naraz. Przełącznik tutaj zapisuje dokładnie to, a okno mówi o tym wprost, gdy jest wyłączony, bo repozytorium po cichu ignorujące własne podmiany to mylące miejsce.
Z wiersza poleceń git --no-replace-objects log pokazuje prawdziwą historię, nie
zmieniając żadnego ustawienia.
Kiedy sięgnąć po to zamiast po przepisanie
| Cel | Narzędzie |
|---|---|
| Klon jest za duży, historia w porządku | Graft — nic nie przepisane, odwracalne |
| Sekret albo ogromny blob musi zniknąć | Usuwanie pliku z historii — prawdziwe przepisanie |
| Chodzi tylko o mniej do ściągnięcia raz | git clone --depth — płytki, bez referencji do pilnowania |
Graft niczego nie usuwa. Jeśli powodem, dla którego chcesz się pozbyć starych commitów, jest to, że zawierają coś, co nigdy nie powinno było zostać zacommitowane, to jest zła strona: obiekty wciąż tam są, wciąż da się je pobrać po sha i wciąż siedzą w każdym istniejącym klonie.
Ograniczenia warte wiedzy
- To, co widzisz, przestaje odpowiadać temu, co jest przechowywane. To jednocześnie funkcja i zagrożenie. Ktokolwiek debuguje klon z podmianami, musi wiedzieć, że one istnieją.
- Podmiany domyślnie nie podróżują, więc
git logkolegi i twój mogą się całkiem zasadnie nie zgadzać. - Podmiana potrafi ukryć commit przed narzędziami, nie przed gitem.
git cat-filei eksplorator obiektów nadal otworzą oryginał po sha. - Gitcito nie oferuje
git replace --edit(ręcznego przepisania treści obiektu). To robota dla edytora tekstu na surowym obiekcie i strzał w stopę z interfejsem dookoła.
Zobacz też: Eksplorator obiektów · Usuwanie pliku z historii · Konserwacja repozytorium