Как клонировать репозиторий git с определенной ревизией / набором изменений?

Как я могу клонировать git-репозиторий с определенной ревизией, как я обычно делаю в Mercurial:

hg clone -r 3 /path/to/repository

21 ответ

Решение

ОБНОВЛЕНИЕ 2 Начиная с Git 2.5.0, описанная ниже функция может быть включена на стороне сервера с помощью переменной конфигурации uploadpack.allowReachableSHA1InWantздесь запрос функции GitHub и фиксация GitHub, включающая эту функцию. Обратите внимание, что некоторые серверы Git активируют эту опцию по умолчанию, например, Bitbucket Server включил ее с версии 5.5+. Посмотрите этот ответ на Stackexchange, чтобы узнать, как активировать опцию конфигурации.

ОБНОВЛЕНИЕ 1 Для версий Git 1.7 < v < 2.5 используйте git clone и git reset, как описано в ответе Вайбхава Баджпаи

Если вы не хотите получать полный репозиторий, вам, вероятно, не следует использовать clone, Вы всегда можете просто использовать выборку, чтобы выбрать ветку, которую хотите получить. Я не эксперт по рт, поэтому я не знаю деталей -r но в Git вы можете сделать что-то вроде этого.

# make a new blank repository in the current directory
git init

# add a remote
git remote add origin url://to/source/repository

# fetch a commit (or branch or tag) of interest
# Note: the full history up to this commit will be retrieved unless 
#       you limit it with '--depth=...' or '--shallow-since=...'
git fetch origin <sha1-of-commit-of-interest>

# reset this repository's master branch to the commit of interest
git reset --hard FETCH_HEAD
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

Чтобы снова вернуться к самой последней фиксации

$ git pull

Для клонирования только одного отдельного коммита в определенной ветви или теге используйте:

git clone --depth=1 --branch NAME https://github.com/your/repo.git

К несчастью, NAME может быть только именем ветви или именем тега (но не коммитом SHA).

Опустить --depth Отметить, чтобы загрузить всю историю, а затем оформить эту ветку или тег:

git clone --branch NAME https://github.com/your/repo.git

Это работает с последней версией Git (я сделал это с версией 2.18.0).

Клонирование репозитория git удачно клонирует весь репозиторий: не существует способа выбрать только одну ревизию для клонирования. Однако, как только вы выполните git clone, вы можете оформить заказ, выполнив checkout <rev>,

Вы можете использовать просто git checkout <commit hash>

в этой последовательности

bash git clone [URLTORepository] git checkout [commithash]

Хеш коммита выглядит следующим образом: "45ef55ac20ce2389c9180658fdba35f4a663d204"

Если вы имеете в виду, что хотите получить все от начала до определенного момента, ответ Чарльза Бейли идеален. Если вы хотите сделать обратное и получить подмножество истории, начиная с текущей даты, вы можете использовать git clone --depth [N] где N - это количество оборотов истории, которые вы хотите. Тем не мение:

--depth

Создайте неглубокий клон с историей, усеченной до указанного количества ревизий. Мелкий репозиторий имеет ряд ограничений (вы не можете клонировать или извлекать из него, ни выдвигать из него, ни в него), но он подходит, если вас интересует только недавняя история большого проекта с длинной историей, и вы хотите отправить исправления в виде исправлений.

Просто подвести итог (git v. 1.7.2.1):

  1. регулярно git clone где вы хотите репо (получает все на сегодняшний день - я знаю, не то, что нужно, мы добираемся туда)
  2. git checkout <sha1 rev> вы хотите
  3. git reset --hard
  4. git checkout -b master

TL;DR - Просто создайте тег в исходном репозитории против коммита, который вы хотите клонировать, и используйте тег в команде fetch. Вы можете удалить метку из исходного репо позже, чтобы очистить.

Ну, это 2014 год, и похоже, что принятый ответ Чарльза Бэйли от 2010 года к настоящему времени действительно устарел, и большинство (все?) Других ответов связаны с клонированием, которого многие люди надеются избежать.

Следующее решение позволяет достичь того, что ищет OP и многие другие, - это способ создать копию репозитория, включая историю, но только до определенного коммита.

Вот команды, которые я использовал с git версии 2.1.2 для клонирования локального репо (то есть репозитория в другом каталоге) до определенного момента:

# in the source repository, create a tag against the commit you want to check out
git tag -m "Temporary tag" tmptag <sha1>

# create a new directory and change into that directory
cd somewhere_else;mkdir newdir;cd newdir

# ...and create a new repository
git init

# add the source repository as a remote (this can be a URL or a directory)
git remote add origin /path/to/original/repo

# fetch the tag, which will include the entire repo and history up to that point
git fetch origin refs/tags/tmptag

# reset the head of the repository
git reset --hard FETCH_HEAD

# you can now change back to the original repository and remove the temporary tag
cd original_repo
git tag -d tmptag

Надеемся, что это решение будет работать еще несколько лет!:-)

Не нужно скачивать всю историю, и не нужно звонить git init:

      git clone --depth=1 URL
