Вы не можете сделать это вообще. Никакая часть какого-либо коммита не может быть когда-либо измененной.
Вы можете сделать что-то другое , которое может быть - или не может - быть достаточно хорошим .
При любом Git коммите вы можете:
- извлечь этот коммит, чтобы вы могли работать над ним
- выполнить некоторую работу
- сделать новый коммит, который будет иметь другой га sh ID
и, сделав этот новый коммит, вы можете повторить это , Итак, предположим, что у вас есть эта серия коммитов:
A--B <-- branch_1, origin/branch_1
\
C--D <-- branch_2, origin/branch_2
\
E--F <-- branch_3, origin/branch_3
\
G--H <-- branch_4, origin/branch_4
(это тот же график, который вы нарисовали, за исключением того, что я использовал заглавные буквы для обозначения идентификаторов ha sh и добавил новые фиксирует направо, а не к вершине). Совершенно невозможно изменить какой-либо из существующих коммитов, но мы можем извлечь D
в рабочую область, затем внести изменения, а затем сделать новый и улучшенный D'
:
A--B <-- branch_1, origin/branch_1
\
C--D <-- branch_2, origin/branch_2
\ \
D' \ <-- [remember this hash]
\
E--F <-- branch_3, origin/branch_3
\
G--H <-- branch_4, origin/branch_4
Теперь, когда у нас есть D'
, мы копируем E
поверх него, изменяя одну вещь - его родителя - чтобы сделать E'
, так же, как мы скопировали, но изменили D
, чтобы сделать D'
:
A--B <-- branch_1, origin/branch_1
\
C--D <-- branch_2, origin/branch_2
\ \
D' \ <-- [remember this hash]
\ \
E' E--F <-- branch_3, origin/branch_3
\
G--H <-- branch_4, origin/branch_4
Нам нужно будет скопировать F
в F'
и G
в G'
, а также H
в H'
, чтобы получить в общей сложности пять коммитов, скопированных в новые и улучшенные коммиты:
A--B <-- branch_1, origin/branch_1
\
C--D <-- branch_2, origin/branch_2
\ \
\ \ <-- [remember this hash]
\ \
\ E--F <-- branch_3, origin/branch_3
\ \
\ G--H <-- branch_4, origin/branch_4
\
D' <-- new_branch_2
\
E'-F' <-- new_branch_3
\
G'--H' <-- new_branch_4
Теперь у нас есть новые ветви, которые "так же хороши", как и старые (потому что они имеют коммиты, которые так же хороши или лучше, но с разными га sh идентификаторами). Теперь мы должны отбросить старые имена ветвей в пользу новых, возможно, переименовав старые ветви в old_*
, а новые, чтобы убрать new_
.
(наши old_*
имена больше не очень полезен, поэтому мы можем удалить их полностью, рано или поздно.)
Наконец, наши имена для удаленного отслеживания origin/*
запоминают имена веток, сохраненные в некоторых других Git Итак, теперь мы должны убедить, что другой Git репозиторий сбросить его копий этих коммитов и начать использовать наши новые копии. Чтобы сделать это, нам нужно будет использовать git push --force
или что-то подобное, чтобы отправить наши новые коммиты этому другому Git и сказать ему отказаться от всей работы, которую вы имели, в пользу этих новых и улучшенных коммитов . Например:
git push --force-with-lease branch_2 branch_3 branch_4
сделает свое дело (а --force-with-lease
сделает так, чтобы их идентификаторы ha sh, которые есть в наших origin/*
именах, соответствовали тому, что мы думаем, что они делают ).
Чтобы добиться этого в реальных c ситуациях, используйте git rebase
или git filter-branch
или аналогичный
Когда количество коммитов для «улучшения», как это, мало, вы можете делайте это по одному коммиту за раз, используя git cherry-pick
, оставляя себе маркеры: вот где new_branch_3 идет, например, . Когда он большой, это больно. Вы захотите автоматизировать процесс.
К сожалению, это сложно. К счастью, для этого есть несколько электроинструментов, включая git replace
. Это позволяет вам вставить трансплантат . Тем не менее, трансплантаты не переносятся на клонов: кто бы ни клонировал ваш репозиторий, он видит оригинальную незагруженную историю. К счастью, git filter-branch
или новый git filter-repo
могут затем преобразовать внедренный клон в клон с новой серией коммитов, обновляя имена ветвей в массовом порядке. Подробности см. В других ответах StackOverflow.