Есть ли способ отразить мастер другого репо только в неосновную ветку? - PullRequest
1 голос
/ 07 мая 2019

У меня есть два репо - репо 1 и репо 2, а репо 1 имеет две ветви - главную ветвь и ветку 1. Я хочу иметь возможность зеркально отразить основную ветку репо 2 только к ветви 1 и оставить главную ветвь репо 1 как есть. Есть способ сделать это? Есть ли способ зеркально отразить определенную ветвь для мастера другого репо (т.е. отразить ветку 1 репо 1 в репо 2)?

Я попытался следовать вашему типичному URL-адресу git clone --mirror, а затем URL-адресу git push --mirror для репо 1. Однако, похоже, это только подталкивает зеркало к основной ветке репо 1. Я также видел, что некоторые люди ссылаются на URL git push branch1 --mirror, но для этого я получаю фатальное: --mirror не может быть объединен с refspecs.

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

Ответы [ 2 ]

0 голосов
/ 08 мая 2019

Здесь вы можете делать все, что захотите.Настоящий трюк - сначала выяснить, чего вы хотите.После этого, это всего лишь вопрос refspecs , к которому я скоро вернусь.Однако, учитывая то, что вы сказали выше, вы не хотите какой-либо из параметров --mirror.

Выборки, push, имена и хеши фиксации

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

Другими словами, хэшИдентификаторы имеют реальное, конкретное значение.Это хеш-идентификаторы, которые имеют значение.Они являются валютой обмена Git-на-Git.

Имена ветвей , напротив, специфичны для одного или другого хранилища Git.Ваш master может быть совершенно не связан с my master, даже если наши два репозитория Git обмениваются коммитами.У меня есть мой Git, позвоните вашему Git;ваш Git говорит мне, что ваш master является коммитом a123456...;Я получаю этот коммит от вас, и он по-прежнему a123456..., но имя, которое я использую в Git, это совсем другое, например origin/master или dinh/master или yourbranch, или как угодно I называть этоЕсли вы скажете a123456..., а я скажу a123456..., мы можем сказать, что у нас обоих , что коммит.Ваше имя , если таковое имеется, и мое имя не нужно соглашаться, а с git fetch они обычно не согласны.

Команда git push не совсем симметрична, но работает примерно так же: мой Git вызывает ваш Git, предлагает вам некоторые коммиты по необработанному хеш-идентификатору (и ваш Git и мой согласны с ними как обычно),Затем я прошу (обычное нажатие) или команду (принудительное нажатие) ваш Git установить одно или несколько ваших имен для идентификации некоторых конкретных коммитов, которые я называю их универсальным, согласованным-на хэш-идентификаторах.

Мой Git может видеть ваши имена, когда я запускаю git fetch в вашем хранилище.По умолчанию для git fetch установлено, что мой Git копирует ваши имена, переименовывает их: именно поэтому у вас обычно будет origin/master в вашем Git, после того как ваш Git скопирует вещи из другого GitВы звоните origin.Тем временем, мой Git сообщает вашему Git имя, которое нужно использовать, когда я запускаю git push из моего хранилища.Для удобства я обычно сообщаю вашему Git мое имя ветки, когда я git push.Вот почему вы обычно толкаете master к исходному master: здесь не происходит переименование по умолчанию.

Хеш-идентификаторы против ссылок

Если хэш-идентификаторы - это то, как Git находит коммиты - и они- тогда почему, собственно, у нас вообще есть названия филиалов?Хорошо, рассмотрим некоторые фактические хеш-идентификаторы в реальном Git-репозитории:

83232e38648b51abbcbdb56c94632b6906cc85a6
aa8c8d914e4ae709e4fd025f359594f62653d9e5
061ed420ec2dc97e2a922a6f02992869089cefb3

