Резюме: учитывая два неподключенных GIT-репозитория, которые фактически содержат две (измененные) версии одного и того же исходного кода, как я могу добавить одну в качестве восходящей по сравнению с другой?
Настройка восходящих потоковкак это тривиально.Создание графиков connect - это не так: вы просто получите два непересекающихся подграфа в своем собственном хранилище.
Помните, что Git - это всего лишь commits .У коммитов есть хэш-идентификаторы, и эти большие уродливые хэш-идентификаторы являются фактическими именами коммитов.Каждый коммит хранит хэш-идентификатор своего родительского коммита.Имена ветвей, такие как master
, или имена тегов, такие как v1.0
- это просто способы попасть в граф и сделать коммиты достижимыми , чтобы они не сгорали сборщиком мусора в Git.Для справки прочитайте сайт Думайте как (а) Git .
Обратите внимание, что идентификатор хэша коммита - это крипографическая контрольная сумма содержимого этого коммита.Содержимое включает хэш дерева и родительский хеш.Это означает, что сам график действует как Дерево Меркля и, следовательно, проверяет всю историю, но это также означает, что вы не можете изменить хэш-идентификатор любого коммита.
Итак, что происходит, когда вывозьмите несвязанный (графически) репозиторий и вставьте его в свой собственный репозиторий:
your-root--o--...--o <-- your-master
\
o <-- your-branch
o--...--o <-- their-branch-X
/
their-root--o--...--o---o--o <-- their-master
\ /
o--...--o <-- their-branch-Y
Нет общих коммитов - репозитории были созданы независимо;они не просто начинаются с некоторого общего клона, а затем расходятся, поэтому ваш корневой коммит и его корневой коммит также не связаны.
Это делает выполнение слияний практически невозможным.
есть решение, которое состоит в том, чтобы привить два графика вместе.Допустим, по счастливому совпадению, что два корня имеют одинаковый (или достаточно близкий) снимок , так что если бы мы добавили «супер корень» спереди, все было бы слитно:
your-root--o--...--o <-- your-master
/ \
/ o <-- your-branch
/
super
\
\ o--...--o <-- their-branch-X
\ /
their-root--o--...--o---o--o <-- their-master
\ /
o--...--o <-- their-branch-Y
Однако теперь мы сталкиваемся с проблемой дерева Merkle: если мы буквально добавим этот узел, мы должны скопировать все нисходящие узлы, т. Е. Все ваши коммиты и все их коммиты.Эти новые коммиты, сделанные путем копирования (но изменения чего-либо) каждого из оригиналов, будут иметь новые и разные хеш-идентификаторы.
Мы можем использовать git replace
, чтобы добавить узел более образно.Это действительно добавляет узел супер-корня (в ваш репозиторий), но на самом деле не делает его родителем двух существующих корней.Вместо этого мы создаем два коммита замены root, у которых в качестве родителя используется супер-корень, и даем Git команду «смотреть в сторону» на замены.Этот метод работает, но имеет недостаток: клонирование этого хранилища не дает вам заменяющих объектов по умолчанию.(Вы также можете специально запросить их, и тогда клон будет вести себя так же, как и хранилище с заменами.)
Если тот, кто владеет хранилищем «вверх по течению», желает переписать всю свою историю, и выготовы переписать всю вашу историю, есть решение и для этого.Если они не желают переписывать всю свою историю, все еще есть возможное решение, если их история, по крайней мере, настолько глубока, насколько вы заботитесь: вы можете переписать всю вашу историю, чтобы основать ее на всехиз их истории, отбрасывая любую предыдущую историю, которой у вас не было.
Ничто из этого не забавно, но все они могут быть собраны и протестированы с использованием git replace
для прививки (с этимизамена "виртуальных коммитов") двух непересекающихся графов вместе.Как только у вас появится график, подходящий для всех, запустите git filter-branch
, чтобы превратить виртуальный график в новый, другой физический график.Все коммиты, которые имеют новую историю, получают новые уникальные хэш-идентификаторы, и теперь вы можете заставить всех переключаться на новые репозитории вместо старых.