Как отменить определенный коммит, который изменил все файлы, вызывая множество конфликтов во время возврата? - PullRequest
0 голосов
/ 26 апреля 2018

В совместном хранилище кто-то сделал коммит, который каким-то образом заставил его выглядеть так, как будто он снова добавил все файлы в хранилище.

Вот часть истории, когда напечатано с --date-order:

* 28cbf861 - (65 minutes ago) update logs and metadata (HEAD -> master, origin/master, origin/HEAD)
* e589776e - (18 hours ago) P2LTR15 update
...
* d4c61147 - (5 days ago) Delete P2STR03_SRC00150_Q0448_0000_0-7.log
* fa837509 - (5 days ago) Delete P2STR03_SRC00150_Q0427_0000_0-7.log
*   9a5e2300 - (5 days ago) git pull at 20180421 10am.
|\
* | 6567df4b - (5 days ago) add md5 3min
* | 6f7c80f7 - (5 days ago) Added md5sum files for all 3min SRCs
 /
* b97e834f - (6 days ago) Delete P2STR13_SRC00605_Q0325_0000_0-9.log
* 5cd9989b - (6 days ago) Delete P2STR13_SRC00605_Q0129_0000_0-9.log
* 769ae25d - (6 days ago) Delete P2STR13_SRC00605_Q0209_0000_0-9.log
...

Неисправный коммит - 6f7c80f7, и я хотел бы удалить его, но оставить 6567df4b. git pull commit (9a5e2300) - это простой коммит слияния.

Когда я печатаю историю без --date-order, внезапно коммит 6f7c80f7 показывается в самом низу, то есть, как будто это был первый коммит в истории.

* 28cbf861 - (70 minutes ago) update logs and metadata
* e589776e - (18 hours ago) P2LTR15 update
...
* fa837509 - (5 days ago) Delete P2STR03_SRC00150_Q0427_0000_0-7.log
*   9a5e2300 - (5 days ago) git pull at 20180421 10am.
|\
| * b97e834f - (6 days ago) Delete P2STR13_SRC00605_Q0325_0000_0-9.log
...
| * 697a103c - (7 months ago) initial commit
* 6567df4b - (5 days ago) add md5 3min
* 6f7c80f7 - (5 days ago) Added md5sum files for all 3min SRCs

Я пытался сделать git revert 6f7c80f7, но он показывает много конфликтов, которые я не знаю, как разрешить, то есть когда я делаю git status:

On branch master
Your branch is up to date with 'origin/master'.

