Как изменить коммит на ветке, которая имеет дочерние ветви? - PullRequest
1 голос
/ 24 марта 2020

Предположим, у меня есть этот журнал истории:

* hash8 (HEAD -> branch_4, origin/branch_4) Message 8
|
* hash7 Message 7
|
* hash6 (origin/branch_3, branch_3) Message 6
|
* hash5 Message 5
|
* hash4 (origin/branch_2, branch_2) Message 4
|
* hash3 Message 3
|
* hash2 (origin/branch_1, branch_1) Message 2
|
* hash1 Message 1

И я хочу сделать некоторые изменения кода, чтобы зафиксировать с hash4 и историю, чтобы они выглядели одинаково. Обратите внимание, что у меня тоже есть ветки, а не только коммиты. Как бы вы это сделали?

1 Ответ

0 голосов
/ 24 марта 2020

Вы не можете сделать это вообще. Никакая часть какого-либо коммита не может быть когда-либо измененной.

Вы можете сделать что-то другое , которое может быть - или не может - быть достаточно хорошим .

При любом 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...