Получить конкретный коммит из удаленного Git-репозитория
Есть ли способ получить только один конкретный коммит из удаленного репозитория Git, не клонируя его на моем ПК? Структура удаленного репо абсолютно такая же, как у меня, и поэтому никаких конфликтов не будет, но я понятия не имею, как это сделать, и я не хочу клонировать этот огромный репозиторий.
Я новичок в мерзавце, есть ли способ?
11 ответов
Начиная с Git версии 2.5+ (второй квартал 2015 года), получение одного коммита (без клонирования полного репо) действительно возможно.
Смотрите коммит 68ee628 Фредрика Медли ( moroten
), 21 мая 2015 г.
(Объединено Юнио С Хамано - gitster
- в коммите a9d3493, 01 июня 2015 г.)
Теперь у вас есть новый конфиг (на стороне сервера)
uploadpack.allowReachableSHA1InWant
Разрешать
upload-pack
принять запрос на выборку, запрашивающий объект, доступный из любой ссылки ref. Тем не менее, обратите внимание, что вычисление достижимости объекта вычислительно дорого.
По умолчаниюfalse
,
Если вы объедините эту конфигурацию на стороне сервера с мелким клоном (git fetch --depth=1
), вы можете запросить один коммит (см. t/t5516-fetch-push.sh
:
git fetch --depth=1 ../testrepo/.git $SHA1
Вы можете использовать git cat-file
Команда, чтобы увидеть, что фиксация была получена:
git cat-file commit $SHA1
"
git upload-pack
"это служит"git fetch
"может быть сказано, что нужно обслуживать коммиты, которые не находятся на кончике какого-либо ссылки, если они достижимы из ссылки, сuploadpack.allowReachableSHA1InWant
переменная конфигурации.
Полная документация:
upload-pack
: опционально разрешить выборку достижимого ша1С
uploadpack.allowReachableSHA1InWant
параметр конфигурации установлен на стороне сервера,git fetch
"может сделать запрос с помощью строки" want ", в которой указан объект, который не был объявлен (вероятно, был получен вне диапазона или из указателя субмодуля).
Только объекты, достижимые из подсказок ветвей, т.е. объединение рекламируемых веток и скрытых ветокtransfer.hideRefs
, будет обработан.
Обратите внимание, что это связано с необходимостью обходить историю, чтобы проверить достижимость.Эта функция может использоваться при получении содержимого определенного коммита, для которого известен sha1, без необходимости клонирования всего репозитория, особенно если используется мелкая выборка.
Например, полезные случаи
- репозитории, содержащие большие файлы в истории,
- получение только необходимых данных для проверки субмодуля,
- при совместном использовании sha1, не сообщая, к какой именно ветви он принадлежит, и в Gerrit, если вы думаете не в виде чисел, а в терминах коммитов.
(Дело Геррита уже было решено путемallowTipSHA1InWant
так как каждое изменение Геррита имеет ссылку.)
Git 2.6 (3 квартал 2015 года) улучшит эту модель.
Смотрите коммит 2bc31d1, коммит cc118a6 (28 июля 2015 г.) Джеффа Кинга ( peff
)
(Объединено Юнио С Хамано - gitster
- в коммите 824a0be, 19 августа 2015 г.)
refs
: поддержка отрицательнаяtransfer.hideRefs
Если вы скрываете иерархию ссылок, используя
transfer.hideRefs
Конфиг, нет способа позже переопределить этот конфиг, чтобы "показать" его.
Этот патч реализует "отрицательное" скрытие, которое заставляет совпадения немедленно помечаться как скрытые, даже если другое совпадение скрыло бы это.
Мы позаботимся о том, чтобы применить совпадения в обратном порядке по сравнению с тем, как они поступают к нам с помощью механизма конфигурации, поскольку это позволяет нашему обычному приоритету конфигурации "последний выиграл" (и записи в.git/config
, например, переопределит/etc/gitconfig
).Итак, теперь вы можете сделать:
git config --system transfer.hideRefs refs/secret
git config transfer.hideRefs '!refs/secret/not-so-secret'
прятаться
refs/secret
во всех репо, кроме одного публичного бита в одном конкретном репо.
Git 2.7 (ноябрь / декабрь 2015) снова улучшится:
См. Коммит 948bfa2, коммит 00b293e (05 ноября 2015 г.), коммит 78a766a, коммит 92cab49, коммит 92cab49, коммит 92cab49 (03 ноя 2015 г.), коммит 00b293e, коммит 00b293e (05 ноября 2015 г.) и коммит 92cab49, коммит 92cab49, коммит 92cab49, совершить 92cab49 (3 ноября 2015 г.) от Лукаса Флейшера ( lfos
)
Помогает: Эрик Саншайн ( sunshineco
)
(Объединено Джеффом Кингом - peff
- в коммите dbba85e, 20 ноября 2015 г.)
config.txt
: документировать семантикуhideRefs
с пространствами именВ настоящее время нет четкого определения того, как
transfer.hideRefs
должен вести себя, когда пространство имен установлено.
Объяснить, чтоhideRefs
в этом случае префиксы совпадают с вычеркнутыми именами. Вот какhideRefs
шаблоны в настоящее время обрабатываются в receive-pack.hideRefs: добавить поддержку для сопоставления полных ссылок
В дополнение к сопоставлению лишенных ссылок теперь можно добавить
hideRefs
паттерны, с которыми сопоставляется полный (необрезанный) реф.
Чтобы различать разделенные и полные совпадения, эти новые шаблоны должны иметь префикс в виде окружности (^
).
Отсюда новая документация:
transfer.hideRefs:
Если пространство имен используется, префикс пространства имен удаляется из каждой ссылки перед сопоставлением с
transfer.hiderefs
узоры.
Например, еслиrefs/heads/master
указан вtransfer.hideRefs
и текущее пространство именfoo
, затемrefs/namespaces/foo/refs/heads/master
исключен из рекламы, ноrefs/heads/master
а такжеrefs/namespaces/bar/refs/heads/master
до сих пор рекламируются как так называемые строки "иметь".
Чтобы соответствовать ссылкам перед зачисткой, добавьте^
перед именем ссылки. Если вы объединяете!
а также^
,!
должен быть указан первым.
R... упоминает в комментариях свой конфиг uploadpack.allowAnySHA1InWant
, который позволяет upload-pack
принять fetch
запрос, который запрашивает любой объект вообще. (По умолчанию false
).
Смотрите коммит f8edeaa (ноябрь 2016, Git v2.11.1) Дэвида "novalis" Тернера ( novalis
):
upload-pack
: опционально разрешить выборку любого ша1Кажется немного глупым делать проверку достижимости в случае, когда мы доверяем пользователю получить доступ ко всему, что есть в хранилище.
Кроме того, это расплывчато в распределенной системе - возможно, один сервер объявляет ссылку, но другой с тех пор принудительно подталкивает эту ссылку, и, возможно, два HTTP-запроса в конечном итоге направляются на эти разные серверы.
Вы клонируете только один раз, поэтому, если у вас уже есть клон удаленного репозитория, извлечение из него не загрузит все снова. Просто укажите, какую ветвь вы хотите получить, или извлеките изменения и оформите коммит, который вы хотите.
Выборка из нового репозитория очень дешевая в полосе пропускания, поскольку она загружает только те изменения, которых у вас нет. Думайте с точки зрения Git, делающего правильную вещь, с минимальной нагрузкой.
Git хранит все в .git
папка. Коммит не может быть извлечен и сохранен изолированно, ему нужны все его предки. Они взаимосвязаны.
Однако, чтобы уменьшить размер загрузки, вы можете попросить git выбрать только объекты, связанные с определенной веткой или коммитом:
git fetch origin refs/heads/branch:refs/remotes/origin/branch
Это будет загружать только коммиты, содержащиеся в удаленной ветке branch
(и только те, которые вы пропустили), и сохранить его в origin/branch
, Затем вы можете объединить или оформить заказ.
Вы также можете указать только коммит SHA1:
git fetch origin 96de5297df870:refs/remotes/origin/foo-commit
Это загрузит только фиксацию указанного SHA-1 96de5297df870 (и его предков, которые вы пропустили) и сохранит ее как (несуществующую) удаленную ветку origin/foo-commit
,
Вы можете просто получить один коммит удаленного репо с
git fetch <repo> <commit>
где,
<repo>
может быть именем удаленного репо (например,origin
) или даже URL удаленного репо (например,https://git.foo.com/myrepo.git
)<commit>
может быть SHA1 коммит
например
git fetch https://git.foo.com/myrepo.git 0a071603d87e0b89738599c160583a19a6d95545
После того, как вы получили коммит (и пропавших предков), вы можете просто оформить его
git checkout FETCH_HEAD
Обратите внимание, что это приведет вас в состояние "оторванная голова".
Я сделал натяжение моего репозитория git:
git pull --rebase <repo> <branch>
Позволив git вытащить весь код для ветки, а затем я сделал сброс к коммиту, который меня заинтересовал.
git reset --hard <commit-hash>
Надеюсь это поможет.
Вы можете просто получить удаленное репо с:
git fetch <repo>
где,
<repo>
может быть именем удаленного репо (например,origin
) или даже URL удаленного репо (например,https://git.foo.com/myrepo.git
)
например:
git fetch https://git.foo.com/myrepo.git
После того, как вы получили репо, вы можете объединить нужные коммиты (поскольку вопрос заключается в получении одного коммита, вместо слияния вы можете использовать cherry-pick, чтобы выбрать только один коммит):
git merge <commit>
<commit>
может быть SHA1 коммит
например:
git cherry-pick 0a071603d87e0b89738599c160583a19a6d95545
или же
git merge 0a071603d87e0b89738599c160583a19a6d95545
Если это последний коммит, который вы хотите объединить, вы также можете использовать переменную FETCH_HEAD:
git cherry-pick (or merge) FETCH_HEAD
Это работает лучше всего:
git fetch origin specific_commit
git checkout -b temp FETCH_HEAD
назовите "temp" как хотите... эта ветка может быть осиротевшей
Наконец, я нашел способ клонировать конкретный коммит, используя git cherry-pick. Предполагая, что у вас нет локального хранилища и вы извлекаете конкретный коммит из удаленного,
1) создать пустой репозиторий в локальном и git init
2) git remote add origin "url-of-repository"
3) git fetch origin [это не переместит ваши файлы в ваше локальное рабочее пространство, если вы не объединитесь]
4) git cherry-pick "Enter-long-commit-hash-that-you-need"
Готово. Таким образом, вы будете иметь только файлы из этого конкретного коммита в вашем локальном.
Введите длиной фиксации-хэш:
Вы можете получить это используя -> git log --pretty = oneline
Я думаю, что 'git ls-remote' ( http://git-scm.com/docs/git-ls-remote) должен делать то, что вы хотите. Без силы извлекать или тянуть.
Если запрошенный коммит находится в запросах на удаление удаленного репо, вы можете получить его по его ID:
# Add the remote repo path, let's call it 'upstream':
git remote add upstream https://github.com/repo/project.git
# checkout the pull ID, for example ID '60':
git fetch upstream pull/60/head && git checkout FETCH_HEAD
# make sure you fetch from the origin first
$ git fetch origin
# view code at COMMIT_ID (abc123)
$ git checkout abc123
# bring only COMMIT_ID (abc123)
# to your branch
# assuming your branch is master
$ git checkout master
$ git cherry-pick abc123
# bring all changes up to
# COMMIT_ID (abc123) to your branch
# assuming your branch is master
$ git checkout master
$ git merge abc123
ссылка - https://unfuddle.com/stack/tips-tricks/git-pull-specific-commit/
В проекте у нас была проблема, и нам пришлось вернуться к определенной фиксации. Мы успешно сделали это с помощью следующей команды:
git reset --hard <commitID>