Каждый коммит указывает на предшественников

Коммит в Git — не отдельная копия всего проекта, а запись о состоянии файлов вместе со ссылкой на предыдущий коммит. Обычно такая ссылка одна. Когда Git объединяет две ветки, новый коммит слияния связывает сразу две линии истории: у него два родителя. Поэтому последовательность изменений превращается в граф — сеть ветвлений и соединений.

Это важно при отмене: Git должен понять не только какие файлы поменялись, но и какую линию истории считать основной.

Отменить изменения — не значит стереть слияние

Для опубликованной истории обычно безопаснее создать новый коммит, который отменяет изменения прежнего. При отмене слияния нужно указать основную родительскую линию: относительно неё Git вычисляет, какие изменения объединённой ветки следует обратить. Если выбрать не ту линию, результат может быть неожиданным — например, часть нужных изменений исчезнет.

Сам коммит слияния при этом остаётся в графе. Это принципиальное отличие от переписывания истории: прошлое не вырезают, а добавляют новую запись, компенсирующую его последствия.

Почему повторное слияние может удивить

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

Именно поэтому неудачное слияние нельзя всегда исправить простым нажатием «назад»: выбор способа отмены влияет и на файлы сейчас, и на то, что Git сочтёт уже объединённым в будущем.