Удалить некоторые старые коммиты, которые включают файлы данных - PullRequest
0 голосов
/ 22 марта 2019

У меня есть удаленный репозиторий git. Пульт включает в себя кучу коммитов. Я по ошибке перенес свой набор данных (файлы данных почти 3 ГБ) на удаленный компьютер. Я хочу удалить / удалить некоторые старые коммиты, которые включают набор данных как в локальном, так и в удаленном репозитории, чтобы уменьшить размер репозитория. git log --oneline отпечатки:

993ebd6 last commit
cd882ce blah blah blah
...     ...
289a7dd blah blah blah
d750b6c data file ignored (added to .gitignore)
8005019 repo still includes data files
2a85665 repo still includes data files
83601d3 data added!
89b7a4a initial commit

Я хочу удалить коммиты, содержащие файлы данных (от d750b6c до 89b7a4a). Я имею в виду, что нужно удалить не только коммиты, но и файлы, связанные с коммитом. Насколько я знаю, git reset --hard выполняет удаление, однако удаляет только локальные файлы и вызывает ошибку, когда существует общий удаленный репозиторий.

Любая помощь приветствуется.

Ответы [ 2 ]

0 голосов
/ 23 марта 2019

У меня есть следующий пример, который, кажется, работает.

предположительно у меня есть мои коммиты master из хранилища d1:

* 20e4a1f added c.txt
* 79422f7 removed big file
* bc0d9c7 added b.txt
* 5b0c75d big file
* 5a8df10 initial

большой файл был добавлен в 5b0c75d иудалено в 79422f7.что-то произошло в середине и после.

Следующий набор действий делает работу:

git checkout 5a8df10  -b update
git cherry-pick bc0d9c7 
git cherry-pick 20e4a1f 

теперь создайте еще один репозиторий 'd2' и добавьте в него новый бранч.

cd ../d2
git init
git pull ../d1 update

теперь ваш репозиторий d2 будет намного меньше.

Конечно, вам нужно разрешить все конфликты в пути.Однако git checkout --theirs в этом случае работает универсально.

вы определенно потеряете историю пропущенных коммитов.

0 голосов
/ 22 марта 2019

Без --graph, git log --oneline пропускает некоторую информацию.Пропущенная информация может * быть важной здесь.Это , вероятно, , но это может быть неактуально.Давайте предположим, что это уместно, и нарисуем его.

Давайте посмотрим на , что хранит Git (пока не слишком много заботясь о части how ).То, что Git хранит, в любом случае в первом приближении, это коммит .Каждый коммит содержит полный и полный снимок всех файлов , а также всех файлов, которые существовали в Git в index на момент создания вами коммита.Итак, ваш файл больших данных находится в коммите 83601d3 (data added!).Это также в коммитах 2a85665 и 8005019.Он также может быть в d750b6c (здесь отмечен data file ignored (added to .gitignore)), поскольку добавление name в .gitignore не меняет отсутствие или присутствие файла в индексе. 1 Перечисление файла в .gitignore в основном просто закрывает git status, говоря, чтобы он не жаловался, если файл находится в рабочем дереве, но отсутствует в индексе.

Но сохраненный снимокне только вещь в коммите.Каждый коммит также сохраняет некоторые метаданные - некоторые данные о сохраненном снимке.Например, каждый сделанный вами коммит имеет ваше имя и адрес электронной почты.В нем есть ваше сообщение журнала - информация, которую вы сохранили в Git, о , почему вы сделали этот коммит, чтобы вы могли видеть, что вы думали в то время.У него есть отметка даты и времени.И, что особенно важно, он имеет хэш-идентификатор - например, 83601d3 (но с полной длиной в 40 символов) - его parent commit.

Git выглядиткоммиты по этим хэш-идентификаторам.По сути, идентификаторы являются реальными именами коммита.Каждый идентификатор уникален для этого конкретного коммита.Фактически, идентификатор формируется путем вычисления криптографического хэша над содержимым коммита - так что это означает, что parent ID дочернего коммита является важной частью личность ребенка.Помните, что в глубине вашей головы, пока мы берем момент, чтобы нарисовать эту цепочку коммитов:

