Какой лучший способ отменить слияние Git, которое стирает файлы из репо?

13

Итак, представьте, что происходит следующее (и что мы все используем SourceTree):

  1. Мы все работаем от происхождения / развития.
  2. Я иду в отпуск на неделю.
  3. Мой коллега работал локально в течение последних нескольких дней без слияния происхождения / развития обратно в его местное отделение разработки.
  4. Он пытается сделать толчок, ему говорят, что он должен сначала слиться, а затем делает тягу.
  5. Он получает конфликт, останавливая автоматическую фиксацию после слияния.
  6. Предполагая, что Git похож на SVN, мой коллега отбрасывает «новые» файлы в своей рабочей копии, а затем фиксирует слияние - стирает эти «новые» файлы из главы происхождения / разработки.
  7. Недели работы разработчиков продолжаются в дополнение к этой ревизии.
  8. Я возвращаюсь из отпуска и узнаю, что мне не хватает нескольких дней моей работы.

Мы все новички в Git (это наш первый проект, использующий его), но я исправил это:

  1. Переименуйте «Develop» в «Develop_old».
  2. Объединить Develop_old в новую ветку "Develop_New".
  3. Сбросьте ветку develop_new до последнего коммита перед неудачным слиянием.
  4. С тех пор Cherry выбирает каждый коммит один за другим, разрешая конфликты вручную.
  5. Нажмите разработчик и развивай до начала координат.

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

Я надеюсь, что это никогда не повторится, но если это случится снова, я хотел бы узнать о более легком / лучшем способе исправления. Есть ли лучший способ отменить «плохое» слияние, когда в репо на основе этого слияния проделана большая работа?

Джордж
источник
1
Не могли бы вы опубликовать снимок экрана дерева мерзавцев (отредактировано соответствующим образом) или вывод вашего любимого git logформата с соответствующими аннотациями о том, что происходило на различных коммитах? (Я бы отредактировал / аннотировал git log --graph --pretty=oneline --abbrev-commitи пошел бы оттуда)
1
Это слишком поздно для вас, но модульные тесты поймали бы это.
nalply
1
@nalply: Нет, если неудачное объединение также удалило модульные тесты.
Аарона
Вау, это действительно коварная неудача.
nalply

Ответы:

6

Если я правильно понял, это ваша ситуация:

    ,-c--c--c--c--M--a--a--X ← develop
o--o--y--y--y--y-´

После некоторой общей истории (o) вы совершили и отодвинули свою работу (y). Ваш коллега (с) работал над своим локальным хранилищем и плохо произвел слияние (M). После этого может быть несколько дополнительных коммитов (а) поверх M.

git reset --hard develop M^2
git branch coworker M^1

Теперь ваш график выглядит так же, как и до неудачного слияния:

    ,-c--c--c--c ← coworker
o--o--y--y--y--y ← develop

Сделайте хорошее слияние (G):

git checkout develop
git merge coworker

В результате чего:

    ,-c--c--c--c-、
o--o--y--y--y--y--G ← develop

Теперь пересаживаем дополнительные коммиты:

git reset --hard X
git rebase --onto G M develop

Это дает окончательный результат:

    ,-c--c--c--c-、
o--o--y--y--y--y--G--a--a--X ← develop

Помните, что это может привести к большему количеству конфликтов слияния. Также вы только что изменили историю, то есть все ваши коллеги должны клонировать / сбросить / переназначить новую историю.

PS: конечно вы должны заменить G, Mи Xв ваших командах на соответствующий идентификатор коммита.

Михась
источник
В вопросе кажется довольно очевидным, что все эти коммиты уже были перенесены в общий репозиторий, поэтому я не думаю, что перебазирование - это хороший выбор. Отменить все недавние коммиты, а затем отобрать вернутые неконфликтующие коммиты поверх удачного слияния, безопаснее.
Аарона
Это была часть с клоном / сбросом / перебазированием. - Если есть только несколько разработчиков, указание им обновить свои репозитории может быть допустимым вариантом.
Михас
1

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

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

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

Поэтому определенно объясните своему коллеге, что это был грандиозный провал, но подумайте над тем, чтобы ударить по бинту перед подготовкой к серьезной операции.

Aaronaught
источник
Я согласен, если целые файлы исчезли, вы можете сделать одну вещь, если вы не заботитесь об истории старых файлов: 1. создайте новую ветку из текущей испорченной ветки. 2. вернитесь к плохой ветке и создайте другую новую ветвь, которая будет вашей веткой аварийного восстановления. 3. Из ветки аварийного восстановления вернитесь к коммиту до неудачного коммита. 4. Скопируйте удаленные файлы куда-нибудь за пределы git. 5. Переключитесь на другую новую ветку. 6. Скопируйте новые версии удаленных файлов в новую ветку и подтвердите. Есть более сложный способ сохранить историю, это известное сообщение Линуса Т.
Элин
1
На самом деле это показывает, как вы можете использовать оформить заказ jasonrudolph.com/blog/2009/02/25/… Это гораздо приятнее.
Элин