git fetch --depth=1 origin SHA1
git checkout SHA1
git branch -D @{-1}  # if you want to tidy up the fetched branch

Недостаток этого, на ответ CB Baileys, заключается в том , что вы все равно загрузите 1 ненужную версию. Но технически это git clone(чего хочет ОП), и это не заставляет вас загружать всю историю какой-то ветки.

Мне удалось сделать это с помощью параметра git clone --config, о котором я узнал из этого ответа: /questions/19945097/pochemu-git-clone-ne-prinimaet-refspec/19945101#19945101

В моем сценарии используется разреженная проверка в конвейере Azure DevOps, где мне нужно клонировать репо, используя хеш фиксации, а не имя ветки. Команда clone не принимает хеш фиксации в качестве параметра. Обходной путь - установить переменную конфигурации (-c), содержащую refspec, потому что эта refspec может использовать хэш фиксации вместо имени ветки:

      git clone -c remote.origin.fetch=+<commit hash>:refs/remotes/origin/<commit hash> <repo_url> --no-checkout --progress --depth 1
git sparse-checkout init --cone
git sparse-checkout set <file list>
git checkout <commit hash>

Использование 2 из приведенных выше ответов (" Как клонировать git-репозиторий с определенной ревизией / набором изменений?" И " Как клонировать git-репозиторий с определенной ревизией / changeset-кодом ?") Помогло мне найти определитель. Если вы хотите клонировать до какой-либо точки, то эта точка должна быть тегом / ветвью, а не просто SHA или FETCH_HEAD запутывается. Следуя набору git fetch, если вы используете имя ветви или тега, вы получите ответ, если вы просто используете SHA-1, вы не получите ответ.
Вот что я сделал:- создать полноценный рабочий клон полного репо из фактического источника

cd <path to create repo>
git clone git@<our gitlab server>:ui-developers/ui.git 

Затем создайте местную ветку, в точке, которая интересна

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Затем создайте мое новое пустое хранилище с моей локальной копией в качестве источника

cd <path to create repo>
mkdir reduced-repo
cd reduced-repo
git init
git remote add local_copy <path to create repo>/ui
git fetch local_copy origin_point

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

/ var/www/html/ui-hacking$ git fetch local_copy origin_point
Удаленный: Подсчет объектов: 45493, сделано.
Удаленный: Сжатие объектов: 100% (15928/15928), сделано.
удаленный: всего 45493 (дельта 27508), повторно используется 45387 (дельта 27463)
Получающие объекты: 100% (45493/45493), 53,64 МиБ | 50,59 МБ / с, готово.
Разрешение дельт: 100% (27508/27508), сделано.
От /var/www/html/ui
 * точка отправления ветви -> FETCH_HEAD
 * [новая ветвь]      origin_point -> origin/origin_point

Теперь в моем случае мне нужно было вернуть это обратно на gitlab, как свежий репо, поэтому я сделал

git remote add origin git@<our gitlab server>:ui-developers/new-ui.git

Это означало, что я мог восстановить свое хранилище с origin_point, используя git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -k чтобы вишня забрать, а затем использовать git push origin загрузить всю партию обратно в ее новый дом.

Надеюсь, что это помогает кому-то

Лично мой любимый способ клонирования одного коммита.

      mkdir repo && cd repo && git init
git remote add origin <url>
git fetch --depth 1 --no-tags --no-write-fetch-head origin tag <tag>
git branch master <tag>
git checkout

Чтобы избежать состояния отсоединенного заголовка, мы устанавливаем нашу ветку по умолчанию (в данном случае master) так, чтобы она указывала на наш тег/commit.

