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


393

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

hg clone -r 3 /path/to/repository

3
Не специфично для наборов изменений или ревизий, но клонирование последних в определенной ветке может быть столь же эффективным, как git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees


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

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

Ответы:


203

ОБНОВЛЕНИЕ 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. Вы всегда можете просто использовать fetch, чтобы выбрать ветку, которую хотите получить. Я не эксперт по hg, поэтому я не знаю деталей, -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

32
Я не думаю, что git fetch origin <sha1>работает; кажется, что вам нужно передать именованную ссылку, такую ​​как имя тега или ветви. См. Kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur

48
@artur: Ты не думаешь, что это работает, или ты попробовал это, и это не работает?
CB Bailey

37
С помощью git 1.4 я обнаружил, что могу использовать git fetch origin <SHA1>переключатель для переключения на любую ревизию, какую захочу, после того, как получу мастер с пульта и выполнил reset --hardфактическую инстанцирование ветви локально. Я не смог получить отдельные ревизии напрямую. С git 1.7 git fetch origin <SHA1>не работал, как сообщает @artur; вам нужно использовать с git checkout <SHA1>последующим reset --hard.
Джо МакМэхон

6
Выборка по SHA-1 будет работать только с протоколами http и rsync. См kerneltrap.org/mailarchive/git/2009/1/14/4716044/...
CharlesB

23
Этот ответ устарел. Это не работает ни с git 1.7, ни с git 1.8, ни с https: //, ни с протоколом ssh. («Не удалось найти удаленный ref df44398762393c67af487edeb0831ad9579df4aa» - это не ссылка, это коммит.)
Paŭlo Ebermann

839
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

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

$ git pull

13
Это работает только в том случае, если коммит находится в основной ветке, если нет, он испортит локальную ссылку. Почему git reset, а не git checkout в первую очередь?
Шутка

72
Это не хороший вариант для больших репо, так как он тянет все.
Инкогнито

1
Это решение должно быть на вершине. Никого не волнует, что это «не оптимально», это то, о чем просил ОП. В частности: «как мне клонировать git-репозиторий с определенной ревизией»?
Флориан Сеггингер

20
@FlorianSegginger Если я хочу клонировать конкретную ревизию, вероятно, я не хочу клонировать все, но только эту ревизию. Для меня это был заданный вопрос. Это решение отвечает на другой вопрос: «Как просмотреть конкретную ревизию в моем репо?». Получение всего репо - это именно то, чего многие люди здесь хотят избежать.
Ренато

1
ИМХО не отвечает на реальный вопрос, поскольку возможность указать ревизию во время клонирования также позволяет мне использовать, --depthчто очень важно для больших репозиториев. Это решение требует извлечения всех объектов, а затем возврата к более ранней версии. Это очень много времени и трата пропускной способности сети.
void.pointer

54

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


4
Я не хочу клонировать только одну ревизию. Я просто хочу указать предел клонирования. Другими словами, я хочу клонировать все до указанной ревизии.
Джон

6
Вы не можете сделать это. git cloneзахватывает весь репозиторий. Как только вы его получите, вы можете оформить заказ.

4
Стоит отметить одну вещь; Git, как правило, довольно эффективно хранит историю, так что это не значит, что вы сэкономите огромное количество места, клонируя только половину ревизий.
Янтарная

Речь идет не о «экономии места» - речь идет только о переходе к конкретной ревизии - например, если новое изменение внесло ошибку, и поэтому я не хочу, чтобы это новейшее изменение - вы говорите, что Git не может сделать это? Это не может быть правдой - зачем вообще нужен контроль версий, если вы не можете откатиться на более старую версию?
BrainSlugs83

1
«нет способа выбрать только одну ревизию для клонирования» - да, есть:git clone --single-branch ...
morxa

33

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

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).


но не на более старой версии 2.17.1
RzR

4
Это требует больше голосов. Это намного лучше, чем другие устаревшие ответы.
Этьен

32

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

--depth

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


4
В более новой версии git улучшены мелкие клоны, и вы можете тянуть и толкать их.
orion78fr

