Bagaimana cara mengkloning git repositori dengan revisi / perubahan tertentu?

393

Bagaimana saya bisa mengkloning repositori git dengan revisi tertentu, sesuatu yang biasanya saya lakukan di Mercurial:

hg clone -r 3 /path/to/repository
John
sumber
3
Tidak spesifik untuk perubahan-set atau revisi, tetapi mengkloning terbaru di cabang tertentu bisa sama efektifnya git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees
Kemungkinan rangkap dari Unduh tag tertentu dengan Git
SlightlyCuban
Apakah Anda ingin riwayat menjadi dangkal, yaitu hanya berisi revisi 3 dalam contoh Anda, atau juga orang tuanya?
sschuberth
Jika repositori yang bersangkutan sedang dikloning dari dalam repositori lain dan Anda ingin mengkloning repo internal itu pada sha tertentu, maka git submodul melakukan hal itu dengan cara otomatis.
J0hnG4lt

Jawaban:

203

PEMBARUAN 2 Karena Git 2.5.0 fitur yang dijelaskan di bawah ini dapat diaktifkan di sisi server dengan variabel konfigurasi uploadpack.allowReachableSHA1InWant, di sini permintaan fitur GitHub dan komit GitHub mengaktifkan fitur ini . Perhatikan bahwa beberapa server Git mengaktifkan opsi ini secara default, mis. Bitbucket Server mengaktifkannya sejak versi 5.5+ . Lihat jawaban ini di Stackexchange untuk contoh cara mengaktifkan opsi konfigurasi.

UPDATE 1 Untuk versi Git 1.7 < v < 2.5gunakan git clone dan git reset, seperti yang dijelaskan dalam jawaban Vaibhav Bajpai

Jika Anda tidak ingin mengambil repositori penuh maka Anda mungkin tidak boleh menggunakan clone. Anda selalu dapat menggunakan fetch untuk memilih cabang yang ingin Anda ambil. Saya bukan ahli hg jadi saya tidak tahu detailnya -rtetapi di git Anda bisa melakukan sesuatu seperti ini.

# 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
CB Bailey
sumber
32
Saya pikir tidak git fetch origin <sha1>berhasil; sepertinya Anda perlu memberikan referensi nama seperti tag atau nama cabang. Lihat kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur
48
@artur: Anda pikir itu tidak berhasil, atau Anda sudah mencobanya dan tidak berhasil?
CB Bailey
37
Dengan git 1.4, saya menemukan bahwa saya dapat menggunakan git fetch origin <SHA1>untuk beralih ke revisi apa pun yang saya inginkan setelah saya mengambil master dari remote dan melakukan yang reset --hardsebenarnya instantiate cabang secara lokal. Saya tidak dapat mengambil revisi secara langsung. Dengan git 1.7, git fetch origin <SHA1>tidak berfungsi, seperti dilansir @artur; Anda perlu menggunakan git checkout <SHA1>diikuti oleh a reset --hard.
Joe McMahon
6
Mengambil oleh SHA-1 hanya akan berfungsi dengan protokol http dan rsync. Lihat kerneltrap.org/mailarchive/git/2009/1/14/4716044/...
CharlesB
23
Jawaban ini sudah usang. Ini tidak bekerja dengan git 1.7 atau git 1.8, baik dengan https: // atau protokol ssh. ("Tidak dapat menemukan ref remote df44398762393c67af487edeb0831ad9579df4aa" - itu bukan ref, ini adalah commit.)
Paŭlo Ebermann
839
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

Untuk kembali ke komit terbaru

$ git pull
Vaibhav Bajpai
sumber
13
Ini hanya berfungsi jika komit ada di cabang master, jika tidak maka akan mengacaukan referensi lokal. Mengapa git reset dan bukan git checkout?
Joky
72
Ini bukan pilihan yang baik untuk repo besar, karena menarik semuanya.
Incognito
1
Solusi ini harus di atas. Tidak ada yang peduli bahwa itu "tidak optimal", itu yang diminta OP. Secara khusus: "bagaimana saya mengkloning repositori git dengan revisi spesifik"?
Florian Segginger
20
@FlorianSegginger Jika saya ingin mengkloning revisi tertentu, mungkin saya tidak ingin mengkloning semuanya, tetapi hanya revisi itu. Bagi saya itu adalah pertanyaan yang diajukan. Solusi ini menjawab pertanyaan yang berbeda: "Bagaimana saya melihat revisi tertentu di repo saya?". Mengambil seluruh repo adalah apa yang ingin dihindari oleh banyak orang di sini.
Renato
1
Tidak menjawab IMHO pertanyaan yang sebenarnya, karena dapat menentukan revisi selama klon juga memungkinkan saya untuk menggunakan --depthyang sangat penting untuk repo besar. Solusi ini membutuhkan menarik semua objek, dan mengatur ulang ke revisi sebelumnya. Ini sangat memakan waktu dan boros bandwidth jaringan.
void.pointer
54