Что делает этот метод лучше, на мой взгляд, так это то, что он действительно извлекает только один тег. Мы также избегаем создания бесполезного FETCH_HEAD в качестве синтаксис сохранит тег локально в refs/tags/*. в предотвратит загрузку git других тегов, которые могут указывать на тот же коммит.

Альтернатива синтаксис будет

      git config --add remote.origin.fetch 'refs/tags/*:refs/tags/*'

Теперь наша операция выборки становится

      git fetch --depth 1 --no-write-fetch-head origin <tag>

Другие перечисленные методы, по моему опыту, загружают один коммит, а также все теги, связанные с этим конкретным коммитом. Например, проверьте любой из исходных репозиториев Google с помощью и вы получите кучу тегов, связанных с одним и тем же коммитом. Это не проблема для большинства, но это делает такие вещи, как довольно некрасиво, когда у вас есть 10-15 тегов, связанных с фиксацией. Третьей стороне также совершенно неясно, какой тег вас интересует. Скажем, вы клонировали это, чтобы добавить в качестве подмодуля в другой проект... пользователи не смогут сказать, что вас интересует тег x, когда он существует теги от s до z. В конечном счете, все теги указывают на один и тот же коммит, поэтому это не имеет значения, но наличие одного тега гораздо понятнее.

Моя версия была комбинацией принятых и наиболее одобренных ответов. Но это немного отличается, потому что все используют SHA1, но никто не говорит вам, как его получить

$ git init
$ git remote add <remote_url>
$ git fetch --all

теперь вы можете видеть все ветки и коммиты

$ git branch -a
$ git log remotes/origin/master <-- or any other branch

Наконец вы знаете SHA1 желаемого коммита

git reset --hard <sha1>
# clone special tag/branch without history
git clone  --branch=<tag/branch> --depth=1 <repository>


# clone special revision with minimal histories
git clone --branch <branch> <repository> --shallow-since=yyyy-MM-ddTHH:mm:ss  # get the commit time
cd <dir>
git reset --hard <revision> 

вы не можете получить ревизию без истории, если не установлен uploadpack.allowReachableSHA1InWant=true на стороне сервера, в то время как вы можете создать для него тег и вместо этого клонировать специальный тег.

git clone https://github.com/ORGANIZATION/repository.git (клонировать хранилище)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD

Я бы предложил, как описано ниже.

Следующее дано в других ответах.

  1. Клонируйте весь репозиторий, затемgit reset --hard $SHA1чтобы перейти к конкретному коммиту, заданному этим хэшем. (Вайбхав Баджпай)
  2. чтобы получить только последний коммит в конкретной ветке и ничего больше (ни истории, ни других веток) (Питер Ковач)
  3. чтобы получить всю историю (желаемой ветки И других веток) и указать последний коммит нужной ветки (Питер Ковач)

Однако они, похоже, не совсем соответствуют тому, о чем задается вопрос, по следующим причинам (соответствующим 3 предложениям выше):

  1. Клонирует весь репозиторий, а не только нужную ветку; Чтобы полный сброс работал, предполагается, что желаемый коммит находится в ветке default/master.
  2. Получается только последний коммит в нужной ветке. История нужной ветки не получена.
  3. Получена структура/история фиксации всего дерева (включая другие ветки), что может быть больше, чем требует вопрос.

Я бы предложил этоgit clone --single-branch --branch NAME https://github.com/your/repo.gitобеспечивает наиболее подходящий ответ: получена только вся история одной ветки, а указатель HEAD указывает на последний коммит (мы видим его как прямую линию с HEAD, указывающим на коммит вверху/на кончике), тогда как:

  • сgit clone --depth=1 --branch NAME https://github.com/your/repo.gitзатем показывает только кончик ветки
  • сgit clone --branch NAME https://github.com/your/repo.gitзатемgit log --all --graphпоказывает древовидную структуру с желаемой ветвью и другими ветвями, ответвляющимися в разное время от других коммитов.

Все вышеперечисленное было протестировано с помощью git версии 2.24.3; я это читал--single-branchбыл добавлен в git версии 1.7.10.

Это просто. Вы просто должны установить восходящий поток для текущей ветви

$ git clone repo
$ git checkout -b newbranch
$ git branch --set-upstream-to=origin/branch newbranch
$ git pull

Это все

Я использую этот фрагмент с GNU make, чтобы закрыть любой тег ревизии, ветку или хэш

он был протестирован на git версии 2.17.1

${dir}:
    mkdir -p ${@D}
    git clone --recursive --depth 1 --branch ${revison} ${url} ${@} \
 || git clone --recursive --branch ${revison} ${url} ${@} \
 || git clone ${url} ${@}
    cd ${@} && git reset --hard ${revison}
    ls $@




      mkdir linux-4.3.20151106
cd linux-4.3.20151106/
git init
git fetch git@github.com:torvalds/linux.git 9154301a47b33bdc273d8254c407792524367558

error: unknown option `no-write-fetch-head'        
usage: git fetch [<options>] [<repository> [<refspec>...]]   or: git fetch [<options>] <group>                                      
   or: git fetch --multiple [<options>] [(<repository> | <group>)...]   or: git fetch --all [<options>]       



 git --version
git version 2.17.1

export https_proxy=http://192.168.1.3:1080;export http_proxy=http://192.168.1.3:1080
add-apt-repository ppa:git-core/ppa
apt update
apt-get install --only-upgrade git

 git --version
git version 2.38.0


 git fetch git@github.com:torvalds/linux.git 9154301a47b33bdc273d8254c407792524367558 --no-write-fetch-head --depth=1 
remote: Enumerating objects: 54692, done.
remote: Counting objects: 100% (54692/54692), done.
remote: Compressing objects: 100% (50960/50960), done.
remote: Total 54692 (delta 3828), reused 29210 (delta 2966), pack-reused 0
Receiving objects: 100% (54692/54692), 147.35 MiB | 2.85 MiB/s, done.
Resolving deltas: 100% (3828/3828), done.
 


git branch master 9154301a47b33bdc273d8254c407792524367558


git checkout
 

Для отдельных файлов и когда известен номер фиксации, можно использовать wget onliner:

      wget https://raw.githubusercontent.com/torvalds/linux/896066ee1cf4d653057dac4e952f49c96ad16fa7/README
git clone -o <sha1-of-the-commit> <repository-url> <local-dir-name>

git использует слово origin вместо общеизвестных revision

Ниже приведен фрагмент из руководства $ git help clone

--origin <name>, -o <name>
    Instead of using the remote name origin to keep track of the upstream repository, use <name>.
Другие вопросы по тегам