Как мне справиться с ошибкой в ​​моей истории .gitmodules? - PullRequest
0 голосов
/ 01 мая 2019

Я получаю сообщение об ошибке при попытке перенести бит репо на новый сервер:

$ git push -f research master
Enumerating objects: 13060, done.
Counting objects: 100% (13060/13060), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3397/3397), done.
Writing objects: 100% (13060/13060), 5.59 MiB | 364.00 KiB/s, done.
Total 13060 (delta 9516), reused 13060 (delta 9516)
remote: Resolving deltas: 100% (9516/9516), done.
remote: error: bad config line 14 in blob .gitmodules
remote: error: object 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb: gitmodulesParse: could not parse gitmodules blob
remote: fatal: fsck error in pack objects
error: remote unpack failed: index-pack abnormal exit
To gitlab.research.com:proj/repo.git
 ! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'git@gitlab.research.com:proj/repo.git'
$ 

Странно, я получаю ту же ошибку при запуске git fsck локально:

$ git fsck
Checking object directories: 100% (256/256), done.
warning in blob 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb: gitmodulesParse: could not parse gitmodules blob
Checking objects: 100% (13060/13060), done.
$ 

Оказывается, что "строка 14" в файле .gitmodules отсутствует в текущей версии файла, длина которой составляет всего 11 строк. Проблема вызвана тем, что была зафиксирована версия .gitmodules с конфликтом.

Могу ли я просто удалить блоб и перенести его в новый репозиторий, или есть серьезная проблема, которую я не могу легко исправить?

РЕДАКТИРОВАТЬ - НОВАЯ ИНФОРМАЦИЯ!

Учитывая превосходную публикацию @ torek ниже, в сочетании со сценарием в Какой коммит имеет этот BLOB-объект? (первый скрипт работал, но второй - нет), я смог найти проблемный коммит:

$ ~/.bin/git-find-object 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb
06407fd merged changes from master and stats

В моем репозитории git есть только одна видимая ветка:

$ git branch -v
* master e8ff018 minor

Я могу проверить проблемный коммит:

$ git checkout 06407fd
Checking out files: 100% (321/321), done.
fatal: bad config line 14 in file /home/xv32/gits/repo/.gitmodules

$

Я отредактировал файл .gitmodules напрямую и удалил неправильные строки:

<<<<<<< HEAD
        branch = ee
=======
>>>>>>> master

Я сделал git add .gitmodules

Я сделал:

$ git commit --amend -m 'fixed conflict in .gitmodules'

О Боже, это многое изменило.

Я тогда сделал статус мерзавца:

$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   submodule1 (new commits)
        modified:   submodule2 (new commits)
        modified:   submodule3(new commits)

no changes added to commit (use "git add" and/or "git commit -a")

$

git fsck больше не сообщает о проблемах:

$ git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (15206/15206), done.

Но я все еще не могу нажать на удаленное хранилище:

$ git push -f research master
Counting objects: 13245, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3395/3395), done.
Writing objects: 100% (13245/13245), 5.68 MiB | 2.81 MiB/s, done.
Total 13245 (delta 9746), reused 13180 (delta 9702)
remote: error: bad config line 14 in blob .gitmodules
remote: error: object 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb: gitmodulesParse: could not parse gitmodules blob
remote: fatal: fsck error in packed object
error: remote unpack failed: index-pack abnormal exit
To https://gitlab.research.com/repo/repo.git
 ! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'https://gitlab.research.com/censyn-sensitive/das_decennial.git'

$

Кроме того, когда я делаю git --amend, целая куча важных вещей исчезает за пределами плохих линий в объекте.

Честно говоря, я не понимаю, почему я даже получаю ошибку, так как ошибка не в верхней части дерева.

1 Ответ

2 голосов
/ 02 мая 2019

Могу ли я просто удалить 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.Это наиболее уместно, если у вас есть десятки тысяч коммитов «вниз по потоку» от плохого и / или много операций ветвления и слияния вниз по потоку.В противном случае вы могли бы также заняться исправлением неудачного слияния, а затем перебазировать или выбрать оставшиеся коммиты.

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