Начните с git replace
. Я не совсем уверен, каким способом читать ваш график, поэтому я просто скажу, что вы можете использовать это с --edit
или с --graft
. Это сделает замену некоторого коммита с заменой на любые изменения, которые вам нравятся.
Новая замена на самом деле не в графике! Например, предположим, что у меня следующий график, который мы читаем, начиная с правой стороны и работая влево, чтобы вернуться во времени:
A <-B <-C <-D <-E <-- master
Commit E
имеет D
в качестве родителя, который имеет C
в качестве родителя и т. Д.
Мы можем сделать новый коммит C'
, чей родитель A
, используя git replace --graft <em>hash-of-C</em> <em>hash-of-A</em>
, давая:
A--B--C--D--E <-- master
\
C' <-- refs/replace/hash-of-C
Когда git log
или другие подобные команды идут по графику, они могут начинаться с E
и показывать его, а затем переходить к D
и показывать его. Сложный случай происходит следующим образом: они переходят на C
, но в этот момент они замечают, что refs/replace/<em>hash-of-C</em>
существует. Они полностью отпускают C
, вместо этого переходят на C'
и показывают это. Они переходят к C'
родителю A
и показывают это. В результате B
кажется исчезло . Тот же трюк сработает для вашего случая: если вы хотите представить двух родителей там, где был только один, вы делаете замену, в которой вместо этих одного есть два родителя.
Недостатком этого типа замены является то, что git clone
обычно пропускает пространство имен refs/replace/
и его фиксации. Таким образом, кто-то, клонирующий хранилище, видит исходные коммиты - их Git вообще не имеет refs/replace/<em>hash</em>
и никогда не копировал коммиты замены.
Вы можете организовать их клонирование, но вместо этого теперь вы можете использовать 1047 * в противном случае, чтобы "зацементировать" замену на месте в новом хранилище. Например, после:
git filter-branch --tag-name-filter cat -- --all
в репозитории с пятью коммитами и одной заменой, который я нарисовал выше, вы получите:
A--B--C--D--E <-- refs/original/refs/heads/master
\
C' <-- refs/replace/hash-of-C
\
D'-E' <-- master
Отбрасывая имена пространств имен refs/original/
и refs/replace/
, создав еще один клон, вы получите:
A--C'-D'-E' <-- master
, который сделал прививку постоянной. Таким образом, теперь вы можете либо клонировать репозиторий и использовать клон в качестве репозитория замены, либо просто отбросить имена refs/replace/
и refs/original/
из исходного репозитория, чтобы он выглядел так же, как и предлагаемая клонированная замена (за исключением того, что исходные объекты как правило, задерживаются на некоторое время - в основном, до тех пор, пока сборщик мусора не сможет их очистить).