Имена ветви здесь не важны. Какое значение имеют коммиты .
Хитрость заключается в том, чтобы получить ваши коммиты и найти базу слияния . База слияния - это место, где объединяются ваши филиалы. Давайте нарисуем ваши фактические ветви. Конечно, я должен угадать каковы ваши коммиты; Вы не показали нам свой репозиторий и его коммиты. Но они, вероятно, выглядят примерно так:
I--J <-- BranchA
/
...--G--H
\
K--L <-- BranchB
Здесь каждая заглавная буква заменяет некоторый фактический коммит ha sh ID. Используйте git log --graph BranchA BranchB
, чтобы Git нарисовал график для вас, вертикально с новыми коммитами к вершине, вместо того, как я нарисовал, горизонтально с более новыми коммитами вправо. Команда git log
будет также включать действительные идентификаторы ha sh (хотя и сокращенно).
Обратите внимание, как в какой-то момент две ветви объединяются. На графике, который я нарисовал выше, они объединяются при коммите H
. Этот коммит является базой слияния , а база слияния является ключом к слиянию.
То, что вы делаете, сравнивает содержимое коммитов J
и L
. Один из этих коммитов имеет на пять файлов больше, чем другой. Это не важно.
Важно то, что вы получите, если вы:
Сначала сравните H
против J
. Это говорит вам о том, что вы или кто-то другой изменили в серии коммитов, ведущих от H
до J
.
Затем сравните H
против L
. Это говорит вам о том, что вы или кто-то другой изменили в серии коммитов, ведущих от H
до L
.
Git собирается объединить эти два набора изменений .
Что вы найдете, когда найдете коммит H
(или его фактический идентификатор ha sh), так это то, что один из этих двух сравнений говорит удалить пять файлов . Это одно из множества изменений, которые Git объединяет. (Исходя из вашего описания выше, это H
-vs- J
: удаление произошло в верхней строке.)
Другой из двух сравнений говорит: «Вы не не нужно ничего делать с этими пятью файлами ". Эти две инструкции легко объединить: «ничего не делать» плюс «удалить» равно «удалить». Так что git merge
удалит эти пять файлов .
Лучше всего сделать новый коммит на ветке A, который говорит, что поместит эти пять файлов из базы слияния H
или из коммита L
назад :
I--J--M <-- BranchA
/
...--G--H
\
K--L <-- BranchB
Теперь сравнение H
против M
говорит ничего не делать с этими пятью файлами . Сравнение H
против L
также показывает, что ничего не делать с этими пятью файлами . Легко объединить эти два набора инструкций: Git сохранит эти пять файлов, которые одинаковы для всех трех коммитов.
Как ответил bk2204, пока я набирал все это , вы можете go вперед и выполнить слияние, затем изменить его, или вы можете запустить git merge --no-commit
, чтобы Git еще не сделал окончательный коммит, а затем изменить его перед фиксацией, чтобы результат слияния сохранил пять файлов, несмотря на более естественный результат. Затем вы получите:
I--J
/ \
...--G--H M
\ /
K--L
где снимок в коммите merge M
объединяет изменения, но сохраняет пять файлов. (Имя ветви, которая перемещается в направлении M
, зависит от того, какую ветку вы git checkout
перед запуском git merge
.)
Последнее, если есть какая-то причина не делать восстановительный коммит до слияние - что обычно является лучшей практикой - и вы не хотите совершать «злое слияние», которое требует повторения этого трюка, если вы когда-либо используете git rebase --rebase-merges
, вы можете go вперед и сделать коммит слияния M
, который удаляет пять файлов, но затем возвращает их в последующий коммит. Например, предположим, что вы используете git checkout BranchA; git merge BranchB
, чтобы получить:
I--J
/ \
...--G--H M <-- BranchA (HEAD)
\ /
K--L <-- BranchB
Теперь вы можете сделать еще один коммит, который просто возвращает файлы обратно:
git checkout <hash-of-H> -- file1 file2 ... file5
git commit -m "restore five files that were erroneously deleted in commit <hash>"
, например, что результат:
I--J
/ \
...--G--H M--N <-- BranchA (HEAD)
\ /
K--L <-- BranchB
, где commit N
имеет пять файлов назад.
(Используйте git checkout BranchB
или git checkout <em>hash-of-L</em>
, если вы хотите вместо этого взять пять файлов из коммита L
, хотя, если не было конфликта изменения / удаления, это означает, что эти пять файлов совпадают в коммитах H
и L
. Таким образом, не имеет значения, какой файл вы используете для получения пяти файлов: используйте любую простую команду. Обратите внимание, что имя BranchB
здесь работает корректно только потому, что мы произвели слияние на BranchA
, так что имя BranchB
не двигалось. Если бы мы сделали git checkout BranchB; git merge BranchA
, имя, которое переместилось бы на M
, было бы BranchB
.)