26

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

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

6
что делают шаги 3 и 4?
BrainSlugs83

Шаг 4 не работал для меня, но до шага 3 добился цели - Спасибо
Джин Бо

@ BrainSlugs83: Шаг 4 создает локальную ветвь с именем masterи переключается на нее.
LarsH

3
@phill: почему git reset --hard? Документы для этого говорят: «Сбрасывает индекс и рабочее дерево. Любые изменения отслеживаемых файлов в рабочем дереве, так как <commit> [по умолчанию HEAD, который сейчас <sha1 rev>] отбрасывается». Но на данный момент мы не внесли никаких изменений с момента клонирования, так какова цель? Это обрезает текущую ветку в <sha1 rev>?
LarsH

19

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

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


2
Это хорошая идея, что вы являетесь владельцем репо, но не уверены, что он работает с публичными репо, которые вы не поддерживаете
Suhaib

18

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

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

bash git clone [URLTORepository] git checkout [commithash]

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


как и предыдущий - зачем оформлять заказ после клонирования. Как только вы клонируете, у вас есть вся история в локальном репо. Почему в этом ответе слишком много голосов?
Дмитрий Перфильев

2

Использование 2 из приведенных выше ответов (« Как клонировать git-репозиторий с определенной ревизией / набором изменений?» И « Как клонировать git-репозиторий с определенной ревизией / набором изменений?» ) Помогло мне найти определитель. Если вы хотите клонировать до некоторой точки, то эта точка должна быть тегом / ветвью, а не просто 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для загрузки всего лота в его новый дом.

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


Можете ли вы объяснить, что вы имеете в виду под "FETCH_HEAD запутывается"? А чем вы git fetch local_copy origin_pointотличаетесь от JamesGs git fetch origin refs/tags/tmptag?
not2qubit

git fetch local_copy origin_pointОставить вас в состоянии с пустым reduced-repoкаталогом, только содержащим .git. В этих инструкциях чего-то не хватает ...
not2qubit

2

Моя версия была комбинацией принятых и наиболее одобренных ответов. Но это немного отличается, потому что все используют 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>

1

Я использую этот фрагмент с 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 $@





0

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

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD


2
зачем искать после клона Как только вы клонируете, у вас есть вся история в локальном репо. Почему в этом ответе есть два ответа?
Madhairsilence

0
# 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на стороне сервера, тогда как вы можете создать для нее тег и клонировать специальный тег.


-3

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

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

Это все


-4
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>.

4
Понятия не имею, почему вы получаете здесь проголосовали; это было именно то, что я надеялся увидеть в моем случае использования: получение конкретной версии ядра Linux из версии, которую не имело смысла отмечать как релиз (кажется, проблема с людьми из RPi), без загрузка всей мультигигабайтной истории Linux. Кстати, это сработало.
Fordi

1
--depth=1не упоминается в ответе, так почему вы сказали бы, что этот ответ сработал, если вы добавили больше вещей, которые здесь не упомянуты? Я рад, что это сработало для вас, но этот ответ вводит в заблуждение и не отвечает на вопрос даже частично. Отсюда и недостатки.
Эмиль Стирке

5
@Fordi: Нет Используя этот ответ дословно получает вас точно такое же дерево , как вы получили бы от ванили git clone <url> <local_dir_name>, просто попробуйте сами. Единственное отличие состоит в том, что удаленный (показанный с использованием git remote) будет называться некой загадочной последовательностью sha1 вместо обычного имени «origin». Другими словами, <sha1-of-the-commit>упомянутое в этом ответе не имеет никакого отношения к тому, какие ревизии выбираются с сервера или какая ветвь будет проверена.
Эмиль Стирке

6
@Fordi: я только что сделал git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. Это дает мне пересмотр, 8a28d674а не 896066ee как вы и этот ответ утверждает.
Эмиль Стирке

4
подчеркивая, что «происхождение» не имеет ничего общего с «пересмотром», и этот ответ совершенно неверен.
Eevee
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.