git — удалить коммиты из объединенной ветки

Я случайно нажал коммит с огромными файлами, а потом отменил его. Но это заставляет любого, кто тянет эту ветку, получить эти файлы в истории, поэтому я решаю удалить или раздавить эти два коммита. Однако некоторые ветки были объединены. Я не знаю, как заставить «git rebase -i» сохранить структуру ветвей.

Теперь история выглядит так:

H - new commits
|
G - merge
| \
|  F - commits on another branch
|  |
E  | - some other commits
|  |
D  | - corrected B
|  |
C  | - revert B
|  |
B  | - huge files
| /
A - early commit

Могу ли я изменить его на следующее?

h - new commits
|
g - merge
| \
|  F - commits on another branch
|  |
e  | - some other commits
|  |
d  | - corrected B
| /
A - early commit

person Xiao    schedule 16.09.2016    source источник
comment
Возможно ли, чтобы другая сторона повторила слияние?   -  person Tim Biegeleisen    schedule 16.09.2016
comment
@TimBiegeleisen Да, но нужно сохранить структуру.   -  person Xiao    schedule 16.09.2016
comment
Интерактивная перебазировка и удаление huge files и revert B. Затем повторите слияние. Наконец, выберите новые коммиты, которые появятся после этого.   -  person Tim Biegeleisen    schedule 16.09.2016
comment
@TimBiegeleisen Спасибо. Есть ли скрипты для этого? Поскольку после этой точки есть несколько новых ветвей и слияний, воспроизведение вручную затруднительно.   -  person Xiao    schedule 16.09.2016
comment
Учитывая, что с момента фиксации большого файла произошло так много коммитов и слияний, вы можете посмотреть здесь, чтобы узнать, как удалить этот большой файл.   -  person Tim Biegeleisen    schedule 16.09.2016
comment
Выполнение интерактивной перебазировки вручную сейчас рискованно и может быть подвержено ошибкам.   -  person Tim Biegeleisen    schedule 16.09.2016
comment
Всегда есть git filter-branch для смелых...   -  person nonsensickle    schedule 16.09.2016
comment
@TimBiegeleisen @nonsensickle Спасибо. git filter-branch помогло сэкономить место. Хотя еще не придумал, как полностью удалить коммиты с его помощью, для этого случая этого достаточно.   -  person Xiao    schedule 16.09.2016
comment
@nonsensickle Смотрите ваш ответ, спасибо.   -  person Xiao    schedule 16.09.2016


Ответы (2)


Да, можно но не следует.

Вам потребуется переписать историю и заменить уже отправленную историю на сервер (что требует принудительной отправки и чаще всего приводит к тому, что все на вас кричат).

Но если вы действительно хотите, то git filter-branch - это то, что вы хотите использовать, как в этом ответе SO. Итак, вы бы сделали что-то вроде этого:

git filter-branch --commit-filter '
    if [ "$GIT_COMMIT" = "<your commit to remove here>" ]
    then
        skip_commit "$@";
    else
        git commit-tree "$@";
    fi'  HEAD

Есть еще несколько примеров здесь< /а>.

person nonsensickle    schedule 16.09.2016
comment
Отлично, это то, что я ищу. Это внутреннее репо, и не проблема, чтобы другие сделали принудительное извлечение. - person Xiao; 16.09.2016

Нет, ты не можешь.

Хэш каждого коммита включает в себя не только хешированное содержимое всех файлов в индексе, но и хэши родителей коммита.

«Исправленный B» будет иметь другого родителя, чем сейчас. Это изменило бы хеш.

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

Единственным реальным способом исправить это будет следующий процесс:

 git checkout A

Проверьте родительский коммит до разветвления ветки. Затем создайте две рабочие ветки:

 git checkout -b corrected-mainline
 git checkout -b corrected-fork

Теперь вы находитесь на ветке исправленной вилки. Теперь в этой ветке вы сможете git cherry-pick выполнить все коммиты до F, пропустив коммит с огромными файлами и его откат. Если какой-либо из этих коммитов является слиянием, сделайте то же слияние.

Теперь сделайте то же самое на ветке corrected-mainline

 git checkout corrected-mainline

Теперь git cherry-pick все коммиты в основной ветке, вплоть до последнего коммита перед G слиянием. Затем выполните слияние с веткой corrected-fork. Теперь это ваш исправленный коммит слияния G.

Завершите выборку всех коммитов, которые изначально были поверх G на вашей диаграмме, закончив последним коммитом в исходной ветке.

На этом этапе содержимое вашей рабочей ветки должно совпадать с содержимым исходной ветки. Убедитесь, что это так.

Затем удалите исходную ветку и переименуйте рабочую ветку в ее имя. Или используйте git reset --hard, чтобы сбросить исходную ветку на исправленную рабочую ветку.

Затем сделайте git push --force, чтобы подтолкнуть исправленную ветвь вверх. Конечно, любой, кто потянет за ветку, в конечном итоге получит силу.

person Sam Varshavchik    schedule 16.09.2016
comment
Я использую git filter-branch. Спасибо за Ваш ответ. - person Xiao; 16.09.2016