TL; DR: вам нужно создать фактические имена ветвей для каждой ветви, которую вы хотите иметь в качестве ветви. Имена удаленного слежения просто не учитываются при клонировании (обычно). Это может быть очень дешево! Прочитайте подробное объяснение.
Вот дешевый способ создания локальных ветвей из каждого refs/remotes/svn/*
имени:
git for-each-ref --format='%(refname)' refs/remotes/svn |
while read name; do
local=${name#refs/remotes/svn/} # remove the icky part from the name
[ "$local" == HEAD ] && continue
git branch $local $name
done
. Это (примечание: не проверено, могут иметь незначительные ошибки)выведите сообщение об ошибке для тех имен, которые имеют соответствующие имена локальных ветвей;по-видимому, вы можете игнорировать это.
... Итак, я понял, что git клонирует только проверенные ветви, а не удаленные ...
Нетна самом деле не существует такой вещи, как «удаленная ветвь». Ну, если вы не определите «удаленную ветку» таким образом, чтобы она существовала. Что в конечном итоге ставит нас перед проблемой определения «ветви» в первую очередь: см. Что именно мы подразумеваем под «ветвью»? Когда мы осторожны с этим - в отличие от повседневного разговора - мне нравится бытьОбязательно используйте фразу из двух слов имя ветки для обозначения таких имен, как master
, которые на самом деле уже сокращены: см. ниже.
То, с чем Git имеет дело с commitits , как найдено names и другими коммитами. См. Думайте как (а) Git для правильного определения достижимости и множества связанных вещей, 1 , но общая идея заключается в том, что имена - полные именакак refs/heads/master
или refs/remotes/svn/foo
- каждый из них содержит хэш-идентификатор одного коммита. Этот коммит запоминает, какой коммит (ы) пришел прямо перед ним. Эти коммиты - родительский коммит - помнят их коммиты предшественника, бабушка и дедушка запоминают их предшественников и т. Д.
Что делает git clone
:
- создать новый пустой каталог (или использовать тот, который вы указали для использования);
- создать новый пустой репозиторий в этом каталоге, с помощью
git init
; - добавить remote , который состоит из простого имени, такого как
origin
и URL-адреса (и некоторой конфигурации - его можно перейти к шагу 4 или считать частью шага 3); - сделать любоедополнительная необходимая конфигурация;
- run
git fetch
;и в последний раз - введите
git checkout
для имени, которое вы предоставляете, или для других ресурсов Git, или - наихудший запасной вариант - попробуйте git checkout master
.
Шаг 5вот самый важный для вас здесь, потому что git fetch
- это то место, где находятся все основные действия.
Почему он не клонирует все ветви?
Когдаgit fetch
запускается, он получает список из other Git, в котором другой Git сообщает ему о всех его имен. Другой Git скажет, например: У меня есть refs/heads/master
, то есть commit a123456...
;У меня есть refs/remotes/svn/foo
, это коммит b789abc...
и т. Д.
Ваш Git затем выбрасывает любое имя, которое не начать с refs/heads/
или refs/tags/
. Результирующий список имен представляет собой имена веток Git и тегов . Все остальные имена попадают в другие категории. В частности, любое имя, начинающееся с refs/remotes/
, представляет собой имя для удаленного отслеживания , 2 , поэтому оно выбрасывается.
Затем ваш Git запрашивает у своего Gitкоммиты (по хеш-идентификатору) и любые другие объекты, необходимые для того, чтобы коммиты были полными и полезными. Ваш Git также запрашивает объекты, идентифицированные с помощью имен тегов, пока вы берете теги, хотя какие именно теги выбираются, когда становятся очень сложными, в зависимости от git fetch
параметров.
Как только ваш Git получает коммитобъекты и другие внутренние объекты, если / при необходимости, ваш Git затем копирует свои ветви имен - их refs/heads/master
и т. п. - в ваши имена для удаленного слежения. Их refs/heads/master
становится вашим refs/remotes/origin/master
. Их refs/heads/develop
(если таковой существует) становится вашим refs/remotes/origin/develop
.
Все это происходитs во время шага git fetch
(шаг 5). Такие параметры, как --single-branch
или --no-single-branch
, влияют на то, какие имена их ветвей совпадают, но не на преобразование имени ветви в имя удаленного отслеживания. Опция --mirror
влияет на преобразование , полностью исключая его, но иногда имеет и нежелательный побочный эффект:
Последний шаг, git checkout
на шаге 6 имеет один очень большой побочный эффект. Новый клон, который вы только что создали, имеет нет названий ветвей. 3 Так что git checkout master
или любое другое имя явно обречено на провал, верно? Но это не подводит. Вместо этого Git использует хитрый (?) Трюк: Когда вы просите проверить имя ветви, которая не существует, Git просматривает имена удаленного отслеживания , чтобы увидеть, есть ли такая, котораябудет соответствовать. Если это так, Git создаст (локальное) имя ветви, используя идентификатор хеша фиксации, сохраненный в соответствующем имени удаленного отслеживания.
Так что это создает ту ветку, о которой вы просили - или в этом случае, поскольку вы не указали одну ветку, другой Git сообщает вашему Git, какое имя ветви рекомендует другой Git. (Обычно это просто master
.) Это создаёт шаг 6.
Если у вас есть теги в репозитории origin
, у вас будет некоторое их количество - от нуля до всех - в новомклон тоже. Вы можете явно запросить теги позже, или нет, с более поздним git fetch
. Вы можете явно попросить , а не иметь теги в вашем новом клоне во время клонирования. Теги, которые у вас есть на данный момент, просто копируются из тегов в другом хранилище. Идея заключается в том, что, в отличие от имен веток, которые являются полностью частными для каждого репозитория, имена тегов будут общими для всех репозиториев, распределенных путем присоединения к репозиторию, почти как какой-то вирус. 4
Поскольку ваш исходный репозиторий имеет в основном только имена для удаленного отслеживания, а не ветви, ваш клон - мелкий или нет - пропускает эти имена и коммиты, которые доступны только из техnames.
1 Это немного отличается от SVN, в котором есть один центральный сервер, который может просто нумеровать каждую ревизию последовательно. Git буквально не может полагаться на последовательную нумерацию, потому что могут быть отдельные клоны, которые последовательно-но-параллельно-извиняются (извинения за не-слово здесь ?), получающие разные коммиты,То есть предположим, что клоны A и B идентичны и каждый имеет 500 коммитов. Затем Алиса, работающая в клоне А, создает коммит # 501. Тем временем Боб, работающий в клоне B, создает коммит # 501. Эти два коммита разные - возможно, в разных ветках - и оба они # 501. Последовательные номера здесь не могут работать.
2 Git называет это именем удаленного отслеживания ветви . Раньше я использовал эту фразу, но теперь я думаю, что слово branch здесь больше вводит в заблуждение, чем полезно. Вы можете называть это как хотите: просто помните, что это не имя branch , так как они на самом деле начинаются с refs/heads/
.
Примечание: Git обычно удаляет refs/heads/
, refs/tags/
и refs/remotes/
разделяются здесь при печати имен, при условии, что вывод все еще будет достаточно четким. Иногда Git удаляет только refs/
: попробуйте git branch -r
, затем попробуйте git branch -a
. (Чем они отличаются? Это загадка.)
3 Если вы использовали --mirror
, у вашего нового клона есть все имена ветвей, но затем git clone
пропускает шаг 6. Ваш новый клон пуст, поэтому нет рабочего дерева, и git checkout
не может быть использовано.
4 Это также способ распространения коммитов. Предположим, у вас есть коммиты W, X и Y подряд, которых у них нет. Вы подключаетесь к их Git как операция push
, и вы даете им все эти три коммита и просите их установить одно из их имен для запоминания коммита Y
, который запоминает X
, который запоминает W
, который запоминаеткоммит у них уже есть.
или: у них есть тон совершает, а ты нет. Вы подключаетесь к их Git как fetch
операция, они дают вам все три, и ваш Git устанавливает ваш origin/whatever
для запоминания коммита Y
сейчас.
По сути, вы получаете два репозитория Git для сопряжения. Один отправляет, другой получает. Получатель получает все новые данные, которые получатель запрашивает, которые отправляет отправитель, даже если получатель в конце концов действительно не хотел этого: в этот момент получатель может отклонить запрос на обновление какого-либо имени чтобы запомнить последний коммит в цепочке коммитов. Таким образом, получатель сохраняет свое старое имя и старый хэш-идентификатор или не имеет имени (и не имеет хэш-идентификатора).
Коммит или другой объект Git, у которого хэш-идентификатор не может найти его, в конечном итоге собирается сборщиком мусора. и выбросил. Для пустых репозиториев это имеет тенденцию быть быстрее, и, начиная с Git 2.11, сервер «получает коммиты и другие объекты Git» сначала помещает их в область карантина, прежде чем решить, что они хороши, и принять их или решить, что ониплохо и отвергая их. Принятые затем переносятся из карантина в реальную базу данных хранилища, а отклоненные быстро отбрасываются. До 2.11 полученные объекты сразу отправлялись, временно вздувая серверы, которые, например, отклоняли большие файлы (вспомните ограничения размера файла GitHub в 100 МБ).
Мелкие клоны изменяют (некоторые из) эти правила: с мелкимклон, получающий Git имеет специальный файл, полный хеш-идентификаторов. Ему не хватает этих фактических коммитов, но делает вид, что утверждает, что они есть, поэтому, когда отправитель спрашивает «у вас есть коммит X», ответом будет «да», так что отправитель никогда не отправляет коммит X.