993ebd6 last commit
   ↓

cd882ce blah blah blah
   ↓
...     ...
   ↓

289a7dd blah blah blah
   ↓

d750b6c data file ignored (added to .gitignore)
   ↓

8005019 repo still includes data files
   ↓

2a85665 repo still includes data files
   ↓

83601d3 data added!
   ↓

89b7a4a initial commit

, встроенный в каждый коммит, другими словами, является своего рода стрелкой назад (или вниз вэто вертикальный рисунок).Добавление --graph к git log, с или без --oneline, заставляет Git рисовать стрелки / линии одинакового типа (в основном используя вертикальную черту | для соединения маркеров * при каждом коммите, с указанием направления стрелкивместо того, чтобы рисовать).

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

Итак, давайте заменим плохой коммит 83601d3 новым, лучшим.Мы пока не знаем, каков его хэш-идентификатор, но мы все равно можем его нарисовать:

2a85665 repo still includes data files
   ↓
83601d3 data added!                       XXXXXXX improved: no extra data
   ↓                                         │
89b7a4a initial commit                 ←─────┘

Так что ... все в порядке, но теперь нам нужно также скопировать 2a85665.В любом случае, мы бы сделали, потому что у него все еще есть большие файлы, поэтому мы должны сделать новый и улучшенный коммит, в котором их нет. родительский нового и улучшенного 2a85665 будет иметь новый хэш-идентификатор YYYYYYYY.

Теперь нам также нужно скопировать 8005019 минус большие файлы.И затем, поскольку он получает новый хэш-идентификатор, мы определенно должны также скопировать d750b6c, , даже если d750b6c не имеет больших файлов .Мы должны сделать новую копию с новым идентификатором хеша в качестве родителя.

Имея копиюТо есть d750b6c, мы должны скопировать его дочерний элемент, чтобы, опять же, заменить идентификатор родительского хэша, если ничего больше. Это пульсирует при каждом другом коммите, пока мы не достигнем 993ebd6. Скопировав это, мы получили новую цепочку, заканчивающуюся тем, чем является этот новый хеш. Git заменил хеш-идентификатор 993ebd6, хранящийся под именем master (или любым другим именем ветви, которое вы используете), на хеш-идентификатор последнего замещающего коммита, по сути, «забыв» исходную цепочку коммитов.

Эта операция - внесение некоторых изменений в некоторые ранние коммиты, а затем их изменение будет распространяться по всей цепочке коммитов, копирование и замена каждого на новую и улучшенную версию - вот что git rebase построен, чтобы делать. С git rebase -i вы получаете возможность исправить более ранний коммит, а затем скопировать все последующие коммиты в новые и улучшенные версии. В результате получается новая цепочка коммитов, и всем, кто использовал старую цепочку - вам в вашем Git-репозитории, но также всем, у кого есть отдельный Git-репозиторий, например, тот, что в origin - переключиться на новую цепь. Для вас это просто вопрос использования git push --force для обновления вашего пульта на origin.


1 Более подробную информацию об индексе, например, область размещения или иногда кэш , смотрите в других статьях, в которых описано, как Git создает новый коммит от того, что в индексе в то время. Вот как создаются снимки Git: вы копируете файлы в индекс, а затем запускаете git commit. Шаг копирования в индекс - это то, что фактически сжимает и выполняет Git-файл, делая его готовым к быть подтвержденным. После этого Git продолжает извлекать файлы Git-ified из коммитов и копировать их в индекс, чтобы они были готовы перейти к next commit.

Наличие файла в индексе определяет, отслеживается ли файл . Вы можете использовать git rm --cached, чтобы удалить файл из индекса, не удаляя его из рабочего дерева: теперь он не отслежен, т. Е. Отсутствует в индексе, и поэтому не будет в next commit, если вы не сделаете что-то вроде выбора существующего коммита с файлом, чтобы Git снова скопировал файл в индекс.

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