Как удалить первые N коммитов? - PullRequest
0 голосов
/ 07 июня 2018

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

Другими словами.Я хочу разделить репо в точке n-го коммита, забрать коммиты, начиная с n + 1-го, отменить коммиты с 1-го по n-й.

Я не знаю, как этого добиться,Только попробовал git rebase, но это не сработало.

Вот что я сделал с git rebase.

Например, репо для тестирования: https://github.com/danistefanovic/build-your-own-x.git

  1. Выполнить git rebase -i --root

  2. Отметить первые 20 коммитов как удаленные

    d 4b6d12e Initial commit
    d f81138e Add links to issue form
    d 3530d91 Update README.md
    d 506b834 Update README.md
    d 79f41aa Update README.md
    d f9f9113 Update README.md
    d 9c8f134 Add resource type
    d 133469b Update ISSUE_TEMPLATE
    d 3a47f54 Add tutorials #1
    d 0271577 Add tutorial #2
    d 525953b Add tutorial #3
    d 2796fe5 Update ISSUE_TEMPLATE
    d 4f58667 Updated wrong link language from Go to Node.js
    d 0c525a7 Add tutorial #5
    d 0484fca Add OS: Build a minimal multi-tasking kernel for ARM
    d 457d5bb Add tutorial #9
    d 41ba7fc Add tutorial
    d dfbbf0f Add tutorial #11
    d b76dad5 Add tutorial #12
    d cd3bd26 Add tutorial #13
    pick c5f6c94 readme: Add my tutorial on shell
    pick 1f3c285 Add a minimal interpreter, compiler (x86/Arm) and JIT compiler
    ...
    
  3. Не повезло.Я должен обрабатывать конфликты вручную, как show blow.

    $ git rebase -i --root 
    error: could not apply c5f6c94... readme: Add my tutorial on shell
    
    Resolve all conflicts manually, mark them as resolved with
    "git add/rm <conflicted_files>", then run "git rebase --continue".
    You can instead skip this commit: run "git rebase --skip".
    To abort and get back to the state before "git rebase", run "git rebase --abort".
    Could not apply c5f6c94859d852797c26d815e438e6a697c137a9... readme: Add my tutorial on shell
    

Обновление

Дублировано с Удалить / обрезать историю изменений / коммитов Git

Но не удалось сохранить метки времени.

1 Ответ

0 голосов
/ 07 июня 2018

Прежде всего, вы пытаетесь удалить первые 20 коммитов или 20 коммитов после первого ?Как вы могли заметить в опубликованном вами списке TODO, commit 4b6d12e не указан, поэтому даже если операция работает, это не повлияет.Это потому, что вы указали 4b6d12e как upstream .Если вы хотите включить его (и если у него нет родителя, поскольку вы сказали, что пытаетесь удалить first 20 фиксаций), вы бы использовали опцию --root, чтобы у вас не былоуказать коммит как upstream.

Во-вторых, как вы определяете «удалить коммит»?Если commit A добавляет file1, а commit B добавляет file2, и я «удаляю» commit A, так что у меня остается только коммит B' - должен B' содержать и file1 и file2, илитолько file2?

Если коммит B' должен содержать только file2 - это означает, что вы удаляете коммит A и внесенные в него изменения - тогда способ сделать это - интерактивная перебазировка с опцией d.Но конечно это вызовет конфликты, которые вам придется разрешать вручную;из каждого коммита, который вы сохраняете, любой, который изменяет файл, который больше не создается (потому что он изначально был создан коммитом, который вы удалили) является конфликтом.У git нет возможности сделать вывод, что вы хотите, поэтому вы должны разрешить конфликт вручную.То, как ваш вопрос прерывается, предполагает, что вы ожидаете, что процесс будет автоматическим, но если вы удаляете исходные коммиты репо вместе с их изменениями, это не может быть автоматическим.

Обратите внимание, что этопереписать историю.Если репо используется совместно с другими, и ветвь даже была нажата (в то время, когда она содержала один из этих первых 20 коммитов), тогда

(a) вам придется использовать push -f для обновленияудаленный и

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

С другой стороны, если B' должен содержать оба файла - в этом случае он должен называться как AB вместо B' - тогда вы хотите сделать одну из двух вещей:

Один из вариантов - squash коммиты вместо delete их[1].Это просто вопрос использования разных команд для каждого коммита в списке rebase -i TODO.Если все, что вы делаете, это коммиты в сквош, то не должно быть конфликтовно это по-прежнему переписывание истории, так что приведенные выше замечания по-прежнему применимы.

Другой вариант - создать мелкий клон репо.Это не переписывание истории;его главное преимущество заключается в том, что он сохраняет идентификаторы коммитов, поэтому никто не нарушает репо (и, как побочный эффект, вы можете повторно связать удаленную историю в будущем, если возникнет такая необходимость).См. Параметры depth и shallow-* git commit.https://git -scm.com / docs / git-clone

Быть мелким - это не то, чем вы действительно можете поделиться с помощью толкания и вытягивания.Если удаленному пользователю необходимо удалить коммиты, вам придется заменить его на неглубокий (и предположительно зеркальный) клон.Каждый пользователь, имеющий клон, может обновить указанный клон [2].


[1] На самом деле я не люблю эту терминологию rebaseкоманда, потому что это продвигает неправильное представление о том, что коммит определяется его патчем, что на физическом уровне совершенно неверно.Но вот как rebase использует слова.

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

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