Як клонувати репозиторій 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 у своєму прикладі, або також це батьки?
sschuberth

Якщо відповідний сховище клонується з іншого сховища і ви хочете клонувати це внутрішнє репо в конкретному ша, то підмодулі git роблять саме це автоматичним способом.
J0hnG4lt

Відповіді:


202

ОНОВЛЕННЯ 2 Оскільки Git 2.5.0, описана нижче функція може бути включена на сервері зі змінною конфігурації uploadpack.allowReachableSHA1InWant, тут запит на функцію GitHub та GitHub зобов’язують цю функцію . Зауважте, що деякі сервери Git активують цю опцію за замовчуванням, наприклад, сервер Bitbucket включив її з версії 5.5+ . Дивіться цю відповідь на Stackexchange для прикладу того, як активувати параметр конфігурації.

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

Якщо ви не хочете отримати повний сховище, ви, ймовірно, не повинні використовувати clone. Ви завжди можете просто отримати функцію "Вибір", щоб вибрати галузь, яку ви хочете отримати. Я не експерт з 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>а потім a 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. ( «Не вдалося знайти віддалений реф df44398762393c67af487edeb0831ad9579df4aa» - це не посилання, це зробити.)
PAULO Еберманн

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

Щоб знову повернутися до останнього комітету

$ git pull

13
Це працює лише в тому випадку, якщо фіксація знаходиться в головній гілці, якщо ні, то вона зіпсує локальну посилання. Чому git скидає, а не git checkout в першу чергу?
Жарти

72
Це не гарний варіант для великих репостів, оскільки він все тягне.
інкогніто

1
Це рішення повинно бути зверху. Ніхто не переймається тим, що це "не оптимально", це те, про що попросила ОП. Конкретно: "як мені клонувати git сховище конкретною редакцією"?
Флоріан Сегінгер

20
@FlorianSegginger Якщо я хочу клонувати певну редакцію, то, мабуть, я не хочу клонувати все, а лише цю редакцію. Мені це було запитання. Це рішення відповідає на інше запитання: "Як я бачу конкретну редакцію в моїй репо?". Збір всього репо - це саме те, чого багато людей хочуть тут уникати.
Ренато

1
Не стосується фактичного питання IMHO, оскільки можливість встановити ревізію під час клонування також дозволяє мені використовувати, --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 - кількість обертів історії, яку ви хочете. Однак:

- поглиблення

Створіть неглибокий клон з усіченою історією до визначеної кількості ревізій. Неглибоке сховище має ряд обмежень (ви не можете його клонувати чи вибирати з нього, ані проштовхуватись із нього, ані всуватися в нього), але є адекватним, якщо вас цікавить лише недавня історія великого проекту з довгою історією, і ви хочете надсилати виправлення у вигляді патчів.


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 - Просто створіть тег у вихідному сховищі проти коміту, до якого ви хочете клонуватись, і використовуйте тег у команді "Вибір". Пізніше ви можете видалити тег з початкового репо, щоб очистити.

Що ж, його 2014 рік, і схоже, що прийнята відповідь Чарльза Бейлі з 2010 року вже є справді застарілою, і більшість (усіх?) Інших відповідей передбачають клонування, чого багато людей сподіваються уникнути.

Наступним рішенням досягається те, що шукають ОП та багато інших, це спосіб створити копію сховища, включаючи історію, але лише до певної комісії.

Ось команди, які я використав з 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
 * відділення origin_point -> FETCH_HEAD
 * [нова гілка] origin_point -> origin / origin_point

Тепер у моєму випадку мені тоді потрібно було повернути це на гітлаб, як свіже репо, так що я і зробив

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. До речі, це спрацювало частування.
Форді

1
--depth=1у відповіді не згадується, так чому б ви сказали, що ця відповідь спрацювала, якщо ви додали більше речей, які тут не згадуються? Я щасливий, що це склалось для вас, але ця відповідь вводить в оману і не відповідає частково на питання. Звідси низості.
Еміль Стірке

5
@Fordi: Ні. Використовуючи цю відповідь, дослівно ви отримаєте саме те саме дерево, що і ваніль git clone <url> <local_dir_name>, просто спробуйте самі. Єдина відмінність полягає в тому, що віддалений (показаний за допомогою git remote) буде називатися якоюсь криптованою послідовністю sha1 замість імені "походження", що є звичним. Іншими словами, <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.