Mengkloning repositori git, dengan tepat, mengkloning seluruh repositori: tidak ada cara untuk memilih hanya satu revisi untuk dikloning. Namun, begitu Anda melakukan git clone, Anda dapat checkout revisi tertentu dengan melakukan checkout <rev>.


sumber
4
Saya tidak ingin mengkloning satu revisi saja. Saya hanya ingin menentukan batas kloning. Dengan kata lain, saya ingin mengkloning semuanya hingga revisi yang ditentukan.
John
6
Kamu tidak bisa melakukan itu git clonemeraih seluruh repositori. Setelah memilikinya, Anda dapat checkout revisi tertentu.
4
Satu hal yang perlu diperhatikan; Git umumnya cukup efisien untuk menyimpan histori, jadi Anda tidak akan menghemat banyak ruang hanya dengan mengkloning setengah dari revisi.
Amber
Ini bukan tentang "menghemat ruang" - ini tentang hanya bangun untuk revisi tertentu - seperti jika perubahan baru memperkenalkan bug, dan jadi saya tidak ingin perubahan terbaru - Anda mengatakan Git tidak dapat melakukan ini? Itu tidak benar - mengapa harus mengontrol sumber sama sekali jika Anda tidak dapat kembali ke versi yang lebih lama?
BrainSlugs83
1
"tidak ada cara untuk memilih hanya satu revisi untuk dikloning" - ya, ada:git clone --single-branch ...
morxa
33

Untuk mengkloning hanya satu komit tunggal pada cabang atau penggunaan tag tertentu:

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

Sayangnya, NAMEhanya bisa berupa nama cabang atau nama tag (bukan komit SHA).

Hilangkan --depthbendera untuk mengunduh seluruh riwayat dan kemudian memeriksa cabang atau tag itu:

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

Ini bekerja dengan git versi terbaru (saya melakukannya dengan versi 2.18.0).

Peter Kovac
sumber
tetapi tidak pada versi yang lebih lama 2.17.1
RzR
4
Ini membutuhkan lebih banyak upvotes. Ini jauh lebih baik daripada jawaban usang lainnya.
Étienne
32

Jika Anda ingin mengambil semuanya dari awal hingga titik tertentu, jawaban Charles Bailey sempurna. Jika Anda ingin melakukan kebalikan dan mengambil bagian dari riwayat yang kembali dari tanggal saat ini, Anda dapat menggunakan di git clone --depth [N] mana N adalah jumlah putaran sejarah yang Anda inginkan. Namun:

--kedalaman

Buat klon dangkal dengan riwayat terpotong ke jumlah revisi yang ditentukan. Repositori dangkal memiliki sejumlah keterbatasan (Anda tidak dapat mengkloning atau mengambil darinya, atau mendorong dari atau ke dalamnya), tetapi cukup jika Anda hanya tertarik pada sejarah baru-baru ini dari proyek besar dengan sejarah yang panjang, dan ingin kirim perbaikan sebagai tambalan.

Walter Mundt
sumber
4
Versi git yang lebih baru telah meningkatkan klon dangkal, dan Anda dapat menarik dan mendorongnya.
orion78fr
26

Singkatnya (git v. 1.7.2.1):

  1. lakukan secara teratur di git clonemana Anda ingin repo (mendapatkan segalanya untuk tanggal - saya tahu, bukan apa yang diinginkan, kami sampai di sana)
  2. git checkout <sha1 rev> dari rev yang Anda inginkan
  3. git reset --hard
  4. git checkout -b master