Это три коммита, в порядке их создания (сначала самые новые).Можете ли вы вспомнить любой из этих чисел?(Может быть, но я бы не захотел бы .) Git нужно , чтобы запомнить все из них, но Git настроен так, что сам фиксирует 83232e...запоминает число aa8c8d..., а aa8c8d... запоминает число 061ed4....Так что нам нужно помнить только этого большого уродливого 83232e....Мы могли бы записать это;но было бы лучше, если бы Git записал для us.

Мы можем сделать это с помощью имени ветви, имени тега или любого другого такого имени. имя будет содержать 83232e..., и теперь нам нужно запомнить только имя .Эти имена в совокупности называются Git refs или reference .Имена ветвей - это имена, которые начинаются с refs/heads/, имена тегов начинаются с refs/tags/, а имена удаленного отслеживания начинаются с refs/remotes/ и продолжаются с имени удаленного устройства (например, refs/remotes/origin/).После последней косой черты у вас есть название ветки, тега или удаленного отслеживания.Git имеет тенденцию скрывать префикс, но он появляется время от времени, особенно при использовании полных ссылок.

Итак, у нас есть ссылки - имена ветвей, имена тегов, имена для удаленного отслеживания и т. Д. - которые помнят один идентификатор хэша. По этому одному хеш-идентификатору Git находит оставшиеся хеш-идентификаторы. Единственная особенность имен branch заключается в том, что мы можем использовать git checkout, чтобы "включить" ветку - git status скажет on branch master - и затем, как только мы это сделаем, мы можем сделать new commit. Новый коммит, который мы сделаем, будет помнить 83232e... для нас, и Git автоматически вставит хэш-идентификатор нового коммита, который будет новым и уникальным, отличным от любого другого коммита, в master, который теперь автоматически запоминает последний коммит. .

Следовательно, имена веток просто автоматически обозначают last commit в ветке. Из этого коммита, который Git находит по своему хеш-идентификатору, как это найдено под именем, Git находит предыдущий хеш-идентификатор, который возвращает Git в коммит, который получает другой предыдущий хэш-идентификатор и так далее. Результатом является история: серия коммитов, которые заканчиваются на назначенной подсказке, чей ID хеша хранится в имени ветви.

Когда git fetch и git push обмениваются коммитами, они делают это по хэш-идентификатору, но они также видят, а иногда и копируют имена. Это где refspecs войти.

Refspecs

Refspec - это, по сути, пара ссылок, разделенных двоеточием :, например ,::1135*

refs/heads/master:refs/remotes/origin/master

Вы можете поставить любую ссылку на любую сторону. Здесь у нас master слева - refs/heads/, помечающий его как имя ветви - и origin/master справа как имя удаленного слежения. Имя слева - источник , а имя справа - пункт назначения . Это тот тип refspec, который используется git fetch, потому что ссылка на источник является именем ветви, а ссылка назначения - именем удаленного отслеживания. Это говорит вашему Git: Используя их ветку master, получайте любые коммиты, которые у меня есть, и помните тот, который их master обозначает, используя мой origin/master.

С git push вы можете написать git push origin master:master. Ваш Git переведет это на refs/heads/master:refs/heads/master - с полным расширением имени на месте - и таким образом примет все ваши коммиты, которых у вас нет, отправит их, а затем попросит их установить их master перейти к последнему коммиту в этой цепочке. Или вы могли бы git push origin master:bren, сказав вашему Git взять ваш master - источник с левой стороны - и отправить любые ваши коммиты, которых у них нет, но затем попросить их установить свою ветвь bren.

Вы можете - и, по крайней мере, в сценариях, вероятно, должны - прописать полные имена, с refs/heads/ спереди. Это гарантирует, что если по какой-то причине кто-то случайно создаст тег с именем master, то нет никакой двусмысленности: вы имеете в виду branch refs/heads/master, а не тег refs/tags/master.