You are currently reverting commit 6f7c80f7.
  (fix conflicts and run "git revert --continue")
  (use "git revert --abort" to cancel the revert operation)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    P2LTR15/.gitkeep
    deleted:    P2LTR15/MOS_P2LTR15_MO.csv
    ... (this is basically a list of almost all the files in the repository)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add/rm <file>..." as appropriate to mark resolution)

    deleted by them: P2LTR15/P2LTR15.yaml
    deleted by them: P2LTR15/audioFrameInformation/P2LTR15_SRC00712_HRC021.afi
    ... (this is another list of files, I don't know why it is there, possibly those were actually changed)

Есть ли какой-нибудь другой способ, которым я мог бы переписать историю Git таким образом, чтобы этот плохой коммит никогда не происходил?

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

1 Ответ

0 голосов
/ 26 апреля 2018

Вы говорите, что ваша git log выходная кавычка является только частью истории, но вы также говорите, что commit 6f7c80f7 добавляет всех файлов и в цитируемом тексте, 6f7c80f7 никогда не показывает родительский коммит, к которому он подключается.

Это говорит о том, что 6f7c80f7 является корневым коммитом : начальный коммит, который, по сути, добавляет каждый файл, к которому он относитсяпоказывает, что «предыдущий» коммит не существует, поэтому каждый файл по определению должен быть новым в этом коммите.

График может иметь более одного корня.Это немного необычно в графике коммитов Git, так как мы обычно делаем новые коммиты, сначала проверяя существующий коммит, затем вносим изменения, затем запускаем git commit, чтобы сохранить новый полный снимок.Но есть и другие способы:

  • Мы можем использовать git fetch для получения несвязанного репозитория, затем git merge с --allow-unrelated-histories.Если версия Git достаточно старая, git merge всегда разрешает несвязанные истории и не имеет флага --allow-unrelated-histories: он просто объединяет их без предупреждения.(Вы можете увидеть здесь множество add/add conflict ошибок, и вам придется много решать вручную!)

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

  • Мы можем использовать git checkout --orphan, чтобы установить наше собственное состояние репозитория так, чтобы следующий коммит, который мы делаем, былбыть корневым коммитом.

    (Если и когда мы делаем делаем этот корневой коммит, у нас будут те же проблемы слияния, что и в случае «извлечения несвязанного репозитория».)

  • Мы можем, случайно или преднамеренно, возиться с внутренностями Git, используя такие команды, как git commit-tree, или просто тыкать в файлы внутри .git, чтобы создать новый корневой коммит.

В любом случае, когда у нас есть это состояние, в котором есть несколько корней и коммит слияния, который объединяет дополнительный корень и затем строит больше коммитов на вершине слияния, мы как бы застреваем с ситуацией.Коммит слияния - в вашем случае 9a5e2300 - имеет хеш-идентификатор, который зависит от существования обеих цепочек коммитов: от одного, ведущего к исходному корневому коммиту, итот, который ведет к новому корневому коммиту.Хеш-идентификатор любого коммита, который имеет 9a5e2300 в качестве родителя - в вашем случае это всего лишь один коммит fa837509 - зависит от существования 9a5e2300, поскольку он буквально включает этот хэш-идентификатор в свой собственный ID.Идентификатор хэша дочернего элемента fa837509 (опять же, здесь есть только один коммит в вашем графе), зависит от существования fa837509;если остальная часть графика является линейной, то каждый дочерний элемент в свою очередь зависит от его родительского идентификатора вплоть до конца.

Следовательно, если бы вы каким-то образом избавились от лишнегоКорневой коммит, ваш коммит слияния должен иметь другой хэш-идентификатор, что означает, что каждый последующий коммит также должен иметь другой хэш-идентификатор.Более того, если бы вы действительно избавились от 6f7c80f7, копия, которую вы должны были бы сделать из его текущего потомка 6567df4b, была бы другим корневым коммитом!Вам также придется избавиться от этого, что будет означать, что для слияния не будет ничего для коммита 9a5e2300 слияния, так что вы, вероятно, захотите также отказаться от него - за исключением того, что вы захотите как-то сохранить его исходный снимок .Затем вам нужно будет взять всю оставшуюся (предположительно линейную) цепочку от fa837509 до верхушки и скопировать каждый из этих коммитов в новые коммиты, которые не зависят от существования 9a5e2300, но используйте любой сделанный вами коммит, который имеет обновленный моментальный снимок источника из коммита слияния.

Следовательно, это приведет к процессу, который вам придется использовать, чтобы избежать двух корневых коммитов:

  • Скопируйте снимок в слиянии 9a5e2300 в новый коммит без слияния.Это получает новый хэш-идентификатор (потому что это новый уникальный коммит).Сохраните этот идентификатор где-нибудь.

  • Copy снимок в fa837509 для нового коммита, который также получает новый хэш-идентификатор. Родитель нового коммита будет идентификатором, который вы только что сохранили. Сохраните этот идентификатор где-нибудь.

  • Скопируйте снимок из дочернего элемента fa837509 в новый коммит, используя предыдущую копию в качестве нового родителя.

  • Повторяйте каждый коммит, пока не дойдете до верхушки.

Как только вы получите эту линейную цепочку коммитов, которая не зависит от коммитов, от которых вы хотите избавиться, вы можете просто прекратить использовать исходную цепочку коммитов, которую делает зависит от коммитов, от которых вы хотите избавиться. Если вы и все остальные делают это, и вы удаляете имена, по которым ваш Git находит старую цепочку, то создается впечатление, что эта старая цепочка никогда не существовала. С исчезновением имен старые коммиты действительно удаляются. (Это происходит, когда истекает срок действия всего таймера проверки безопасности. Эти проверки безопасности существуют, так что вы можете вернуть старые коммиты, если сделаете ошибку, но поймаете ее достаточно быстро - обычно 30 дней - и чтобы Git мог создавать объекты, которые не являются все же подключены к графу фиксации, но будет в течение 14 дней. Обычные команды Git в худшем случае соединяют их в течение нескольких миллисекунд, поэтому 14 дней - это практически тысячелетия.)

Выше показано, что возможно сделать то, что вы предлагаете (хотя, возможно, вы захотите построить немного другую историю замены, чем та, которую я описал). Будь то хорошая идея - это совсем другой вопрос. Главный недостаток переписывания истории, однако вы делаете это - с git rebase, с git filter-branch, с BFG Repo Cleaner , или с чем-то, что вы придумали самостоятельно - то, что переписанный репозиторий по сути, это новый репозиторий. Или, по крайней мере, новая цепочка является новой: старые вещи, до точки перезаписи, остаются такими же. Вы должны заставить каждого, у кого есть копии старого репозитория , переключаться с old на new . Если даже одиночный человек сохраняет старые коммиты и использует Git для слияния старых с новыми (что Git очень рад сделать), все старые коммиты возвращаются . Теперь у вас есть старое и новое все вместе в одном большом счастливом (?) Хранилище, и ваши проблемы только обострились!

Нет ничего принципиально неправильного в том, чтобы переписать (некоторые или все) ваши коммиты в новую историю, вам просто нужно (а) знать, как это сделать и (б) знать об этом «каждый должен переключиться». Если ни у кого больше нет коммитов, которые вы заменяете, этот вид перезаписи полностью безопасен - нет другого человека или другого репозитория Git , который вернет старые коммиты в игру , Если каждый, кто имеет , имеет старые коммиты, понимает, как это работает, и планирует сотрудничать, этот вид переписывания истории будет в основном безопасным: он пойдет не так, только если кто-то совершит ошибку (и затем, в зависимости от вашего уровня осторожности и / или паранойи, может быть, только для них!). Когда у вас есть наивные пользователи, которые просто позволяют Git по умолчанию Borg-подобное действие интегрировать все технологии, с которыми он когда-либо сталкивался, такое переписывание создает беспорядок.

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