Исправление git истории двойного фиксации

Мне нужно было запустить git filter-branch на днях. Я выполнил инструкции в github, но что-то пошло не так. Я думаю, что кто-то из команды не использовал rebase в локальном филиале и вместо этого объединил изменения. С тех пор журнал фиксации заполняется двойными коммитами, например:

commit b0c03ec925c0b97150594a99861d8f21fd3ab22d
Author: XXX
Date:   Wed Mar 19 17:01:52 2014 -0400

    Removed most clearfixs in templates

commit f30c21d21b5ea715a99b0844793cb4b5f5df97a1
Author: XXX
Date:   Wed Mar 19 17:01:52 2014 -0400

    Removed most clearfixs in templates

commit 2346be43d0e02d3987331f0a9eeb2f12cd698ede
Author: XXX
Date:   Wed Mar 19 16:40:26 2014 -0400

    new redirect logic

commit 1383070b31bde1aaa9eda7c2a9bcb598dd72247b
Merge: d1e2eb6 94e07fe
Author: XXX
Date:   Wed Mar 19 16:28:41 2014 -0400

    Merge branch 'develop' of github.com:xxx/xxx into develop

commit 79ce7824688cf2a71efd9ff82e3c7a71d53af229
Merge: 6079061 1ed3967
Author: XXX
Date:   Wed Mar 19 16:28:41 2014 -0400

    Merge branch 'develop' of github.com:xxx/xxx into develop

commit d1e2eb645a4fe2a1b3986082d0409b4075a0dbc9
Author: XXX
Date:   Wed Mar 19 16:28:36 2014 -0400

    Fixed broken responsiveness for companies listing page and code refactoring.

commit 6079061f6ef1f856f94d92bc0fdacf18854b8a89
Author: XXX
Date:   Wed Mar 19 16:28:36 2014 -0400

    Fixed broken responsiveness for companies listing page and code refactoring.

Как ни странно, не все коммиты удваиваются, например, "новая логика перенаправления" выше. Есть ли что-нибудь, что я могу сделать, чтобы исправить это? Это относительно мягко, но теперь наша история фиксации выглядит как дерьмо. Этот SO post предложил оставить его как есть, но я предпочел бы иметь чистую историю фиксации для потомков.

Ответ 1

Команда для выполнения:

git rebase -i HEAD~7

Это откроет ваш редактор примерно так:

pick f392171 Removed most clearfixs in templates
pick ba9dd9a Removed most clearfixs in templates
pick df71a27 Unew redirect logic
pick 79ce782 Merge branch 'develop' of github.com:xxx/xxx into develop
pick 1383070 Merge branch 'develop' of github.com:xxx/xxx into develop
...

Теперь вы можете сказать git, что делать с каждой фиксацией. Пусть сохранится фиксация f392171, та, где мы добавили нашу функцию. Мы раздавим следующие два коммита в первый, оставив нас с одним чистым.

Измените файл следующим образом:

pick f392171 Removed most clearfixs in templates
squash ba9dd9a Removed most clearfixs in templates
pick df71a27 Unew redirect logic
pick 79ce782 Merge branch 'develop' of github.com:xxx/xxx into develop
squash 1383070 Merge branch 'develop' of github.com:xxx/xxx into develop

Когда вы сохраняете и выходите из редактора, git применяет все два изменения, а затем возвращает вас обратно в редактор, чтобы объединить три сообщения фиксации:

# This is a combination of  commits.
# The first commit message is:
Removed most clearfixs in templates

# This is the 2nd commit message:

Removed most clearfixs in templates

По завершении сохраните и закройте редактор. git теперь выдаст коммит в один. Все сделано!

Затем вам нужно сделать

git push origin your-branch -f

чтобы принудительно вносить изменения локально в удаленную ветвь.

Примечание. Вы должны делать сквош для каждого дублированного фиксации.

Ответ 2

Ответа на этот вопрос @VAIRIX замечательно, но существуют сложные случаи, когда дублирующие коммиты не отображаются рядом друг с другом, поэтому раздавить не поможет.

Итак, беря ниже истории, (предположим, что ~ является дубликатом a)

 # h
 # g
 # f
 # c~
 # b~
 # a~
 # e
 # d
 # c
 # b
 # a

Команда, которой следует следовать: (как сказано в ответе @VAIRIX или ниже, если вы хотите переустановить с помощью мастера) git rebase master -i (лучше избегать git rebase -i HEAD~n, чтобы избежать переустановления головной боли)

Теперь! 1) раздавить повторные фиксации, как показано ниже:

 pick h
 pick g
 pick f
 pick c~
 s b~
 s a~
 pick e
 pick d
 pick c
 pick b
 pick a

Теперь это будет выдавливать ваши коммиты в c

 # h
 # g
 # f
 # c~ (having changes of a~ and b~)
 # e
 # d
 # c
 # b
 # a

В моем случае c ~ была анти-фиксацией c, поэтому мне просто нужно было выполнить этот процесс еще раз, но теперь вместо squash с s я отбрасываю фиксацию с помощью d

 pick h
 pick g
 pick f
 d c~ (having changes of a~ and b~)
 pick e
 pick d
 pick c
 pick b
 pick a

Теперь вы будете удалять все дубликаты. Теперь вы можете сравнить с веткой происхождения, с которой вы использовали git diff, который дублировал вашу ветку. Не должно быть никакого различия, если вы сделали это отлично.

Этот процесс может показаться немного длиннее, но вы уверены, что не пропустили никаких коммитов.