phill
sumber
6
apa yang dilakukan langkah 3 dan 4?
BrainSlugs83
Langkah 4 tidak berhasil untuk saya, tetapi sampai langkah 3 berhasil - Terima kasih
Gene Bo
@ BrainSlugs83: Langkah 4 membuat cabang lokal dipanggil masterdan beralih ke sana.
LarsH
3
@phill: Kenapa git reset --hard? Dokumen untuk itu mengatakan "Mereset ulang indeks dan pohon kerja. Setiap perubahan pada file yang dilacak di pohon kerja sejak <commit> [yang default ke HEAD, yang sekarang <sha1 rev>] dibuang." Tetapi pada saat ini kami belum melakukan perubahan sejak kloning, jadi apa tujuannya? Apakah itu memotong cabang saat ini di <sha1 rev>?
LarsH
19

TL; DR - Cukup buat tag di repositori sumber melawan komit yang ingin Anda tiru dan gunakan tag dalam perintah ambil. Anda dapat menghapus tag dari repo asli nanti untuk membersihkan.

Nah, ini 2014 dan sepertinya jawaban Charles Bailey yang diterima dari 2010 sudah baik dan benar-benar ketinggalan jaman sekarang dan sebagian besar (semua?) Jawaban lain melibatkan kloning, yang banyak orang berharap untuk menghindarinya.

Solusi berikut ini mencapai apa yang dicari OP dan banyak lainnya, yang merupakan cara untuk membuat salinan repositori, termasuk sejarah, tetapi hanya sampai komit tertentu.

Berikut adalah perintah yang saya gunakan dengan git versi 2.1.2 untuk mengkloning repo lokal (mis. Repositori di direktori lain) hingga titik tertentu:

# 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

Semoga solusi ini terus bekerja selama beberapa tahun lagi! :-)

JamesG
sumber
2
Ini adalah ide yang baik dari Anda adalah pemilik repo, tidak yakin apakah itu bekerja dengan repo publik yang tidak Anda pertahankan
Suhaib
18

Anda dapat menggunakannya secara sederhana git checkout <commit hash>

dalam urutan ini

bash git clone [URLTORepository] git checkout [commithash]

komit hash terlihat seperti ini "45ef55ac20ce2389c9180658fdba35f4a663d204"

M.Othman
sumber
seperti yang sebelumnya - mengapa checkout setelah Anda mengkloning. Setelah Anda mengkloning, Anda memiliki seluruh riwayat di repo lokal. Mengapa jawaban ini memiliki terlalu banyak upvotes?
Dmitry Perfilyev
2

Menggunakan 2 jawaban di atas ( Bagaimana mengkloning repositori git dengan revisi / perubahan tertentu? Dan Bagaimana mengkloning repositori git dengan revisi / perubahan tertentu? ) Membantu saya membuat definisi. Jika Anda ingin mengkloning suatu titik, maka titik itu harus berupa tag / cabang bukan hanya SHA atau FETCH_HEAD jadi bingung. Mengikuti set git fetch, jika Anda menggunakan nama cabang atau tag, Anda mendapatkan respons, jika Anda hanya menggunakan SHA-1, Anda tidak mendapatkan respons.
Inilah yang saya lakukan: - membuat klon kerja penuh dari repo penuh, dari asal sebenarnya

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

Kemudian buat cabang lokal, pada titik yang menarik

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Kemudian buat repo kosong baru saya, dengan salinan lokal saya sebagai asalnya

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

Pada saat itu saya mendapat tanggapan ini. Saya perhatikan karena jika Anda menggunakan SHA-1 sebagai pengganti cabang di atas, tidak ada yang terjadi, jadi responsnya, berarti berhasil

/ var / www / html / ui-hacking $ git untuk mengambil local_copy origin_point
jarak jauh: Menghitung objek: 45493, selesai.
jarak jauh: Mengompresi objek: 100% (15928/15928), selesai.
jarak jauh: Total 45493 (delta 27508), digunakan kembali 45387 (delta 27463)
Menerima objek: 100% (45493/45493), 53,64 MiB | 50,59 MiB / s, selesai.
Menyelesaikan delta: 100% (27508/27508), selesai.
Dari / var / www / html / ui
 * branch origin_point -> FETCH_HEAD
 * [cabang baru] origin_point -> origin / origin_point

Sekarang dalam kasus saya, saya kemudian perlu mengembalikannya ke gitlab, sebagai repo baru jadi saya lakukan

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