Любой refspec может предшествовать один знак плюс +. Это говорит Git: Выполните эту операцию, даже если вы обычно возражаете против этого. То есть он устанавливает флаг --force для этого конкретного обновления ссылки. Git обычно возражает, если изменение имени ветки потеряет некоторые коммиты, например. То есть, если имя ветви в настоящее время говорит «commit a123456», которое говорит «отсюда, вернитесь на один шаг назад к fedcba9», и вы попросите их установить свое имя на «fedcba9», они не смогут найти «a123456». "больше - направленные ссылки в коммитах указывают только в обратном направлении , на более старые коммиты, никогда не пересылаются на новые. (Подробнее об этом см. Думай как (а) Git .)

Соответствие Refspec и опции --mirror

Вы можете, и git fetch обычно это делает, использовать специальный метасимвол *, чтобы сопоставить все ветви:

+refs/heads/*:refs/remotes/origin/*

Этот ориентированный на выборку refspecговорит: Возьмите все их имена веток - все под refs/heads/ - и получите все коммиты и тому подобное, а затем принудительно обновите все мои имена удаленного отслеживания в refs/remotes/origin/, чтобы они соответствовали. Это нормальный refspec git fetch использует для связи с пультом с именем origin. Таким образом, вы получите все их ветки, в качестве имен для удаленного отслеживания.

Однако вы можете использовать от git clone --mirror до изменить эту ссылку на:

+refs/*:refs/*

Этот говорит: Берите все их ссылки, независимо от того, какие они имена, и перезаписывайте все мои ссылки с любыми хеш-идентификаторами в каждом из них. Это означает, что каждый git fetch заменяет все имена ваших веток и тегов. Любые ваши коммиты, которых у вас нет, теперь вы проиграли. Любые коммиты, которые у них есть, у вас нет, теперь у вас есть - и ваш клон теперь является их зеркалом.

Команда git push --mirror означает, что у вас будет ваша команда Git (как с --force или префиксом плюса) для:

  • создайте любые имена, которые у вас есть, которых у них нет;
  • обновить любые имена, которые вы изменили; и
  • удалите все имена, которые у вас есть, но вы не можете.

Это полностью уничтожает все их ветви, теги и другие имена, заменяя их вашими. (Конечно, вы сначала отправите любые свои коммиты и другие объекты, которые им понадобятся для выполнения этого действия.) Это зависит от того, будут ли они выполнять принудительные операции, но это обычная настройка по умолчанию.

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

Вы можете сделать это в любом направлении: вы можете git fetch repoA +refs/heads/theirs:refs/heads/mine заменить свою ветку mine последней версией theirs, и вы можете git push repoB +refs/heads/mine:refs/heads/theirs заменить их ветку theirs с последними новостями mine. За исключением того, где вы запускаете команду и направление потока данных, они почти симметричны: единственная реальная разница в том, что с git push они могут отказаться (через предварительный прием, обновление, или после получения крючка).

0 голосов
/ 07 мая 2019

Вы задали два вопроса:

  • Зеркало repo1:branch1 до repo2:master
  • Зеркало repo2:master до repo1:branch1

Вы можетевыполните оба эти действия в основном с одной и той же процедурой.


Зеркало repo1:branch1 до repo2:master

  1. Клон repo1.

    git clone <git URL for repo1>
    
  2. Введите ваш новый клон.

    cd repo1
    
  3. Настройте новый пульт для repo2 master ветви.

    git remote add -t master repo2 <git URL for repo2>
    
  4. Оформить заказ repo1:branch1

    git checkout branch1
    
  5. Нажмите repo1:branch1 до repo2:master.

    git push repo2 +branch1:master
    

Зеркало repo2:master до repo1:branch1

  1. Клон repo2.

    git clone <git URL for repo2>
    
  2. Введите новый клон.

    cd repo2
    
  3. Настройте новый пульт для repo1.

    git remote add -t branch1 <git URL for repo1>
    
  4. Оформление master для repo2 (возможно, уже извлечено)

    git checkout master
    
  5. Нажмите repo2:master до repo1:branch1

    git push repo1 +master:branch1
    
...