Могу ли я просто удалить BLOB-объект ...
Нет: есть объект дерева T , который говорит: «У меня должен быть блоб 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb
». Поэтому вы должны найти дерево и разобраться с этим. На дерево T ссылается некоторый объект фиксации C . Поскольку файл .gitmodules
, это, вероятно, дерево верхнего уровня этого коммита. Возможно, вам придется найти этот коммит, но:
Проблема вызвана тем, что была зафиксирована версия .gitmodules
с конфликтом.
... этот является коммитом или, может быть, просто первым коммитом из нескольких, в котором есть дерево с надписью "У меня должен быть блоб". Другими словами, вы уже нашли нужный коммит.
Хитрость в том, чтобы переписать этот коммит новой и улучшенной версией. Новая версия должна быть почти такой же, как и оригинальная, за исключением того, что ее совершенный .gitmodules
(большой двоичный объект) должен быть верным, а не неправильным.
Как только вы замените на этот коммит, вы должны заменить дочернего или дочернего коммита этого коммита, потому что дочерний / дочерний элемент ссылается на неверный коммит по его хэш-идентификатору, а новая исправленная замена имеет другой хеш Я БЫ. Конечно, как только вы замените их, вы должны будете заменить их потомков, и так далее вплоть до любых коммитов с ветвями кончика потомка.
В идеале вы могли бы просто использовать git rebase
, чтобы исправить это (как подсказал phd ). К сожалению, вы сказали:
... был конфликт
, что означает, что первый плохой коммит сам по себе является слиянием. Вы не можете отменить слияние: вместо этого вы должны создать новое исправленное слияние.
Точно, насколько это трудно или просто, зависит от ряда вещей, например, от того, насколько хорошо вы знакомы с внутренней работой Git, и от того, сколько коммитов находится «вниз по течению» от неудачного слияния. Если их всего несколько, вы можете просто повторить слияние, на этот раз без ошибки, а затем вручную скопировать один или два оставшихся коммита.
Предположим, что плохое слияние - коммит X
, а его первый родитель - коммит P
:
...--o--P--X--1--2 <-- master (HEAD)
/
...---o--o <-- otherbranch
Здесь есть только два последующих коммита, поэтому вы можете:
git checkout <hash-of-P>
git merge otherbranch
Те же конфликты будут происходить, что и в прошлый раз, но на этот раз вы можете разрешить их правильно , чтобы .gitmodules
было правильным. Тогда:
git cherry-pick <hash-of-1>
git cherry-pick <hash-of-2>
скопирует коммиты 1
и 2
поверх этого нового замены:
,-X'-1'-2' <-- HEAD
/ /
...--o--P-/-X--1--2 <-- master
| /
|/
...---o--o <-- otherbranch
, где X'
, 1'
и 2'
- новые и улучшенные версии. (Возможно, вам придется исправить конфликт слияния, когда сбор вишни в зависимости от 1
или 2
фиксированный .gitmodules
, путем принятия исправленного .gitmodules
; или Git может увидеть, что оба изменения приводят к одной и той же вещи, и решите, что конфликта нет.)
Затем вы можете заставить имя master
идентифицировать коммит вместо 1077 *, после чего вы можете забыть, что коммиты X
, 1
и 2
когда-либо существовали:
...--o--P--X'-1'-2' <-- master (HEAD)
/
...---o--o <-- otherbranch
и теперь вы можете git push -f research master
.
Альтернативы
Помимо этого метода вы можете:
git checkout
плохое слияние напрямую (git checkout <em>hash-of-X</em>
);
- отредактируйте файл
.gitmodules
, чтобы исправить это, и git add
результат;
- run
git commit --amend
: это делает X'
.
Вероятно, это, по крайней мере, немного проще, поскольку вам не нужно повторять оставшуюся часть слияния. Затем вы можете повторить сбор вишни.
Если существует много коммитов «после» неудачного слияния, вместо того, чтобы выбирать их по одному, вы можете использовать git rebase --onto
для массового их копирования. Это работает только в том случае, если в этой серии коммитов нет слияний. То есть вышеприведенные виды графиков работают нормально, но:
3--4--5
/ \
...--o--P--X--1--2------6--7--8 <-- master (HEAD)
/
...---o--o <-- otherbranch
может и не быть, потому что commit 7
- это слияние: git rebase
полностью его отбросит и попытается создать новую цепочку поверх X'
, которая будет 1-2-3-4-5-6-8
или 1-2-6-3-4-5-8
. Что может быть в порядке, в зависимости от ваших потребностей.
В новейших версиях Git есть флаг --rebase-merges
, который будет повторно выполнять слияние (при копировании других коммитов а-ля git cherry-pick
).Вы можете использовать это для таких случаев.
Или, наконец, вы можете использовать git replace
в сочетании с git filter-branch
.Это наиболее уместно, если у вас есть десятки тысяч коммитов «вниз по потоку» от плохого и / или много операций ветвления и слияния вниз по потоку.В противном случае вы могли бы также заняться исправлением неудачного слияния, а затем перебазировать или выбрать оставшиеся коммиты.