Yang berarti saya bisa membangun kembali repo saya dari origin_point dengan menggunakan git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -kuntuk memilih cherry dari jarak jauh kemudian menggunakan git push originuntuk mengunggah seluruh lot kembali ke rumah barunya.

Semoga itu bisa membantu seseorang

sibaz
sumber
Bisakah Anda menjelaskan apa yang Anda maksud dengan "FETCH_HEAD bingung"? Dan bagaimana git fetch local_copy origin_pointperbedaan Anda dari JamesGs git fetch origin refs/tags/tmptag?
not2qubit
The git fetch local_copy origin_pointmeninggalkan Anda dalam keadaan dengan kosong reduced-repodirektori, hanya berisi .git. Ada sesuatu yang hilang dari instruksi ini ...
not2qubit
2

Versi saya adalah kombinasi dari jawaban yang diterima dan paling banyak dipilih. Tapi ini sedikit berbeda, karena semua orang menggunakan SHA1 tetapi tidak ada yang memberitahu Anda cara mendapatkannya

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

sekarang Anda dapat melihat semua cabang & melakukan

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

Akhirnya Anda tahu SHA1 dari komit yang diinginkan

git reset --hard <sha1>
vladkras
sumber
1

Saya menggunakan cuplikan ini dengan GNU make untuk menutup tag revisi, cabang, atau hash

itu diuji pada git versi 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 $@




RzR
sumber
0

git clone https://github.com/ORGANIZATION/repository.git (mengklon repositori)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD

JeffDropsIT
sumber
2
mengapa menjemput setelah Anda mengkloning. Setelah Anda mengkloning, Anda memiliki seluruh riwayat di repo lokal. Mengapa jawaban ini memiliki dua upvotes?
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> 

Anda tidak bisa mendapatkan revisi tanpa riwayat jika tidak diatur uploadpack.allowReachableSHA1InWant=truedi sisi server, sementara Anda dapat membuat tag untuk itu dan mengkloning tag khusus sebagai gantinya.

wongoo
sumber
-3

Itu mudah. Anda hanya perlu mengatur upstream untuk cabang saat ini

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

Itu saja

NEOJPK
sumber
-4
git clone -o <sha1-of-the-commit> <repository-url> <local-dir-name>

gitmenggunakan kata ini originsebagai ganti dari yang terkenalrevision

Berikut ini adalah cuplikan dari manual $ git help clone

--origin <name>, -o <name>
    Instead of using the remote name origin to keep track of the upstream repository, use <name>.
hell_ical_vortex
sumber
4
Tidak tahu mengapa Anda dipilih di sini; ini adalah persis apa yang saya harapkan untuk dilihat pada kasus penggunaan saya: Mendapatkan versi tertentu dari kernel Linux dari versi yang mereka tidak memiliki akal yang baik untuk menandai sebagai rilis (tampaknya menjadi masalah dengan orang-orang RPi), tanpa mengunduh seluruh sejarah multi-gigabyte Linux. Kebetulan, itu berhasil memperlakukan.
Fordi
1
--depth=1tidak disebutkan dalam jawaban, jadi mengapa Anda mengatakan jawaban ini berhasil jika Anda menambahkan lebih banyak hal yang tidak disebutkan di sini? Saya senang itu berhasil untuk Anda, tetapi jawaban ini menyesatkan dan sebagian tidak menjawab pertanyaan. Karena itu downvotes.
Emil Styrke
5
@Fordi: Tidak. Menggunakan jawaban ini kata demi kata membuat Anda pohon yang persis sama dengan yang Anda dapatkan dari vanilla git clone <url> <local_dir_name>, coba saja sendiri. Satu-satunya perbedaan adalah bahwa remote (ditampilkan menggunakan git remote) akan disebut beberapa urutan shta cryptic bukannya nama "asal" yang biasa. Dengan kata lain, yang <sha1-of-the-commit>disebutkan dalam jawaban ini tidak ada kaitannya dengan revisi mana yang diambil dari server atau cabang mana yang akan diperiksa.
Emil Styrke
6
@Fordi: Saya baru saja melakukannya git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. Ini memberi saya revisi 8a28d674dan bukan 896066ee seperti yang Anda dan jawaban ini klaim.
Emil Styrke
4
menekankan bahwa "asal" tidak ada hubungannya dengan "revisi" dan jawaban ini sepenuhnya salah.
Eevee