Файлы удаляются в GIT при объединении - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть две ветви в GIT - ветвь A и ветвь B. Ветвь A содержит 10 файлов. Ветвь B содержит 15 файлов, из которых 10 общих для ветви A.

Пока я объединяю ветвь От A до ветви B видно следующее поведение: 1. Дополнительные 5 файлов, которые не являются общими, удаляются. 2. Дополнительные строки в общих файлах в ветви B. удаляются.

Во время слияния ветви B с веткой A видно следующее поведение: 1. Дополнительные 5 файлов не добавляются в ветку A.

Я пробовал это и на GIT bash, и на Черепахе GIT и могу видеть то же самое поведение. Подскажите, пожалуйста, как мне справиться с этим сценарием, чтобы файлы не удалялись и не пропускались изменения.

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

Когда вы объединяете две ветви, Git рассматривает ровно три точки, чтобы рассмотреть, что объединить: две головы и третье место, называемое база слияния , которая обычно является точкой, в которой ветви разветвляются. Все, что он производит в результате слияния, является суммой изменений между базой слияния и каждой головкой. Другими словами, если вы вносите изменение с одной стороны, а не с другой, полученное объединение будет содержать это изменение.

В вашем случае в одной ветке вы удалили файлы, а в другой ветке вы сделали ничего с этими файлами. Поскольку удаление файлов считается изменением, оно включается в результат.

Если вы не хотите удалять эти файлы, настройте ветвь A так, чтобы она не удаляла их, а затем выполните объединение. Это лучший и самый простой способ решения проблемы.

В качестве альтернативы, вы можете сделать то, что называется злое слияние , которое является слиянием, когда вы вмешиваетесь в результат, который обычно Git обычно произвели. Если вы хотите сделать это, выполните объединение как обычно, затем запустите git checkout B -- file1 file2 file3 file4 file5, где файлы - это пути, которые были удалены. Затем запустите git commit --amend, чтобы squa sh изменения в коммите слияния.

0 голосов
/ 14 февраля 2020

Имена ветви здесь не важны. Какое значение имеют коммиты .

Хитрость заключается в том, чтобы получить ваши коммиты и найти базу слияния . База слияния - это место, где объединяются ваши филиалы. Давайте нарисуем ваши фактические ветви. Конечно, я должен угадать каковы ваши коммиты; Вы не показали нам свой репозиторий и его коммиты. Но они, вероятно, выглядят примерно так:

          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.)

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