Как мне исправить поддерево git после того, как вышестоящая проектная сила была перенесена на master?

13

Я экспериментировал с использованием git поддерева и столкнулся со следующей ситуацией.

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

Оказывается, другой участник вышестоящего проекта случайно поместил большой файл в основную ветку. Чтобы это исправить, вышестоящий проект переписал историю и принудительно перенес на мастер. При создании моего "monorepo" я включил этот коммит, и я также хотел бы удалить его.

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

Моей первой попыткой было использование filter-branch для полного удаления поддерева и всей истории.

git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch upstream-project-dir' --prune-empty HEAD

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

Обновить

Я написал шаги, чтобы создать минимально воспроизводимый пример.

  1. Сначала создайте пустой репозиторий git.

    git init test-monorepo
    cd ./test-monorepo
    
  2. Создайте начальный коммит.

    echo hello world > README
    git add README
    git commit -m 'initial commit'
    
  3. Теперь добавьте поддерево для внешнего проекта.

    git remote add thirdparty git@github.com:teivah/algodeck.git
    git fetch thirdparty
    git subtree add --prefix algodeck thirdparty master
    
  4. Сделай коммит на монорепо

    echo dont panic >> algodeck/README.md
    git commit -a -m 'test commit'
    
  5. Теперь попытайтесь использовать git filter-branch для удаления поддерева.

    git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
    
  6. Проверьте вывод журнала git, я ожидаю увидеть только мой начальный коммит.

    git log
    
csnate
источник
Вы пытались git gc --prune = сейчас выбросить старые коммиты? Есть ли ссылки на старые версии коммитов?
Дамиано
1
Я еще не пробовал, но не будет ли git gc --prune=nowудалять только коммиты, которые не отображаются в git log?
csnate
использование git branch -all (которое, я полагаю, вы используете для просмотра "старых" коммитов) должно показать также коммиты, не связанные с вашей текущей веткой.
Дамиано
1
На самом деле, я просто делал git log, без аргументов, и я все еще вижу старые коммиты.
csnate
Пожалуйста, вы можете опубликовать свой журнал git --pretty --all --graph? Просто чтобы понять вашу ситуацию
Дамиано

Ответы:

0

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

давайте предположим, что вы masterперенаправили последний коммит и не смогли ничего сделать (у меня действительно нет ваших ветвей в поле зрения, поэтому мне нужно предположить что-то для начала)

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

например

git checkout master~1
git branch master -f
git checkout master
git pull
  1. git checkout master~1 чтобы проверить родительский коммит мастера, git предупреждает, что мы отключены
  2. git branch master -f чтобы заставить текущую проверку снова стать мастером, то есть она на самом деле перематывает ветку master к своему предыдущему коммиту (или X предыдущему коммиту), и отсюда не имеет значения, применил ли апстрим форс или нет, мы можем возобновить нормально, или даже вернитесь к шагу выше, если это необходимо, мы можем только извлечь мастер снова, не теряя ничего из апстрима (что для нас может быть доступно только для чтения, мы не будем ничего толкать для этого)
  3. git checkout master чтобы быть в нашей "перемотанной" главной ветке, тот же коммит, на который мы пошли, но теперь вместо этого на ветке
  4. git pullснова вытащить хозяина (может быть с или без --prune), если вверх по течению отвлечется, мы вернемся отсюда, если нет, мы получим то же, что и у нас, если мы получили то же самое и не предполагалось, возможно, мы необходимо вернуться к 1-му шагу выше и перемотать больше коммитов, например git checkout master~5или что-то еще (по мере необходимости)
arhak
источник
Я не думаю, что это будет работать сgit subtree
csnate
@csnate можно извлекать предыдущие коммиты из подпункта и следовать очень похожей процедуре, если вы создадите MCVE, было бы проще сказать вам точные команды, чтобы следовать stackoverflow.com/help/minimal-reproducible-example
arhak
Я постараюсь создать пример репо на GitHub.
csnate
Я создал набор шагов в исходном вопросе, который показывает проблему.
csnate
0
  1. на вашем репо очистите историю коммитов для этого пульта:

    git fetch upstream
    
  2. если один из ваших собственных коммитов имеет коммит, включающий большой файл, переписайте свою историю, чтобы на этот большой файл больше не ссылались

    # using one or more of the following commands :
    git rebase --interactive
    git filter-branch
    ...
    

С этими двумя шагами на большой файл больше не будет ссылаться ни один коммит в вашем репо.
Кроме того, он будет удален с вашего жесткого диска в некоторый момент времени, когда git запустит сборщик мусора и истечет время задержки для висячих больших двоичных объектов.


Если вам необходимо срочно удалить этот большой файл как можно скорее с жесткого диска:

Запустить вручную

git gc --prune=now
LeGEC
источник