Последствия флага --allow-unrelated-history - PullRequest
0 голосов
/ 13 июня 2018

Вот ситуация:

  • Я клонировал большой текущий репозиторий проекта, скажем RepoA
  • Скопировал все файлы без папки .git в новую папку RepoB
  • Сделал git init и добавил другой пульт в RepoB
  • Я работал на RepoB и выдвинул много коммитов на пульт
  • Они такжеподтолкнул множество коммитов в RepoA

Теперь я хочу объединить свою работу с их репо.Это то, что я сделал в RepoA.

git checkout develop  
git remote add repoBOrigin https://www.cloud.com/repoB.git   
git fetch repoBOrigin aBranchOfRepoB // all of the work is in this branch  
git merge repoBOrigin/aBranchOfRepoB  

И я получил эту ошибку: fatal: refusing to merge unrelated histories

Я посмотрел это на stackoverflow и обнаружил, что это можно решить с помощью--allow-unrelated-histories флаг, но это сопровождается предупреждением о том, что его следует использовать в редких случаях.

Теперь, я действительно обеспокоен тем, какие эффекты / проблемы вызовет этот флаг.Как будет развиваться история мерзавцев RepoA?

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

1 Ответ

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

меня беспокоит то, что эффекты / проблемы --allow-unrelated-histories вызовут ...

Сам флаг ничего не вызывает.Он выполняет действие, которое не соответствует ожиданиям новых пользователей Git.

Чтобы понять его - или Git в целом, на самом деле - вам нужно иметь некоторые базовые знания о графиках, как это определено обычными математическимиопределение, в котором граф G представляет собой набор вершин V , соединенных ребрами E или записанных в обычных обозначениях, G = (V,E) .Когда у ребер есть направление - своего рода односторонняя стрелка, так что каждая вершина (или узел) «переходит» к другой вершине, но вы не можете вернуться назад, ребра называются arcs .

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

A  <-B  <-C   <--master

Commit A это первый сделанный вами коммит, поэтому у него нет родителя.Commit B перечисляет commit A в качестве родителя, а C перечисляет B в качестве родителя;и Git находит commit C - чье настоящее имя, то есть его хеш-идентификатор, выглядит совершенно случайным - используя имя master для хранения хеш-идентификатора C.

Зная, что эти ссылки -дуги - все идут в обратном направлении, от дочернего к родительскому, мы можем рисовать их более удобно в виде ссылок и добавлять больше коммитов:

A--B--C--D   <-- master
    \
     E--F--G   <-- branch

Если мы теперь перейдем к объединить ответвление обратно вmaster, Git использует эти соединительные стрелки, чтобы выяснить, где в истории ваша работа по master разделялась на чью-либо работу в branch.Это снова в коммите B, где узлы графа воссоединяются.Теперь Git может сравнить снимок, сохраненный в этой базе слияния B, с кончиком master:

git diff --find-renames <hash-of-B> <hash-of-D>

, чтобы выяснить, что вы изменили.Затем Git может сравнить снимок в B со снимком в кончике branch:

git diff --find-renames <hash-of-B> <hash-of-G>

Акт слияния - глагол to merge - делает эти два сравнения иобъединяет их, применяя объединенные изменения к тому, что было в базовом коммите.Если все идет хорошо, Git фиксирует окончательный результат самостоятельно.(Если нет, Git останавливается и заставляет вас убрать беспорядок и выполнять коммит самостоятельно; что входит в этот коммит, зависит от того, как вы исправите конфликты, обнаруженные Git.) В результате получается Фиксация слияния , не с одним, а с двумя родителями:

A--B--C--D---H   <-- master (HEAD)
    \       /
     E--F--G   <-- branch

Опять же, снимок исходного кода для нового коммита слияния H - эторезультат объединения изменений , сделанных после базы слияния, - общая отправная точка двух кончиков ветвей.

Однако в вашем случае вы сделали два несвязанных репозитория .Результатом является то, что математики называют несвязным графом .Это может выглядеть примерно так, например:

A--B--C--D---H   <-- br1
    \       /
     E--F--G

        L--M
       /    \
I--J--K------N   <-- br2

Если вы теперь git checkout одна из этих двух ветвей, так что HEAD присоединяется, скажем, к br1, и запускаете git merge br2, Git идет, чтобы найти общую отправную точку, работая в обратном направлении (влево) из двух кончиков веток.Но нет общей отправной точки: истории не связаны.

Старые версии Git просто продолжали бы и сливались.Новые жалуются, если вы не поставите флаг;если вы поставите флаг, они продолжат и объединятся точно таким же образом.

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

Это означает, чтоКаждый файл в каждой из двух ветвей создается заново.Два файла с одинаковым именем пути вызовут "конфликт добавления / добавления": Git говорит, что you написал README.txt с нуля, и они write README.txt с нуля, и сам Git не знает, как их объединить, поэтому вы должны сделать это самостоятельно.Это повторяется для каждого файла с тем же именем.

С другой стороны, если вы создали README.md, а они создали README.rst, два имени отличаются, поэтому Git предполагает, что правильный способ объединенияREADME.md ни с чем - это взять README.md, а правильный способ объединить README.rst с ничем - это взять README.rst.Таким образом, вы получите оба файла, и Git считает, что теперь они правильно объединены.(Это правда? Я понятия не имею. Так же как и Git, но Git предполагает , что это правда.)

Это повторяется для всех файлов: либо каждое имя файла уникально для этого конкретного diff,поэтому Git добавляет его или нет, поэтому Git объявляет конфликт и оставляет его на ваше усмотрение, чтобы решить проблему.В конце, если не было конфликтов имен файлов, Git делает новый коммит самостоятельно;если были конфликты, Git заставляет вас их убирать и делать коммит самостоятельно.Мы можем нарисовать новый коммит:

A--B--C--D---H-----O   <-- br1 (HEAD)
    \       /     /
     E--F--G     /
                /
        L--M   /
       /    \ /
I--J--K------N   <-- br2

Было ли это разумно сделать?Я не могу ответить на это;только ты можешь ответить на это.

...